Ruby  2.0.0p247(2013-06-27revision41674)
vm_dump.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   vm_dump.c -
00004 
00005   $Author: ko1 $
00006 
00007   Copyright (C) 2004-2007 Koichi Sasada
00008 
00009 **********************************************************************/
00010 
00011 
00012 #include "ruby/ruby.h"
00013 #include "addr2line.h"
00014 #include "vm_core.h"
00015 #include "internal.h"
00016 
00017 /* see vm_insnhelper.h for the values */
00018 #ifndef VMDEBUG
00019 #define VMDEBUG 0
00020 #endif
00021 
00022 #define MAX_POSBUF 128
00023 
00024 #define VM_CFP_CNT(th, cfp) \
00025   ((rb_control_frame_t *)((th)->stack + (th)->stack_size) - (rb_control_frame_t *)(cfp))
00026 
00027 static void
00028 control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
00029 {
00030     ptrdiff_t pc = -1;
00031     ptrdiff_t ep = cfp->ep - th->stack;
00032     char ep_in_heap = ' ';
00033     char posbuf[MAX_POSBUF+1];
00034     int line = 0;
00035 
00036     const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
00037     VALUE tmp;
00038 
00039     if (cfp->block_iseq != 0 && BUILTIN_TYPE(cfp->block_iseq) != T_NODE) {
00040         biseq_name = "";        /* RSTRING(cfp->block_iseq->location.label)->ptr; */
00041     }
00042 
00043     if (ep < 0 || (size_t)ep > th->stack_size) {
00044         ep = (ptrdiff_t)cfp->ep;
00045         ep_in_heap = 'p';
00046     }
00047 
00048     switch (VM_FRAME_TYPE(cfp)) {
00049       case VM_FRAME_MAGIC_TOP:
00050         magic = "TOP";
00051         break;
00052       case VM_FRAME_MAGIC_METHOD:
00053         magic = "METHOD";
00054         break;
00055       case VM_FRAME_MAGIC_CLASS:
00056         magic = "CLASS";
00057         break;
00058       case VM_FRAME_MAGIC_BLOCK:
00059         magic = "BLOCK";
00060         break;
00061       case VM_FRAME_MAGIC_CFUNC:
00062         magic = "CFUNC";
00063         break;
00064       case VM_FRAME_MAGIC_PROC:
00065         magic = "PROC";
00066         break;
00067       case VM_FRAME_MAGIC_LAMBDA:
00068         magic = "LAMBDA";
00069         break;
00070       case VM_FRAME_MAGIC_IFUNC:
00071         magic = "IFUNC";
00072         break;
00073       case VM_FRAME_MAGIC_EVAL:
00074         magic = "EVAL";
00075         break;
00076       case 0:
00077         magic = "------";
00078         break;
00079       default:
00080         magic = "(none)";
00081         break;
00082     }
00083 
00084     if (0) {
00085         tmp = rb_inspect(cfp->self);
00086         selfstr = StringValueCStr(tmp);
00087     }
00088     else {
00089         selfstr = "";
00090     }
00091 
00092     if (cfp->iseq != 0) {
00093         if (RUBY_VM_IFUNC_P(cfp->iseq)) {
00094             iseq_name = "<ifunc>";
00095         }
00096         else {
00097             pc = cfp->pc - cfp->iseq->iseq_encoded;
00098             iseq_name = RSTRING_PTR(cfp->iseq->location.label);
00099             line = rb_vm_get_sourceline(cfp);
00100             if (line) {
00101                 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->location.path), line);
00102             }
00103         }
00104     }
00105     else if (cfp->me) {
00106         iseq_name = rb_id2name(cfp->me->def->original_id);
00107         snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
00108         line = -1;
00109     }
00110 
00111     fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
00112             ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp));
00113     if (pc == -1) {
00114         fprintf(stderr, "p:---- ");
00115     }
00116     else {
00117         fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
00118     }
00119     fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack);
00120     fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
00121     fprintf(stderr, "%-6s", magic);
00122     if (line) {
00123         fprintf(stderr, " %s", posbuf);
00124     }
00125     if (VM_FRAME_TYPE_FINISH_P(cfp)) {
00126         fprintf(stderr, " [FINISH]");
00127     }
00128     if (0) {
00129         fprintf(stderr, "              \t");
00130         fprintf(stderr, "iseq: %-24s ", iseq_name);
00131         fprintf(stderr, "self: %-24s ", selfstr);
00132         fprintf(stderr, "%-1s ", biseq_name);
00133     }
00134     fprintf(stderr, "\n");
00135 }
00136 
00137 void
00138 rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
00139 {
00140 #if 0
00141     VALUE *sp = cfp->sp, *ep = cfp->ep;
00142     VALUE *p, *st, *t;
00143 
00144     fprintf(stderr, "-- stack frame ------------\n");
00145     for (p = st = th->stack; p < sp; p++) {
00146         fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
00147 
00148         t = (VALUE *)*p;
00149         if (th->stack <= t && t < sp) {
00150             fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack));
00151         }
00152 
00153         if (p == ep)
00154             fprintf(stderr, " <- ep");
00155 
00156         fprintf(stderr, "\n");
00157     }
00158 #endif
00159 
00160     fprintf(stderr, "-- Control frame information "
00161             "-----------------------------------------------\n");
00162     while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
00163         control_frame_dump(th, cfp);
00164         cfp++;
00165     }
00166     fprintf(stderr, "\n");
00167 }
00168 
00169 void
00170 rb_vmdebug_stack_dump_raw_current(void)
00171 {
00172     rb_thread_t *th = GET_THREAD();
00173     rb_vmdebug_stack_dump_raw(th, th->cfp);
00174 }
00175 
00176 void
00177 rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *ep)
00178 {
00179     int i;
00180     fprintf(stderr, "-- env --------------------\n");
00181 
00182     while (env) {
00183         fprintf(stderr, "--\n");
00184         for (i = 0; i < env->env_size; i++) {
00185             fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", -env->local_size + i, env->env[i],
00186                    (void *)&env->env[i]);
00187             if (&env->env[i] == ep)
00188                 fprintf(stderr, " <- ep");
00189             fprintf(stderr, "\n");
00190         }
00191 
00192         if (env->prev_envval != 0) {
00193             GetEnvPtr(env->prev_envval, env);
00194         }
00195         else {
00196             env = 0;
00197         }
00198     }
00199     fprintf(stderr, "---------------------------\n");
00200 }
00201 
00202 void
00203 rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
00204 {
00205     rb_env_t *env;
00206     char *selfstr;
00207     VALUE val = rb_inspect(proc->block.self);
00208     selfstr = StringValueCStr(val);
00209 
00210     fprintf(stderr, "-- proc -------------------\n");
00211     fprintf(stderr, "self: %s\n", selfstr);
00212     GetEnvPtr(proc->envval, env);
00213     rb_vmdebug_env_dump_raw(env, proc->block.ep);
00214 }
00215 
00216 void
00217 rb_vmdebug_stack_dump_th(VALUE thval)
00218 {
00219     rb_thread_t *th;
00220     GetThreadPtr(thval, th);
00221     rb_vmdebug_stack_dump_raw(th, th->cfp);
00222 }
00223 
00224 #if VMDEBUG > 2
00225 
00226 /* copy from vm.c */
00227 static VALUE *
00228 vm_base_ptr(rb_control_frame_t *cfp)
00229 {
00230     rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00231     VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1;
00232 
00233     if (cfp->iseq->type == ISEQ_TYPE_METHOD) {
00234         bp += 1;
00235     }
00236     return bp;
00237 }
00238 
00239 static void
00240 vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
00241 {
00242     int i;
00243 
00244     VALUE rstr;
00245     VALUE *sp = cfp->sp;
00246     VALUE *ep = cfp->ep;
00247 
00248     int argc = 0, local_size = 0;
00249     const char *name;
00250     rb_iseq_t *iseq = cfp->iseq;
00251 
00252     if (iseq == 0) {
00253         if (RUBYVM_CFUNC_FRAME_P(cfp)) {
00254             name = rb_id2name(cfp->me->called_id);
00255         }
00256         else {
00257             name = "?";
00258         }
00259     }
00260     else if (RUBY_VM_IFUNC_P(iseq)) {
00261         name = "<ifunc>";
00262     }
00263     else {
00264         argc = iseq->argc;
00265         local_size = iseq->local_size;
00266         name = RSTRING_PTR(iseq->location.label);
00267     }
00268 
00269     /* stack trace header */
00270 
00271     if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD ||
00272         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP ||
00273         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK ||
00274         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS ||
00275         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC ||
00276         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA ||
00277         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC ||
00278         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC ||
00279         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL) {
00280 
00281         VALUE *ptr = ep - local_size;
00282 
00283         control_frame_dump(th, cfp);
00284 
00285         for (i = 0; i < argc; i++) {
00286             rstr = rb_inspect(*ptr);
00287             fprintf(stderr, "  arg   %2d: %8s (%p)\n", i, StringValueCStr(rstr),
00288                    (void *)ptr++);
00289         }
00290         for (; i < local_size - 1; i++) {
00291             rstr = rb_inspect(*ptr);
00292             fprintf(stderr, "  local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
00293                    (void *)ptr++);
00294         }
00295 
00296         ptr = vm_base_ptr(cfp);
00297         for (; ptr < sp; ptr++, i++) {
00298             if (*ptr == Qundef) {
00299                 rstr = rb_str_new2("undef");
00300             }
00301             else {
00302                 rstr = rb_inspect(*ptr);
00303             }
00304             fprintf(stderr, "  stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
00305                     (ptr - th->stack));
00306         }
00307     }
00308     else if (VM_FRAME_TYPE_FINISH_P(cfp)) {
00309         if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) {
00310             vm_stack_dump_each(th, cfp + 1);
00311         }
00312         else {
00313             /* SDR(); */
00314         }
00315     }
00316     else {
00317         rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
00318     }
00319 }
00320 #endif
00321 
00322 void
00323 rb_vmdebug_debug_print_register(rb_thread_t *th)
00324 {
00325     rb_control_frame_t *cfp = th->cfp;
00326     ptrdiff_t pc = -1;
00327     ptrdiff_t ep = cfp->ep - th->stack;
00328     ptrdiff_t cfpi;
00329 
00330     if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00331         pc = cfp->pc - cfp->iseq->iseq_encoded;
00332     }
00333 
00334     if (ep < 0 || (size_t)ep > th->stack_size) {
00335         ep = -1;
00336     }
00337 
00338     cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp;
00339     fprintf(stderr, "  [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
00340             pc, (cfp->sp - th->stack), ep, cfpi);
00341 }
00342 
00343 void
00344 rb_vmdebug_thread_dump_regs(VALUE thval)
00345 {
00346     rb_thread_t *th;
00347     GetThreadPtr(thval, th);
00348     rb_vmdebug_debug_print_register(th);
00349 }
00350 
00351 void
00352 rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp)
00353 {
00354     rb_iseq_t *iseq = cfp->iseq;
00355 
00356     if (iseq != 0) {
00357         VALUE *seq = iseq->iseq;
00358         ptrdiff_t pc = cfp->pc - iseq->iseq_encoded;
00359         int i;
00360 
00361         for (i=0; i<(int)VM_CFP_CNT(th, cfp); i++) {
00362             printf(" ");
00363         }
00364         printf("| ");
00365         /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */
00366         if (pc >= 0) {
00367             rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0);
00368         }
00369     }
00370 
00371 #if VMDEBUG > 3
00372     fprintf(stderr, "        (1)");
00373     rb_vmdebug_debug_print_register(th);
00374 #endif
00375 }
00376 
00377 void
00378 rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp
00379 #if OPT_STACK_CACHING
00380                  , VALUE reg_a, VALUE reg_b
00381 #endif
00382     )
00383 {
00384 #if VMDEBUG > 9
00385     SDR2(cfp);
00386 #endif
00387 
00388 #if VMDEBUG > 3
00389     fprintf(stderr, "        (2)");
00390     rb_vmdebug_debug_print_register(th);
00391 #endif
00392     /* stack_dump_raw(th, cfp); */
00393 
00394 #if VMDEBUG > 2
00395     /* stack_dump_thobj(th); */
00396     vm_stack_dump_each(th, th->cfp);
00397 
00398 #if OPT_STACK_CACHING
00399     {
00400         VALUE rstr;
00401         rstr = rb_inspect(reg_a);
00402         fprintf(stderr, "  sc reg A: %s\n", StringValueCStr(rstr));
00403         rstr = rb_inspect(reg_b);
00404         fprintf(stderr, "  sc reg B: %s\n", StringValueCStr(rstr));
00405     }
00406 #endif
00407     printf
00408         ("--------------------------------------------------------------\n");
00409 #endif
00410 }
00411 
00412 VALUE
00413 rb_vmdebug_thread_dump_state(VALUE self)
00414 {
00415     rb_thread_t *th;
00416     rb_control_frame_t *cfp;
00417     GetThreadPtr(self, th);
00418     cfp = th->cfp;
00419 
00420     fprintf(stderr, "Thread state dump:\n");
00421     fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
00422     fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
00423 
00424     return Qnil;
00425 }
00426 
00427 #ifndef HAVE_BACKTRACE
00428 #define HAVE_BACKTRACE 0
00429 #endif
00430 #if HAVE_BACKTRACE
00431 # include <execinfo.h>
00432 #elif defined(_WIN32)
00433 # include <imagehlp.h>
00434 # ifndef SYMOPT_DEBUG
00435 #  define SYMOPT_DEBUG 0x80000000
00436 # endif
00437 # ifndef MAX_SYM_NAME
00438 # define MAX_SYM_NAME 2000
00439 typedef struct {
00440     DWORD64 Offset;
00441     WORD Segment;
00442     ADDRESS_MODE Mode;
00443 } ADDRESS64;
00444 typedef struct {
00445     DWORD64 Thread;
00446     DWORD ThCallbackStack;
00447     DWORD ThCallbackBStore;
00448     DWORD NextCallback;
00449     DWORD FramePointer;
00450     DWORD64 KiCallUserMode;
00451     DWORD64 KeUserCallbackDispatcher;
00452     DWORD64 SystemRangeStart;
00453     DWORD64 KiUserExceptionDispatcher;
00454     DWORD64 StackBase;
00455     DWORD64 StackLimit;
00456     DWORD64 Reserved[5];
00457 } KDHELP64;
00458 typedef struct {
00459     ADDRESS64 AddrPC;
00460     ADDRESS64 AddrReturn;
00461     ADDRESS64 AddrFrame;
00462     ADDRESS64 AddrStack;
00463     ADDRESS64 AddrBStore;
00464     void *FuncTableEntry;
00465     DWORD64 Params[4];
00466     BOOL Far;
00467     BOOL Virtual;
00468     DWORD64 Reserved[3];
00469     KDHELP64 KdHelp;
00470 } STACKFRAME64;
00471 typedef struct {
00472     ULONG SizeOfStruct;
00473     ULONG TypeIndex;
00474     ULONG64 Reserved[2];
00475     ULONG Index;
00476     ULONG Size;
00477     ULONG64 ModBase;
00478     ULONG Flags;
00479     ULONG64 Value;
00480     ULONG64 Address;
00481     ULONG Register;
00482     ULONG Scope;
00483     ULONG Tag;
00484     ULONG NameLen;
00485     ULONG MaxNameLen;
00486     char Name[1];
00487 } SYMBOL_INFO;
00488 typedef struct {
00489     DWORD SizeOfStruct;
00490     void *Key;
00491     DWORD LineNumber;
00492     char *FileName;
00493     DWORD64 Address;
00494 } IMAGEHLP_LINE64;
00495 typedef void *PREAD_PROCESS_MEMORY_ROUTINE64;
00496 typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64;
00497 typedef void *PGET_MODULE_BASE_ROUTINE64;
00498 typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
00499 # endif
00500 
00501 static void
00502 dump_thread(void *arg)
00503 {
00504     HANDLE dbghelp;
00505     BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL);
00506     BOOL (WINAPI *pSymCleanup)(HANDLE);
00507     BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
00508     DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64);
00509     BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
00510     BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
00511     HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
00512     DWORD tid = *(DWORD *)arg;
00513     HANDLE ph;
00514     HANDLE th;
00515 
00516     dbghelp = LoadLibrary("dbghelp.dll");
00517     if (!dbghelp) return;
00518     pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize");
00519     pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup");
00520     pStackWalk64 = (BOOL (WINAPI *)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64))GetProcAddress(dbghelp, "StackWalk64");
00521     pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64");
00522     pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr");
00523     pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64");
00524     pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread");
00525     if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 &&
00526         pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) {
00527         SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
00528         ph = GetCurrentProcess();
00529         pSymInitialize(ph, NULL, TRUE);
00530         th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid);
00531         if (th) {
00532             if (SuspendThread(th) != (DWORD)-1) {
00533                 CONTEXT context;
00534                 memset(&context, 0, sizeof(context));
00535                 context.ContextFlags = CONTEXT_FULL;
00536                 if (GetThreadContext(th, &context)) {
00537                     char libpath[MAX_PATH];
00538                     char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
00539                     SYMBOL_INFO *info = (SYMBOL_INFO *)buf;
00540                     DWORD mac;
00541                     STACKFRAME64 frame;
00542                     memset(&frame, 0, sizeof(frame));
00543 #if defined(_M_AMD64) || defined(__x86_64__)
00544                     mac = IMAGE_FILE_MACHINE_AMD64;
00545                     frame.AddrPC.Mode = AddrModeFlat;
00546                     frame.AddrPC.Offset = context.Rip;
00547                     frame.AddrFrame.Mode = AddrModeFlat;
00548                     frame.AddrFrame.Offset = context.Rbp;
00549                     frame.AddrStack.Mode = AddrModeFlat;
00550                     frame.AddrStack.Offset = context.Rsp;
00551 #elif defined(_M_IA64) || defined(__ia64__)
00552                     mac = IMAGE_FILE_MACHINE_IA64;
00553                     frame.AddrPC.Mode = AddrModeFlat;
00554                     frame.AddrPC.Offset = context.StIIP;
00555                     frame.AddrBStore.Mode = AddrModeFlat;
00556                     frame.AddrBStore.Offset = context.RsBSP;
00557                     frame.AddrStack.Mode = AddrModeFlat;
00558                     frame.AddrStack.Offset = context.IntSp;
00559 #else   /* i386 */
00560                     mac = IMAGE_FILE_MACHINE_I386;
00561                     frame.AddrPC.Mode = AddrModeFlat;
00562                     frame.AddrPC.Offset = context.Eip;
00563                     frame.AddrFrame.Mode = AddrModeFlat;
00564                     frame.AddrFrame.Offset = context.Ebp;
00565                     frame.AddrStack.Mode = AddrModeFlat;
00566                     frame.AddrStack.Offset = context.Esp;
00567 #endif
00568 
00569                     while (pStackWalk64(mac, ph, th, &frame, &context, NULL,
00570                                         NULL, NULL, NULL)) {
00571                         DWORD64 addr = frame.AddrPC.Offset;
00572                         IMAGEHLP_LINE64 line;
00573                         DWORD64 displacement;
00574                         DWORD tmp;
00575 
00576                         if (addr == frame.AddrReturn.Offset || addr == 0 ||
00577                             frame.AddrReturn.Offset == 0)
00578                             break;
00579 
00580                         memset(buf, 0, sizeof(buf));
00581                         info->SizeOfStruct = sizeof(SYMBOL_INFO);
00582                         info->MaxNameLen = MAX_SYM_NAME;
00583                         if (pSymFromAddr(ph, addr, &displacement, info)) {
00584                             if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath)))
00585                                 fprintf(stderr, "%s", libpath);
00586                             fprintf(stderr, "(%s+0x%I64x)",
00587                                     info->Name, displacement);
00588                         }
00589                         fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
00590                         memset(&line, 0, sizeof(line));
00591                         line.SizeOfStruct = sizeof(line);
00592                         if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
00593                             fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
00594                         fprintf(stderr, "\n");
00595                     }
00596                 }
00597 
00598                 ResumeThread(th);
00599             }
00600             CloseHandle(th);
00601         }
00602         pSymCleanup(ph);
00603     }
00604     FreeLibrary(dbghelp);
00605 }
00606 #endif
00607 
00608 void
00609 rb_vm_bugreport(void)
00610 {
00611 #ifdef __linux__
00612 # define PROC_MAPS_NAME "/proc/self/maps"
00613 #endif
00614 #ifdef PROC_MAPS_NAME
00615     enum {other_runtime_info = 1};
00616 #else
00617     enum {other_runtime_info = 0};
00618 #endif
00619     const rb_vm_t *const vm = GET_VM();
00620 
00621 #if defined __APPLE__
00622     fputs("-- Crash Report log information "
00623           "--------------------------------------------\n"
00624           "   See Crash Report log file under the one of following:\n"
00625           "     * ~/Library/Logs/CrashReporter\n"
00626           "     * /Library/Logs/CrashReporter\n"
00627           "     * ~/Library/Logs/DiagnosticReports\n"
00628           "     * /Library/Logs/DiagnosticReports\n"
00629           "   the more detail of.\n"
00630           "\n",
00631           stderr);
00632 #endif
00633     if (vm) {
00634         SDR();
00635         rb_backtrace_print_as_bugreport();
00636         fputs("\n", stderr);
00637     }
00638 
00639 #if HAVE_BACKTRACE || defined(_WIN32)
00640     fprintf(stderr, "-- C level backtrace information "
00641             "-------------------------------------------\n");
00642 
00643     {
00644 #if HAVE_BACKTRACE
00645 #define MAX_NATIVE_TRACE 1024
00646         static void *trace[MAX_NATIVE_TRACE];
00647         int n = backtrace(trace, MAX_NATIVE_TRACE);
00648         char **syms = backtrace_symbols(trace, n);
00649 
00650         if (syms) {
00651 #ifdef USE_ELF
00652             rb_dump_backtrace_with_lines(n, trace, syms);
00653 #else
00654             int i;
00655             for (i=0; i<n; i++) {
00656                 fprintf(stderr, "%s\n", syms[i]);
00657             }
00658 #endif
00659             free(syms);
00660         }
00661 #elif defined(_WIN32)
00662         DWORD tid = GetCurrentThreadId();
00663         HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
00664         if (th != (HANDLE)-1)
00665             WaitForSingleObject(th, INFINITE);
00666 #endif
00667     }
00668 
00669     fprintf(stderr, "\n");
00670 #endif /* HAVE_BACKTRACE */
00671 
00672     if (other_runtime_info || vm) {
00673         fprintf(stderr, "-- Other runtime information "
00674                 "-----------------------------------------------\n\n");
00675     }
00676     if (vm) {
00677         int i;
00678         VALUE name;
00679         long len;
00680         const int max_name_length = 1024;
00681 # define LIMITED_NAME_LENGTH(s) \
00682         (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)
00683 
00684         name = vm->progname;
00685         fprintf(stderr, "* Loaded script: %.*s\n",
00686                 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
00687         fprintf(stderr, "\n");
00688         fprintf(stderr, "* Loaded features:\n\n");
00689         for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
00690             name = RARRAY_PTR(vm->loaded_features)[i];
00691             if (RB_TYPE_P(name, T_STRING)) {
00692                 fprintf(stderr, " %4d %.*s\n", i,
00693                         LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
00694             }
00695             else {
00696                 fprintf(stderr, " %4d #<%s:%p>\n", i,
00697                         rb_class2name(CLASS_OF(name)), (void *)name);
00698             }
00699         }
00700         fprintf(stderr, "\n");
00701     }
00702 
00703     {
00704 #ifdef PROC_MAPS_NAME
00705         {
00706             FILE *fp = fopen(PROC_MAPS_NAME, "r");
00707             if (fp) {
00708                 fprintf(stderr, "* Process memory map:\n\n");
00709 
00710                 while (!feof(fp)) {
00711                     char buff[0x100];
00712                     size_t rn = fread(buff, 1, 0x100, fp);
00713                     if (fwrite(buff, 1, rn, stderr) != rn)
00714                         break;
00715                 }
00716 
00717                 fclose(fp);
00718                 fprintf(stderr, "\n\n");
00719             }
00720         }
00721 #endif /* __linux__ */
00722     }
00723 }
00724