1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
17
#define DONT_DEFINE_VOID 1
19
#include <my_global.h>
20
#include <my_stacktrace.h>
24
#include <my_pthread.h>
26
#ifdef HAVE_STACKTRACE
34
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
36
static char *heap_start;
39
extern char *__bss_start;
42
void my_init_stacktrace()
45
heap_start = (char*) &__bss_start;
49
void my_safe_print_str(const char* name, const char* val, int max_len)
51
char *heap_end= (char*) sbrk(0);
52
fprintf(stderr, "%s at %p ", name, val);
56
fprintf(stderr, "is an invalid pointer\n");
60
fprintf(stderr, "= ");
61
for (; max_len && PTR_SANE(val) && *val; --max_len)
62
fputc(*val++, stderr);
66
#if defined(HAVE_PRINTSTACK)
68
/* Use Solaris' symbolic stack trace routine. */
71
void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
72
ulong thread_stack __attribute__((unused)))
74
if (printstack(fileno(stderr)) == -1)
75
fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n");
79
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
80
"and follow instructions on how to resolve the stack trace.\n"
81
"Resolved stack trace is much more helpful in diagnosing the\n"
82
"problem, so please do resolve it\n");
85
#elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
87
#if BACKTRACE_DEMANGLE
89
char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status)
94
static void my_demangle_symbols(char **addrs, int n)
97
char *begin, *end, *demangled;
99
for (i= 0; i < n; i++)
102
begin= strchr(addrs[i], '(');
103
end= begin ? strchr(begin, '+') : NULL;
107
*begin++= *end++= '\0';
108
demangled= my_demangle(begin, &status);
109
if (!demangled || status)
118
fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
120
fprintf(stderr, "%s\n", addrs[i]);
124
#endif /* BACKTRACE_DEMANGLE */
126
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
129
char **strings= NULL;
130
int n = backtrace(addrs, array_elements(addrs));
131
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n",
132
stack_bottom, thread_stack);
133
#if BACKTRACE_DEMANGLE
134
if ((strings= backtrace_symbols(addrs, n)))
136
my_demangle_symbols(strings, n);
140
#if HAVE_BACKTRACE_SYMBOLS_FD
143
backtrace_symbols_fd(addrs, n, fileno(stderr));
148
#elif defined(TARGET_OS_LINUX)
151
#define SIGRETURN_FRAME_OFFSET 17
155
#define SIGRETURN_FRAME_OFFSET 23
158
#if defined(__alpha__) && defined(__GNUC__)
160
The only way to backtrace without a symbol table on alpha
161
is to find stq fp,N(sp), and the first byte
162
of the instruction opcode will give us the value of N. From this
163
we can find where the old value of fp is stored
166
#define MAX_INSTR_IN_FUNC 10000
168
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
171
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
173
uchar* p = (uchar*)pc;
174
if (p[2] == 222 && p[3] == 35)
176
return (uchar**)((uchar*)fp - *(short int*)p);
182
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
185
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
188
if (p[1] == 0 && p[2] == 94 && p[3] == -73)
190
uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
196
#endif /* defined(__alpha__) && defined(__GNUC__) */
198
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
201
uint frame_count = 0, sigreturn_frame_count;
202
#if defined(__alpha__) && defined(__GNUC__)
209
__asm __volatile__ ("movl %%ebp,%0"
214
__asm __volatile__ ("movq %%rbp,%0"
218
#if defined(__alpha__) && defined(__GNUC__)
219
__asm __volatile__ ("mov $30,%0"
225
fprintf(stderr, "frame pointer is NULL, did you compile with\n\
226
-fomit-frame-pointer? Aborting backtrace!\n");
230
if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
232
ulong tmp= min(0x10000,thread_stack);
233
/* Assume that the stack starts at the previous even 65K */
234
stack_bottom= (uchar*) (((ulong) &fp + tmp) &
236
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
238
if (fp > (uchar**) stack_bottom ||
239
fp < (uchar**) stack_bottom - thread_stack)
241
fprintf(stderr, "Bogus stack limit or frame pointer,\
242
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
243
fp, stack_bottom, thread_stack);
247
fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
248
#if defined(__alpha__) && defined(__GNUC__)
249
fprintf(stderr, "Warning: Alpha stacks are difficult -\
250
will be taking some wild guesses, stack trace may be incorrect or \
251
terminate abruptly\n");
252
/* On Alpha, we need to get pc */
253
__asm __volatile__ ("bsr %0, do_next; do_next: "
256
#endif /* __alpha__ */
258
/* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
259
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
261
while (fp < (uchar**) stack_bottom)
263
#if defined(__i386__) || defined(__x86_64__)
264
uchar** new_fp = (uchar**)*fp;
265
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
266
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
267
#endif /* defined(__386__) || defined(__x86_64__) */
269
#if defined(__alpha__) && defined(__GNUC__)
270
uchar** new_fp = find_prev_fp(pc, fp);
271
if (frame_count == sigreturn_frame_count - 1)
278
pc = find_prev_pc(pc, fp);
280
fprintf(stderr, "%p\n", pc);
283
fprintf(stderr, "Not smart enough to deal with the rest\
290
fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
293
#endif /* defined(__alpha__) && defined(__GNUC__) */
296
fprintf(stderr, "New value of fp=%p failed sanity check,\
297
terminating stack trace!\n", new_fp);
304
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
308
"Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
309
"and follow instructions on how to resolve the stack trace.\n"
310
"Resolved stack trace is much more helpful in diagnosing the\n"
311
"problem, so please do resolve it\n");
313
#endif /* TARGET_OS_LINUX */
314
#endif /* HAVE_STACKTRACE */
316
/* Produce a core for the thread */
317
void my_write_core(int sig)
319
signal(sig, SIG_DFL);
322
For GCOV build, crashing will prevent the writing of code coverage
323
information from this process, causing gcov output to be incomplete.
324
So we force the writing of coverage information here before terminating.
326
extern void __gcov_flush(void);
329
pthread_kill(pthread_self(), sig);
330
#if defined(P_MYID) && !defined(SCO)
331
/* On Solaris, the above kill is not enough */
332
sigsend(P_PID,P_MYID,sig);
339
#include <tlhelp32.h>
342
Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll)
343
We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000)
344
is missing some important functions like functions StackWalk64 or MinidumpWriteDump.
345
Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress.
348
typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions);
349
typedef BOOL (WINAPI *SymGetModuleInfo64_FctType)
350
(HANDLE,DWORD64,PIMAGEHLP_MODULE64) ;
351
typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType)
352
(HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ;
353
typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType)
354
(HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64);
355
typedef BOOL (WINAPI *SymInitialize_FctType)
357
typedef BOOL (WINAPI *StackWalk64_FctType)
358
(DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64,
359
PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 ,
360
PTRANSLATE_ADDRESS_ROUTINE64);
361
typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)(
365
IN MINIDUMP_TYPE DumpType,
366
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
367
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
368
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
371
static SymSetOptions_FctType pSymSetOptions;
372
static SymGetModuleInfo64_FctType pSymGetModuleInfo64;
373
static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64;
374
static SymInitialize_FctType pSymInitialize;
375
static StackWalk64_FctType pStackWalk64;
376
static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64;
377
static MiniDumpWriteDump_FctType pMiniDumpWriteDump;
379
static EXCEPTION_POINTERS *exception_ptrs;
381
#define MODULE64_SIZE_WINXP 576
382
#define STACKWALK_MAX_FRAMES 64
384
void my_init_stacktrace()
389
Dynamically load dbghelp functions
391
BOOL init_dbghelp_functions()
393
static BOOL first_time= TRUE;
400
hDbghlp= LoadLibrary("dbghelp");
406
pSymSetOptions= (SymSetOptions_FctType)
407
GetProcAddress(hDbghlp,"SymSetOptions");
408
pSymInitialize= (SymInitialize_FctType)
409
GetProcAddress(hDbghlp,"SymInitialize");
410
pSymGetModuleInfo64= (SymGetModuleInfo64_FctType)
411
GetProcAddress(hDbghlp,"SymGetModuleInfo64");
412
pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType)
413
GetProcAddress(hDbghlp,"SymGetLineFromAddr64");
414
pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType)
415
GetProcAddress(hDbghlp,"SymGetSymFromAddr64");
416
pStackWalk64= (StackWalk64_FctType)
417
GetProcAddress(hDbghlp,"StackWalk64");
418
pMiniDumpWriteDump = (MiniDumpWriteDump_FctType)
419
GetProcAddress(hDbghlp,"MiniDumpWriteDump");
421
rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64
422
&& pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64);
427
void my_set_exception_pointers(EXCEPTION_POINTERS *ep)
434
Get symbol path - semicolon-separated list of directories to search for debug
435
symbols. We expect PDB in the same directory as corresponding exe or dll,
436
so the path is build from directories of the loaded modules. If environment
437
variable _NT_SYMBOL_PATH is set, it's value appended to the symbol search path
439
static void get_symbol_path(char *path, size_t size)
446
Enumerate all modules, and add their directories to the path.
447
Avoid duplicate entries.
449
hSnap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
450
if (hSnap != INVALID_HANDLE_VALUE)
454
mod.dwSize= sizeof(MODULEENTRY32);
455
for (ret= Module32First(hSnap, &mod); ret; ret= Module32Next(hSnap, &mod))
457
char *module_dir= mod.szExePath;
458
char *p= strrchr(module_dir,'\\');
462
Path separator was not found. Not known to happen, if ever happens,
463
will indicate current directory.
471
if (!strstr(path, module_dir))
473
size_t dir_len = strlen(module_dir);
476
strncat(path, module_dir, size-1);
484
/* Add _NT_SYMBOL_PATH, if present. */
485
envvar= getenv("_NT_SYMBOL_PATH");
488
strncat(path, envvar, size-1);
492
#define MAX_SYMBOL_PATH 32768
494
/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
495
#ifndef SYMOPT_NO_PROMPTS
496
#define SYMOPT_NO_PROMPTS 0
499
void my_print_stacktrace(uchar* unused1, ulong unused2)
501
HANDLE hProcess= GetCurrentProcess();
502
HANDLE hThread= GetCurrentThread();
503
static IMAGEHLP_MODULE64 module= {sizeof(module)};
504
static IMAGEHLP_SYMBOL64_PACKAGE package;
509
STACKFRAME64 frame={0};
510
static char symbol_path[MAX_SYMBOL_PATH];
512
if(!exception_ptrs || !init_dbghelp_functions())
515
/* Copy context, as stackwalking on original will unwind the stack */
516
context = *(exception_ptrs->ContextRecord);
517
/*Initialize symbols.*/
518
pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
519
get_symbol_path(symbol_path, sizeof(symbol_path));
520
pSymInitialize(hProcess, symbol_path, TRUE);
522
/*Prepare stackframe for the first StackWalk64 call*/
523
frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
524
#if (defined _M_IX86)
525
machine= IMAGE_FILE_MACHINE_I386;
526
frame.AddrFrame.Offset= context.Ebp;
527
frame.AddrPC.Offset= context.Eip;
528
frame.AddrStack.Offset= context.Esp;
529
#elif (defined _M_X64)
530
machine = IMAGE_FILE_MACHINE_AMD64;
531
frame.AddrFrame.Offset= context.Rbp;
532
frame.AddrPC.Offset= context.Rip;
533
frame.AddrStack.Offset= context.Rsp;
535
/*There is currently no need to support IA64*/
536
#pragma error ("unsupported architecture")
539
package.sym.SizeOfStruct= sizeof(package.sym);
540
package.sym.MaxNameLength= sizeof(package.name);
542
/*Walk the stack, output useful information*/
543
for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
545
DWORD64 function_offset= 0;
546
DWORD line_offset= 0;
547
IMAGEHLP_LINE64 line= {sizeof(line)};
548
BOOL have_module= FALSE;
549
BOOL have_symbol= FALSE;
550
BOOL have_source= FALSE;
552
if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
554
addr= frame.AddrPC.Offset;
556
have_module= pSymGetModuleInfo64(hProcess,addr,&module);
561
ModuleInfo structure has been "compatibly" extended in releases after XP,
562
and its size was increased. To make XP dbghelp.dll function
563
happy, pretend passing the old structure.
565
module.SizeOfStruct= MODULE64_SIZE_WINXP;
566
have_module= pSymGetModuleInfo64(hProcess, addr, &module);
570
have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset,
572
have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
574
fprintf(stderr, "%p ", addr);
577
char *base_image_name= strrchr(module.ImageName, '\\');
581
base_image_name= module.ImageName;
582
fprintf(stderr, "%s!", base_image_name);
585
fprintf(stderr, "%s()", package.sym.Name);
587
fprintf(stderr, "???");
591
char *base_file_name= strrchr(line.FileName, '\\');
595
base_file_name= line.FileName;
596
fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
598
fprintf(stderr, "\n");
605
Write dump. The dump is created in current directory,
606
file name is constructed from executable name plus
609
void my_write_core(int unused)
612
char dump_fname[MAX_PATH]= "core.dmp";
613
MINIDUMP_EXCEPTION_INFORMATION info;
616
if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump)
619
info.ExceptionPointers= exception_ptrs;
620
info.ClientPointers= FALSE;
621
info.ThreadId= GetCurrentThreadId();
623
if(GetModuleFileName(NULL, path, sizeof(path)))
625
_splitpath(path, NULL, NULL,dump_fname,NULL);
626
strncat(dump_fname, ".dmp", sizeof(dump_fname));
629
hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
630
FILE_ATTRIBUTE_NORMAL, 0);
633
/* Create minidump */
634
if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
635
hFile, MiniDumpNormal, &info, 0, 0))
637
fprintf(stderr, "Minidump written to %s\n",
638
_fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
642
fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
649
fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
656
void my_safe_print_str(const char *name, const char *val, int len)
658
fprintf(stderr,"%s at %p", name, val);
661
fprintf(stderr,"=%.*s\n", len, val);
663
__except(EXCEPTION_EXECUTE_HANDLER)
665
fprintf(stderr,"is an invalid string pointer\n");