Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /********************************************************************** 00002 00003 vm_dump.c - 00004 00005 $Author: naruse $ 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 00016 #define MAX_POSBUF 128 00017 00018 #define VM_CFP_CNT(th, cfp) \ 00019 ((rb_control_frame_t *)((th)->stack + (th)->stack_size) - (rb_control_frame_t *)(cfp)) 00020 00021 static void 00022 control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) 00023 { 00024 ptrdiff_t pc = -1, bp = -1; 00025 ptrdiff_t lfp = cfp->lfp - th->stack; 00026 ptrdiff_t dfp = cfp->dfp - th->stack; 00027 char lfp_in_heap = ' ', dfp_in_heap = ' '; 00028 char posbuf[MAX_POSBUF+1]; 00029 int line = 0; 00030 int nopos = 0; 00031 00032 const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; 00033 VALUE tmp; 00034 00035 if (cfp->block_iseq != 0 && BUILTIN_TYPE(cfp->block_iseq) != T_NODE) { 00036 biseq_name = ""; /* RSTRING(cfp->block_iseq->name)->ptr; */ 00037 } 00038 00039 if (lfp < 0 || (size_t)lfp > th->stack_size) { 00040 lfp = (ptrdiff_t)cfp->lfp; 00041 lfp_in_heap = 'p'; 00042 } 00043 if (dfp < 0 || (size_t)dfp > th->stack_size) { 00044 dfp = (ptrdiff_t)cfp->dfp; 00045 dfp_in_heap = 'p'; 00046 } 00047 if (cfp->bp) { 00048 bp = cfp->bp - th->stack; 00049 } 00050 00051 switch (VM_FRAME_TYPE(cfp)) { 00052 case VM_FRAME_MAGIC_TOP: 00053 magic = "TOP"; 00054 break; 00055 case VM_FRAME_MAGIC_METHOD: 00056 magic = "METHOD"; 00057 break; 00058 case VM_FRAME_MAGIC_CLASS: 00059 magic = "CLASS"; 00060 break; 00061 case VM_FRAME_MAGIC_BLOCK: 00062 magic = "BLOCK"; 00063 break; 00064 case VM_FRAME_MAGIC_FINISH: 00065 magic = "FINISH"; 00066 nopos = 1; 00067 break; 00068 case VM_FRAME_MAGIC_CFUNC: 00069 magic = "CFUNC"; 00070 break; 00071 case VM_FRAME_MAGIC_PROC: 00072 magic = "PROC"; 00073 break; 00074 case VM_FRAME_MAGIC_LAMBDA: 00075 magic = "LAMBDA"; 00076 break; 00077 case VM_FRAME_MAGIC_IFUNC: 00078 magic = "IFUNC"; 00079 break; 00080 case VM_FRAME_MAGIC_EVAL: 00081 magic = "EVAL"; 00082 break; 00083 case 0: 00084 magic = "------"; 00085 break; 00086 default: 00087 magic = "(none)"; 00088 break; 00089 } 00090 00091 if (0) { 00092 tmp = rb_inspect(cfp->self); 00093 selfstr = StringValueCStr(tmp); 00094 } 00095 else { 00096 selfstr = ""; 00097 } 00098 00099 if (nopos) { 00100 /* no name */ 00101 } 00102 else if (cfp->iseq != 0) { 00103 if (RUBY_VM_IFUNC_P(cfp->iseq)) { 00104 iseq_name = "<ifunc>"; 00105 } 00106 else { 00107 pc = cfp->pc - cfp->iseq->iseq_encoded; 00108 iseq_name = RSTRING_PTR(cfp->iseq->name); 00109 line = rb_vm_get_sourceline(cfp); 00110 if (line) { 00111 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->filename), line); 00112 } 00113 } 00114 } 00115 else if (cfp->me) { 00116 iseq_name = rb_id2name(cfp->me->def->original_id); 00117 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); 00118 line = -1; 00119 } 00120 00121 fprintf(stderr, "c:%04"PRIdPTRDIFF" ", 00122 ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp)); 00123 if (pc == -1) { 00124 fprintf(stderr, "p:---- "); 00125 } 00126 else { 00127 fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); 00128 } 00129 fprintf(stderr, "s:%04"PRIdPTRDIFF" b:%04"PRIdPTRDIFF" ", (cfp->sp - th->stack), bp); 00130 fprintf(stderr, lfp_in_heap == ' ' ? "l:%06"PRIdPTRDIFF" " : "l:%06"PRIxPTRDIFF" ", lfp % 10000); 00131 fprintf(stderr, dfp_in_heap == ' ' ? "d:%06"PRIdPTRDIFF" " : "d:%06"PRIxPTRDIFF" ", dfp % 10000); 00132 fprintf(stderr, "%-6s", magic); 00133 if (line && !nopos) { 00134 fprintf(stderr, " %s", posbuf); 00135 } 00136 if (0) { 00137 fprintf(stderr, " \t"); 00138 fprintf(stderr, "iseq: %-24s ", iseq_name); 00139 fprintf(stderr, "self: %-24s ", selfstr); 00140 fprintf(stderr, "%-1s ", biseq_name); 00141 } 00142 fprintf(stderr, "\n"); 00143 } 00144 00145 void 00146 rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp) 00147 { 00148 #if 0 00149 VALUE *sp = cfp->sp, *bp = cfp->bp; 00150 VALUE *lfp = cfp->lfp; 00151 VALUE *dfp = cfp->dfp; 00152 VALUE *p, *st, *t; 00153 00154 fprintf(stderr, "-- stack frame ------------\n"); 00155 for (p = st = th->stack; p < sp; p++) { 00156 fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); 00157 00158 t = (VALUE *)*p; 00159 if (th->stack <= t && t < sp) { 00160 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack)); 00161 } 00162 00163 if (p == lfp) 00164 fprintf(stderr, " <- lfp"); 00165 if (p == dfp) 00166 fprintf(stderr, " <- dfp"); 00167 if (p == bp) 00168 fprintf(stderr, " <- bp"); /* should not be */ 00169 00170 fprintf(stderr, "\n"); 00171 } 00172 #endif 00173 00174 fprintf(stderr, "-- Control frame information " 00175 "-----------------------------------------------\n"); 00176 while ((void *)cfp < (void *)(th->stack + th->stack_size)) { 00177 control_frame_dump(th, cfp); 00178 cfp++; 00179 } 00180 fprintf(stderr, "\n"); 00181 } 00182 00183 void 00184 rb_vmdebug_stack_dump_raw_current(void) 00185 { 00186 rb_thread_t *th = GET_THREAD(); 00187 rb_vmdebug_stack_dump_raw(th, th->cfp); 00188 } 00189 00190 void 00191 rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *lfp, VALUE *dfp) 00192 { 00193 int i; 00194 fprintf(stderr, "-- env --------------------\n"); 00195 00196 while (env) { 00197 fprintf(stderr, "--\n"); 00198 for (i = 0; i < env->env_size; i++) { 00199 fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", -env->local_size + i, env->env[i], 00200 (void *)&env->env[i]); 00201 if (&env->env[i] == lfp) 00202 fprintf(stderr, " <- lfp"); 00203 if (&env->env[i] == dfp) 00204 fprintf(stderr, " <- dfp"); 00205 fprintf(stderr, "\n"); 00206 } 00207 00208 if (env->prev_envval != 0) { 00209 GetEnvPtr(env->prev_envval, env); 00210 } 00211 else { 00212 env = 0; 00213 } 00214 } 00215 fprintf(stderr, "---------------------------\n"); 00216 } 00217 00218 void 00219 rb_vmdebug_proc_dump_raw(rb_proc_t *proc) 00220 { 00221 rb_env_t *env; 00222 char *selfstr; 00223 VALUE val = rb_inspect(proc->block.self); 00224 selfstr = StringValueCStr(val); 00225 00226 fprintf(stderr, "-- proc -------------------\n"); 00227 fprintf(stderr, "self: %s\n", selfstr); 00228 GetEnvPtr(proc->envval, env); 00229 rb_vmdebug_env_dump_raw(env, proc->block.lfp, proc->block.dfp); 00230 } 00231 00232 void 00233 rb_vmdebug_stack_dump_th(VALUE thval) 00234 { 00235 rb_thread_t *th; 00236 GetThreadPtr(thval, th); 00237 rb_vmdebug_stack_dump_raw(th, th->cfp); 00238 } 00239 00240 #if VMDEBUG > 2 00241 static void 00242 vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) 00243 { 00244 int i; 00245 00246 VALUE rstr; 00247 VALUE *sp = cfp->sp; 00248 VALUE *lfp = cfp->lfp; 00249 VALUE *dfp = cfp->dfp; 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->original_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->name); 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 00284 VALUE *ptr = dfp - local_size; 00285 00286 vm_stack_dump_each(th, cfp + 1); 00287 control_frame_dump(th, cfp); 00288 00289 if (lfp != dfp) { 00290 local_size++; 00291 } 00292 for (i = 0; i < argc; i++) { 00293 rstr = rb_inspect(*ptr); 00294 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), 00295 (void *)ptr++); 00296 } 00297 for (; i < local_size - 1; i++) { 00298 rstr = rb_inspect(*ptr); 00299 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), 00300 (void *)ptr++); 00301 } 00302 00303 ptr = cfp->bp; 00304 for (; ptr < sp; ptr++, i++) { 00305 if (*ptr == Qundef) { 00306 rstr = rb_str_new2("undef"); 00307 } 00308 else { 00309 rstr = rb_inspect(*ptr); 00310 } 00311 fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), 00312 (ptr - th->stack)); 00313 } 00314 } 00315 else if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) { 00316 if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 2)) { 00317 vm_stack_dump_each(th, cfp + 1); 00318 } 00319 else { 00320 /* SDR(); */ 00321 } 00322 } 00323 else { 00324 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp)); 00325 } 00326 } 00327 #endif 00328 00329 void 00330 rb_vmdebug_debug_print_register(rb_thread_t *th) 00331 { 00332 rb_control_frame_t *cfp = th->cfp; 00333 ptrdiff_t pc = -1; 00334 ptrdiff_t lfp = cfp->lfp - th->stack; 00335 ptrdiff_t dfp = cfp->dfp - th->stack; 00336 ptrdiff_t cfpi; 00337 00338 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 00339 pc = cfp->pc - cfp->iseq->iseq_encoded; 00340 } 00341 00342 if (lfp < 0 || (size_t)lfp > th->stack_size) 00343 lfp = -1; 00344 if (dfp < 0 || (size_t)dfp > th->stack_size) 00345 dfp = -1; 00346 00347 cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp; 00348 fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [LFP] %04"PRIdPTRDIFF", [DFP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", 00349 pc, (cfp->sp - th->stack), lfp, dfp, cfpi); 00350 } 00351 00352 void 00353 rb_vmdebug_thread_dump_regs(VALUE thval) 00354 { 00355 rb_thread_t *th; 00356 GetThreadPtr(thval, th); 00357 rb_vmdebug_debug_print_register(th); 00358 } 00359 00360 void 00361 rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp) 00362 { 00363 rb_iseq_t *iseq = cfp->iseq; 00364 00365 if (iseq != 0 && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) { 00366 VALUE *seq = iseq->iseq; 00367 ptrdiff_t pc = cfp->pc - iseq->iseq_encoded; 00368 00369 printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); 00370 if (pc >= 0) { 00371 rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0); 00372 } 00373 } 00374 00375 #if VMDEBUG > 3 00376 fprintf(stderr, " (1)"); 00377 rb_vmdebug_debug_print_register(th); 00378 #endif 00379 } 00380 00381 void 00382 rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp 00383 #if OPT_STACK_CACHING 00384 , VALUE reg_a, VALUE reg_b 00385 #endif 00386 ) 00387 { 00388 #if VMDEBUG > 9 00389 SDR2(cfp); 00390 #endif 00391 00392 #if VMDEBUG > 3 00393 fprintf(stderr, " (2)"); 00394 rb_vmdebug_debug_print_register(th); 00395 #endif 00396 /* stack_dump_raw(th, cfp); */ 00397 00398 #if VMDEBUG > 2 00399 /* stack_dump_thobj(th); */ 00400 vm_stack_dump_each(th, th->cfp); 00401 #if OPT_STACK_CACHING 00402 { 00403 VALUE rstr; 00404 rstr = rb_inspect(reg_a); 00405 fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr)); 00406 rstr = rb_inspect(reg_b); 00407 fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr)); 00408 } 00409 #endif 00410 printf 00411 ("--------------------------------------------------------------\n"); 00412 #endif 00413 } 00414 00415 #ifdef COLLECT_USAGE_ANALYSIS 00416 /* uh = { 00417 * insn(Fixnum) => ihash(Hash) 00418 * } 00419 * ihash = { 00420 * -1(Fixnum) => count, # insn usage 00421 * 0(Fixnum) => ophash, # operand usage 00422 * } 00423 * ophash = { 00424 * val(interned string) => count(Fixnum) 00425 * } 00426 */ 00427 void 00428 vm_analysis_insn(int insn) 00429 { 00430 ID usage_hash; 00431 ID bigram_hash; 00432 static int prev_insn = -1; 00433 00434 VALUE uh; 00435 VALUE ihash; 00436 VALUE cv; 00437 00438 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 00439 CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM"); 00440 uh = rb_const_get(rb_cRubyVM, usage_hash); 00441 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 00442 ihash = rb_hash_new(); 00443 rb_hash_aset(uh, INT2FIX(insn), ihash); 00444 } 00445 if ((cv = rb_hash_aref(ihash, INT2FIX(-1))) == Qnil) { 00446 cv = INT2FIX(0); 00447 } 00448 rb_hash_aset(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1)); 00449 00450 /* calc bigram */ 00451 if (prev_insn != -1) { 00452 VALUE bi; 00453 VALUE ary[2]; 00454 VALUE cv; 00455 00456 ary[0] = INT2FIX(prev_insn); 00457 ary[1] = INT2FIX(insn); 00458 bi = rb_ary_new4(2, &ary[0]); 00459 00460 uh = rb_const_get(rb_cRubyVM, bigram_hash); 00461 if ((cv = rb_hash_aref(uh, bi)) == Qnil) { 00462 cv = INT2FIX(0); 00463 } 00464 rb_hash_aset(uh, bi, INT2FIX(FIX2INT(cv) + 1)); 00465 } 00466 prev_insn = insn; 00467 } 00468 00469 /* from disasm.c */ 00470 extern VALUE insn_operand_intern(int insn, int op_no, VALUE op, 00471 int len, int pos, VALUE child); 00472 00473 void 00474 vm_analysis_operand(int insn, int n, VALUE op) 00475 { 00476 ID usage_hash; 00477 00478 VALUE uh; 00479 VALUE ihash; 00480 VALUE ophash; 00481 VALUE valstr; 00482 VALUE cv; 00483 00484 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 00485 00486 uh = rb_const_get(rb_cRubyVM, usage_hash); 00487 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 00488 ihash = rb_hash_new(); 00489 rb_hash_aset(uh, INT2FIX(insn), ihash); 00490 } 00491 if ((ophash = rb_hash_aref(ihash, INT2FIX(n))) == Qnil) { 00492 ophash = rb_hash_new(); 00493 rb_hash_aset(ihash, INT2FIX(n), ophash); 00494 } 00495 /* intern */ 00496 valstr = insn_operand_intern(insn, n, op, 0, 0, 0); 00497 00498 /* set count */ 00499 if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) { 00500 cv = INT2FIX(0); 00501 } 00502 rb_hash_aset(ophash, valstr, INT2FIX(FIX2INT(cv) + 1)); 00503 } 00504 00505 void 00506 vm_analysis_register(int reg, int isset) 00507 { 00508 ID usage_hash; 00509 VALUE uh; 00510 VALUE rhash; 00511 VALUE valstr; 00512 static const char regstrs[][5] = { 00513 "pc", /* 0 */ 00514 "sp", /* 1 */ 00515 "cfp", /* 2 */ 00516 "lfp", /* 3 */ 00517 "dfp", /* 4 */ 00518 "self", /* 5 */ 00519 "iseq", /* 6 */ 00520 }; 00521 static const char getsetstr[][4] = { 00522 "get", 00523 "set", 00524 }; 00525 static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2]; 00526 00527 VALUE cv; 00528 00529 CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS"); 00530 if (syms[0] == 0) { 00531 char buff[0x10]; 00532 int i; 00533 00534 for (i = 0; i < sizeof(regstrs) / sizeof(regstrs[0]); i++) { 00535 int j; 00536 for (j = 0; j < 2; j++) { 00537 snfprintf(stderr, buff, 0x10, "%d %s %-4s", i, getsetstr[j], 00538 regstrs[i]); 00539 syms[i][j] = ID2SYM(rb_intern(buff)); 00540 } 00541 } 00542 } 00543 valstr = syms[reg][isset]; 00544 00545 uh = rb_const_get(rb_cRubyVM, usage_hash); 00546 if ((cv = rb_hash_aref(uh, valstr)) == Qnil) { 00547 cv = INT2FIX(0); 00548 } 00549 rb_hash_aset(uh, valstr, INT2FIX(FIX2INT(cv) + 1)); 00550 } 00551 00552 00553 #endif 00554 00555 VALUE 00556 rb_vmdebug_thread_dump_state(VALUE self) 00557 { 00558 rb_thread_t *th; 00559 rb_control_frame_t *cfp; 00560 GetThreadPtr(self, th); 00561 cfp = th->cfp; 00562 00563 fprintf(stderr, "Thread state dump:\n"); 00564 fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); 00565 fprintf(stderr, "cfp: %p, lfp: %p, dfp: %p\n", (void *)cfp, (void *)cfp->lfp, (void *)cfp->dfp); 00566 00567 return Qnil; 00568 } 00569 00570 static int 00571 bugreport_backtrace(void *arg, VALUE file, int line, VALUE method) 00572 { 00573 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file); 00574 if (!*(int *)arg) { 00575 fprintf(stderr, "-- Ruby level backtrace information " 00576 "----------------------------------------\n"); 00577 *(int *)arg = 1; 00578 } 00579 if (NIL_P(method)) { 00580 fprintf(stderr, "%s:%d:in unknown method\n", filename, line); 00581 } 00582 else { 00583 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method)); 00584 } 00585 return 0; 00586 } 00587 00588 #if defined(__FreeBSD__) && defined(__OPTIMIZE__) 00589 #undef HAVE_BACKTRACE 00590 #endif 00591 #if HAVE_BACKTRACE 00592 # include <execinfo.h> 00593 #elif defined(_WIN32) 00594 # include <imagehlp.h> 00595 # ifndef SYMOPT_DEBUG 00596 # define SYMOPT_DEBUG 0x80000000 00597 # endif 00598 # ifndef MAX_SYM_NAME 00599 # define MAX_SYM_NAME 2000 00600 typedef struct { 00601 DWORD64 Offset; 00602 WORD Segment; 00603 ADDRESS_MODE Mode; 00604 } ADDRESS64; 00605 typedef struct { 00606 DWORD64 Thread; 00607 DWORD ThCallbackStack; 00608 DWORD ThCallbackBStore; 00609 DWORD NextCallback; 00610 DWORD FramePointer; 00611 DWORD64 KiCallUserMode; 00612 DWORD64 KeUserCallbackDispatcher; 00613 DWORD64 SystemRangeStart; 00614 DWORD64 KiUserExceptionDispatcher; 00615 DWORD64 StackBase; 00616 DWORD64 StackLimit; 00617 DWORD64 Reserved[5]; 00618 } KDHELP64; 00619 typedef struct { 00620 ADDRESS64 AddrPC; 00621 ADDRESS64 AddrReturn; 00622 ADDRESS64 AddrFrame; 00623 ADDRESS64 AddrStack; 00624 ADDRESS64 AddrBStore; 00625 void *FuncTableEntry; 00626 DWORD64 Params[4]; 00627 BOOL Far; 00628 BOOL Virtual; 00629 DWORD64 Reserved[3]; 00630 KDHELP64 KdHelp; 00631 } STACKFRAME64; 00632 typedef struct { 00633 ULONG SizeOfStruct; 00634 ULONG TypeIndex; 00635 ULONG64 Reserved[2]; 00636 ULONG Index; 00637 ULONG Size; 00638 ULONG64 ModBase; 00639 ULONG Flags; 00640 ULONG64 Value; 00641 ULONG64 Address; 00642 ULONG Register; 00643 ULONG Scope; 00644 ULONG Tag; 00645 ULONG NameLen; 00646 ULONG MaxNameLen; 00647 char Name[1]; 00648 } SYMBOL_INFO; 00649 typedef struct { 00650 DWORD SizeOfStruct; 00651 void *Key; 00652 DWORD LineNumber; 00653 char *FileName; 00654 DWORD64 Address; 00655 } IMAGEHLP_LINE64; 00656 typedef void *PREAD_PROCESS_MEMORY_ROUTINE64; 00657 typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64; 00658 typedef void *PGET_MODULE_BASE_ROUTINE64; 00659 typedef void *PTRANSLATE_ADDRESS_ROUTINE64; 00660 # endif 00661 00662 static void 00663 dump_thread(void *arg) 00664 { 00665 HANDLE dbghelp; 00666 BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL); 00667 BOOL (WINAPI *pSymCleanup)(HANDLE); 00668 BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64); 00669 DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64); 00670 BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *); 00671 BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *); 00672 HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD); 00673 DWORD tid = *(DWORD *)arg; 00674 HANDLE ph; 00675 HANDLE th; 00676 00677 dbghelp = LoadLibrary("dbghelp.dll"); 00678 if (!dbghelp) return; 00679 pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize"); 00680 pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup"); 00681 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"); 00682 pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64"); 00683 pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr"); 00684 pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64"); 00685 pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread"); 00686 if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 && 00687 pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) { 00688 SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES); 00689 ph = GetCurrentProcess(); 00690 pSymInitialize(ph, NULL, TRUE); 00691 th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid); 00692 if (th) { 00693 if (SuspendThread(th) != (DWORD)-1) { 00694 CONTEXT context; 00695 memset(&context, 0, sizeof(context)); 00696 context.ContextFlags = CONTEXT_FULL; 00697 if (GetThreadContext(th, &context)) { 00698 char libpath[MAX_PATH]; 00699 char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 00700 SYMBOL_INFO *info = (SYMBOL_INFO *)buf; 00701 DWORD mac; 00702 STACKFRAME64 frame; 00703 memset(&frame, 0, sizeof(frame)); 00704 #if defined(_M_AMD64) || defined(__x86_64__) 00705 mac = IMAGE_FILE_MACHINE_AMD64; 00706 frame.AddrPC.Mode = AddrModeFlat; 00707 frame.AddrPC.Offset = context.Rip; 00708 frame.AddrFrame.Mode = AddrModeFlat; 00709 frame.AddrFrame.Offset = context.Rbp; 00710 frame.AddrStack.Mode = AddrModeFlat; 00711 frame.AddrStack.Offset = context.Rsp; 00712 #elif defined(_M_IA64) || defined(__ia64__) 00713 mac = IMAGE_FILE_MACHINE_IA64; 00714 frame.AddrPC.Mode = AddrModeFlat; 00715 frame.AddrPC.Offset = context.StIIP; 00716 frame.AddrBStore.Mode = AddrModeFlat; 00717 frame.AddrBStore.Offset = context.RsBSP; 00718 frame.AddrStack.Mode = AddrModeFlat; 00719 frame.AddrStack.Offset = context.IntSp; 00720 #else /* i386 */ 00721 mac = IMAGE_FILE_MACHINE_I386; 00722 frame.AddrPC.Mode = AddrModeFlat; 00723 frame.AddrPC.Offset = context.Eip; 00724 frame.AddrFrame.Mode = AddrModeFlat; 00725 frame.AddrFrame.Offset = context.Ebp; 00726 frame.AddrStack.Mode = AddrModeFlat; 00727 frame.AddrStack.Offset = context.Esp; 00728 #endif 00729 00730 while (pStackWalk64(mac, ph, th, &frame, &context, NULL, 00731 NULL, NULL, NULL)) { 00732 DWORD64 addr = frame.AddrPC.Offset; 00733 IMAGEHLP_LINE64 line; 00734 DWORD64 displacement; 00735 DWORD tmp; 00736 00737 if (addr == frame.AddrReturn.Offset || addr == 0 || 00738 frame.AddrReturn.Offset == 0) 00739 break; 00740 00741 memset(buf, 0, sizeof(buf)); 00742 info->SizeOfStruct = sizeof(SYMBOL_INFO); 00743 info->MaxNameLen = MAX_SYM_NAME; 00744 if (pSymFromAddr(ph, addr, &displacement, info)) { 00745 if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath))) 00746 fprintf(stderr, "%s", libpath); 00747 fprintf(stderr, "(%s+0x%I64x)", 00748 info->Name, displacement); 00749 } 00750 fprintf(stderr, " [0x%p]", (void *)(VALUE)addr); 00751 memset(&line, 0, sizeof(line)); 00752 line.SizeOfStruct = sizeof(line); 00753 if (pSymGetLineFromAddr64(ph, addr, &tmp, &line)) 00754 fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber); 00755 fprintf(stderr, "\n"); 00756 } 00757 } 00758 00759 ResumeThread(th); 00760 } 00761 CloseHandle(th); 00762 } 00763 pSymCleanup(ph); 00764 } 00765 FreeLibrary(dbghelp); 00766 } 00767 #endif 00768 00769 void 00770 rb_vm_bugreport(void) 00771 { 00772 rb_vm_t *vm = GET_VM(); 00773 if (vm) { 00774 int i = 0; 00775 SDR(); 00776 00777 if (rb_backtrace_each(bugreport_backtrace, &i)) { 00778 fputs("\n", stderr); 00779 } 00780 } 00781 00782 #if HAVE_BACKTRACE || defined(_WIN32) 00783 fprintf(stderr, "-- C level backtrace information " 00784 "-------------------------------------------\n"); 00785 00786 { 00787 #if defined __MACH__ && defined __APPLE__ 00788 fprintf(stderr, "\n"); 00789 fprintf(stderr, " See Crash Report log file under " 00790 "~/Library/Logs/CrashReporter or\n"); 00791 fprintf(stderr, " /Library/Logs/CrashReporter, for " 00792 "the more detail of.\n"); 00793 #elif HAVE_BACKTRACE 00794 #define MAX_NATIVE_TRACE 1024 00795 static void *trace[MAX_NATIVE_TRACE]; 00796 int n = backtrace(trace, MAX_NATIVE_TRACE); 00797 char **syms = backtrace_symbols(trace, n); 00798 00799 if (syms) { 00800 #ifdef USE_ELF 00801 rb_dump_backtrace_with_lines(n, trace, syms); 00802 #else 00803 int i; 00804 for (i=0; i<n; i++) { 00805 fprintf(stderr, "%s\n", syms[i]); 00806 } 00807 #endif 00808 free(syms); 00809 } 00810 #elif defined(_WIN32) 00811 DWORD tid = GetCurrentThreadId(); 00812 HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid); 00813 if (th != (HANDLE)-1) 00814 WaitForSingleObject(th, INFINITE); 00815 #endif 00816 } 00817 00818 fprintf(stderr, "\n"); 00819 #endif /* HAVE_BACKTRACE */ 00820 00821 fprintf(stderr, "-- Other runtime information " 00822 "-----------------------------------------------\n\n"); 00823 { 00824 int i; 00825 00826 fprintf(stderr, "* Loaded script: %s\n", StringValueCStr(vm->progname)); 00827 fprintf(stderr, "\n"); 00828 fprintf(stderr, "* Loaded features:\n\n"); 00829 for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) { 00830 fprintf(stderr, " %4d %s\n", i, StringValueCStr(RARRAY_PTR(vm->loaded_features)[i])); 00831 } 00832 fprintf(stderr, "\n"); 00833 00834 #if __linux__ 00835 { 00836 FILE *fp = fopen("/proc/self/maps", "r"); 00837 if (fp) { 00838 fprintf(stderr, "* Process memory map:\n\n"); 00839 00840 while (!feof(fp)) { 00841 char buff[0x100]; 00842 size_t rn = fread(buff, 1, 0x100, fp); 00843 fwrite(buff, 1, rn, stderr); 00844 } 00845 00846 fclose(fp); 00847 fprintf(stderr, "\n\n"); 00848 } 00849 } 00850 #endif /* __linux__ */ 00851 } 00852 } 00853