vm_dump.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   vm_dump.c -
00004 
00005   $Author: nagachika $
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 VM_FRAME_MAGIC_RESCUE:
00077         magic = "RESCUE";
00078         break;
00079       case 0:
00080         magic = "------";
00081         break;
00082       default:
00083         magic = "(none)";
00084         break;
00085     }
00086 
00087     if (0) {
00088         tmp = rb_inspect(cfp->self);
00089         selfstr = StringValueCStr(tmp);
00090     }
00091     else {
00092         selfstr = "";
00093     }
00094 
00095     if (cfp->iseq != 0) {
00096         if (RUBY_VM_IFUNC_P(cfp->iseq)) {
00097             iseq_name = "<ifunc>";
00098         }
00099         else {
00100             pc = cfp->pc - cfp->iseq->iseq_encoded;
00101             iseq_name = RSTRING_PTR(cfp->iseq->location.label);
00102             line = rb_vm_get_sourceline(cfp);
00103             if (line) {
00104                 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->location.path), line);
00105             }
00106         }
00107     }
00108     else if (cfp->me) {
00109         iseq_name = rb_id2name(cfp->me->def->original_id);
00110         snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
00111         line = -1;
00112     }
00113 
00114     fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
00115             ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp));
00116     if (pc == -1) {
00117         fprintf(stderr, "p:---- ");
00118     }
00119     else {
00120         fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
00121     }
00122     fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack);
00123     fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
00124     fprintf(stderr, "%-6s", magic);
00125     if (line) {
00126         fprintf(stderr, " %s", posbuf);
00127     }
00128     if (VM_FRAME_TYPE_FINISH_P(cfp)) {
00129         fprintf(stderr, " [FINISH]");
00130     }
00131     if (0) {
00132         fprintf(stderr, "              \t");
00133         fprintf(stderr, "iseq: %-24s ", iseq_name);
00134         fprintf(stderr, "self: %-24s ", selfstr);
00135         fprintf(stderr, "%-1s ", biseq_name);
00136     }
00137     fprintf(stderr, "\n");
00138 }
00139 
00140 void
00141 rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
00142 {
00143 #if 0
00144     VALUE *sp = cfp->sp, *ep = cfp->ep;
00145     VALUE *p, *st, *t;
00146 
00147     fprintf(stderr, "-- stack frame ------------\n");
00148     for (p = st = th->stack; p < sp; p++) {
00149         fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
00150 
00151         t = (VALUE *)*p;
00152         if (th->stack <= t && t < sp) {
00153             fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack));
00154         }
00155 
00156         if (p == ep)
00157             fprintf(stderr, " <- ep");
00158 
00159         fprintf(stderr, "\n");
00160     }
00161 #endif
00162 
00163     fprintf(stderr, "-- Control frame information "
00164             "-----------------------------------------------\n");
00165     while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
00166         control_frame_dump(th, cfp);
00167         cfp++;
00168     }
00169     fprintf(stderr, "\n");
00170 }
00171 
00172 void
00173 rb_vmdebug_stack_dump_raw_current(void)
00174 {
00175     rb_thread_t *th = GET_THREAD();
00176     rb_vmdebug_stack_dump_raw(th, th->cfp);
00177 }
00178 
00179 void
00180 rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *ep)
00181 {
00182     int i;
00183     fprintf(stderr, "-- env --------------------\n");
00184 
00185     while (env) {
00186         fprintf(stderr, "--\n");
00187         for (i = 0; i < env->env_size; i++) {
00188             fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", -env->local_size + i, env->env[i],
00189                    (void *)&env->env[i]);
00190             if (&env->env[i] == ep)
00191                 fprintf(stderr, " <- ep");
00192             fprintf(stderr, "\n");
00193         }
00194 
00195         if (env->prev_envval != 0) {
00196             GetEnvPtr(env->prev_envval, env);
00197         }
00198         else {
00199             env = 0;
00200         }
00201     }
00202     fprintf(stderr, "---------------------------\n");
00203 }
00204 
00205 void
00206 rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
00207 {
00208     rb_env_t *env;
00209     char *selfstr;
00210     VALUE val = rb_inspect(proc->block.self);
00211     selfstr = StringValueCStr(val);
00212 
00213     fprintf(stderr, "-- proc -------------------\n");
00214     fprintf(stderr, "self: %s\n", selfstr);
00215     GetEnvPtr(proc->envval, env);
00216     rb_vmdebug_env_dump_raw(env, proc->block.ep);
00217 }
00218 
00219 void
00220 rb_vmdebug_stack_dump_th(VALUE thval)
00221 {
00222     rb_thread_t *th;
00223     GetThreadPtr(thval, th);
00224     rb_vmdebug_stack_dump_raw(th, th->cfp);
00225 }
00226 
00227 #if VMDEBUG > 2
00228 
00229 /* copy from vm.c */
00230 static VALUE *
00231 vm_base_ptr(rb_control_frame_t *cfp)
00232 {
00233     rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00234     VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1;
00235 
00236     if (cfp->iseq->type == ISEQ_TYPE_METHOD) {
00237         bp += 1;
00238     }
00239     return bp;
00240 }
00241 
00242 static void
00243 vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
00244 {
00245     int i;
00246 
00247     VALUE rstr;
00248     VALUE *sp = cfp->sp;
00249     VALUE *ep = cfp->ep;
00250 
00251     int argc = 0, local_size = 0;
00252     const char *name;
00253     rb_iseq_t *iseq = cfp->iseq;
00254 
00255     if (iseq == 0) {
00256         if (RUBYVM_CFUNC_FRAME_P(cfp)) {
00257             name = rb_id2name(cfp->me->called_id);
00258         }
00259         else {
00260             name = "?";
00261         }
00262     }
00263     else if (RUBY_VM_IFUNC_P(iseq)) {
00264         name = "<ifunc>";
00265     }
00266     else {
00267         argc = iseq->argc;
00268         local_size = iseq->local_size;
00269         name = RSTRING_PTR(iseq->location.label);
00270     }
00271 
00272     /* stack trace header */
00273 
00274     if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD||
00275         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP   ||
00276         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK ||
00277         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS ||
00278         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC  ||
00279         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA||
00280         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC ||
00281         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC ||
00282         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL  ||
00283         VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_RESCUE)
00284       {
00285 
00286         VALUE *ptr = ep - local_size;
00287 
00288         control_frame_dump(th, cfp);
00289 
00290         for (i = 0; i < argc; i++) {
00291             rstr = rb_inspect(*ptr);
00292             fprintf(stderr, "  arg   %2d: %8s (%p)\n", i, StringValueCStr(rstr),
00293                    (void *)ptr++);
00294         }
00295         for (; i < local_size - 1; i++) {
00296             rstr = rb_inspect(*ptr);
00297             fprintf(stderr, "  local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
00298                    (void *)ptr++);
00299         }
00300 
00301         ptr = vm_base_ptr(cfp);
00302         for (; ptr < sp; ptr++, i++) {
00303             if (*ptr == Qundef) {
00304                 rstr = rb_str_new2("undef");
00305             }
00306             else {
00307                 rstr = rb_inspect(*ptr);
00308             }
00309             fprintf(stderr, "  stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
00310                     (ptr - th->stack));
00311         }
00312     }
00313     else if (VM_FRAME_TYPE_FINISH_P(cfp)) {
00314         if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) {
00315             vm_stack_dump_each(th, cfp + 1);
00316         }
00317         else {
00318             /* SDR(); */
00319         }
00320     }
00321     else {
00322         rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
00323     }
00324 }
00325 #endif
00326 
00327 void
00328 rb_vmdebug_debug_print_register(rb_thread_t *th)
00329 {
00330     rb_control_frame_t *cfp = th->cfp;
00331     ptrdiff_t pc = -1;
00332     ptrdiff_t ep = cfp->ep - th->stack;
00333     ptrdiff_t cfpi;
00334 
00335     if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00336         pc = cfp->pc - cfp->iseq->iseq_encoded;
00337     }
00338 
00339     if (ep < 0 || (size_t)ep > th->stack_size) {
00340         ep = -1;
00341     }
00342 
00343     cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp;
00344     fprintf(stderr, "  [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
00345             pc, (cfp->sp - th->stack), ep, cfpi);
00346 }
00347 
00348 void
00349 rb_vmdebug_thread_dump_regs(VALUE thval)
00350 {
00351     rb_thread_t *th;
00352     GetThreadPtr(thval, th);
00353     rb_vmdebug_debug_print_register(th);
00354 }
00355 
00356 void
00357 rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp,VALUE *_pc)
00358 {
00359     rb_iseq_t *iseq = cfp->iseq;
00360 
00361     if (iseq != 0) {
00362         VALUE *seq = iseq->iseq;
00363         ptrdiff_t pc = _pc - iseq->iseq_encoded;
00364         int i;
00365 
00366         for (i=0; i<(int)VM_CFP_CNT(th, cfp); i++) {
00367             printf(" ");
00368         }
00369         printf("| ");
00370         if(0)printf("[%03ld] ", (long)(cfp->sp - th->stack));
00371 
00372         /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */
00373         if (pc >= 0) {
00374             rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0);
00375         }
00376     }
00377 
00378 #if VMDEBUG > 3
00379     fprintf(stderr, "        (1)");
00380     rb_vmdebug_debug_print_register(th);
00381 #endif
00382 }
00383 
00384 void
00385 rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp
00386 #if OPT_STACK_CACHING
00387                  , VALUE reg_a, VALUE reg_b
00388 #endif
00389     )
00390 {
00391 #if VMDEBUG > 9
00392     SDR2(cfp);
00393 #endif
00394 
00395 #if VMDEBUG > 3
00396     fprintf(stderr, "        (2)");
00397     rb_vmdebug_debug_print_register(th);
00398 #endif
00399     /* stack_dump_raw(th, cfp); */
00400 
00401 #if VMDEBUG > 2
00402     /* stack_dump_thobj(th); */
00403     vm_stack_dump_each(th, th->cfp);
00404 
00405 #if OPT_STACK_CACHING
00406     {
00407         VALUE rstr;
00408         rstr = rb_inspect(reg_a);
00409         fprintf(stderr, "  sc reg A: %s\n", StringValueCStr(rstr));
00410         rstr = rb_inspect(reg_b);
00411         fprintf(stderr, "  sc reg B: %s\n", StringValueCStr(rstr));
00412     }
00413 #endif
00414     printf
00415         ("--------------------------------------------------------------\n");
00416 #endif
00417 }
00418 
00419 VALUE
00420 rb_vmdebug_thread_dump_state(VALUE self)
00421 {
00422     rb_thread_t *th;
00423     rb_control_frame_t *cfp;
00424     GetThreadPtr(self, th);
00425     cfp = th->cfp;
00426 
00427     fprintf(stderr, "Thread state dump:\n");
00428     fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
00429     fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
00430 
00431     return Qnil;
00432 }
00433 
00434 #if defined(HAVE_BACKTRACE)
00435 # if HAVE_LIBUNWIND
00436 #  undef backtrace
00437 #  define backtrace unw_backtrace
00438 # elif defined(__APPLE__) && defined(__x86_64__)
00439 #  define UNW_LOCAL_ONLY
00440 #  include <libunwind.h>
00441 #  undef backtrace
00442 int backtrace (void **trace, int size) {
00443     unw_cursor_t cursor; unw_context_t uc;
00444     unw_word_t ip;
00445     int n = 0;
00446 
00447     unw_getcontext(&uc);
00448     unw_init_local(&cursor, &uc);
00449     while (unw_step(&cursor) > 0) {
00450         unw_get_reg(&cursor, UNW_REG_IP, &ip);
00451         trace[n++] = (void *)ip;
00452         {
00453             char buf[256];
00454             unw_get_proc_name(&cursor, buf, 256, &ip);
00455             if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) {
00456                 goto darwin_sigtramp;
00457             }
00458         }
00459     }
00460     return n;
00461 darwin_sigtramp:
00462     /* darwin's bundled libunwind doesn't support signal trampoline */
00463     {
00464         ucontext_t *uctx;
00465         /* get _sigtramp's ucontext_t and set values to cursor
00466          * http://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s
00467          * http://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s
00468          */
00469         unw_get_reg(&cursor, UNW_X86_64_RBX, &ip);
00470         uctx = (ucontext_t *)ip;
00471         unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->__ss.__rax);
00472         unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->__ss.__rbx);
00473         unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->__ss.__rcx);
00474         unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->__ss.__rdx);
00475         unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->__ss.__rdi);
00476         unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->__ss.__rsi);
00477         unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->__ss.__rbp);
00478         unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->__ss.__rsp));
00479         unw_set_reg(&cursor, UNW_X86_64_R8,  uctx->uc_mcontext->__ss.__r8);
00480         unw_set_reg(&cursor, UNW_X86_64_R9,  uctx->uc_mcontext->__ss.__r9);
00481         unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->__ss.__r10);
00482         unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->__ss.__r11);
00483         unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->__ss.__r12);
00484         unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->__ss.__r13);
00485         unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->__ss.__r14);
00486         unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->__ss.__r15);
00487         ip = *(unw_word_t*)uctx->uc_mcontext->__ss.__rsp;
00488         unw_set_reg(&cursor, UNW_REG_IP, ip);
00489         trace[n++] = (void *)uctx->uc_mcontext->__ss.__rip;
00490         trace[n++] = (void *)ip;
00491     }
00492     while (unw_step(&cursor) > 0) {
00493         unw_get_reg(&cursor, UNW_REG_IP, &ip);
00494         trace[n++] = (void *)ip;
00495     }
00496     return n;
00497 }
00498 # elif defined(BROKEN_BACKTRACE)
00499 #  undef HAVE_BACKTRACE
00500 #  define HAVE_BACKTRACE 0
00501 # endif
00502 #else
00503 # define HAVE_BACKTRACE 0
00504 #endif
00505 
00506 #if HAVE_BACKTRACE
00507 # include <execinfo.h>
00508 #elif defined(_WIN32)
00509 # include <imagehlp.h>
00510 # ifndef SYMOPT_DEBUG
00511 #  define SYMOPT_DEBUG 0x80000000
00512 # endif
00513 # ifndef MAX_SYM_NAME
00514 # define MAX_SYM_NAME 2000
00515 typedef struct {
00516     DWORD64 Offset;
00517     WORD Segment;
00518     ADDRESS_MODE Mode;
00519 } ADDRESS64;
00520 typedef struct {
00521     DWORD64 Thread;
00522     DWORD ThCallbackStack;
00523     DWORD ThCallbackBStore;
00524     DWORD NextCallback;
00525     DWORD FramePointer;
00526     DWORD64 KiCallUserMode;
00527     DWORD64 KeUserCallbackDispatcher;
00528     DWORD64 SystemRangeStart;
00529     DWORD64 KiUserExceptionDispatcher;
00530     DWORD64 StackBase;
00531     DWORD64 StackLimit;
00532     DWORD64 Reserved[5];
00533 } KDHELP64;
00534 typedef struct {
00535     ADDRESS64 AddrPC;
00536     ADDRESS64 AddrReturn;
00537     ADDRESS64 AddrFrame;
00538     ADDRESS64 AddrStack;
00539     ADDRESS64 AddrBStore;
00540     void *FuncTableEntry;
00541     DWORD64 Params[4];
00542     BOOL Far;
00543     BOOL Virtual;
00544     DWORD64 Reserved[3];
00545     KDHELP64 KdHelp;
00546 } STACKFRAME64;
00547 typedef struct {
00548     ULONG SizeOfStruct;
00549     ULONG TypeIndex;
00550     ULONG64 Reserved[2];
00551     ULONG Index;
00552     ULONG Size;
00553     ULONG64 ModBase;
00554     ULONG Flags;
00555     ULONG64 Value;
00556     ULONG64 Address;
00557     ULONG Register;
00558     ULONG Scope;
00559     ULONG Tag;
00560     ULONG NameLen;
00561     ULONG MaxNameLen;
00562     char Name[1];
00563 } SYMBOL_INFO;
00564 typedef struct {
00565     DWORD SizeOfStruct;
00566     void *Key;
00567     DWORD LineNumber;
00568     char *FileName;
00569     DWORD64 Address;
00570 } IMAGEHLP_LINE64;
00571 typedef void *PREAD_PROCESS_MEMORY_ROUTINE64;
00572 typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64;
00573 typedef void *PGET_MODULE_BASE_ROUTINE64;
00574 typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
00575 # endif
00576 
00577 static void
00578 dump_thread(void *arg)
00579 {
00580     HANDLE dbghelp;
00581     BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL);
00582     BOOL (WINAPI *pSymCleanup)(HANDLE);
00583     BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
00584     DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64);
00585     BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
00586     BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
00587     HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
00588     DWORD tid = *(DWORD *)arg;
00589     HANDLE ph;
00590     HANDLE th;
00591 
00592     dbghelp = LoadLibrary("dbghelp.dll");
00593     if (!dbghelp) return;
00594     pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize");
00595     pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup");
00596     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");
00597     pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64");
00598     pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr");
00599     pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64");
00600     pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread");
00601     if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 &&
00602         pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) {
00603         SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
00604         ph = GetCurrentProcess();
00605         pSymInitialize(ph, NULL, TRUE);
00606         th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid);
00607         if (th) {
00608             if (SuspendThread(th) != (DWORD)-1) {
00609                 CONTEXT context;
00610                 memset(&context, 0, sizeof(context));
00611                 context.ContextFlags = CONTEXT_FULL;
00612                 if (GetThreadContext(th, &context)) {
00613                     char libpath[MAX_PATH];
00614                     char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
00615                     SYMBOL_INFO *info = (SYMBOL_INFO *)buf;
00616                     DWORD mac;
00617                     STACKFRAME64 frame;
00618                     memset(&frame, 0, sizeof(frame));
00619 #if defined(_M_AMD64) || defined(__x86_64__)
00620                     mac = IMAGE_FILE_MACHINE_AMD64;
00621                     frame.AddrPC.Mode = AddrModeFlat;
00622                     frame.AddrPC.Offset = context.Rip;
00623                     frame.AddrFrame.Mode = AddrModeFlat;
00624                     frame.AddrFrame.Offset = context.Rbp;
00625                     frame.AddrStack.Mode = AddrModeFlat;
00626                     frame.AddrStack.Offset = context.Rsp;
00627 #elif defined(_M_IA64) || defined(__ia64__)
00628                     mac = IMAGE_FILE_MACHINE_IA64;
00629                     frame.AddrPC.Mode = AddrModeFlat;
00630                     frame.AddrPC.Offset = context.StIIP;
00631                     frame.AddrBStore.Mode = AddrModeFlat;
00632                     frame.AddrBStore.Offset = context.RsBSP;
00633                     frame.AddrStack.Mode = AddrModeFlat;
00634                     frame.AddrStack.Offset = context.IntSp;
00635 #else   /* i386 */
00636                     mac = IMAGE_FILE_MACHINE_I386;
00637                     frame.AddrPC.Mode = AddrModeFlat;
00638                     frame.AddrPC.Offset = context.Eip;
00639                     frame.AddrFrame.Mode = AddrModeFlat;
00640                     frame.AddrFrame.Offset = context.Ebp;
00641                     frame.AddrStack.Mode = AddrModeFlat;
00642                     frame.AddrStack.Offset = context.Esp;
00643 #endif
00644 
00645                     while (pStackWalk64(mac, ph, th, &frame, &context, NULL,
00646                                         NULL, NULL, NULL)) {
00647                         DWORD64 addr = frame.AddrPC.Offset;
00648                         IMAGEHLP_LINE64 line;
00649                         DWORD64 displacement;
00650                         DWORD tmp;
00651 
00652                         if (addr == frame.AddrReturn.Offset || addr == 0 ||
00653                             frame.AddrReturn.Offset == 0)
00654                             break;
00655 
00656                         memset(buf, 0, sizeof(buf));
00657                         info->SizeOfStruct = sizeof(SYMBOL_INFO);
00658                         info->MaxNameLen = MAX_SYM_NAME;
00659                         if (pSymFromAddr(ph, addr, &displacement, info)) {
00660                             if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath)))
00661                                 fprintf(stderr, "%s", libpath);
00662                             fprintf(stderr, "(%s+0x%I64x)",
00663                                     info->Name, displacement);
00664                         }
00665                         fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
00666                         memset(&line, 0, sizeof(line));
00667                         line.SizeOfStruct = sizeof(line);
00668                         if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
00669                             fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
00670                         fprintf(stderr, "\n");
00671                     }
00672                 }
00673 
00674                 ResumeThread(th);
00675             }
00676             CloseHandle(th);
00677         }
00678         pSymCleanup(ph);
00679     }
00680     FreeLibrary(dbghelp);
00681 }
00682 #endif
00683 
00684 void
00685 rb_print_backtrace(void)
00686 {
00687 #if HAVE_BACKTRACE
00688 #define MAX_NATIVE_TRACE 1024
00689     static void *trace[MAX_NATIVE_TRACE];
00690     int n = backtrace(trace, MAX_NATIVE_TRACE);
00691     char **syms = backtrace_symbols(trace, n);
00692 
00693     if (syms) {
00694 #ifdef USE_ELF
00695         rb_dump_backtrace_with_lines(n, trace, syms);
00696 #else
00697         int i;
00698         for (i=0; i<n; i++) {
00699             fprintf(stderr, "%s\n", syms[i]);
00700         }
00701 #endif
00702         free(syms);
00703     }
00704 #elif defined(_WIN32)
00705     DWORD tid = GetCurrentThreadId();
00706     HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
00707     if (th != (HANDLE)-1)
00708         WaitForSingleObject(th, INFINITE);
00709 #endif
00710 }
00711 
00712 void
00713 rb_vm_bugreport(void)
00714 {
00715 #ifdef __linux__
00716 # define PROC_MAPS_NAME "/proc/self/maps"
00717 #endif
00718 #ifdef PROC_MAPS_NAME
00719     enum {other_runtime_info = 1};
00720 #else
00721     enum {other_runtime_info = 0};
00722 #endif
00723     const rb_vm_t *const vm = GET_VM();
00724 
00725 #if defined __APPLE__
00726     fputs("-- Crash Report log information "
00727           "--------------------------------------------\n"
00728           "   See Crash Report log file under the one of following:\n"
00729           "     * ~/Library/Logs/CrashReporter\n"
00730           "     * /Library/Logs/CrashReporter\n"
00731           "     * ~/Library/Logs/DiagnosticReports\n"
00732           "     * /Library/Logs/DiagnosticReports\n"
00733           "   for more details.\n"
00734           "\n",
00735           stderr);
00736 #endif
00737     if (vm) {
00738         SDR();
00739         rb_backtrace_print_as_bugreport();
00740         fputs("\n", stderr);
00741     }
00742 
00743 #if HAVE_BACKTRACE || defined(_WIN32)
00744     fprintf(stderr, "-- C level backtrace information "
00745             "-------------------------------------------\n");
00746     rb_print_backtrace();
00747 
00748 
00749     fprintf(stderr, "\n");
00750 #endif /* HAVE_BACKTRACE */
00751 
00752     if (other_runtime_info || vm) {
00753         fprintf(stderr, "-- Other runtime information "
00754                 "-----------------------------------------------\n\n");
00755     }
00756     if (vm) {
00757         int i;
00758         VALUE name;
00759         long len;
00760         const int max_name_length = 1024;
00761 # define LIMITED_NAME_LENGTH(s) \
00762         (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)
00763 
00764         name = vm->progname;
00765         fprintf(stderr, "* Loaded script: %.*s\n",
00766                 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
00767         fprintf(stderr, "\n");
00768         fprintf(stderr, "* Loaded features:\n\n");
00769         for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
00770             name = RARRAY_AREF(vm->loaded_features, i);
00771             if (RB_TYPE_P(name, T_STRING)) {
00772                 fprintf(stderr, " %4d %.*s\n", i,
00773                         LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
00774             }
00775             else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) {
00776                 const char *const type = RB_TYPE_P(name, T_CLASS) ?
00777                     "class" : "module";
00778                 name = rb_class_name(name);
00779                 fprintf(stderr, " %4d %s:%.*s\n", i, type,
00780                         LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
00781             }
00782             else {
00783                 VALUE klass = rb_class_name(CLASS_OF(name));
00784                 fprintf(stderr, " %4d #<%.*s:%p>\n", i,
00785                         LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
00786                         (void *)name);
00787             }
00788         }
00789         fprintf(stderr, "\n");
00790     }
00791 
00792     {
00793 #ifdef PROC_MAPS_NAME
00794         {
00795             FILE *fp = fopen(PROC_MAPS_NAME, "r");
00796             if (fp) {
00797                 fprintf(stderr, "* Process memory map:\n\n");
00798 
00799                 while (!feof(fp)) {
00800                     char buff[0x100];
00801                     size_t rn = fread(buff, 1, 0x100, fp);
00802                     if (fwrite(buff, 1, rn, stderr) != rn)
00803                         break;
00804                 }
00805 
00806                 fclose(fp);
00807                 fprintf(stderr, "\n\n");
00808             }
00809         }
00810 #endif /* __linux__ */
00811     }
00812 }
00813 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7