16 #include <my_global.h>
17 #include <my_stacktrace.h>
21 #include <my_pthread.h>
23 #ifdef HAVE_STACKTRACE
29 #include <sys/syscall.h>
36 #define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
38 static char *heap_start;
41 extern char *__bss_start;
44 void my_init_stacktrace()
47 heap_start = (
char*) &__bss_start;
53 static void print_buffer(
char *buffer,
size_t count)
56 for (; count && *buffer; --count)
58 my_write_stderr(isprint(*buffer) ? buffer : s, 1);
72 static int safe_print_str(
const char *addr,
int max_len)
81 tid= (pid_t) syscall(SYS_gettid);
83 sprintf(buf,
"/proc/self/task/%d/mem", tid);
85 if ((fd= open(buf, O_RDONLY)) < 0)
89 compile_time_assert(
sizeof(off_t) >=
sizeof(intptr));
92 offset= (intptr) addr;
97 count= MY_MIN(
sizeof(buf), total);
99 if ((nbytes= pread(fd, buf, count, offset)) < 0)
114 print_buffer(buf, nbytes);
117 if ((count - nbytes))
122 if (total != (
size_t) max_len)
123 my_safe_printf_stderr(
"%s",
"\n");
126 my_safe_printf_stderr(
"Can't read from address %p\n", addr);
135 void my_safe_print_str(
const char* val,
int max_len)
140 if (!safe_print_str(val, max_len))
144 heap_end= (
char*) sbrk(0);
148 my_safe_printf_stderr(
"%s",
"is an invalid pointer\n");
152 for (; max_len && PTR_SANE(val) && *val; --max_len)
153 my_write_stderr((val++), 1);
154 my_safe_printf_stderr(
"%s",
"\n");
157 #if defined(HAVE_PRINTSTACK)
160 #include <ucontext.h>
162 void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
163 ulong thread_stack __attribute__((unused)))
165 if (printstack(fileno(stderr)) == -1)
166 my_safe_printf_stderr(
"%s",
167 "Error when traversing the stack, stack appears corrupt.\n");
169 my_safe_printf_stderr(
"%s",
171 "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
172 "and follow instructions on how to resolve the stack trace.\n"
173 "Resolved stack trace is much more helpful in diagnosing the\n"
174 "problem, so please do resolve it\n");
177 #elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
179 #if BACKTRACE_DEMANGLE
181 char __attribute__ ((weak)) *
182 my_demangle(
const char *mangled_name __attribute__((unused)),
183 int *status __attribute__((unused)))
188 static void my_demangle_symbols(
char **addrs,
int n)
191 char *begin, *end, *demangled;
193 for (i= 0; i <
n; i++)
196 begin= strchr(addrs[i],
'(');
197 end= begin ? strchr(begin,
'+') : NULL;
201 *begin++= *end++=
'\0';
202 demangled= my_demangle(begin, &status);
203 if (!demangled || status)
212 my_safe_printf_stderr(
"%s(%s+%s\n", addrs[i], demangled, end);
214 my_safe_printf_stderr(
"%s\n", addrs[i]);
220 void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
223 char **strings= NULL;
224 int n = backtrace(addrs, array_elements(addrs));
225 my_safe_printf_stderr(
"stack_bottom = %p thread_stack 0x%lx\n",
226 stack_bottom, thread_stack);
227 #if BACKTRACE_DEMANGLE
228 if ((strings= backtrace_symbols(addrs, n)))
230 my_demangle_symbols(strings, n);
234 #if HAVE_BACKTRACE_SYMBOLS_FD
237 backtrace_symbols_fd(addrs, n, fileno(stderr));
242 #elif defined(TARGET_OS_LINUX)
245 #define SIGRETURN_FRAME_OFFSET 17
249 #define SIGRETURN_FRAME_OFFSET 23
252 #if defined(__alpha__) && defined(__GNUC__)
260 #define MAX_INSTR_IN_FUNC 10000
262 inline uchar** find_prev_fp(uint32* pc, uchar** fp)
265 for (i = 0; i < MAX_INSTR_IN_FUNC; ++
i,--pc)
267 uchar* p = (uchar*)pc;
268 if (p[2] == 222 && p[3] == 35)
270 return (uchar**)((uchar*)fp - *(
short int*)p);
276 inline uint32* find_prev_pc(uint32* pc, uchar** fp)
279 for (i = 0; i < MAX_INSTR_IN_FUNC; ++
i,--pc)
282 if (p[1] == 0 && p[2] == 94 && p[3] == -73)
284 uint32* prev_pc = (uint32*)*((fp+p[0]/
sizeof(fp)));
292 void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
295 uint frame_count = 0, sigreturn_frame_count;
296 #if defined(__alpha__) && defined(__GNUC__)
303 __asm __volatile__ (
"movl %%ebp,%0"
308 __asm __volatile__ (
"movq %%rbp,%0"
312 #if defined(__alpha__) && defined(__GNUC__)
313 __asm __volatile__ (
"mov $30,%0"
319 my_safe_printf_stderr(
"%s",
320 "frame pointer is NULL, did you compile with\n"
321 "-fomit-frame-pointer? Aborting backtrace!\n");
325 if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
327 ulong tmp= MY_MIN(0x10000, thread_stack);
329 stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF);
330 my_safe_printf_stderr(
"Cannot determine thread, fp=%p, "
331 "backtrace may not be correct.\n", fp);
333 if (fp > (uchar**) stack_bottom ||
334 fp < (uchar**) stack_bottom - thread_stack)
336 my_safe_printf_stderr(
"Bogus stack limit or frame pointer, "
337 "fp=%p, stack_bottom=%p, thread_stack=%ld, "
338 "aborting backtrace.\n",
339 fp, stack_bottom, thread_stack);
343 my_safe_printf_stderr(
"%s",
344 "Stack range sanity check OK, backtrace follows:\n");
345 #if defined(__alpha__) && defined(__GNUC__)
346 my_safe_printf_stderr(
"%s",
347 "Warning: Alpha stacks are difficult -"
348 "will be taking some wild guesses, stack trace may be incorrect or "
349 "terminate abruptly\n");
352 __asm __volatile__ (
"bsr %0, do_next; do_next: "
358 sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
360 while (fp < (uchar**) stack_bottom)
362 #if defined(__i386__) || defined(__x86_64__)
363 uchar** new_fp = (uchar**)*fp;
364 my_safe_printf_stderr(
"%p\n",
365 frame_count == sigreturn_frame_count ?
366 *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
369 #if defined(__alpha__) && defined(__GNUC__)
370 uchar** new_fp = find_prev_fp(pc, fp);
371 if (frame_count == sigreturn_frame_count - 1)
378 pc = find_prev_pc(pc, fp);
380 my_safe_printf_stderr(
"%p\n", pc);
383 my_safe_printf_stderr(
"%s",
384 "Not smart enough to deal with the rest of this stack\n");
390 my_safe_printf_stderr(
"%s",
391 "Not smart enough to deal with the rest of this stack\n");
397 my_safe_printf_stderr(
"New value of fp=%p failed sanity check, "
398 "terminating stack trace!\n", new_fp);
404 my_safe_printf_stderr(
"%s",
405 "Stack trace seems successful - bottom reached\n");
408 my_safe_printf_stderr(
"%s",
410 "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
411 "and follow instructions on how to resolve the stack trace.\n"
412 "Resolved stack trace is much more helpful in diagnosing the\n"
413 "problem, so please do resolve it\n");
419 void my_write_core(
int sig)
421 signal(sig, SIG_DFL);
422 pthread_kill(pthread_self(), sig);
423 #if defined(P_MYID) && !defined(SCO)
425 sigsend(P_PID,P_MYID,sig);
432 #include <tlhelp32.h>
434 #pragma comment(lib, "dbghelp")
437 static EXCEPTION_POINTERS *exception_ptrs;
439 #define MODULE64_SIZE_WINXP 576
440 #define STACKWALK_MAX_FRAMES 64
442 void my_init_stacktrace()
447 void my_set_exception_pointers(EXCEPTION_POINTERS *ep)
455 static void add_to_symbol_path(
char *path,
size_t path_buffer_size,
456 char *dir,
size_t dir_buffer_size)
458 strcat_s(dir, dir_buffer_size,
";");
459 if (!strstr(path, dir))
461 strcat_s(path, path_buffer_size, dir);
471 static void get_symbol_path(
char *path,
size_t size)
477 static char pdb_debug_dir[MAX_PATH + 7];
487 GetModuleFileName(NULL, pdb_debug_dir, MAX_PATH);
488 p= strrchr(pdb_debug_dir,
'\\');
492 strcat_s(pdb_debug_dir,
sizeof(pdb_debug_dir),
"\\debug;");
493 add_to_symbol_path(path, size, pdb_debug_dir,
sizeof(pdb_debug_dir));
501 hSnap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
502 if (hSnap != INVALID_HANDLE_VALUE)
506 mod.dwSize=
sizeof(MODULEENTRY32);
507 for (ret= Module32First(hSnap, &mod);
ret; ret= Module32Next(hSnap, &mod))
509 char *module_dir= mod.szExePath;
510 p= strrchr(module_dir,
'\\');
524 add_to_symbol_path(path, size, module_dir,
sizeof(mod.szExePath));
531 envvar= getenv(
"_NT_SYMBOL_PATH");
534 strcat_s(path, size, envvar);
538 #define MAX_SYMBOL_PATH 32768
541 #ifndef SYMOPT_NO_PROMPTS
542 #define SYMOPT_NO_PROMPTS 0
545 void my_print_stacktrace(uchar* unused1, ulong unused2)
547 HANDLE hProcess= GetCurrentProcess();
548 HANDLE hThread= GetCurrentThread();
549 static IMAGEHLP_MODULE64 module= {
sizeof(module)};
550 static IMAGEHLP_SYMBOL64_PACKAGE package;
555 STACKFRAME64 frame={0};
556 static char symbol_path[MAX_SYMBOL_PATH];
562 context = *(exception_ptrs->ContextRecord);
564 SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
565 get_symbol_path(symbol_path,
sizeof(symbol_path));
566 SymInitialize(hProcess, symbol_path, TRUE);
569 frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
570 #if (defined _M_IX86)
571 machine= IMAGE_FILE_MACHINE_I386;
572 frame.AddrFrame.Offset= context.Ebp;
573 frame.AddrPC.Offset= context.Eip;
574 frame.AddrStack.Offset= context.Esp;
575 #elif (defined _M_X64)
576 machine = IMAGE_FILE_MACHINE_AMD64;
577 frame.AddrFrame.Offset= context.Rbp;
578 frame.AddrPC.Offset= context.Rip;
579 frame.AddrStack.Offset= context.Rsp;
582 #pragma error ("unsupported architecture")
585 package.sym.SizeOfStruct=
sizeof(package.sym);
586 package.sym.MaxNameLength=
sizeof(package.name);
589 for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
591 DWORD64 function_offset= 0;
592 DWORD line_offset= 0;
593 IMAGEHLP_LINE64 line= {
sizeof(line)};
594 BOOL have_module= FALSE;
595 BOOL have_symbol= FALSE;
596 BOOL have_source= FALSE;
598 if(!StackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
600 addr= frame.AddrPC.Offset;
602 have_module= SymGetModuleInfo64(hProcess,addr,&module);
611 module.SizeOfStruct= MODULE64_SIZE_WINXP;
612 have_module= SymGetModuleInfo64(hProcess, addr, &module);
616 have_symbol= SymGetSymFromAddr64(hProcess, addr, &function_offset,
618 have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
620 my_safe_printf_stderr(
"%p ", addr);
623 char *base_image_name= strrchr(module.ImageName,
'\\');
627 base_image_name= module.ImageName;
628 my_safe_printf_stderr(
"%s!", base_image_name);
631 my_safe_printf_stderr(
"%s()", package.sym.Name);
634 my_safe_printf_stderr(
"%s",
"???");
638 char *base_file_name= strrchr(line.FileName,
'\\');
642 base_file_name= line.FileName;
643 my_safe_printf_stderr(
"[%s:%u]",
644 base_file_name, line.LineNumber);
646 my_safe_printf_stderr(
"%s",
"\n");
656 void my_write_core(
int unused)
659 char dump_fname[MAX_PATH]=
"core.dmp";
660 MINIDUMP_EXCEPTION_INFORMATION info;
666 info.ExceptionPointers= exception_ptrs;
667 info.ClientPointers= FALSE;
668 info.ThreadId= GetCurrentThreadId();
670 if(GetModuleFileName(NULL, path,
sizeof(path)))
672 _splitpath(path, NULL, NULL,dump_fname,NULL);
673 strncat(dump_fname,
".dmp",
sizeof(dump_fname));
676 hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
677 FILE_ATTRIBUTE_NORMAL, 0);
681 if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
682 hFile, MiniDumpNormal, &info, 0, 0))
684 my_safe_printf_stderr(
"Minidump written to %s\n",
685 _fullpath(path, dump_fname,
sizeof(path)) ?
690 my_safe_printf_stderr(
"MiniDumpWriteDump() failed, last error %u\n",
691 (uint) GetLastError());
697 my_safe_printf_stderr(
"CreateFile(%s) failed, last error %u\n",
698 dump_fname, (uint) GetLastError());
703 void my_safe_print_str(
const char *val,
int len)
707 my_write_stderr(val, len);
709 __except(EXCEPTION_EXECUTE_HANDLER)
711 my_safe_printf_stderr(
"%s",
"is an invalid string pointer\n");
718 size_t my_write_stderr(
const void *buf,
size_t count)
721 SetFilePointer(GetStdHandle(STD_ERROR_HANDLE), 0, NULL, FILE_END);
722 WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, count, &bytes_written, NULL);
723 return bytes_written;
726 size_t my_write_stderr(
const void *buf,
size_t count)
728 return (
size_t) write(STDERR_FILENO, buf, count);
733 static const char digits[]=
"0123456789abcdef";
735 char *my_safe_utoa(
int base, ulonglong val,
char *buf)
739 *buf--= digits[val % base];
740 }
while ((val /= base) != 0);
745 char *my_safe_itoa(
int base, longlong val,
char *buf)
748 const my_bool is_neg= (val < 0);
753 if (is_neg && base == 16)
757 for (ix= 0; ix < 16; ++ix)
762 *buf--= digits[val % base];
763 }
while ((val /= base) != 0);
765 if (is_neg && base == 10)
768 if (is_neg && base == 16)
772 for (ix= 0; ix < 16; ++ix, --
buf)
776 case '0': *buf=
'f';
break;
777 case '1': *buf=
'e';
break;
778 case '2': *buf=
'd';
break;
779 case '3': *buf=
'c';
break;
780 case '4': *buf=
'b';
break;
781 case '5': *buf=
'a';
break;
782 case '6': *buf=
'9';
break;
783 case '7': *buf=
'8';
break;
784 case '8': *buf=
'7';
break;
785 case '9': *buf=
'6';
break;
786 case 'a': *buf=
'5';
break;
787 case 'b': *buf=
'4';
break;
788 case 'c': *buf=
'3';
break;
789 case 'd': *buf=
'2';
break;
790 case 'e': *buf=
'1';
break;
791 case 'f': *buf=
'0';
break;
799 static const char *check_longlong(
const char *
fmt, my_bool *have_longlong)
801 *have_longlong= FALSE;
806 *have_longlong= (
sizeof(long) ==
sizeof(longlong));
810 *have_longlong= TRUE;
816 static size_t my_safe_vsnprintf(
char *
to,
size_t size,
817 const char* format, va_list ap)
820 char *end= start + size - 1;
821 for (; *format; ++format)
823 my_bool have_longlong = FALSE;
833 format= check_longlong(format, &have_longlong);
846 have_longlong= (
sizeof(
void *) ==
sizeof(longlong));
850 uval= va_arg(ap, ulonglong);
852 ival= va_arg(ap, longlong);
857 uval= va_arg(ap,
unsigned int);
859 ival= va_arg(ap,
int);
864 const int base= (*format ==
'x' || *format ==
'p') ? 16 : 10;
865 char *val_as_str= (*format ==
'u') ?
866 my_safe_utoa(base, uval, &buff[
sizeof(buff)-1]) :
867 my_safe_itoa(base, ival, &buff[
sizeof(buff)-1]);
870 if (*format ==
'x' && !have_longlong && ival < 0)
873 while (*val_as_str && to < end)
874 *to++= *val_as_str++;
880 const char *val= va_arg(ap,
char*);
883 while (*val && to < end)
894 size_t my_safe_snprintf(
char* to,
size_t n,
const char* fmt, ...)
899 result= my_safe_vsnprintf(to, n, fmt, args);
905 size_t my_safe_printf_stderr(
const char* fmt, ...)
911 result= my_safe_vsnprintf(to,
sizeof(to), fmt, args);
913 my_write_stderr(to, result);