~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to mysys/stacktrace.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */
 
15
 
 
16
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
 
17
#define DONT_DEFINE_VOID 1
 
18
 
 
19
#include <my_global.h>
 
20
#include <my_stacktrace.h>
 
21
 
 
22
#ifndef __WIN__
 
23
#include <signal.h>
 
24
#include <my_pthread.h>
 
25
#include <m_string.h>
 
26
#ifdef HAVE_STACKTRACE
 
27
#include <unistd.h>
 
28
#include <strings.h>
 
29
 
 
30
#if HAVE_EXECINFO_H
 
31
#include <execinfo.h>
 
32
#endif
 
33
 
 
34
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
 
35
 
 
36
static char *heap_start;
 
37
 
 
38
#ifdef HAVE_BSS_START
 
39
extern char *__bss_start;
 
40
#endif
 
41
 
 
42
void my_init_stacktrace()
 
43
{
 
44
#ifdef HAVE_BSS_START
 
45
  heap_start = (char*) &__bss_start;
 
46
#endif
 
47
}
 
48
 
 
49
void my_safe_print_str(const char* name, const char* val, int max_len)
 
50
{
 
51
  char *heap_end= (char*) sbrk(0);
 
52
  fprintf(stderr, "%s at %p ", name, val);
 
53
 
 
54
  if (!PTR_SANE(val))
 
55
  {
 
56
    fprintf(stderr, "is an invalid pointer\n");
 
57
    return;
 
58
  }
 
59
 
 
60
  fprintf(stderr, "= ");
 
61
  for (; max_len && PTR_SANE(val) && *val; --max_len)
 
62
    fputc(*val++, stderr);
 
63
  fputc('\n', stderr);
 
64
}
 
65
 
 
66
#if defined(HAVE_PRINTSTACK)
 
67
 
 
68
/* Use Solaris' symbolic stack trace routine. */
 
69
#include <ucontext.h>
 
70
 
 
71
void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)), 
 
72
                         ulong thread_stack __attribute__((unused)))
 
73
{
 
74
  if (printstack(fileno(stderr)) == -1)
 
75
    fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n");
 
76
  else
 
77
    fprintf(stderr,
 
78
            "Please read "
 
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");
 
83
}
 
84
 
 
85
#elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
 
86
 
 
87
#if BACKTRACE_DEMANGLE
 
88
 
 
89
char __attribute__ ((weak)) *my_demangle(const char *mangled_name, int *status)
 
90
{
 
91
  return NULL;
 
92
}
 
93
 
 
94
static void my_demangle_symbols(char **addrs, int n)
 
95
{
 
96
  int status, i;
 
97
  char *begin, *end, *demangled;
 
98
 
 
99
  for (i= 0; i < n; i++)
 
100
  {
 
101
    demangled= NULL;
 
102
    begin= strchr(addrs[i], '(');
 
103
    end= begin ? strchr(begin, '+') : NULL;
 
104
 
 
105
    if (begin && end)
 
106
    {
 
107
      *begin++= *end++= '\0';
 
108
      demangled= my_demangle(begin, &status);
 
109
      if (!demangled || status)
 
110
      {
 
111
        demangled= NULL;
 
112
        begin[-1]= '(';
 
113
        end[-1]= '+';
 
114
      }
 
115
    }
 
116
 
 
117
    if (demangled)
 
118
      fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
 
119
    else
 
120
      fprintf(stderr, "%s\n", addrs[i]);
 
121
  }
 
122
}
 
123
 
 
124
#endif /* BACKTRACE_DEMANGLE */
 
125
 
 
126
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
 
127
{
 
128
  void *addrs[128];
 
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)))
 
135
  {
 
136
    my_demangle_symbols(strings, n);
 
137
    free(strings);
 
138
  }
 
139
#endif
 
140
#if HAVE_BACKTRACE_SYMBOLS_FD
 
141
  if (!strings)
 
142
  {
 
143
    backtrace_symbols_fd(addrs, n, fileno(stderr));
 
144
  }
 
145
#endif
 
146
}
 
147
 
 
148
#elif defined(TARGET_OS_LINUX)
 
149
 
 
150
#ifdef __i386__
 
151
#define SIGRETURN_FRAME_OFFSET 17
 
152
#endif
 
153
 
 
154
#ifdef __x86_64__
 
155
#define SIGRETURN_FRAME_OFFSET 23
 
156
#endif
 
157
 
 
158
#if defined(__alpha__) && defined(__GNUC__)
 
159
/*
 
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
 
164
*/
 
165
 
 
166
#define MAX_INSTR_IN_FUNC  10000
 
