Ruby
2.0.0p247(2013-06-27revision41674)
|
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