1/********************************************************************** 2 3 vm_dump.c - 4 5 $Author: ko1 $ 6 7 Copyright (C) 2004-2007 Koichi Sasada 8 9**********************************************************************/ 10 11 12#include "ruby/ruby.h" 13#include "addr2line.h" 14#include "vm_core.h" 15#include "internal.h" 16 17/* see vm_insnhelper.h for the values */ 18#ifndef VMDEBUG 19#define VMDEBUG 0 20#endif 21 22#define MAX_POSBUF 128 23 24#define VM_CFP_CNT(th, cfp) \ 25 ((rb_control_frame_t *)((th)->stack + (th)->stack_size) - (rb_control_frame_t *)(cfp)) 26 27static void 28control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) 29{ 30 ptrdiff_t pc = -1; 31 ptrdiff_t ep = cfp->ep - th->stack; 32 char ep_in_heap = ' '; 33 char posbuf[MAX_POSBUF+1]; 34 int line = 0; 35 36 const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; 37 VALUE tmp; 38 39 if (cfp->block_iseq != 0 && BUILTIN_TYPE(cfp->block_iseq) != T_NODE) { 40 biseq_name = ""; /* RSTRING(cfp->block_iseq->location.label)->ptr; */ 41 } 42 43 if (ep < 0 || (size_t)ep > th->stack_size) { 44 ep = (ptrdiff_t)cfp->ep; 45 ep_in_heap = 'p'; 46 } 47 48 switch (VM_FRAME_TYPE(cfp)) { 49 case VM_FRAME_MAGIC_TOP: 50 magic = "TOP"; 51 break; 52 case VM_FRAME_MAGIC_METHOD: 53 magic = "METHOD"; 54 break; 55 case VM_FRAME_MAGIC_CLASS: 56 magic = "CLASS"; 57 break; 58 case VM_FRAME_MAGIC_BLOCK: 59 magic = "BLOCK"; 60 break; 61 case VM_FRAME_MAGIC_CFUNC: 62 magic = "CFUNC"; 63 break; 64 case VM_FRAME_MAGIC_PROC: 65 magic = "PROC"; 66 break; 67 case VM_FRAME_MAGIC_LAMBDA: 68 magic = "LAMBDA"; 69 break; 70 case VM_FRAME_MAGIC_IFUNC: 71 magic = "IFUNC"; 72 break; 73 case VM_FRAME_MAGIC_EVAL: 74 magic = "EVAL"; 75 break; 76 case 0: 77 magic = "------"; 78 break; 79 default: 80 magic = "(none)"; 81 break; 82 } 83 84 if (0) { 85 tmp = rb_inspect(cfp->self); 86 selfstr = StringValueCStr(tmp); 87 } 88 else { 89 selfstr = ""; 90 } 91 92 if (cfp->iseq != 0) { 93 if (RUBY_VM_IFUNC_P(cfp->iseq)) { 94 iseq_name = "<ifunc>"; 95 } 96 else { 97 pc = cfp->pc - cfp->iseq->iseq_encoded; 98 iseq_name = RSTRING_PTR(cfp->iseq->location.label); 99 line = rb_vm_get_sourceline(cfp); 100 if (line) { 101 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->location.path), line); 102 } 103 } 104 } 105 else if (cfp->me) { 106 iseq_name = rb_id2name(cfp->me->def->original_id); 107 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); 108 line = -1; 109 } 110 111 fprintf(stderr, "c:%04"PRIdPTRDIFF" ", 112 ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp)); 113 if (pc == -1) { 114 fprintf(stderr, "p:---- "); 115 } 116 else { 117 fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); 118 } 119 fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack); 120 fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); 121 fprintf(stderr, "%-6s", magic); 122 if (line) { 123 fprintf(stderr, " %s", posbuf); 124 } 125 if (VM_FRAME_TYPE_FINISH_P(cfp)) { 126 fprintf(stderr, " [FINISH]"); 127 } 128 if (0) { 129 fprintf(stderr, " \t"); 130 fprintf(stderr, "iseq: %-24s ", iseq_name); 131 fprintf(stderr, "self: %-24s ", selfstr); 132 fprintf(stderr, "%-1s ", biseq_name); 133 } 134 fprintf(stderr, "\n"); 135} 136 137void 138rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp) 139{ 140#if 0 141 VALUE *sp = cfp->sp, *ep = cfp->ep; 142 VALUE *p, *st, *t; 143 144 fprintf(stderr, "-- stack frame ------------\n"); 145 for (p = st = th->stack; p < sp; p++) { 146 fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); 147 148 t = (VALUE *)*p; 149 if (th->stack <= t && t < sp) { 150 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack)); 151 } 152 153 if (p == ep) 154 fprintf(stderr, " <- ep"); 155 156 fprintf(stderr, "\n"); 157 } 158#endif 159 160 fprintf(stderr, "-- Control frame information " 161 "-----------------------------------------------\n"); 162 while ((void *)cfp < (void *)(th->stack + th->stack_size)) { 163 control_frame_dump(th, cfp); 164 cfp++; 165 } 166 fprintf(stderr, "\n"); 167} 168 169void 170rb_vmdebug_stack_dump_raw_current(void) 171{ 172 rb_thread_t *th = GET_THREAD(); 173 rb_vmdebug_stack_dump_raw(th, th->cfp); 174} 175 176void 177rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *ep) 178{ 179 int i; 180 fprintf(stderr, "-- env --------------------\n"); 181 182 while (env) { 183 fprintf(stderr, "--\n"); 184 for (i = 0; i < env->env_size; i++) { 185 fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", -env->local_size + i, env->env[i], 186 (void *)&env->env[i]); 187 if (&env->env[i] == ep) 188 fprintf(stderr, " <- ep"); 189 fprintf(stderr, "\n"); 190 } 191 192 if (env->prev_envval != 0) { 193 GetEnvPtr(env->prev_envval, env); 194 } 195 else { 196 env = 0; 197 } 198 } 199 fprintf(stderr, "---------------------------\n"); 200} 201 202void 203rb_vmdebug_proc_dump_raw(rb_proc_t *proc) 204{ 205 rb_env_t *env; 206 char *selfstr; 207 VALUE val = rb_inspect(proc->block.self); 208 selfstr = StringValueCStr(val); 209 210 fprintf(stderr, "-- proc -------------------\n"); 211 fprintf(stderr, "self: %s\n", selfstr); 212 GetEnvPtr(proc->envval, env); 213 rb_vmdebug_env_dump_raw(env, proc->block.ep); 214} 215 216void 217rb_vmdebug_stack_dump_th(VALUE thval) 218{ 219 rb_thread_t *th; 220 GetThreadPtr(thval, th); 221 rb_vmdebug_stack_dump_raw(th, th->cfp); 222} 223 224#if VMDEBUG > 2 225 226/* copy from vm.c */ 227static VALUE * 228vm_base_ptr(rb_control_frame_t *cfp) 229{ 230 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 231 VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1; 232 233 if (cfp->iseq->type == ISEQ_TYPE_METHOD) { 234 bp += 1; 235 } 236 return bp; 237} 238 239static void 240vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) 241{ 242 int i; 243 244 VALUE rstr; 245 VALUE *sp = cfp->sp; 246 VALUE *ep = cfp->ep; 247 248 int argc = 0, local_size = 0; 249 const char *name; 250 rb_iseq_t *iseq = cfp->iseq; 251 252 if (iseq == 0) { 253 if (RUBYVM_CFUNC_FRAME_P(cfp)) { 254 name = rb_id2name(cfp->me->called_id); 255 } 256 else { 257 name = "?"; 258 } 259 } 260 else if (RUBY_VM_IFUNC_P(iseq)) { 261 name = "<ifunc>"; 262 } 263 else { 264 argc = iseq->argc; 265 local_size = iseq->local_size; 266 name = RSTRING_PTR(iseq->location.label); 267 } 268 269 /* stack trace header */ 270 271 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD || 272 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || 273 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK || 274 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS || 275 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || 276 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA || 277 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC || 278 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC || 279 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL) { 280 281 VALUE *ptr = ep - local_size; 282 283 control_frame_dump(th, cfp); 284 285 for (i = 0; i < argc; i++) { 286 rstr = rb_inspect(*ptr); 287 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), 288 (void *)ptr++); 289 } 290 for (; i < local_size - 1; i++) { 291 rstr = rb_inspect(*ptr); 292 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), 293 (void *)ptr++); 294 } 295 296 ptr = vm_base_ptr(cfp); 297 for (; ptr < sp; ptr++, i++) { 298 if (*ptr == Qundef) { 299 rstr = rb_str_new2("undef"); 300 } 301 else { 302 rstr = rb_inspect(*ptr); 303 } 304 fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), 305 (ptr - th->stack)); 306 } 307 } 308 else if (VM_FRAME_TYPE_FINISH_P(cfp)) { 309 if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) { 310 vm_stack_dump_each(th, cfp + 1); 311 } 312 else { 313 /* SDR(); */ 314 } 315 } 316 else { 317 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp)); 318 } 319} 320#endif 321 322void 323rb_vmdebug_debug_print_register(rb_thread_t *th) 324{ 325 rb_control_frame_t *cfp = th->cfp; 326 ptrdiff_t pc = -1; 327 ptrdiff_t ep = cfp->ep - th->stack; 328 ptrdiff_t cfpi; 329 330 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 331 pc = cfp->pc - cfp->iseq->iseq_encoded; 332 } 333 334 if (ep < 0 || (size_t)ep > th->stack_size) { 335 ep = -1; 336 } 337 338 cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp; 339 fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", 340 pc, (cfp->sp - th->stack), ep, cfpi); 341} 342 343void 344rb_vmdebug_thread_dump_regs(VALUE thval) 345{ 346 rb_thread_t *th; 347 GetThreadPtr(thval, th); 348 rb_vmdebug_debug_print_register(th); 349} 350 351void 352rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp) 353{ 354 rb_iseq_t *iseq = cfp->iseq; 355 356 if (iseq != 0) { 357 VALUE *seq = iseq->iseq; 358 ptrdiff_t pc = cfp->pc - iseq->iseq_encoded; 359 int i; 360 361 for (i=0; i<(int)VM_CFP_CNT(th, cfp); i++) { 362 printf(" "); 363 } 364 printf("| "); 365 /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */ 366 if (pc >= 0) { 367 rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0); 368 } 369 } 370 371#if VMDEBUG > 3 372 fprintf(stderr, " (1)"); 373 rb_vmdebug_debug_print_register(th); 374#endif 375} 376 377void 378rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp 379#if OPT_STACK_CACHING 380 , VALUE reg_a, VALUE reg_b 381#endif 382 ) 383{ 384#if VMDEBUG > 9 385 SDR2(cfp); 386#endif 387 388#if VMDEBUG > 3 389 fprintf(stderr, " (2)"); 390 rb_vmdebug_debug_print_register(th); 391#endif 392 /* stack_dump_raw(th, cfp); */ 393 394#if VMDEBUG > 2 395 /* stack_dump_thobj(th); */ 396 vm_stack_dump_each(th, th->cfp); 397 398#if OPT_STACK_CACHING 399 { 400 VALUE rstr; 401 rstr = rb_inspect(reg_a); 402 fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr)); 403 rstr = rb_inspect(reg_b); 404 fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr)); 405 } 406#endif 407 printf 408 ("--------------------------------------------------------------\n"); 409#endif 410} 411 412VALUE 413rb_vmdebug_thread_dump_state(VALUE self) 414{ 415 rb_thread_t *th; 416 rb_control_frame_t *cfp; 417 GetThreadPtr(self, th); 418 cfp = th->cfp; 419 420 fprintf(stderr, "Thread state dump:\n"); 421 fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); 422 fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep); 423 424 return Qnil; 425} 426 427#ifndef HAVE_BACKTRACE 428#define HAVE_BACKTRACE 0 429#endif 430#if HAVE_BACKTRACE 431# include <execinfo.h> 432#elif defined(_WIN32) 433# include <imagehlp.h> 434# ifndef SYMOPT_DEBUG 435# define SYMOPT_DEBUG 0x80000000 436# endif 437# ifndef MAX_SYM_NAME 438# define MAX_SYM_NAME 2000 439typedef struct { 440 DWORD64 Offset; 441 WORD Segment; 442 ADDRESS_MODE Mode; 443} ADDRESS64; 444typedef struct { 445 DWORD64 Thread; 446 DWORD ThCallbackStack; 447 DWORD ThCallbackBStore; 448 DWORD NextCallback; 449 DWORD FramePointer; 450 DWORD64 KiCallUserMode; 451 DWORD64 KeUserCallbackDispatcher; 452 DWORD64 SystemRangeStart; 453 DWORD64 KiUserExceptionDispatcher; 454 DWORD64 StackBase; 455 DWORD64 StackLimit; 456 DWORD64 Reserved[5]; 457} KDHELP64; 458typedef struct { 459 ADDRESS64 AddrPC; 460 ADDRESS64 AddrReturn; 461 ADDRESS64 AddrFrame; 462 ADDRESS64 AddrStack; 463 ADDRESS64 AddrBStore; 464 void *FuncTableEntry; 465 DWORD64 Params[4]; 466 BOOL Far; 467 BOOL Virtual; 468 DWORD64 Reserved[3]; 469 KDHELP64 KdHelp; 470} STACKFRAME64; 471typedef struct { 472 ULONG SizeOfStruct; 473 ULONG TypeIndex; 474 ULONG64 Reserved[2]; 475 ULONG Index; 476 ULONG Size; 477 ULONG64 ModBase; 478 ULONG Flags; 479 ULONG64 Value; 480 ULONG64 Address; 481 ULONG Register; 482 ULONG Scope; 483 ULONG Tag; 484 ULONG NameLen; 485 ULONG MaxNameLen; 486 char Name[1]; 487} SYMBOL_INFO; 488typedef struct { 489 DWORD SizeOfStruct; 490 void *Key; 491 DWORD LineNumber; 492 char *FileName; 493 DWORD64 Address; 494} IMAGEHLP_LINE64; 495typedef void *PREAD_PROCESS_MEMORY_ROUTINE64; 496typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64; 497typedef void *PGET_MODULE_BASE_ROUTINE64; 498typedef void *PTRANSLATE_ADDRESS_ROUTINE64; 499# endif 500 501static void 502dump_thread(void *arg) 503{ 504 HANDLE dbghelp; 505 BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL); 506 BOOL (WINAPI *pSymCleanup)(HANDLE); 507 BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64); 508 DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64); 509 BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *); 510 BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *); 511 HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD); 512 DWORD tid = *(DWORD *)arg; 513 HANDLE ph; 514 HANDLE th; 515 516 dbghelp = LoadLibrary("dbghelp.dll"); 517 if (!dbghelp) return; 518 pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize"); 519 pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup"); 520 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"); 521 pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64"); 522 pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr"); 523 pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64"); 524 pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread"); 525 if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 && 526 pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) { 527 SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES); 528 ph = GetCurrentProcess(); 529 pSymInitialize(ph, NULL, TRUE); 530 th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid); 531 if (th) { 532 if (SuspendThread(th) != (DWORD)-1) { 533 CONTEXT context; 534 memset(&context, 0, sizeof(context)); 535 context.ContextFlags = CONTEXT_FULL; 536 if (GetThreadContext(th, &context)) { 537 char libpath[MAX_PATH]; 538 char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 539 SYMBOL_INFO *info = (SYMBOL_INFO *)buf; 540 DWORD mac; 541 STACKFRAME64 frame; 542 memset(&frame, 0, sizeof(frame)); 543#if defined(_M_AMD64) || defined(__x86_64__) 544 mac = IMAGE_FILE_MACHINE_AMD64; 545 frame.AddrPC.Mode = AddrModeFlat; 546 frame.AddrPC.Offset = context.Rip; 547 frame.AddrFrame.Mode = AddrModeFlat; 548 frame.AddrFrame.Offset = context.Rbp; 549 frame.AddrStack.Mode = AddrModeFlat; 550 frame.AddrStack.Offset = context.Rsp; 551#elif defined(_M_IA64) || defined(__ia64__) 552 mac = IMAGE_FILE_MACHINE_IA64; 553 frame.AddrPC.Mode = AddrModeFlat; 554 frame.AddrPC.Offset = context.StIIP; 555 frame.AddrBStore.Mode = AddrModeFlat; 556 frame.AddrBStore.Offset = context.RsBSP; 557 frame.AddrStack.Mode = AddrModeFlat; 558 frame.AddrStack.Offset = context.IntSp; 559#else /* i386 */ 560 mac = IMAGE_FILE_MACHINE_I386; 561 frame.AddrPC.Mode = AddrModeFlat; 562 frame.AddrPC.Offset = context.Eip; 563 frame.AddrFrame.Mode = AddrModeFlat; 564 frame.AddrFrame.Offset = context.Ebp; 565 frame.AddrStack.Mode = AddrModeFlat; 566 frame.AddrStack.Offset = context.Esp; 567#endif 568 569 while (pStackWalk64(mac, ph, th, &frame, &context, NULL, 570 NULL, NULL, NULL)) { 571 DWORD64 addr = frame.AddrPC.Offset; 572 IMAGEHLP_LINE64 line; 573 DWORD64 displacement; 574 DWORD tmp; 575 576 if (addr == frame.AddrReturn.Offset || addr == 0 || 577 frame.AddrReturn.Offset == 0) 578 break; 579 580 memset(buf, 0, sizeof(buf)); 581 info->SizeOfStruct = sizeof(SYMBOL_INFO); 582 info->MaxNameLen = MAX_SYM_NAME; 583 if (pSymFromAddr(ph, addr, &displacement, info)) { 584 if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath))) 585 fprintf(stderr, "%s", libpath); 586 fprintf(stderr, "(%s+0x%I64x)", 587 info->Name, displacement); 588 } 589 fprintf(stderr, " [0x%p]", (void *)(VALUE)addr); 590 memset(&line, 0, sizeof(line)); 591 line.SizeOfStruct = sizeof(line); 592 if (pSymGetLineFromAddr64(ph, addr, &tmp, &line)) 593 fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber); 594 fprintf(stderr, "\n"); 595 } 596 } 597 598 ResumeThread(th); 599 } 600 CloseHandle(th); 601 } 602 pSymCleanup(ph); 603 } 604 FreeLibrary(dbghelp); 605} 606#endif 607 608void 609rb_vm_bugreport(void) 610{ 611#ifdef __linux__ 612# define PROC_MAPS_NAME "/proc/self/maps" 613#endif 614#ifdef PROC_MAPS_NAME 615 enum {other_runtime_info = 1}; 616#else 617 enum {other_runtime_info = 0}; 618#endif 619 const rb_vm_t *const vm = GET_VM(); 620 621#if defined __APPLE__ 622 fputs("-- Crash Report log information " 623 "--------------------------------------------\n" 624 " See Crash Report log file under the one of following:\n" 625 " * ~/Library/Logs/CrashReporter\n" 626 " * /Library/Logs/CrashReporter\n" 627 " * ~/Library/Logs/DiagnosticReports\n" 628 " * /Library/Logs/DiagnosticReports\n" 629 " the more detail of.\n" 630 "\n", 631 stderr); 632#endif 633 if (vm) { 634 SDR(); 635 rb_backtrace_print_as_bugreport(); 636 fputs("\n", stderr); 637 } 638 639#if HAVE_BACKTRACE || defined(_WIN32) 640 fprintf(stderr, "-- C level backtrace information " 641 "-------------------------------------------\n"); 642 643 { 644#if HAVE_BACKTRACE 645#define MAX_NATIVE_TRACE 1024 646 static void *trace[MAX_NATIVE_TRACE]; 647 int n = backtrace(trace, MAX_NATIVE_TRACE); 648 char **syms = backtrace_symbols(trace, n); 649 650 if (syms) { 651#ifdef USE_ELF 652 rb_dump_backtrace_with_lines(n, trace, syms); 653#else 654 int i; 655 for (i=0; i<n; i++) { 656 fprintf(stderr, "%s\n", syms[i]); 657 } 658#endif 659 free(syms); 660 } 661#elif defined(_WIN32) 662 DWORD tid = GetCurrentThreadId(); 663 HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid); 664 if (th != (HANDLE)-1) 665 WaitForSingleObject(th, INFINITE); 666#endif 667 } 668 669 fprintf(stderr, "\n"); 670#endif /* HAVE_BACKTRACE */ 671 672 if (other_runtime_info || vm) { 673 fprintf(stderr, "-- Other runtime information " 674 "-----------------------------------------------\n\n"); 675 } 676 if (vm) { 677 int i; 678 VALUE name; 679 long len; 680 const int max_name_length = 1024; 681# define LIMITED_NAME_LENGTH(s) \ 682 (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len) 683 684 name = vm->progname; 685 fprintf(stderr, "* Loaded script: %.*s\n", 686 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); 687 fprintf(stderr, "\n"); 688 fprintf(stderr, "* Loaded features:\n\n"); 689 for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) { 690 name = RARRAY_PTR(vm->loaded_features)[i]; 691 if (RB_TYPE_P(name, T_STRING)) { 692 fprintf(stderr, " %4d %.*s\n", i, 693 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); 694 } 695 else { 696 fprintf(stderr, " %4d #<%s:%p>\n", i, 697 rb_class2name(CLASS_OF(name)), (void *)name); 698 } 699 } 700 fprintf(stderr, "\n"); 701 } 702 703 { 704#ifdef PROC_MAPS_NAME 705 { 706 FILE *fp = fopen(PROC_MAPS_NAME, "r"); 707 if (fp) { 708 fprintf(stderr, "* Process memory map:\n\n"); 709 710 while (!feof(fp)) { 711 char buff[0x100]; 712 size_t rn = fread(buff, 1, 0x100, fp); 713 if (fwrite(buff, 1, rn, stderr) != rn) 714 break; 715 } 716 717 fclose(fp); 718 fprintf(stderr, "\n\n"); 719 } 720 } 721#endif /* __linux__ */ 722 } 723} 724