167
 
 
168
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
 
169
{
 
170
  int i;
 
171
  for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
 
172
  {
 
173
    uchar* p = (uchar*)pc;
 
174
    if (p[2] == 222 &&  p[3] == 35)
 
175
    {
 
176
      return (uchar**)((uchar*)fp - *(short int*)p);
 
177
    }
 
178
  }
 
179
  return 0;
 
180
}
 
181
 
 
182
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
 
183
{
 
184
  int i;
 
185
  for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
 
186
  {
 
187
    char* p = (char*)pc;
 
188
    if (p[1] == 0 && p[2] == 94 &&  p[3] == -73)
 
189
    {
 
190
      uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
 
191
      return prev_pc;
 
192
    }
 
193
  }
 
194
  return 0;
 
195
}
 
196
#endif /* defined(__alpha__) && defined(__GNUC__) */
 
197
 
 
198
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
 
199
{
 
200
  uchar** fp;
 
201
  uint frame_count = 0, sigreturn_frame_count;
 
202
#if defined(__alpha__) && defined(__GNUC__)
 
203
  uint32* pc;
 
204
#endif
 
205
  LINT_INIT(fp);
 
206
 
 
207
 
 
208
#ifdef __i386__
 
209
  __asm __volatile__ ("movl %%ebp,%0"
 
210
                      :"=r"(fp)
 
211
                      :"r"(fp));
 
212
#endif
 
213
#ifdef __x86_64__
 
214
  __asm __volatile__ ("movq %%rbp,%0"
 
215
                      :"=r"(fp)
 
216
                      :"r"(fp));
 
217
#endif
 
218
#if defined(__alpha__) && defined(__GNUC__) 
 
219
  __asm __volatile__ ("mov $30,%0"
 
220
                      :"=r"(fp)
 
221
                      :"r"(fp));
 
222
#endif
 
223
  if (!fp)
 
224
  {
 
225
    fprintf(stderr, "frame pointer is NULL, did you compile with\n\
 
226
-fomit-frame-pointer? Aborting backtrace!\n");
 
227
    return;
 
228
  }
 
229
 
 
230
  if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
 
231
  {
 
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) &
 
235
                          ~(ulong) 0xFFFF);
 
236
    fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
 
237
  }
 
238
  if (fp > (uchar**) stack_bottom ||
 
239
      fp < (uchar**) stack_bottom - thread_stack)
 
240
  {
 
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);
 
244
    return;
 
245
  }
 
246
 
 
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: "
 
254
                      :"=r"(pc)
 
255
                      :"r"(pc));
 
256
#endif  /* __alpha__ */
 
257
 
 
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;
 
260
 
 
261
  while (fp < (uchar**) stack_bottom)
 
262
  {
 
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__) */
 
268
 
 
269
#if defined(__alpha__) && defined(__GNUC__)
 
270
    uchar** new_fp = find_prev_fp(pc, fp);
 
271
    if (frame_count == sigreturn_frame_count - 1)
 
272
    {
 
273
      new_fp += 90;
 
274
    }
 
275
 
 
276
    if (fp && pc)
 
277
    {
 
278
      pc = find_prev_pc(pc, fp);
 
279
      if (pc)
 
280
        fprintf(stderr, "%p\n", pc);
 
281
      else
 
282
      {
 
283
        fprintf(stderr, "Not smart enough to deal with the rest\
 
284
 of this stack\n");
 
285
        goto end;
 
286
      }
 
287
    }
 
288
    else
 
289
    {
 
290
      fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
 
291
      goto end;
 
292
    }
 
293
#endif /* defined(__alpha__) && defined(__GNUC__) */
 
294
    if (new_fp <= fp )
 
295
    {
 
296
      fprintf(stderr, "New value of fp=%p failed sanity check,\
 
297
 terminating stack trace!\n", new_fp);
 
298
      goto end;
 
299
    }
 
300
    fp = new_fp;
 
301
    ++frame_count;
 
302
  }
 
303
 
 
304
  fprintf(stderr, "Stack trace seems successful - bottom reached\n");
 
305
 
 
306
end:
 
307
  fprintf(stderr,
 
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");
 
312
}
 
313
#endif /* TARGET_OS_LINUX */
 
314
#endif /* HAVE_STACKTRACE */
 
315
 
 
316
/* Produce a core for the thread */
 
317
void my_write_core(int sig)
 
318
{
 
319
  signal(sig, SIG_DFL);
 
320
#ifdef HAVE_gcov
 
321
  /*
 
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.
 
325
  */
 
326
  extern void __gcov_flush(void);
 
327
  __gcov_flush();
 
328
#endif
 
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);
 
333
#endif
 
334
}
 
