Ruby 2.0.0p247(2013-06-27revision41674)

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