|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /********************************************************************** 00002 00003 vm_dump.c - 00004 00005 $Author: nobu $ 00006 00007 Copyright (C) 2004-2007 Koichi Sasada 00008 00009 **********************************************************************/ 00010 00011 00012 #include "ruby/ruby.h" 00013 #include "vm_core.h" 00014 00015 #define MAX_POSBUF 128 00016 00017 #define VM_CFP_CNT(th, cfp) \ 00018 ((rb_control_frame_t *)(th->stack + th->stack_size) - (rb_control_frame_t *)(cfp)) 00019 00020 static void 00021 control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) 00022 { 00023 ptrdiff_t pc = -1, bp = -1; 00024 ptrdiff_t lfp = cfp->lfp - th->stack; 00025 ptrdiff_t dfp = cfp->dfp - th->stack; 00026 char lfp_in_heap = ' ', dfp_in_heap = ' '; 00027 char posbuf[MAX_POSBUF+1]; 00028 int line = 0; 00029 int nopos = 0; 00030 00031 const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; 00032 VALUE tmp; 00033 00034 if (cfp->block_iseq != 0 && BUILTIN_TYPE(cfp->block_iseq) != T_NODE) { 00035 biseq_name = ""; /* RSTRING(cfp->block_iseq->name)->ptr; */ 00036 } 00037 00038 if (lfp < 0 || (size_t)lfp > th->stack_size) { 00039 lfp = (ptrdiff_t)cfp->lfp; 00040 lfp_in_heap = 'p'; 00041 } 00042 if (dfp < 0 || (size_t)dfp > th->stack_size) { 00043 dfp = (ptrdiff_t)cfp->dfp; 00044 dfp_in_heap = 'p'; 00045 } 00046 if (cfp->bp) { 00047 bp = cfp->bp - th->stack; 00048 } 00049 00050 switch (VM_FRAME_TYPE(cfp)) { 00051 case VM_FRAME_MAGIC_TOP: 00052 magic = "TOP"; 00053 break; 00054 case VM_FRAME_MAGIC_METHOD: 00055 magic = "METHOD"; 00056 break; 00057 case VM_FRAME_MAGIC_CLASS: 00058 magic = "CLASS"; 00059 break; 00060 case VM_FRAME_MAGIC_BLOCK: 00061 magic = "BLOCK"; 00062 break; 00063 case VM_FRAME_MAGIC_FINISH: 00064 magic = "FINISH"; 00065 nopos = 1; 00066 break; 00067 case VM_FRAME_MAGIC_CFUNC: 00068 magic = "CFUNC"; 00069 break; 00070 case VM_FRAME_MAGIC_PROC: 00071 magic = "PROC"; 00072 break; 00073 case VM_FRAME_MAGIC_LAMBDA: 00074 magic = "LAMBDA"; 00075 break; 00076 case VM_FRAME_MAGIC_IFUNC: 00077 magic = "IFUNC"; 00078 break; 00079 case VM_FRAME_MAGIC_EVAL: 00080 magic = "EVAL"; 00081 break; 00082 case 0: 00083 magic = "------"; 00084 break; 00085 default: 00086 magic = "(none)"; 00087 break; 00088 } 00089 00090 if (0) { 00091 tmp = rb_inspect(cfp->self); 00092 selfstr = StringValueCStr(tmp); 00093 } 00094 else { 00095 selfstr = ""; 00096 } 00097 00098 if (nopos) { 00099 /* no name */ 00100 } 00101 else if (cfp->iseq != 0) { 00102 if (RUBY_VM_IFUNC_P(cfp->iseq)) { 00103 iseq_name = "<ifunc>"; 00104 } 00105 else { 00106 pc = cfp->pc - cfp->iseq->iseq_encoded; 00107 iseq_name = RSTRING_PTR(cfp->iseq->name); 00108 line = rb_vm_get_sourceline(cfp); 00109 if (line) { 00110 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->filename), line); 00111 } 00112 } 00113 } 00114 else if (cfp->me) { 00115 iseq_name = rb_id2name(cfp->me->def->original_id); 00116 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); 00117 line = -1; 00118 } 00119 00120 fprintf(stderr, "c:%04"PRIdPTRDIFF" ", 00121 ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp)); 00122 if (pc == -1) { 00123 fprintf(stderr, "p:---- "); 00124 } 00125 else { 00126 fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); 00127 } 00128 fprintf(stderr, "s:%04"PRIdPTRDIFF" b:%04"PRIdPTRDIFF" ", (cfp->sp - th->stack), bp); 00129 fprintf(stderr, lfp_in_heap == ' ' ? "l:%06"PRIdPTRDIFF" " : "l:%06"PRIxPTRDIFF" ", lfp % 10000); 00130 fprintf(stderr, dfp_in_heap == ' ' ? "d:%06"PRIdPTRDIFF" " : "d:%06"PRIxPTRDIFF" ", dfp % 10000); 00131 fprintf(stderr, "%-6s", magic); 00132 if (line && !nopos) { 00133 fprintf(stderr, " %s", posbuf); 00134 } 00135 if (0) { 00136 fprintf(stderr, " \t"); 00137 fprintf(stderr, "iseq: %-24s ", iseq_name); 00138 fprintf(stderr, "self: %-24s ", selfstr); 00139 fprintf(stderr, "%-1s ", biseq_name); 00140 } 00141 fprintf(stderr, "\n"); 00142 } 00143 00144 void 00145 rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp) 00146 { 00147 #if 0 00148 VALUE *sp = cfp->sp, *bp = cfp->bp; 00149 VALUE *lfp = cfp->lfp; 00150 VALUE *dfp = cfp->dfp; 00151 VALUE *p, *st, *t; 00152 00153 fprintf(stderr, "-- stack frame ------------\n"); 00154 for (p = st = th->stack; p < sp; p++) { 00155 fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); 00156 00157 t = (VALUE *)*p; 00158 if (th->stack <= t && t < sp) { 00159 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack)); 00160 } 00161 00162 if (p == lfp) 00163 fprintf(stderr, " <- lfp"); 00164 if (p == dfp) 00165 fprintf(stderr, " <- dfp"); 00166 if (p == bp) 00167 fprintf(stderr, " <- bp"); /* should not be */ 00168 00169 fprintf(stderr, "\n"); 00170 } 00171 #endif 00172 00173 fprintf(stderr, "-- control frame ----------\n"); 00174 while ((void *)cfp < (void *)(th->stack + th->stack_size)) { 00175 control_frame_dump(th, cfp); 00176 cfp++; 00177 } 00178 fprintf(stderr, "---------------------------\n"); 00179 } 00180 00181 void 00182 rb_vmdebug_stack_dump_raw_current(void) 00183 { 00184 rb_thread_t *th = GET_THREAD(); 00185 rb_vmdebug_stack_dump_raw(th, th->cfp); 00186 } 00187 00188 void 00189 rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *lfp, VALUE *dfp) 00190 { 00191 int i; 00192 fprintf(stderr, "-- env --------------------\n"); 00193 00194 while (env) { 00195 fprintf(stderr, "--\n"); 00196 for (i = 0; i < env->env_size; i++) { 00197 fprintf(stderr, "%04d: %08lx (%p)", -env->local_size + i, env->env[i], 00198 (void *)&env->env[i]); 00199 if (&env->env[i] == lfp) 00200 fprintf(stderr, " <- lfp"); 00201 if (&env->env[i] == dfp) 00202 fprintf(stderr, " <- dfp"); 00203 fprintf(stderr, "\n"); 00204 } 00205 00206 if (env->prev_envval != 0) { 00207 GetEnvPtr(env->prev_envval, env); 00208 } 00209 else { 00210 env = 0; 00211 } 00212 } 00213 fprintf(stderr, "---------------------------\n"); 00214 } 00215 00216 void 00217 rb_vmdebug_proc_dump_raw(rb_proc_t *proc) 00218 { 00219 rb_env_t *env; 00220 char *selfstr; 00221 VALUE val = rb_inspect(proc->block.self); 00222 selfstr = StringValueCStr(val); 00223 00224 fprintf(stderr, "-- proc -------------------\n"); 00225 fprintf(stderr, "self: %s\n", selfstr); 00226 GetEnvPtr(proc->envval, env); 00227 rb_vmdebug_env_dump_raw(env, proc->block.lfp, proc->block.dfp); 00228 } 00229 00230 void 00231 rb_vmdebug_stack_dump_th(VALUE thval) 00232 { 00233 rb_thread_t *th; 00234 GetThreadPtr(thval, th); 00235 rb_vmdebug_stack_dump_raw(th, th->cfp); 00236 } 00237 00238 #if VMDEBUG > 2 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 *lfp = cfp->lfp; 00247 VALUE *dfp = cfp->dfp; 00248 00249 int argc = 0, local_size = 0; 00250 const char *name; 00251 rb_iseq_t *iseq = cfp->iseq; 00252 00253 if (iseq == 0) { 00254 if (RUBYVM_CFUNC_FRAME_P(cfp)) { 00255 name = rb_id2name(cfp->me->original_id); 00256 } 00257 else { 00258 name = "?"; 00259 } 00260 } 00261 else if (RUBY_VM_IFUNC_P(iseq)) { 00262 name = "<ifunc>"; 00263 } 00264 else { 00265 argc = iseq->argc; 00266 local_size = iseq->local_size; 00267 name = RSTRING_PTR(iseq->name); 00268 } 00269 00270 /* stack trace header */ 00271 00272 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD || 00273 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || 00274 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK || 00275 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS || 00276 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || 00277 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA || 00278 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC || 00279 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC || 00280 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL) { 00281 00282 VALUE *ptr = dfp - local_size; 00283 00284 vm_stack_dump_each(th, cfp + 1); 00285 control_frame_dump(th, cfp); 00286 00287 if (lfp != dfp) { 00288 local_size++; 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 = cfp->bp; 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(cfp) == VM_FRAME_MAGIC_FINISH) { 00314 if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 2)) { 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 lfp = cfp->lfp - th->stack; 00333 ptrdiff_t dfp = cfp->dfp - th->stack; 00334 ptrdiff_t cfpi; 00335 00336 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 00337 pc = cfp->pc - cfp->iseq->iseq_encoded; 00338 } 00339 00340 if (lfp < 0 || (size_t)lfp > th->stack_size) 00341 lfp = -1; 00342 if (dfp < 0 || (size_t)dfp > th->stack_size) 00343 dfp = -1; 00344 00345 cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp; 00346 fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [LFP] %04"PRIdPTRDIFF", [DFP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", 00347 pc, (cfp->sp - th->stack), lfp, dfp, cfpi); 00348 } 00349 00350 void 00351 rb_vmdebug_thread_dump_regs(VALUE thval) 00352 { 00353 rb_thread_t *th; 00354 GetThreadPtr(thval, th); 00355 rb_vmdebug_debug_print_register(th); 00356 } 00357 00358 void 00359 rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp) 00360 { 00361 rb_iseq_t *iseq = cfp->iseq; 00362 00363 if (iseq != 0 && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) { 00364 VALUE *seq = iseq->iseq; 00365 ptrdiff_t pc = cfp->pc - iseq->iseq_encoded; 00366 00367 printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); 00368 if (pc >= 0) { 00369 rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0); 00370 } 00371 } 00372 00373 #if VMDEBUG > 3 00374 fprintf(stderr, " (1)"); 00375 rb_vmdebug_debug_print_register(th); 00376 #endif 00377 } 00378 00379 void 00380 rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp 00381 #if OPT_STACK_CACHING 00382 , VALUE reg_a, VALUE reg_b 00383 #endif 00384 ) 00385 { 00386 #if VMDEBUG > 9 00387 SDR2(cfp); 00388 #endif 00389 00390 #if VMDEBUG > 3 00391 fprintf(stderr, " (2)"); 00392 rb_vmdebug_debug_print_register(th); 00393 #endif 00394 /* stack_dump_raw(th, cfp); */ 00395 00396 #if VMDEBUG > 2 00397 /* stack_dump_thobj(th); */ 00398 vm_stack_dump_each(th, th->cfp); 00399 #if OPT_STACK_CACHING 00400 { 00401 VALUE rstr; 00402 rstr = rb_inspect(reg_a); 00403 fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr)); 00404 rstr = rb_inspect(reg_b); 00405 fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr)); 00406 } 00407 #endif 00408 printf 00409 ("--------------------------------------------------------------\n"); 00410 #endif 00411 } 00412 00413 #ifdef COLLECT_USAGE_ANALYSIS 00414 /* uh = { 00415 * insn(Fixnum) => ihash(Hash) 00416 * } 00417 * ihash = { 00418 * -1(Fixnum) => count, # insn usage 00419 * 0(Fixnum) => ophash, # operand usage 00420 * } 00421 * ophash = { 00422 * val(interned string) => count(Fixnum) 00423 * } 00424 */ 00425 void 00426 vm_analysis_insn(int insn) 00427 { 00428 ID usage_hash; 00429 ID bigram_hash; 00430 static int prev_insn = -1; 00431 00432 VALUE uh; 00433 VALUE ihash; 00434 VALUE cv; 00435 00436 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 00437 CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM"); 00438 uh = rb_const_get(rb_cRubyVM, usage_hash); 00439 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 00440 ihash = rb_hash_new(); 00441 rb_hash_aset(uh, INT2FIX(insn), ihash); 00442 } 00443 if ((cv = rb_hash_aref(ihash, INT2FIX(-1))) == Qnil) { 00444 cv = INT2FIX(0); 00445 } 00446 rb_hash_aset(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1)); 00447 00448 /* calc bigram */ 00449 if (prev_insn != -1) { 00450 VALUE bi; 00451 VALUE ary[2]; 00452 VALUE cv; 00453 00454 ary[0] = INT2FIX(prev_insn); 00455 ary[1] = INT2FIX(insn); 00456 bi = rb_ary_new4(2, &ary[0]); 00457 00458 uh = rb_const_get(rb_cRubyVM, bigram_hash); 00459 if ((cv = rb_hash_aref(uh, bi)) == Qnil) { 00460 cv = INT2FIX(0); 00461 } 00462 rb_hash_aset(uh, bi, INT2FIX(FIX2INT(cv) + 1)); 00463 } 00464 prev_insn = insn; 00465 } 00466 00467 /* from disasm.c */ 00468 extern VALUE insn_operand_intern(int insn, int op_no, VALUE op, 00469 int len, int pos, VALUE child); 00470 00471 void 00472 vm_analysis_operand(int insn, int n, VALUE op) 00473 { 00474 ID usage_hash; 00475 00476 VALUE uh; 00477 VALUE ihash; 00478 VALUE ophash; 00479 VALUE valstr; 00480 VALUE cv; 00481 00482 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 00483 00484 uh = rb_const_get(rb_cRubyVM, usage_hash); 00485 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 00486 ihash = rb_hash_new(); 00487 rb_hash_aset(uh, INT2FIX(insn), ihash); 00488 } 00489 if ((ophash = rb_hash_aref(ihash, INT2FIX(n))) == Qnil) { 00490 ophash = rb_hash_new(); 00491 rb_hash_aset(ihash, INT2FIX(n), ophash); 00492 } 00493 /* intern */ 00494 valstr = insn_operand_intern(insn, n, op, 0, 0, 0); 00495 00496 /* set count */ 00497 if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) { 00498 cv = INT2FIX(0); 00499 } 00500 rb_hash_aset(ophash, valstr, INT2FIX(FIX2INT(cv) + 1)); 00501 } 00502 00503 void 00504 vm_analysis_register(int reg, int isset) 00505 { 00506 ID usage_hash; 00507 VALUE uh; 00508 VALUE rhash; 00509 VALUE valstr; 00510 static const char regstrs[][5] = { 00511 "pc", /* 0 */ 00512 "sp", /* 1 */ 00513 "cfp", /* 2 */ 00514 "lfp", /* 3 */ 00515 "dfp", /* 4 */ 00516 "self", /* 5 */ 00517 "iseq", /* 6 */ 00518 }; 00519 static const char getsetstr[][4] = { 00520 "get", 00521 "set", 00522 }; 00523 static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2]; 00524 00525 VALUE cv; 00526 00527 CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS"); 00528 if (syms[0] == 0) { 00529 char buff[0x10]; 00530 int i; 00531 00532 for (i = 0; i < sizeof(regstrs) / sizeof(regstrs[0]); i++) { 00533 int j; 00534 for (j = 0; j < 2; j++) { 00535 snfprintf(stderr, buff, 0x10, "%d %s %-4s", i, getsetstr[j], 00536 regstrs[i]); 00537 syms[i][j] = ID2SYM(rb_intern(buff)); 00538 } 00539 } 00540 } 00541 valstr = syms[reg][isset]; 00542 00543 uh = rb_const_get(rb_cRubyVM, usage_hash); 00544 if ((cv = rb_hash_aref(uh, valstr)) == Qnil) { 00545 cv = INT2FIX(0); 00546 } 00547 rb_hash_aset(uh, valstr, INT2FIX(FIX2INT(cv) + 1)); 00548 } 00549 00550 00551 #endif 00552 00553 VALUE 00554 rb_vmdebug_thread_dump_state(VALUE self) 00555 { 00556 rb_thread_t *th; 00557 rb_control_frame_t *cfp; 00558 GetThreadPtr(self, th); 00559 cfp = th->cfp; 00560 00561 fprintf(stderr, "Thread state dump:\n"); 00562 fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); 00563 fprintf(stderr, "cfp: %p, lfp: %p, dfp: %p\n", (void *)cfp, (void *)cfp->lfp, (void *)cfp->dfp); 00564 00565 return Qnil; 00566 } 00567 00568 static int 00569 bugreport_backtrace(void *arg, VALUE file, int line, VALUE method) 00570 { 00571 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file); 00572 if (!*(int *)arg) { 00573 fprintf(stderr, "-- Ruby level backtrace information " 00574 "----------------------------------------\n"); 00575 *(int *)arg = 1; 00576 } 00577 if (NIL_P(method)) { 00578 fprintf(stderr, "%s:%d:in unknown method\n", filename, line); 00579 } 00580 else { 00581 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method)); 00582 } 00583 return 0; 00584 } 00585 00586 #if HAVE_BACKTRACE 00587 #include <execinfo.h> 00588 #endif 00589 void 00590 rb_vm_bugreport(void) 00591 { 00592 if (GET_THREAD()->vm) { 00593 int i = 0; 00594 SDR(); 00595 00596 if (rb_backtrace_each(bugreport_backtrace, &i)) { 00597 fputs("\n", stderr); 00598 } 00599 } 00600 00601 #if HAVE_BACKTRACE 00602 #define MAX_NATIVE_TRACE 1024 00603 { 00604 static void *trace[MAX_NATIVE_TRACE]; 00605 int n = backtrace(trace, MAX_NATIVE_TRACE); 00606 char **syms = backtrace_symbols(trace, n); 00607 int i; 00608 00609 fprintf(stderr, "-- C level backtrace information " 00610 "-------------------------------------------\n"); 00611 if (syms) { 00612 for (i=0; i<n; i++) { 00613 fprintf(stderr, "%s\n", syms[i]); 00614 } 00615 free(syms); 00616 } 00617 fprintf(stderr, "\n"); 00618 } 00619 #endif 00620 } 00621
1.7.3