Merge vvaintroub@bk-internal.mysql.com:/home/bk/mysql-5.0-build
into wva.:C:/bk/bug31745_2/mysql-5.0-build sql/sql_parse.cc: Auto merged
This commit is contained in:
commit
54fc802a6c
@ -48,7 +48,7 @@ ENDIF(DISABLE_GRANT_OPTIONS)
|
|||||||
|
|
||||||
ADD_EXECUTABLE(mysqld${MYSQLD_EXE_SUFFIX}
|
ADD_EXECUTABLE(mysqld${MYSQLD_EXE_SUFFIX}
|
||||||
../sql-common/client.c derror.cc des_key_file.cc
|
../sql-common/client.c derror.cc des_key_file.cc
|
||||||
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
|
discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc
|
||||||
filesort.cc gstream.cc ha_blackhole.cc
|
filesort.cc gstream.cc ha_blackhole.cc
|
||||||
ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.cc
|
ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.cc
|
||||||
ha_innodb.cc ha_federated.cc ha_berkeley.cc
|
ha_innodb.cc ha_federated.cc ha_berkeley.cc
|
||||||
|
225
sql/mysqld.cc
225
sql/mysqld.cc
@ -138,6 +138,13 @@ extern "C" { // Because of SCO 3.2V4.2
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN__
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#define SIGNAL_FMT "exception 0x%x"
|
||||||
|
#else
|
||||||
|
#define SIGNAL_FMT "signal %d"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __NETWARE__
|
#ifdef __NETWARE__
|
||||||
#define zVOLSTATE_ACTIVE 6
|
#define zVOLSTATE_ACTIVE 6
|
||||||
#define zVOLSTATE_DEACTIVE 2
|
#define zVOLSTATE_DEACTIVE 2
|
||||||
@ -227,6 +234,7 @@ inline void set_proper_floating_point_mode()
|
|||||||
extern "C" int gethostname(char *name, int namelen);
|
extern "C" int gethostname(char *name, int namelen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern "C" sig_handler handle_segfault(int sig);
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
|
|
||||||
@ -1031,9 +1039,6 @@ static void __cdecl kill_server(int sig_ptr)
|
|||||||
#endif
|
#endif
|
||||||
close_connections();
|
close_connections();
|
||||||
if (sig != MYSQL_KILL_SIGNAL &&
|
if (sig != MYSQL_KILL_SIGNAL &&
|
||||||
#ifdef __WIN__
|
|
||||||
sig != SIGINT && /* Bug#18235 */
|
|
||||||
#endif
|
|
||||||
sig != 0)
|
sig != 0)
|
||||||
unireg_abort(1); /* purecov: inspected */
|
unireg_abort(1); /* purecov: inspected */
|
||||||
else
|
else
|
||||||
@ -1592,8 +1597,7 @@ static void network_init(void)
|
|||||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
(LPTSTR) &lpMsgBuf, 0, NULL );
|
(LPTSTR) &lpMsgBuf, 0, NULL );
|
||||||
MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
|
sql_perror((char *)lpMsgBuf);
|
||||||
MB_OK|MB_ICONINFORMATION);
|
|
||||||
LocalFree(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
unireg_abort(1);
|
unireg_abort(1);
|
||||||
}
|
}
|
||||||
@ -1796,17 +1800,163 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#if defined(__WIN__) || defined(OS2)
|
#if defined(__WIN__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C
|
||||||
|
with graceful shutdown.
|
||||||
|
Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it
|
||||||
|
provides possibility to pass the exception to just-in-time debugger, collect
|
||||||
|
dumps and potentially also the exception and thread context used to output
|
||||||
|
callstack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static BOOL WINAPI console_event_handler( DWORD type )
|
||||||
|
{
|
||||||
|
DBUG_ENTER("console_event_handler");
|
||||||
|
if(type == CTRL_C_EVENT)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Do not shutdown before startup is finished and shutdown
|
||||||
|
thread is initialized. Otherwise there is a race condition
|
||||||
|
between main thread doing initialization and CTRL-C thread doing
|
||||||
|
cleanup, which can result into crash.
|
||||||
|
*/
|
||||||
|
if(hEventShutdown)
|
||||||
|
kill_mysql();
|
||||||
|
else
|
||||||
|
sql_print_warning("CTRL-C ignored during startup");
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
In Visual Studio 2005 and later, default SIGABRT handler will overwrite
|
||||||
|
any unhandled exception filter set by the application and will try to
|
||||||
|
call JIT debugger. This is not what we want, this we calling __debugbreak
|
||||||
|
to stop in debugger, if process is being debugged or to generate
|
||||||
|
EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (_MSC_VER >= 1400)
|
||||||
|
static void my_sigabrt_handler(int sig)
|
||||||
|
{
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
#endif /*_MSC_VER >=1400 */
|
||||||
|
|
||||||
|
void win_install_sigabrt_handler(void)
|
||||||
|
{
|
||||||
|
#if (_MSC_VER >=1400)
|
||||||
|
/*abort() should not override our exception filter*/
|
||||||
|
_set_abort_behavior(0,_CALL_REPORTFAULT);
|
||||||
|
signal(SIGABRT,my_sigabrt_handler);
|
||||||
|
#endif /* _MSC_VER >=1400 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
|
||||||
|
#define DEBUGGER_ATTACH_TIMEOUT 120
|
||||||
|
/*
|
||||||
|
Wait for debugger to attach and break into debugger. If debugger is not attached,
|
||||||
|
resume after timeout.
|
||||||
|
*/
|
||||||
|
static void wait_for_debugger(int timeout_sec)
|
||||||
|
{
|
||||||
|
if(!IsDebuggerPresent())
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId());
|
||||||
|
fflush(stdout);
|
||||||
|
for(i= 0; i < timeout_sec; i++)
|
||||||
|
{
|
||||||
|
Sleep(1000);
|
||||||
|
if(IsDebuggerPresent())
|
||||||
|
{
|
||||||
|
/* Break into debugger */
|
||||||
|
__debugbreak();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(),
|
||||||
|
timeout_sec);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
|
||||||
|
|
||||||
|
LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
|
||||||
|
{
|
||||||
|
static BOOL first_time= TRUE;
|
||||||
|
if(!first_time)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This routine can be called twice, typically
|
||||||
|
when detaching in JIT debugger.
|
||||||
|
Return EXCEPTION_EXECUTE_HANDLER to terminate process.
|
||||||
|
*/
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
first_time= FALSE;
|
||||||
|
#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
|
||||||
|
/*
|
||||||
|
Unfortunately there is no clean way to debug unhandled exception filters,
|
||||||
|
as debugger does not stop there(also documented in MSDN)
|
||||||
|
To overcome, one could put a MessageBox, but this will not work in service.
|
||||||
|
Better solution is to print error message and sleep some minutes
|
||||||
|
until debugger is attached
|
||||||
|
*/
|
||||||
|
wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT);
|
||||||
|
#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
set_exception_pointers(ex_pointers);
|
||||||
|
handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode);
|
||||||
|
}
|
||||||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
DWORD written;
|
||||||
|
const char msg[] = "Got exception in exception handler!\n";
|
||||||
|
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1,
|
||||||
|
&written,NULL);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger
|
||||||
|
(drwtsn32 or vsjitdebugger) possibility to attach,
|
||||||
|
if JIT debugger is configured.
|
||||||
|
Windows Error reporting might generate a dump here.
|
||||||
|
*/
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void init_signals(void)
|
static void init_signals(void)
|
||||||
{
|
{
|
||||||
int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
|
win_install_sigabrt_handler();
|
||||||
for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
|
if(opt_console)
|
||||||
signal(signals[i], kill_server) ;
|
SetConsoleCtrlHandler(console_event_handler,TRUE);
|
||||||
#if defined(__WIN__)
|
else
|
||||||
signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
|
{
|
||||||
#else
|
/* Avoid MessageBox()es*/
|
||||||
signal(SIGBREAK, kill_server);
|
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
|
||||||
#endif
|
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
||||||
|
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
|
||||||
|
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
||||||
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
|
||||||
|
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (),
|
||||||
|
because it would prevent JIT debugger and Windows error reporting
|
||||||
|
from working. We need WER or JIT-debugging, since our own unhandled
|
||||||
|
exception filter is not guaranteed to work in all situation
|
||||||
|
(like heap corruption or stack overflow)
|
||||||
|
*/
|
||||||
|
SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
|
||||||
|
}
|
||||||
|
SetUnhandledExceptionFilter(my_unhandler_exception_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_signal_handler(void)
|
static void start_signal_handler(void)
|
||||||
@ -2094,8 +2244,8 @@ static void start_signal_handler(void)
|
|||||||
|
|
||||||
static void check_data_home(const char *path)
|
static void check_data_home(const char *path)
|
||||||
{}
|
{}
|
||||||
|
#endif /*__WIN__ || __NETWARE || __EMX__*/
|
||||||
|
|
||||||
#else /* if ! __WIN__ && ! __EMX__ */
|
|
||||||
|
|
||||||
#ifdef HAVE_LINUXTHREADS
|
#ifdef HAVE_LINUXTHREADS
|
||||||
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
||||||
@ -2115,7 +2265,7 @@ extern "C" sig_handler handle_segfault(int sig)
|
|||||||
*/
|
*/
|
||||||
if (segfaulted)
|
if (segfaulted)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
|
fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2125,7 +2275,7 @@ extern "C" sig_handler handle_segfault(int sig)
|
|||||||
localtime_r(&curr_time, &tm);
|
localtime_r(&curr_time, &tm);
|
||||||
|
|
||||||
fprintf(stderr,"\
|
fprintf(stderr,"\
|
||||||
%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\
|
%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\
|
||||||
This could be because you hit a bug. It is also possible that this binary\n\
|
This could be because you hit a bug. It is also possible that this binary\n\
|
||||||
or one of the libraries it was linked against is corrupt, improperly built,\n\
|
or one of the libraries it was linked against is corrupt, improperly built,\n\
|
||||||
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
|
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
|
||||||
@ -2166,6 +2316,10 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
|
|||||||
if (!(test_flags & TEST_NO_STACKTRACE))
|
if (!(test_flags & TEST_NO_STACKTRACE))
|
||||||
{
|
{
|
||||||
fprintf(stderr,"thd=%p\n",thd);
|
fprintf(stderr,"thd=%p\n",thd);
|
||||||
|
fprintf(stderr,"\
|
||||||
|
Attempting backtrace. You can use the following information to find out\n\
|
||||||
|
where mysqld died. If you see no messages after this, something went\n\
|
||||||
|
terribly wrong...\n");
|
||||||
print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
|
print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
|
||||||
thread_stack);
|
thread_stack);
|
||||||
}
|
}
|
||||||
@ -2214,15 +2368,22 @@ of those buggy OS calls. You should consider whether you really need the\n\
|
|||||||
bugs.\n");
|
bugs.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_WRITE_CORE
|
||||||
if (test_flags & TEST_CORE_ON_SIGNAL)
|
if (test_flags & TEST_CORE_ON_SIGNAL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Writing a core file\n");
|
fprintf(stderr, "Writing a core file\n");
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
write_core(sig);
|
write_core(sig);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __WIN__
|
||||||
|
/* On Windows, do not terminate, but pass control to exception filter */
|
||||||
exit(1);
|
exit(1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(__EMX__)
|
||||||
#ifndef SA_RESETHAND
|
#ifndef SA_RESETHAND
|
||||||
#define SA_RESETHAND 0
|
#define SA_RESETHAND 0
|
||||||
#endif
|
#endif
|
||||||
@ -2567,19 +2728,6 @@ static void my_str_free_mysqld(void *ptr)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
|
|
||||||
struct utsname
|
|
||||||
{
|
|
||||||
char nodename[FN_REFLEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int uname(struct utsname *a)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pthread_handler_t handle_shutdown(void *arg)
|
pthread_handler_t handle_shutdown(void *arg)
|
||||||
{
|
{
|
||||||
MSG msg;
|
MSG msg;
|
||||||
@ -2593,18 +2741,6 @@ pthread_handler_t handle_shutdown(void *arg)
|
|||||||
kill_server(MYSQL_KILL_SIGNAL);
|
kill_server(MYSQL_KILL_SIGNAL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int STDCALL handle_kill(ulong ctrl_type)
|
|
||||||
{
|
|
||||||
if (ctrl_type == CTRL_CLOSE_EVENT ||
|
|
||||||
ctrl_type == CTRL_SHUTDOWN_EVENT)
|
|
||||||
{
|
|
||||||
kill_server(MYSQL_KILL_SIGNAL);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -3633,11 +3769,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
|||||||
freopen(log_error_file,"a+",stderr);
|
freopen(log_error_file,"a+",stderr);
|
||||||
FreeConsole(); // Remove window
|
FreeConsole(); // Remove window
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Don't show error dialog box when on foreground: it stops the server */
|
|
||||||
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,22 +98,7 @@ static bool do_command(THD *thd);
|
|||||||
#endif // EMBEDDED_LIBRARY
|
#endif // EMBEDDED_LIBRARY
|
||||||
|
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
static void test_signal(int sig_ptr)
|
extern void win_install_sigabrt_handler(void);
|
||||||
{
|
|
||||||
#if !defined( DBUG_OFF)
|
|
||||||
MessageBox(NULL,"Test signal","DBUG",MB_OK);
|
|
||||||
#endif
|
|
||||||
#if defined(OS2)
|
|
||||||
fprintf(stderr, "Test signal %d\n", sig_ptr);
|
|
||||||
fflush(stderr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
static void init_signals(void)
|
|
||||||
{
|
|
||||||
int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
|
|
||||||
for (int i=0 ; i < 7 ; i++)
|
|
||||||
signal( signals[i], test_signal) ;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void unlock_locked_tables(THD *thd)
|
static void unlock_locked_tables(THD *thd)
|
||||||
@ -1124,7 +1109,7 @@ pthread_handler_t handle_one_connection(void *arg)
|
|||||||
/* now that we've called my_thread_init(), it is safe to call DBUG_* */
|
/* now that we've called my_thread_init(), it is safe to call DBUG_* */
|
||||||
|
|
||||||
#if defined(__WIN__)
|
#if defined(__WIN__)
|
||||||
init_signals();
|
win_install_sigabrt_handler();
|
||||||
#elif !defined(OS2) && !defined(__NETWARE__)
|
#elif !defined(OS2) && !defined(__NETWARE__)
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
VOID(sigemptyset(&set)); // Get mask in use
|
VOID(sigemptyset(&set)); // Get mask in use
|
||||||
|
275
sql/stacktrace.c
275
sql/stacktrace.c
@ -13,11 +13,15 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
|
||||||
|
#define DONT_DEFINE_VOID 1
|
||||||
|
|
||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
|
#ifndef __WIN__
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <my_pthread.h>
|
#include <my_pthread.h>
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
@ -118,10 +122,7 @@ void print_stacktrace(gptr stack_bottom, ulong thread_stack)
|
|||||||
#endif
|
#endif
|
||||||
LINT_INIT(fp);
|
LINT_INIT(fp);
|
||||||
|
|
||||||
fprintf(stderr,"\
|
|
||||||
Attempting backtrace. You can use the following information to find out\n\
|
|
||||||
where mysqld died. If you see no messages after this, something went\n\
|
|
||||||
terribly wrong...\n");
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
__asm __volatile__ ("movl %%ebp,%0"
|
__asm __volatile__ ("movl %%ebp,%0"
|
||||||
:"=r"(fp)
|
:"=r"(fp)
|
||||||
@ -257,3 +258,267 @@ void write_core(int sig)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#else /* __WIN__*/
|
||||||
|
|
||||||
|
#include <dbghelp.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll)
|
||||||
|
We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000)
|
||||||
|
is missing some important functions like functions StackWalk64 or MinidumpWriteDump.
|
||||||
|
Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions);
|
||||||
|
typedef BOOL (WINAPI *SymGetModuleInfo64_FctType)
|
||||||
|
(HANDLE,DWORD64,PIMAGEHLP_MODULE64) ;
|
||||||
|
typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType)
|
||||||
|
(HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ;
|
||||||
|
typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType)
|
||||||
|
(HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64);
|
||||||
|
typedef BOOL (WINAPI *SymInitialize_FctType)
|
||||||
|
(HANDLE,PSTR,BOOL);
|
||||||
|
typedef BOOL (WINAPI *StackWalk64_FctType)
|
||||||
|
(DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64,
|
||||||
|
PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 ,
|
||||||
|
PTRANSLATE_ADDRESS_ROUTINE64);
|
||||||
|
typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)(
|
||||||
|
IN HANDLE hProcess,
|
||||||
|
IN DWORD ProcessId,
|
||||||
|
IN HANDLE hFile,
|
||||||
|
IN MINIDUMP_TYPE DumpType,
|
||||||
|
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
|
||||||
|
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
|
||||||
|
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
|
||||||
|
);
|
||||||
|
|
||||||
|
static SymSetOptions_FctType pSymSetOptions;
|
||||||
|
static SymGetModuleInfo64_FctType pSymGetModuleInfo64;
|
||||||
|
static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64;
|
||||||
|
static SymInitialize_FctType pSymInitialize;
|
||||||
|
static StackWalk64_FctType pStackWalk64;
|
||||||
|
static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64;
|
||||||
|
static MiniDumpWriteDump_FctType pMiniDumpWriteDump;
|
||||||
|
|
||||||
|
static EXCEPTION_POINTERS *exception_ptrs;
|
||||||
|
|
||||||
|
#define MODULE64_SIZE_WINXP 576
|
||||||
|
#define STACKWALK_MAX_FRAMES 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dynamically load dbghelp functions
|
||||||
|
*/
|
||||||
|
BOOL init_dbghelp_functions()
|
||||||
|
{
|
||||||
|
static BOOL first_time= TRUE;
|
||||||
|
static BOOL rc;
|
||||||
|
HMODULE hDbghlp;
|
||||||
|
|
||||||
|
if(first_time)
|
||||||
|
{
|
||||||
|
first_time= FALSE;
|
||||||
|
hDbghlp= LoadLibrary("dbghelp");
|
||||||
|
if(!hDbghlp)
|
||||||
|
{
|
||||||
|
rc= FALSE;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
pSymSetOptions= (SymSetOptions_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"SymSetOptions");
|
||||||
|
pSymInitialize= (SymInitialize_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"SymInitialize");
|
||||||
|
pSymGetModuleInfo64= (SymGetModuleInfo64_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"SymGetModuleInfo64");
|
||||||
|
pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"SymGetLineFromAddr64");
|
||||||
|
pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"SymGetSymFromAddr64");
|
||||||
|
pStackWalk64= (StackWalk64_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"StackWalk64");
|
||||||
|
pMiniDumpWriteDump = (MiniDumpWriteDump_FctType)
|
||||||
|
GetProcAddress(hDbghlp,"MiniDumpWriteDump");
|
||||||
|
|
||||||
|
rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64
|
||||||
|
&& pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exception_pointers(EXCEPTION_POINTERS *ep)
|
||||||
|
{
|
||||||
|
exception_ptrs = ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
|
||||||
|
#ifndef SYMOPT_NO_PROMPTS
|
||||||
|
#define SYMOPT_NO_PROMPTS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void print_stacktrace(gptr unused1, ulong unused2)
|
||||||
|
{
|
||||||
|
HANDLE hProcess= GetCurrentProcess();
|
||||||
|
HANDLE hThread= GetCurrentThread();
|
||||||
|
static IMAGEHLP_MODULE64 module= {sizeof(module)};
|
||||||
|
static IMAGEHLP_SYMBOL64_PACKAGE package;
|
||||||
|
DWORD64 addr;
|
||||||
|
DWORD machine;
|
||||||
|
int i;
|
||||||
|
CONTEXT context;
|
||||||
|
STACKFRAME64 frame={0};
|
||||||
|
|
||||||
|
if(!exception_ptrs || !init_dbghelp_functions())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Copy context, as stackwalking on original will unwind the stack */
|
||||||
|
context = *(exception_ptrs->ContextRecord);
|
||||||
|
/*Initialize symbols.*/
|
||||||
|
pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
|
||||||
|
pSymInitialize(hProcess,NULL,TRUE);
|
||||||
|
|
||||||
|
/*Prepare stackframe for the first StackWalk64 call*/
|
||||||
|
frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
|
||||||
|
#if (defined _M_IX86)
|
||||||
|
machine= IMAGE_FILE_MACHINE_I386;
|
||||||
|
frame.AddrFrame.Offset= context.Ebp;
|
||||||
|
frame.AddrPC.Offset= context.Eip;
|
||||||
|
frame.AddrStack.Offset= context.Esp;
|
||||||
|
#elif (defined _M_X64)
|
||||||
|
machine = IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
frame.AddrFrame.Offset= context.Rbp;
|
||||||
|
frame.AddrPC.Offset= context.Rip;
|
||||||
|
frame.AddrStack.Offset= context.Rsp;
|
||||||
|
#else
|
||||||
|
/*There is currently no need to support IA64*/
|
||||||
|
#pragma error ("unsupported architecture")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
package.sym.SizeOfStruct= sizeof(package.sym);
|
||||||
|
package.sym.MaxNameLength= sizeof(package.name);
|
||||||
|
|
||||||
|
/*Walk the stack, output useful information*/
|
||||||
|
for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
|
||||||
|
{
|
||||||
|
DWORD64 function_offset= 0;
|
||||||
|
DWORD line_offset= 0;
|
||||||
|
IMAGEHLP_LINE64 line= {sizeof(line)};
|
||||||
|
BOOL have_module= FALSE;
|
||||||
|
BOOL have_symbol= FALSE;
|
||||||
|
BOOL have_source= FALSE;
|
||||||
|
|
||||||
|
if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
|
||||||
|
break;
|
||||||
|
addr= frame.AddrPC.Offset;
|
||||||
|
|
||||||
|
have_module= pSymGetModuleInfo64(hProcess,addr,&module);
|
||||||
|
#ifdef _M_IX86
|
||||||
|
if(!have_module)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
ModuleInfo structure has been "compatibly" extended in releases after XP,
|
||||||
|
and its size was increased. To make XP dbghelp.dll function
|
||||||
|
happy, pretend passing the old structure.
|
||||||
|
*/
|
||||||
|
module.SizeOfStruct= MODULE64_SIZE_WINXP;
|
||||||
|
have_module= pSymGetModuleInfo64(hProcess, addr, &module);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset,
|
||||||
|
&(package.sym));
|
||||||
|
have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
|
||||||
|
|
||||||
|
fprintf(stderr, "%p ", addr);
|
||||||
|
if(have_module)
|
||||||
|
{
|
||||||
|
char *base_image_name= strrchr(module.ImageName, '\\');
|
||||||
|
if(base_image_name)
|
||||||
|
base_image_name++;
|
||||||
|
else
|
||||||
|
base_image_name= module.ImageName;
|
||||||
|
fprintf(stderr, "%s!", base_image_name);
|
||||||
|
}
|
||||||
|
if(have_symbol)
|
||||||
|
fprintf(stderr, "%s()", package.sym.Name);
|
||||||
|
else if(have_module)
|
||||||
|
fprintf(stderr, "???");
|
||||||
|
|
||||||
|
if(have_source)
|
||||||
|
{
|
||||||
|
char *base_file_name= strrchr(line.FileName, '\\');
|
||||||
|
if(base_file_name)
|
||||||
|
base_file_name++;
|
||||||
|
else
|
||||||
|
base_file_name= line.FileName;
|
||||||
|
fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write dump. The dump is created in current directory,
|
||||||
|
file name is constructed from executable name plus
|
||||||
|
".dmp" extension
|
||||||
|
*/
|
||||||
|
void write_core(int unused)
|
||||||
|
{
|
||||||
|
char path[MAX_PATH];
|
||||||
|
char dump_fname[MAX_PATH]= "core.dmp";
|
||||||
|
MINIDUMP_EXCEPTION_INFORMATION info;
|
||||||
|
HANDLE hFile;
|
||||||
|
|
||||||
|
if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump)
|
||||||
|
return;
|
||||||
|
|
||||||
|
info.ExceptionPointers= exception_ptrs;
|
||||||
|
info.ClientPointers= FALSE;
|
||||||
|
info.ThreadId= GetCurrentThreadId();
|
||||||
|
|
||||||
|
if(GetModuleFileName(NULL, path, sizeof(path)))
|
||||||
|
{
|
||||||
|
_splitpath(path, NULL, NULL,dump_fname,NULL);
|
||||||
|
strncat(dump_fname, ".dmp", sizeof(dump_fname));
|
||||||
|
}
|
||||||
|
|
||||||
|
hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if(hFile)
|
||||||
|
{
|
||||||
|
/* Create minidump */
|
||||||
|
if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
|
||||||
|
hFile, MiniDumpNormal, &info, 0, 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Minidump written to %s\n",
|
||||||
|
_fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
|
||||||
|
GetLastError());
|
||||||
|
}
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
|
||||||
|
GetLastError());
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void safe_print_str(const char *name, const char *val, int len)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"%s at %p", name, val);
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
fprintf(stderr,"=%.*s\n", len, val);
|
||||||
|
}
|
||||||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"is an invalid string pointer\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /*__WIN__*/
|
||||||
|
@ -29,20 +29,33 @@ extern char* heap_start;
|
|||||||
heap_start = (char*) &__bss_start; \
|
heap_start = (char*) &__bss_start; \
|
||||||
check_thread_lib(); \
|
check_thread_lib(); \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
void check_thread_lib(void);
|
||||||
|
#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
|
||||||
|
#elif defined (__WIN__)
|
||||||
|
#define HAVE_STACKTRACE
|
||||||
|
extern void set_exception_pointers(EXCEPTION_POINTERS *ep);
|
||||||
|
#define init_stacktrace() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STACKTRACE
|
||||||
void print_stacktrace(gptr stack_bottom, ulong thread_stack);
|
void print_stacktrace(gptr stack_bottom, ulong thread_stack);
|
||||||
void safe_print_str(const char* name, const char* val, int max_len);
|
void safe_print_str(const char* name, const char* val, int max_len);
|
||||||
void check_thread_lib(void);
|
#else
|
||||||
#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
|
|
||||||
#endif /* TARGET_OS_LINUX */
|
|
||||||
|
|
||||||
/* Define empty prototypes for functions that are not implemented */
|
/* Define empty prototypes for functions that are not implemented */
|
||||||
#ifndef HAVE_STACKTRACE
|
|
||||||
#define init_stacktrace() {}
|
#define init_stacktrace() {}
|
||||||
#define print_stacktrace(A,B) {}
|
#define print_stacktrace(A,B) {}
|
||||||
#define safe_print_str(A,B,C) {}
|
#define safe_print_str(A,B,C) {}
|
||||||
#endif /* HAVE_STACKTRACE */
|
#endif /* HAVE_STACKTRACE */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(__NETWARE__)
|
||||||
|
#define HAVE_WRITE_CORE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_WRITE_CORE
|
||||||
void write_core(int sig);
|
void write_core(int sig);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user