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}
|
||||
../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
|
||||
ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.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>
|
||||
#endif
|
||||
|
||||
#ifdef __WIN__
|
||||
#include <crtdbg.h>
|
||||
#define SIGNAL_FMT "exception 0x%x"
|
||||
#else
|
||||
#define SIGNAL_FMT "signal %d"
|
||||
#endif
|
||||
|
||||
#ifdef __NETWARE__
|
||||
#define zVOLSTATE_ACTIVE 6
|
||||
#define zVOLSTATE_DEACTIVE 2
|
||||
@ -227,6 +234,7 @@ inline void set_proper_floating_point_mode()
|
||||
extern "C" int gethostname(char *name, int namelen);
|
||||
#endif
|
||||
|
||||
extern "C" sig_handler handle_segfault(int sig);
|
||||
|
||||
/* Constants */
|
||||
|
||||
@ -1031,9 +1039,6 @@ static void __cdecl kill_server(int sig_ptr)
|
||||
#endif
|
||||
close_connections();
|
||||
if (sig != MYSQL_KILL_SIGNAL &&
|
||||
#ifdef __WIN__
|
||||
sig != SIGINT && /* Bug#18235 */
|
||||
#endif
|
||||
sig != 0)
|
||||
unireg_abort(1); /* purecov: inspected */
|
||||
else
|
||||
@ -1592,8 +1597,7 @@ static void network_init(void)
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf, 0, NULL );
|
||||
MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
|
||||
MB_OK|MB_ICONINFORMATION);
|
||||
sql_perror((char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
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)
|
||||
{
|
||||
int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
|
||||
for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
|
||||
signal(signals[i], kill_server) ;
|
||||
#if defined(__WIN__)
|
||||
signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
|
||||
#else
|
||||
signal(SIGBREAK, kill_server);
|
||||
#endif
|
||||
win_install_sigabrt_handler();
|
||||
if(opt_console)
|
||||
SetConsoleCtrlHandler(console_event_handler,TRUE);
|
||||
else
|
||||
{
|
||||
/* Avoid MessageBox()es*/
|
||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
|
||||
_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)
|
||||
@ -2094,8 +2244,8 @@ static void start_signal_handler(void)
|
||||
|
||||
static void check_data_home(const char *path)
|
||||
{}
|
||||
#endif /*__WIN__ || __NETWARE || __EMX__*/
|
||||
|
||||
#else /* if ! __WIN__ && ! __EMX__ */
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
||||
@ -2115,7 +2265,7 @@ extern "C" sig_handler handle_segfault(int sig)
|
||||
*/
|
||||
if (segfaulted)
|
||||
{
|
||||
fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
|
||||
fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -2125,7 +2275,7 @@ extern "C" sig_handler handle_segfault(int sig)
|
||||
localtime_r(&curr_time, &tm);
|
||||
|
||||
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\
|
||||
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",
|
||||
@ -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))
|
||||
{
|
||||
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,
|
||||
thread_stack);
|
||||
}
|
||||
@ -2214,15 +2368,22 @@ of those buggy OS calls. You should consider whether you really need the\n\
|
||||
bugs.\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_WRITE_CORE
|
||||
if (test_flags & TEST_CORE_ON_SIGNAL)
|
||||
{
|
||||
fprintf(stderr, "Writing a core file\n");
|
||||
fflush(stderr);
|
||||
write_core(sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __WIN__
|
||||
/* On Windows, do not terminate, but pass control to exception filter */
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(__EMX__)
|
||||
#ifndef SA_RESETHAND
|
||||
#define SA_RESETHAND 0
|
||||
#endif
|
||||
@ -2567,19 +2728,6 @@ static void my_str_free_mysqld(void *ptr)
|
||||
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
struct utsname
|
||||
{
|
||||
char nodename[FN_REFLEN];
|
||||
};
|
||||
|
||||
|
||||
int uname(struct utsname *a)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
pthread_handler_t handle_shutdown(void *arg)
|
||||
{
|
||||
MSG msg;
|
||||
@ -2593,18 +2741,6 @@ pthread_handler_t handle_shutdown(void *arg)
|
||||
kill_server(MYSQL_KILL_SIGNAL);
|
||||
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
|
||||
|
||||
|
||||
@ -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);
|
||||
FreeConsole(); // Remove window
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't show error dialog box when on foreground: it stops the server */
|
||||
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -98,22 +98,7 @@ static bool do_command(THD *thd);
|
||||
#endif // EMBEDDED_LIBRARY
|
||||
|
||||
#ifdef __WIN__
|
||||
static void test_signal(int sig_ptr)
|
||||
{
|
||||
#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) ;
|
||||
}
|
||||
extern void win_install_sigabrt_handler(void);
|
||||
#endif
|
||||
|
||||
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_* */
|
||||
|
||||
#if defined(__WIN__)
|
||||
init_signals();
|
||||
win_install_sigabrt_handler();
|
||||
#elif !defined(OS2) && !defined(__NETWARE__)
|
||||
sigset_t set;
|
||||
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
|
||||
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 "stacktrace.h"
|
||||
|
||||
#ifndef __WIN__
|
||||
#include <signal.h>
|
||||
#include <my_pthread.h>
|
||||
|
||||
#ifdef HAVE_STACKTRACE
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
@ -118,10 +122,7 @@ void print_stacktrace(gptr stack_bottom, ulong thread_stack)
|
||||
#endif
|
||||
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__
|
||||
__asm __volatile__ ("movl %%ebp,%0"
|
||||
:"=r"(fp)
|
||||
@ -257,3 +258,267 @@ void write_core(int sig)
|
||||
#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; \
|
||||
check_thread_lib(); \
|
||||
} 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 safe_print_str(const char* name, const char* val, int max_len);
|
||||
void check_thread_lib(void);
|
||||
#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
|
||||
#endif /* TARGET_OS_LINUX */
|
||||
|
||||
#else
|
||||
/* Define empty prototypes for functions that are not implemented */
|
||||
#ifndef HAVE_STACKTRACE
|
||||
#define init_stacktrace() {}
|
||||
#define print_stacktrace(A,B) {}
|
||||
#define safe_print_str(A,B,C) {}
|
||||
#endif /* HAVE_STACKTRACE */
|
||||
|
||||
|
||||
#if !defined(__NETWARE__)
|
||||
#define HAVE_WRITE_CORE
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WRITE_CORE
|
||||
void write_core(int sig);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user