00001
00002
00003
00004
00005
00006
00007
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 = "";
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
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");
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
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
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
00397
00398 #if VMDEBUG > 2
00399
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
00417
00418
00419
00420
00421
00422
00423
00424
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
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
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
00496 valstr = insn_operand_intern(insn, n, op, 0, 0, 0);
00497
00498
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",
00514 "sp",
00515 "cfp",
00516 "lfp",
00517 "dfp",
00518 "self",
00519 "iseq",
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
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
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
00851 }
00852 }
00853