335
 
 
336
#else /* __WIN__*/
 
337
 
 
338
#include <dbghelp.h>
 
339
#include <tlhelp32.h>
 
340
 
 
341
/*
 
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.
 
346
*/
 
347
 
 
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)
 
356
  (HANDLE,PSTR,BOOL);
 
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)(
 
362
    IN HANDLE hProcess,
 
363
    IN DWORD ProcessId,
 
364
    IN HANDLE hFile,
 
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
 
369
    );
 
370
 
 
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;
 
378
 
 
379
static EXCEPTION_POINTERS *exception_ptrs;
 
380
 
 
381
#define MODULE64_SIZE_WINXP 576
 
382
#define STACKWALK_MAX_FRAMES 64
 
383
 
 
384
void my_init_stacktrace()
 
385
{
 
386
}
 
387
 
 
388
/*
 
389
  Dynamically load dbghelp functions
 
390
*/
 
391
BOOL init_dbghelp_functions()
 
392
{
 
393
  static BOOL first_time= TRUE;
 
394
  static BOOL rc;
 
395
  HMODULE hDbghlp;
 
396
 
 
397
  if(first_time)
 
398
  {
 
399
    first_time= FALSE;
 
400
    hDbghlp= LoadLibrary("dbghelp");
 
401
    if(!hDbghlp)
 
402
    {
 
403
      rc= FALSE;
 
404
      return rc;
 
405
    }
 
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");
 
420
 
 
421
    rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64
 
422
    && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64);
 
423
  }
 
424
  return rc;
 
425
}
 
426
 
 
427
void my_set_exception_pointers(EXCEPTION_POINTERS *ep)
 
428
{
 
429
  exception_ptrs = ep;
 
430
}
 
431
 
 
432
 
 
433
/*
 
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
 
438
*/
 
439
static void get_symbol_path(char *path, size_t size)
 
440
 
441
  HANDLE hSnap; 
 
442
  char *envvar;
 
443
 
 
444
  path[0]= '\0';
 
445
  /*
 
446
    Enumerate all modules, and add their directories to the path.
 
447
    Avoid duplicate entries.
 
448
  */
 
449
  hSnap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
 
450
  if (hSnap != INVALID_HANDLE_VALUE)
 
451
  {
 
452
    BOOL ret;
 
453
    MODULEENTRY32 mod;
 
454
    mod.dwSize= sizeof(MODULEENTRY32);
 
455
    for (ret= Module32First(hSnap, &mod); ret; ret= Module32Next(hSnap, &mod))
 
456
    {
 
457
      char *module_dir= mod.szExePath;
 
458
      char *p= strrchr(module_dir,'\\');
 
459
      if (!p)
 
460
      {
 
461
        /*
 
462
          Path separator was not found. Not known to happen, if ever happens,
 
463
          will indicate current directory.
 
464
        */
 
465
        module_dir[0]= '.';
 
466
        p= module_dir + 1;
 
467
      }
 
468
      *p++= ';';
 
469
      *p= '\0';
 
470
 
 
471
      if (!strstr(path, module_dir))
 
472
      {
 
473
        size_t dir_len = strlen(module_dir);
 
474
        if (size > dir_len)
 
475
        {
 
476
          strncat(path, module_dir, size-1);
 
477
          size -= dir_len;
 
478
        }
 
479
      }
 
480
    }
 
481
    CloseHandle(hSnap);
 
482
  }
 
483
 
 
484
  /* Add _NT_SYMBOL_PATH, if present. */
 
485
  envvar= getenv("_NT_SYMBOL_PATH");
 
486
  if(envvar && size)
 
487
  {
 
488
    strncat(path, envvar, size-1);
 
489
  }
 
490
}
 
491
 
 
492
#define MAX_SYMBOL_PATH 32768
 
493
 
 
494
/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
 
495
#ifndef SYMOPT_NO_PROMPTS
 
496
#define SYMOPT_NO_PROMPTS 0
 
497
#endif
 
498
 
 
499
void my_print_stacktrace(uchar* unused1, ulong unused2)
 
500
{
 
501
  HANDLE  hProcess= GetCurrentProcess();
 
502
  HANDLE  hThread= GetCurrentThread();
 
503
  static  IMAGEHLP_MODULE64 module= {sizeof(module)};
 
504
  static  IMAGEHLP_SYMBOL64_PACKAGE package;
 
505
  DWORD64 addr;
 
506
  DWORD   machine;
 
507
  int     i;
 
508
  CONTEXT context;
 
509
  STACKFRAME64 frame={0};
 
510
  static char symbol_path[MAX_SYMBOL_PATH];
 
511
 
 
512
  if(!exception_ptrs || !init_dbghelp_functions())
 
513
    return;
 
514
 
 
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);
 
