Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

vm_dump.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 vm_dump.c -
4
5 $Author: nagachika $
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
27 static void
28 control_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 VM_FRAME_MAGIC_RESCUE:
77 magic = "RESCUE";
78 break;
79 case 0:
80 magic = "------";
81 break;
82 default:
83 magic = "(none)";
84 break;
85 }
86
87 if (0) {
88 tmp = rb_inspect(cfp->self);
89 selfstr = StringValueCStr(tmp);
90 }
91 else {
92 selfstr = "";
93 }
94
95 if (cfp->iseq != 0) {
96 if (RUBY_VM_IFUNC_P(cfp->iseq)) {
97 iseq_name = "<ifunc>";
98 }
99 else {
100 pc = cfp->pc - cfp->iseq->iseq_encoded;
101 iseq_name = RSTRING_PTR(cfp->iseq->location.label);
102 line = rb_vm_get_sourceline(cfp);
103 if (line) {
104 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->location.path), line);
105 }
106 }
107 }
108 else if (cfp->me) {
109 iseq_name = rb_id2name(cfp->me->def->original_id);
110 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
111 line = -1;
112 }
113
114 fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
115 ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp));
116 if (pc == -1) {
117 fprintf(stderr, "p:---- ");
118 }
119 else {
120 fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
121 }
122 fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack);
123 fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
124 fprintf(stderr, "%-6s", magic);
125 if (line) {
126 fprintf(stderr, " %s", posbuf);
127 }
128 if (VM_FRAME_TYPE_FINISH_P(cfp)) {
129 fprintf(stderr, " [FINISH]");
130 }
131 if (0) {
132 fprintf(stderr, " \t");
133 fprintf(stderr, "iseq: %-24s ", iseq_name);
134 fprintf(stderr, "self: %-24s ", selfstr);
135 fprintf(stderr, "%-1s ", biseq_name);
136 }
137 fprintf(stderr, "\n");
138 }
139
140 void
141 rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
142 {
143 #if 0
144 VALUE *sp = cfp->sp, *ep = cfp->ep;
145 VALUE *p, *st, *t;
146
147 fprintf(stderr, "-- stack frame ------------\n");
148 for (p = st = th->stack; p < sp; p++) {
149 fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
150
151 t = (VALUE *)*p;
152 if (th->stack <= t && t < sp) {
153 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack));
154 }
155
156 if (p == ep)
157 fprintf(stderr, " <- ep");
158
159 fprintf(stderr, "\n");
160 }
161 #endif
162
163 fprintf(stderr, "-- Control frame information "
164 "-----------------------------------------------\n");
165 while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
166 control_frame_dump(th, cfp);
167 cfp++;
168 }
169 fprintf(stderr, "\n");
170 }
171
172 void
173 rb_vmdebug_stack_dump_raw_current(void)
174 {
175 rb_thread_t *th = GET_THREAD();
176 rb_vmdebug_stack_dump_raw(th, th->cfp);
177 }
178
179 void
180 rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *ep)
181 {
182 int i;
183 fprintf(stderr, "-- env --------------------\n");
184
185 while (env) {
186 fprintf(stderr, "--\n");
187 for (i = 0; i < env->env_size; i++) {
188 fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", -env->local_size + i, env->env[i],
189 (void *)&env->env[i]);
190 if (&env->env[i] == ep)
191 fprintf(stderr, " <- ep");
192 fprintf(stderr, "\n");
193 }
194
195 if (env->prev_envval != 0) {
196 GetEnvPtr(env->prev_envval, env);
197 }
198 else {
199 env = 0;
200 }
201 }
202 fprintf(stderr, "---------------------------\n");
203 }
204
205 void
206 rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
207 {
208 rb_env_t *env;
209 char *selfstr;
210 VALUE val = rb_inspect(proc->block.self);
211 selfstr = StringValueCStr(val);
212
213 fprintf(stderr, "-- proc -------------------\n");
214 fprintf(stderr, "self: %s\n", selfstr);
215 GetEnvPtr(proc->envval, env);
216 rb_vmdebug_env_dump_raw(env, proc->block.ep);
217 }
218
219 void
220 rb_vmdebug_stack_dump_th(VALUE thval)
221 {
222 rb_thread_t *th;
223 GetThreadPtr(thval, th);
224 rb_vmdebug_stack_dump_raw(th, th->cfp);
225 }
226
227 #if VMDEBUG > 2
228
229 /* copy from vm.c */
230 static VALUE *
231 vm_base_ptr(rb_control_frame_t *cfp)
232 {
233 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
234 VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1;
235
236 if (cfp->iseq->type == ISEQ_TYPE_METHOD) {
237 bp += 1;
238 }
239 return bp;
240 }
241
242 static void
243 vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
244 {
245 int i;
246
247 VALUE rstr;
248 VALUE *sp = cfp->sp;
249 VALUE *ep = cfp->ep;
250
251 int argc = 0, local_size = 0;
252 const char *name;
253 rb_iseq_t *iseq = cfp->iseq;
254
255 if (iseq == 0) {
256 if (RUBYVM_CFUNC_FRAME_P(cfp)) {
257 name = rb_id2name(cfp->me->called_id);
258 }
259 else {
260 name = "?";
261 }
262 }
263 else if (RUBY_VM_IFUNC_P(iseq)) {
264 name = "<ifunc>";
265 }
266 else {
267 argc = iseq->argc;
268 local_size = iseq->local_size;
269 name = RSTRING_PTR(iseq->location.label);
270 }
271
272 /* stack trace header */
273
274 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD||
275 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP ||
276 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK ||
277 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS ||
278 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC ||
279 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA||
280 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC ||
281 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC ||
282 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL ||
283 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_RESCUE)
284 {
285
286 VALUE *ptr = ep - local_size;
287
288 control_frame_dump(th, cfp);
289
290 for (i = 0; i < argc; i++) {
291 rstr = rb_inspect(*ptr);
292 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
293 (void *)ptr++);
294 }
295 for (; i < local_size - 1; i++) {
296 rstr = rb_inspect(*ptr);
297 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
298 (void *)ptr++);
299 }
300
301 ptr = vm_base_ptr(cfp);
302 for (; ptr < sp; ptr++, i++) {
303 if (*ptr == Qundef) {
304 rstr = rb_str_new2("undef");
305 }
306 else {
307 rstr = rb_inspect(*ptr);
308 }
309 fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
310 (ptr - th->stack));
311 }
312 }
313 else if (VM_FRAME_TYPE_FINISH_P(cfp)) {
314 if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) {
315 vm_stack_dump_each(th, cfp + 1);
316 }
317 else {
318 /* SDR(); */
319 }
320 }
321 else {
322 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
323 }
324 }
325 #endif
326
327 void
328 rb_vmdebug_debug_print_register(rb_thread_t *th)
329 {
330 rb_control_frame_t *cfp = th->cfp;
331 ptrdiff_t pc = -1;
332 ptrdiff_t ep = cfp->ep - th->stack;
333 ptrdiff_t cfpi;
334
335 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
336 pc = cfp->pc - cfp->iseq->iseq_encoded;
337 }
338
339 if (ep < 0 || (size_t)ep > th->stack_size) {
340 ep = -1;
341 }
342
343 cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp;
344 fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
345 pc, (cfp->sp - th->stack), ep, cfpi);
346 }
347
348 void
349 rb_vmdebug_thread_dump_regs(VALUE thval)
350 {
351 rb_thread_t *th;
352 GetThreadPtr(thval, th);
353 rb_vmdebug_debug_print_register(th);
354 }
355
356 void
357 rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp,VALUE *_pc)
358 {
359 rb_iseq_t *iseq = cfp->iseq;
360
361 if (iseq != 0) {
362 VALUE *seq = iseq->iseq;
363 ptrdiff_t pc = _pc - iseq->iseq_encoded;
364 int i;
365
366 for (i=0; i<(int)VM_CFP_CNT(th, cfp); i++) {
367 printf(" ");
368 }
369 printf("| ");
370 if(0)printf("[%03ld] ", (long)(cfp->sp - th->stack));
371
372 /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */
373 if (pc >= 0) {
374 rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0);
375 }
376 }
377
378 #if VMDEBUG > 3
379 fprintf(stderr, " (1)");
380 rb_vmdebug_debug_print_register(th);
381 #endif
382 }
383
384 void
385 rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp
386 #if OPT_STACK_CACHING
387 , VALUE reg_a, VALUE reg_b
388 #endif
389 )
390 {
391 #if VMDEBUG > 9
392 SDR2(cfp);
393 #endif
394
395 #if VMDEBUG > 3
396 fprintf(stderr, " (2)");
397 rb_vmdebug_debug_print_register(th);
398 #endif
399 /* stack_dump_raw(th, cfp); */
400
401 #if VMDEBUG > 2
402 /* stack_dump_thobj(th); */
403 vm_stack_dump_each(th, th->cfp);
404
405 #if OPT_STACK_CACHING
406 {
407 VALUE rstr;
408 rstr = rb_inspect(reg_a);
409 fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr));
410 rstr = rb_inspect(reg_b);
411 fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr));
412 }
413 #endif
414 printf
415 ("--------------------------------------------------------------\n");
416 #endif
417 }
418
419 VALUE
420 rb_vmdebug_thread_dump_state(VALUE self)
421 {
422 rb_thread_t *th;
423 rb_control_frame_t *cfp;
424 GetThreadPtr(self, th);
425 cfp = th->cfp;
426
427 fprintf(stderr, "Thread state dump:\n");
428 fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
429 fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
430
431 return Qnil;
432 }
433
434 #if defined(HAVE_BACKTRACE)
435 # if HAVE_LIBUNWIND
436 # undef backtrace
437 # define backtrace unw_backtrace
438 # elif defined(__APPLE__) && defined(__x86_64__)
439 # define UNW_LOCAL_ONLY
440 # include <libunwind.h>
441 # undef backtrace
442 int backtrace (void **trace, int size) {
443 unw_cursor_t cursor; unw_context_t uc;
444 unw_word_t ip;
445 int n = 0;
446
447 unw_getcontext(&uc);
448 unw_init_local(&cursor, &uc);
449 while (unw_step(&cursor) > 0) {
450 unw_get_reg(&cursor, UNW_REG_IP, &ip);
451 trace[n++] = (void *)ip;
452 {
453 char buf[256];
454 unw_get_proc_name(&cursor, buf, 256, &ip);
455 if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) {
456 goto darwin_sigtramp;
457 }
458 }
459 }
460 return n;
461 darwin_sigtramp:
462 /* darwin's bundled libunwind doesn't support signal trampoline */
463 {
464 ucontext_t *uctx;
465 /* get _sigtramp's ucontext_t and set values to cursor
466 * http://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s
467 * http://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s
468 */
469 unw_get_reg(&cursor, UNW_X86_64_RBX, &ip);
470 uctx = (ucontext_t *)ip;
471 unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->__ss.__rax);
472 unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->__ss.__rbx);
473 unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->__ss.__rcx);
474 unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->__ss.__rdx);
475 unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->__ss.__rdi);
476 unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->__ss.__rsi);
477 unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->__ss.__rbp);
478 unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->__ss.__rsp));
479 unw_set_reg(&cursor, UNW_X86_64_R8, uctx->uc_mcontext->__ss.__r8);
480 unw_set_reg(&cursor, UNW_X86_64_R9, uctx->uc_mcontext->__ss.__r9);
481 unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->__ss.__r10);
482 unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->__ss.__r11);
483 unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->__ss.__r12);
484 unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->__ss.__r13);
485 unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->__ss.__r14);
486 unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->__ss.__r15);
487 ip = *(unw_word_t*)uctx->uc_mcontext->__ss.__rsp;
488 unw_set_reg(&cursor, UNW_REG_IP, ip);
489 trace[n++] = (void *)uctx->uc_mcontext->__ss.__rip;
490 trace[n++] = (void *)ip;
491 }
492 while (unw_step(&cursor) > 0) {
493 unw_get_reg(&cursor, UNW_REG_IP, &ip);
494 trace[n++] = (void *)ip;
495 }
496 return n;
497 }
498 # elif defined(BROKEN_BACKTRACE)
499 # undef HAVE_BACKTRACE
500 # define HAVE_BACKTRACE 0
501 # endif
502 #else
503 # define HAVE_BACKTRACE 0
504 #endif
505
506 #if HAVE_BACKTRACE
507 # include <execinfo.h>
508 #elif defined(_WIN32)
509 # include <imagehlp.h>
510 # ifndef SYMOPT_DEBUG
511 # define SYMOPT_DEBUG 0x80000000
512 # endif
513 # ifndef MAX_SYM_NAME
514 # define MAX_SYM_NAME 2000
515 typedef struct {
516 DWORD64 Offset;
517 WORD Segment;
518 ADDRESS_MODE Mode;
519 } ADDRESS64;
520 typedef struct {
521 DWORD64 Thread;
522 DWORD ThCallbackStack;
523 DWORD ThCallbackBStore;
524 DWORD NextCallback;
525 DWORD FramePointer;
526 DWORD64 KiCallUserMode;
527 DWORD64 KeUserCallbackDispatcher;
528 DWORD64 SystemRangeStart;
529 DWORD64 KiUserExceptionDispatcher;
530 DWORD64 StackBase;
531 DWORD64 StackLimit;
532 DWORD64 Reserved[5];
533 } KDHELP64;
534 typedef struct {
535 ADDRESS64 AddrPC;
536 ADDRESS64 AddrReturn;
537 ADDRESS64 AddrFrame;
538 ADDRESS64 AddrStack;
539 ADDRESS64 AddrBStore;
540 void *FuncTableEntry;
541 DWORD64 Params[4];
542 BOOL Far;
543 BOOL Virtual;
544 DWORD64 Reserved[3];
545 KDHELP64 KdHelp;
546 } STACKFRAME64;
547 typedef struct {
548 ULONG SizeOfStruct;
549 ULONG TypeIndex;
550 ULONG64 Reserved[2];
551 ULONG Index;
552 ULONG Size;
553 ULONG64 ModBase;
554 ULONG Flags;
555 ULONG64 Value;
556 ULONG64 Address;
557 ULONG Register;
558 ULONG Scope;
559 ULONG Tag;
560 ULONG NameLen;
561 ULONG MaxNameLen;
562 char Name[1];
563 } SYMBOL_INFO;
564 typedef struct {
565 DWORD SizeOfStruct;
566 void *Key;
567 DWORD LineNumber;
568 char *FileName;
569 DWORD64 Address;
570 } IMAGEHLP_LINE64;
571 typedef void *PREAD_PROCESS_MEMORY_ROUTINE64;
572 typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64;
573 typedef void *PGET_MODULE_BASE_ROUTINE64;
574 typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
575 # endif
576
577 static void
578 dump_thread(void *arg)
579 {
580 HANDLE dbghelp;
581 BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL);
582 BOOL (WINAPI *pSymCleanup)(HANDLE);
583 BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
584 DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64);
585 BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
586 BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
587 HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
588 DWORD tid = *(DWORD *)arg;
589 HANDLE ph;
590 HANDLE th;
591
592 dbghelp = LoadLibrary("dbghelp.dll");
593 if (!dbghelp) return;
594 pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize");
595 pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup");
596 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");
597 pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64");
598 pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr");
599 pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64");
600 pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread");
601 if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 &&
602 pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) {
603 SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
604 ph = GetCurrentProcess();
605 pSymInitialize(ph, NULL, TRUE);
606 th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid);
607 if (th) {
608 if (SuspendThread(th) != (DWORD)-1) {
609 CONTEXT context;
610 memset(&context, 0, sizeof(context));
611 context.ContextFlags = CONTEXT_FULL;
612 if (GetThreadContext(th, &context)) {
613 char libpath[MAX_PATH];
614 char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
615 SYMBOL_INFO *info = (SYMBOL_INFO *)buf;
616 DWORD mac;
617 STACKFRAME64 frame;
618 memset(&frame, 0, sizeof(frame));
619 #if defined(_M_AMD64) || defined(__x86_64__)
620 mac = IMAGE_FILE_MACHINE_AMD64;
621 frame.AddrPC.Mode = AddrModeFlat;
622 frame.AddrPC.Offset = context.Rip;
623 frame.AddrFrame.Mode = AddrModeFlat;
624 frame.AddrFrame.Offset = context.Rbp;
625 frame.AddrStack.Mode = AddrModeFlat;
626 frame.AddrStack.Offset = context.Rsp;
627 #elif defined(_M_IA64) || defined(__ia64__)
628 mac = IMAGE_FILE_MACHINE_IA64;
629 frame.AddrPC.Mode = AddrModeFlat;
630 frame.AddrPC.Offset = context.StIIP;
631 frame.AddrBStore.Mode = AddrModeFlat;
632 frame.AddrBStore.Offset = context.RsBSP;
633 frame.AddrStack.Mode = AddrModeFlat;
634 frame.AddrStack.Offset = context.IntSp;
635 #else /* i386 */
636 mac = IMAGE_FILE_MACHINE_I386;
637 frame.AddrPC.Mode = AddrModeFlat;
638 frame.AddrPC.Offset = context.Eip;
639 frame.AddrFrame.Mode = AddrModeFlat;
640 frame.AddrFrame.Offset = context.Ebp;
641 frame.AddrStack.Mode = AddrModeFlat;
642 frame.AddrStack.Offset = context.Esp;
643 #endif
644
645 while (pStackWalk64(mac, ph, th, &frame, &context, NULL,
646 NULL, NULL, NULL)) {
647 DWORD64 addr = frame.AddrPC.Offset;
648 IMAGEHLP_LINE64 line;
649 DWORD64 displacement;
650 DWORD tmp;
651
652 if (addr == frame.AddrReturn.Offset || addr == 0 ||
653 frame.AddrReturn.Offset == 0)
654 break;
655
656 memset(buf, 0, sizeof(buf));
657 info->SizeOfStruct = sizeof(SYMBOL_INFO);
658 info->MaxNameLen = MAX_SYM_NAME;
659 if (pSymFromAddr(ph, addr, &displacement, info)) {
660 if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath)))
661 fprintf(stderr, "%s", libpath);
662 fprintf(stderr, "(%s+0x%I64x)",
663 info->Name, displacement);
664 }
665 fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
666 memset(&line, 0, sizeof(line));
667 line.SizeOfStruct = sizeof(line);
668 if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
669 fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
670 fprintf(stderr, "\n");
671 }
672 }
673
674 ResumeThread(th);
675 }
676 CloseHandle(th);
677 }
678 pSymCleanup(ph);
679 }
680 FreeLibrary(dbghelp);
681 }
682 #endif
683
684 void
685 rb_print_backtrace(void)
686 {
687 #if HAVE_BACKTRACE
688 #define MAX_NATIVE_TRACE 1024
689 static void *trace[MAX_NATIVE_TRACE];
690 int n = backtrace(trace, MAX_NATIVE_TRACE);
691 char **syms = backtrace_symbols(trace, n);
692
693 if (syms) {
694 #ifdef USE_ELF
695 rb_dump_backtrace_with_lines(n, trace, syms);
696 #else
697 int i;
698 for (i=0; i<n; i++) {
699 fprintf(stderr, "%s\n", syms[i]);
700 }
701 #endif
702 free(syms);
703 }
704 #elif defined(_WIN32)
705 DWORD tid = GetCurrentThreadId();
706 HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
707 if (th != (HANDLE)-1)
708 WaitForSingleObject(th, INFINITE);
709 #endif
710 }
711
712 void
713 rb_vm_bugreport(void)
714 {
715 #ifdef __linux__
716 # define PROC_MAPS_NAME "/proc/self/maps"
717 #endif
718 #ifdef PROC_MAPS_NAME
719 enum {other_runtime_info = 1};
720 #else
721 enum {other_runtime_info = 0};
722 #endif
723 const rb_vm_t *const vm = GET_VM();
724
725 #if defined __APPLE__
726 fputs("-- Crash Report log information "
727 "--------------------------------------------\n"
728 " See Crash Report log file under the one of following:\n"
729 " * ~/Library/Logs/CrashReporter\n"
730 " * /Library/Logs/CrashReporter\n"
731 " * ~/Library/Logs/DiagnosticReports\n"
732 " * /Library/Logs/DiagnosticReports\n"
733 " for more details.\n"
734 "\n",
735 stderr);
736 #endif
737 if (vm) {
738 SDR();
739 rb_backtrace_print_as_bugreport();
740 fputs("\n", stderr);
741 }
742
743 #if HAVE_BACKTRACE || defined(_WIN32)
744 fprintf(stderr, "-- C level backtrace information "
745 "-------------------------------------------\n");
746 rb_print_backtrace();
747
748
749 fprintf(stderr, "\n");
750 #endif /* HAVE_BACKTRACE */
751
752 if (other_runtime_info || vm) {
753 fprintf(stderr, "-- Other runtime information "
754 "-----------------------------------------------\n\n");
755 }
756 if (vm) {
757 int i;
758 VALUE name;
759 long len;
760 const int max_name_length = 1024;
761 # define LIMITED_NAME_LENGTH(s) \
762 (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)
763
764 name = vm->progname;
765 fprintf(stderr, "* Loaded script: %.*s\n",
766 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
767 fprintf(stderr, "\n");
768 fprintf(stderr, "* Loaded features:\n\n");
769 for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
770 name = RARRAY_AREF(vm->loaded_features, i);
771 if (RB_TYPE_P(name, T_STRING)) {
772 fprintf(stderr, " %4d %.*s\n", i,
773 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
774 }
775 else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) {
776 const char *const type = RB_TYPE_P(name, T_CLASS) ?
777 "class" : "module";
778 name = rb_class_name(name);
779 fprintf(stderr, " %4d %s:%.*s\n", i, type,
780 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
781 }
782 else {
783 VALUE klass = rb_class_name(CLASS_OF(name));
784 fprintf(stderr, " %4d #<%.*s:%p>\n", i,
785 LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
786 (void *)name);
787 }
788 }
789 fprintf(stderr, "\n");
790 }
791
792 {
793 #ifdef PROC_MAPS_NAME
794 {
795 FILE *fp = fopen(PROC_MAPS_NAME, "r");
796 if (fp) {
797 fprintf(stderr, "* Process memory map:\n\n");
798
799 while (!feof(fp)) {
800 char buff[0x100];
801 size_t rn = fread(buff, 1, 0x100, fp);
802 if (fwrite(buff, 1, rn, stderr) != rn)
803 break;
804 }
805
806 fclose(fp);
807 fprintf(stderr, "\n\n");
808 }
809 }
810 #endif /* __linux__ */
811 }
812 }
rb_thread_struct::cfp
rb_control_frame_t * cfp
Definition: vm_core.h:531
VM_FRAME_MAGIC_BLOCK
#define VM_FRAME_MAGIC_BLOCK
Definition: vm_core.h:760
rb_iseq_disasm_insn
int rb_iseq_disasm_insn(VALUE ret, VALUE *iseq, size_t pos, rb_iseq_t *iseqdat, VALUE child)
Disassemble a instruction Iseq -> Iseq inspect object.
Definition: iseq.c:1286
rb_env_t::env
VALUE * env
Definition: vm_core.h:714
rb_env_t::prev_envval
VALUE prev_envval
Definition: vm_core.h:717
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:878
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
FALSE
#define FALSE
Definition: nkf.h:174
RUBY_VM_IFUNC_P
#define RUBY_VM_IFUNC_P(ptr)
Definition: vm_core.h:834
rb_vm_get_sourceline
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:33
VM_CFP_CNT
#define VM_CFP_CNT(th, cfp)
Definition: vm_dump.c:24
control_frame_dump
static void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:28
VM_FRAME_TYPE_FINISH_P
#define VM_FRAME_TYPE_FINISH_P(cfp)
Definition: vm_core.h:778
VM_FRAME_MAGIC_CFUNC
#define VM_FRAME_MAGIC_CFUNC
Definition: vm_core.h:763
rb_vmdebug_thread_dump_state
VALUE rb_vmdebug_thread_dump_state(VALUE self)
Definition: vm_dump.c:420
RUBY_VM_PREVIOUS_CONTROL_FRAME
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
Definition: vm_core.h:825
ruby.h
RUBY_VM_NORMAL_ISEQ_P
#define RUBY_VM_NORMAL_ISEQ_P(ptr)
Definition: vm_core.h:835
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:440
T_MODULE
#define T_MODULE
Definition: ruby.h:480
rb_vm_struct::progname
VALUE progname
Definition: vm_core.h:399
rb_env_t::env_size
int env_size
Definition: vm_core.h:715
rb_control_frame_struct::sp
VALUE * sp
Definition: vm_core.h:447
rb_vmdebug_stack_dump_th
void rb_vmdebug_stack_dump_th(VALUE thval)
Definition: vm_dump.c:220
MAX_POSBUF
#define MAX_POSBUF
Definition: vm_dump.c:22
SDR2
#define SDR2(cfp)
Definition: vm_core.h:854
rb_block_struct::self
VALUE self
Definition: vm_core.h:463
PRIxVALUE
#define PRIxVALUE
Definition: ruby.h:135
VM_FRAME_MAGIC_METHOD
#define VM_FRAME_MAGIC_METHOD
Definition: vm_core.h:759
VM_FRAME_TYPE
#define VM_FRAME_TYPE(cfp)
Definition: vm_core.h:772
rb_method_entry_struct::called_id
ID called_id
Definition: method.h:101
VM_FRAME_MAGIC_IFUNC
#define VM_FRAME_MAGIC_IFUNC
Definition: vm_core.h:765
SDR
#define SDR()
Definition: vm_core.h:853
VM_FRAME_MAGIC_RESCUE
#define VM_FRAME_MAGIC_RESCUE
Definition: vm_core.h:768
GetEnvPtr
#define GetEnvPtr(obj, ptr)
Definition: vm_core.h:710
rb_thread_struct
Definition: vm_core.h:524
rb_method_definition_struct::original_id
ID original_id
Definition: method.h:80
rb_proc_t::envval
VALUE envval
Definition: vm_core.h:703
__sFILE
Definition: vsnprintf.c:175
rb_iseq_struct::iseq
VALUE * iseq
Definition: vm_core.h:225
rb_thread_struct::stack
VALUE * stack
Definition: vm_core.h:529
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
rb_iseq_struct::type
enum rb_iseq_struct::iseq_type type
rb_control_frame_struct::self
VALUE self
Definition: vm_core.h:450
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:391
val
#define val
rb_control_frame_struct::block_iseq
rb_iseq_t * block_iseq
Definition: vm_core.h:453
DWORD
IUnknown DWORD
Definition: win32ole.c:149
rb_iseq_struct::argc
int argc
argument information
Definition: vm_core.h:274
snprintf
#define snprintf
Definition: subst.h:6
rb_control_frame_struct::iseq
rb_iseq_t * iseq
Definition: vm_core.h:448
argc
int argc
Definition: ruby.c:131
VM_FRAME_MAGIC_CLASS
#define VM_FRAME_MAGIC_CLASS
Definition: vm_core.h:761
rb_vm_bugreport
void rb_vm_bugreport(void)
Definition: vm_dump.c:713
T_NODE
#define T_NODE
Definition: ruby.h:498
rb_str_new2
#define rb_str_new2
Definition: intern.h:840
PRIdPTRDIFF
#define PRIdPTRDIFF
Definition: ruby.h:161
rb_vmdebug_debug_print_register
void rb_vmdebug_debug_print_register(rb_thread_t *th)
Definition: vm_dump.c:328
rb_control_frame_struct
Definition: vm_core.h:445
TRUE
#define TRUE
Definition: nkf.h:175
rb_proc_t
Definition: vm_core.h:700
rb_vm_struct::loaded_features
VALUE loaded_features
Definition: vm_core.h:376
rb_vmdebug_stack_dump_raw
void rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:141
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
internal.h
rb_iseq_location_struct::path
const VALUE path
Definition: vm_core.h:197
RUBYVM_CFUNC_FRAME_P
#define RUBYVM_CFUNC_FRAME_P(cfp)
Definition: vm_core.h:781
rb_env_t::local_size
int local_size
Definition: vm_core.h:716
Qnil
#define Qnil
Definition: ruby.h:427
uintptr_t
unsigned int uintptr_t
Definition: win32.h:103
type
int type
Definition: tcltklib.c:112
vm_core.h
VM_FRAME_MAGIC_EVAL
#define VM_FRAME_MAGIC_EVAL
Definition: vm_core.h:766
rb_iseq_struct::iseq_encoded
VALUE * iseq_encoded
Definition: vm_core.h:226
BUILTIN_TYPE
#define BUILTIN_TYPE(x)
Definition: ruby.h:502
VALUE
unsigned long VALUE
Definition: ruby.h:88
vm_base_ptr
static VALUE * vm_base_ptr(rb_control_frame_t *cfp)
Definition: vm_insnhelper.c:978
rb_iseq_struct::location
rb_iseq_location_t location
Definition: vm_core.h:223
rb_vmdebug_env_dump_raw
void rb_vmdebug_env_dump_raw(rb_env_t *env, VALUE *ep)
Definition: vm_dump.c:180
OPT_STACK_CACHING
#define OPT_STACK_CACHING
Definition: vm_opts.h:47
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:541
VM_FRAME_MAGIC_TOP
#define VM_FRAME_MAGIC_TOP
Definition: vm_core.h:762
VM_FRAME_MAGIC_PROC
#define VM_FRAME_MAGIC_PROC
Definition: vm_core.h:764
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
size
int size
Definition: encoding.c:49
VM_FRAME_MAGIC_LAMBDA
#define VM_FRAME_MAGIC_LAMBDA
Definition: vm_core.h:767
rb_print_backtrace
void rb_print_backtrace(void)
Definition: vm_dump.c:685
rb_proc_t::block
rb_block_t block
Definition: vm_core.h:701
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: ruby.h:901
rb_control_frame_struct::pc
VALUE * pc
Definition: vm_core.h:446
rb_method_entry_struct::def
rb_method_definition_t * def
Definition: method.h:100
rb_control_frame_struct::me
const rb_method_entry_t * me
Definition: vm_core.h:455
rb_vmdebug_thread_dump_regs
void rb_vmdebug_thread_dump_regs(VALUE thval)
Definition: vm_dump.c:349
rb_control_frame_struct::ep
VALUE * ep
Definition: vm_core.h:452
T_STRING
#define T_STRING
Definition: ruby.h:482
rb_iseq_struct::local_size
int local_size
Definition: vm_core.h:239
GetThreadPtr
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:472
T_CLASS
#define T_CLASS
Definition: ruby.h:478
rb_vmdebug_proc_dump_raw
void rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
Definition: vm_dump.c:206
name
const char * name
Definition: nkf.c:208
rb_vm_struct
Definition: vm_core.h:348
rb_vmdebug_stack_dump_raw_current
void rb_vmdebug_stack_dump_raw_current(void)
Definition: vm_dump.c:173
rb_iseq_struct
Definition: vm_core.h:206
rb_id2name
const char * rb_id2name(ID id)
Definition: ripper.c:17230
rb_thread_struct::stack_size
size_t stack_size
Definition: vm_core.h:530
rb_inspect
VALUE rb_inspect(VALUE)
Definition: object.c:470
GC_GUARDED_PTR_REF
#define GC_GUARDED_PTR_REF(p)
Definition: vm_core.h:800
rb_vmdebug_debug_print_pre
void rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp, VALUE *_pc)
Definition: vm_dump.c:357
rb_backtrace_print_as_bugreport
void rb_backtrace_print_as_bugreport(void)
Definition: vm_backtrace.c:766
addr2line.h
feof
#define feof(p)
Definition: vsnprintf.c:218
env
#define env
PRIxPTRDIFF
#define PRIxPTRDIFF
Definition: ruby.h:165
NULL
#define NULL
Definition: _sdbm.c:103
Qundef
#define Qundef
Definition: ruby.h:428
rb_iseq_location_struct::label
const VALUE label
Definition: vm_core.h:200
GET_THREAD
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
ULONG
static ULONG(STDMETHODCALLTYPE AddRef)(IDispatch __RPC_FAR *This)
Definition: win32ole.c:615
free
free(psz)
bp
#define bp()
Definition: vm_debug.h:25
rb_vmdebug_debug_print_post
void rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:385
LIMITED_NAME_LENGTH
#define LIMITED_NAME_LENGTH(s)
rb_block_struct::ep
VALUE * ep
Definition: vm_core.h:465
rb_env_t
Definition: vm_core.h:713
GET_VM
#define GET_VM()
Definition: vm_core.h:920