521
 
 
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;
 
534
#else
 
535
  /*There is currently no need to support IA64*/
 
536
#pragma error ("unsupported architecture")
 
537
#endif
 
538
 
 
539
  package.sym.SizeOfStruct= sizeof(package.sym);
 
540
  package.sym.MaxNameLength= sizeof(package.name);
 
541
 
 
542
  /*Walk the stack, output useful information*/ 
 
543
  for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
 
544
  {
 
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;
 
551
 
 
552
    if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
 
553
      break;
 
554
    addr= frame.AddrPC.Offset;
 
555
 
 
556
    have_module= pSymGetModuleInfo64(hProcess,addr,&module);
 
557
#ifdef _M_IX86
 
558
    if(!have_module)
 
559
    {
 
560
      /*
 
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.
 
564
      */
 
565
      module.SizeOfStruct= MODULE64_SIZE_WINXP;
 
566
      have_module= pSymGetModuleInfo64(hProcess, addr, &module);
 
567
    }
 
568
#endif
 
569
 
 
570
    have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset,
 
571
      &(package.sym));
 
572
    have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
 
573
 
 
574
    fprintf(stderr, "%p    ", addr);
 
575
    if(have_module)
 
576
    {
 
577
      char *base_image_name= strrchr(module.ImageName, '\\');
 
578
      if(base_image_name)
 
579
        base_image_name++;
 
580
      else
 
581
        base_image_name= module.ImageName;
 
582
      fprintf(stderr, "%s!", base_image_name);
 
583
    }
 
584
    if(have_symbol)
 
585
      fprintf(stderr, "%s()", package.sym.Name);
 
586
    else if(have_module)
 
587
      fprintf(stderr, "???");
 
588
 
 
589
    if(have_source)
 
590
    {
 
591
      char *base_file_name= strrchr(line.FileName, '\\');
 
592
      if(base_file_name)
 
593
        base_file_name++;
 
594
      else
 
595
        base_file_name= line.FileName;
 
596
      fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
 
597
    }
 
598
    fprintf(stderr, "\n");
 
599
  }
 
600
  fflush(stderr);
 
601
}
 
602
 
 
603
 
 
604
/*
 
605
  Write dump. The dump is created in current directory,
 
606
  file name is constructed from executable name plus
 
607
  ".dmp" extension
 
608
*/
 
609
void my_write_core(int unused)
 
610
{
 
611
  char path[MAX_PATH];
 
612
  char dump_fname[MAX_PATH]= "core.dmp";
 
613
  MINIDUMP_EXCEPTION_INFORMATION info;
 
614
  HANDLE hFile;
 
615
 
 
616
  if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump)
 
617
    return;
 
618
 
 
619
  info.ExceptionPointers= exception_ptrs;
 
620
  info.ClientPointers= FALSE;
 
621
  info.ThreadId= GetCurrentThreadId();
 
622
 
 
623
  if(GetModuleFileName(NULL, path, sizeof(path)))
 
624
  {
 
625
    _splitpath(path, NULL, NULL,dump_fname,NULL);
 
626
    strncat(dump_fname, ".dmp", sizeof(dump_fname));
 
627
  }
 
628
 
 
629
  hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
 
630
    FILE_ATTRIBUTE_NORMAL, 0);
 
631
  if(hFile)
 
632
  {
 
633
    /* Create minidump */
 
634
    if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
 
635
      hFile, MiniDumpNormal, &info, 0, 0))
 
636
    {
 
637
      fprintf(stderr, "Minidump written to %s\n",
 
638
        _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
 
639
    }
 
640
    else
 
641
    {
 
642
      fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
 
643
        GetLastError());
 
644
    }
 
645
    CloseHandle(hFile);
 
646
  }
 
647
  else
 
648
  {
 
649
    fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
 
650
      GetLastError());
 
651
  }
 
652
  fflush(stderr);
 
653
}
 
654
 
 
655
 
 
656
void my_safe_print_str(const char *name, const char *val, int len)
 
657
{
 
658
  fprintf(stderr,"%s at %p", name, val);
 
659
  __try 
 
660
  {
 
661
    fprintf(stderr,"=%.*s\n", len, val);
 
662
  }
 
663
  __except(EXCEPTION_EXECUTE_HANDLER)
 
664
  {
 
665
    fprintf(stderr,"is an invalid string pointer\n");
 
666
  }
 
667
}
 
668
#endif /*__WIN__*/