Ruby  2.4.2p198(2017-09-14revision59899)
vm_dump.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  vm_dump.c -
4 
5  $Author: naruse $
6 
7  Copyright (C) 2004-2007 Koichi Sasada
8 
9 **********************************************************************/
10 
11 
12 #include "internal.h"
13 #include "addr2line.h"
14 #include "vm_core.h"
15 #include "iseq.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
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 
40 
41  if (ep < 0 || (size_t)ep > th->stack_size) {
42  ep = (ptrdiff_t)cfp->ep;
43  ep_in_heap = 'p';
44  }
45 
46  switch (VM_FRAME_TYPE(cfp)) {
47  case VM_FRAME_MAGIC_TOP:
48  magic = "TOP";
49  break;
51  magic = "METHOD";
52  break;
54  magic = "CLASS";
55  break;
57  magic = "BLOCK";
58  break;
60  magic = "CFUNC";
61  break;
63  magic = "PROC";
64  break;
66  magic = "LAMBDA";
67  break;
69  magic = "IFUNC";
70  break;
72  magic = "EVAL";
73  break;
75  magic = "RESCUE";
76  break;
77  case 0:
78  magic = "------";
79  break;
80  default:
81  magic = "(none)";
82  break;
83  }
84 
85  if (0) {
86  tmp = rb_inspect(cfp->self);
87  selfstr = StringValueCStr(tmp);
88  }
89  else {
90  selfstr = "";
91  }
92 
93  if (cfp->iseq != 0) {
94 #define RUBY_VM_IFUNC_P(ptr) (RB_TYPE_P((VALUE)(ptr), T_IMEMO) && imemo_type((VALUE)ptr) == imemo_ifunc)
95  if (RUBY_VM_IFUNC_P(cfp->iseq)) {
96  iseq_name = "<ifunc>";
97  }
98  else if (SYMBOL_P(cfp->iseq)) {
99  tmp = rb_sym2str((VALUE)cfp->iseq);
100  iseq_name = RSTRING_PTR(tmp);
101  snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
102  line = -1;
103  }
104  else {
105  pc = cfp->pc - cfp->iseq->body->iseq_encoded;
106  iseq_name = RSTRING_PTR(cfp->iseq->body->location.label);
107  line = rb_vm_get_sourceline(cfp);
108  if (line) {
109  snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->body->location.path), line);
110  }
111  }
112  }
113  else if ((me = rb_vm_frame_method_entry(cfp)) != NULL) {
114  iseq_name = rb_id2name(me->def->original_id);
115  snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
116  line = -1;
117  }
118 
119  fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
120  ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp));
121  if (pc == -1) {
122  fprintf(stderr, "p:---- ");
123  }
124  else {
125  fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
126  }
127  fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack);
128  fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
129  fprintf(stderr, "%-6s", magic);
130  if (line) {
131  fprintf(stderr, " %s", posbuf);
132  }
133  if (VM_FRAME_FINISHED_P(cfp)) {
134  fprintf(stderr, " [FINISH]");
135  }
136  if (0) {
137  fprintf(stderr, " \t");
138  fprintf(stderr, "iseq: %-24s ", iseq_name);
139  fprintf(stderr, "self: %-24s ", selfstr);
140  fprintf(stderr, "%-1s ", biseq_name);
141  }
142  fprintf(stderr, "\n");
143 }
144 
145 void
147 {
148 #if 0
149  VALUE *sp = cfp->sp, *ep = cfp->ep;
150  VALUE *p, *st, *t;
151 
152  fprintf(stderr, "-- stack frame ------------\n");
153  for (p = st = th->stack; p < sp; p++) {
154  fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
155 
156  t = (VALUE *)*p;
157  if (th->stack <= t && t < sp) {
158  fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack));
159  }
160 
161  if (p == ep)
162  fprintf(stderr, " <- ep");
163 
164  fprintf(stderr, "\n");
165  }
166 #endif
167 
168  fprintf(stderr, "-- Control frame information "
169  "-----------------------------------------------\n");
170  while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
171  control_frame_dump(th, cfp);
172  cfp++;
173  }
174  fprintf(stderr, "\n");
175 }
176 
177 void
179 {
182 }
183 
184 void
186 {
187  unsigned int i;
188  fprintf(stderr, "-- env --------------------\n");
189 
190  while (env) {
191  fprintf(stderr, "--\n");
192  for (i = 0; i < env->env_size; i++) {
193  fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]);
194  if (&env->env[i] == ep) fprintf(stderr, " <- ep");
195  fprintf(stderr, "\n");
196  }
197 
198  env = rb_vm_env_prev_env(env);
199  }
200  fprintf(stderr, "---------------------------\n");
201 }
202 
203 void
205 {
206  const rb_env_t *env;
207  char *selfstr;
209  selfstr = StringValueCStr(val);
210 
211  fprintf(stderr, "-- proc -------------------\n");
212  fprintf(stderr, "self: %s\n", selfstr);
213  env = VM_ENV_ENVVAL_PTR(vm_block_ep(&proc->block));
215 }
216 
217 void
219 {
220  rb_thread_t *th;
221  GetThreadPtr(thval, th);
223 }
224 
225 #if VMDEBUG > 2
226 
227 /* copy from vm.c */
228 static VALUE *
230 {
232  VALUE *bp = prev_cfp->sp + iseq->body->local_table_size + VM_ENV_DATA_SIZE;
233 
234  if (cfp->iseq->body->type == ISEQ_TYPE_METHOD) {
235  bp += 1;
236  }
237  return bp;
238 }
239 
240 static void
241 vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
242 {
243  int i, argc = 0, local_size = 0;
244  VALUE rstr;
245  VALUE *sp = cfp->sp;
246  VALUE *ep = cfp->ep;
247 
248  if (VM_FRAME_RUBYFRAME_P(cfp)) {
249  rb_iseq_t *iseq = cfp->iseq;
250  argc = iseq->body->param.lead_num;
251  local_size = iseq->body->local_size;
252  }
253 
254  /* stack trace header */
255 
266  {
267 
268  VALUE *ptr = ep - local_size;
269 
270  control_frame_dump(th, cfp);
271 
272  for (i = 0; i < argc; i++) {
273  rstr = rb_inspect(*ptr);
274  fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
275  (void *)ptr++);
276  }
277  for (; i < local_size - 1; i++) {
278  rstr = rb_inspect(*ptr);
279  fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
280  (void *)ptr++);
281  }
282 
283  ptr = vm_base_ptr(cfp);
284  for (; ptr < sp; ptr++, i++) {
285  switch (TYPE(*ptr)) {
286  case T_UNDEF:
287  rstr = rb_str_new2("undef");
288  break;
289  case T_IMEMO:
290  rstr = rb_str_new2("imemo"); /* TODO: can put mode detail information */
291  break;
292  default:
293  rstr = rb_inspect(*ptr);
294  break;
295  }
296  fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
297  (ptr - th->stack));
298  }
299  }
300  else if (VM_FRAME_FINISHED_P(cfp)) {
301  if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) {
302  vm_stack_dump_each(th, cfp + 1);
303  }
304  else {
305  /* SDR(); */
306  }
307  }
308  else {
309  rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
310  }
311 }
312 #endif
313 
314 void
316 {
317  rb_control_frame_t *cfp = th->cfp;
318  ptrdiff_t pc = -1;
319  ptrdiff_t ep = cfp->ep - th->stack;
320  ptrdiff_t cfpi;
321 
322  if (VM_FRAME_RUBYFRAME_P(cfp)) {
323  pc = cfp->pc - cfp->iseq->body->iseq_encoded;
324  }
325 
326  if (ep < 0 || (size_t)ep > th->stack_size) {
327  ep = -1;
328  }
329 
330  cfpi = ((rb_control_frame_t *)(th->stack + th->stack_size)) - cfp;
331  fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
332  pc, (cfp->sp - th->stack), ep, cfpi);
333 }
334 
335 void
337 {
338  rb_thread_t *th;
339  GetThreadPtr(thval, th);
341 }
342 
343 void
345 {
346  const rb_iseq_t *iseq = cfp->iseq;
347 
348  if (iseq != 0) {
349  ptrdiff_t pc = _pc - iseq->body->iseq_encoded;
350  int i;
351 
352  for (i=0; i<(int)VM_CFP_CNT(th, cfp); i++) {
353  printf(" ");
354  }
355  printf("| ");
356  if(0)printf("[%03ld] ", (long)(cfp->sp - th->stack));
357 
358  /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); */
359  if (pc >= 0) {
360  const VALUE *iseq_original = rb_iseq_original_iseq((rb_iseq_t *)iseq);
361 
362  rb_iseq_disasm_insn(0, iseq_original, (size_t)pc, iseq, 0);
363  }
364  }
365 
366 #if VMDEBUG > 3
367  fprintf(stderr, " (1)");
369 #endif
370 }
371 
372 void
375  , VALUE reg_a, VALUE reg_b
376 #endif
377  )
378 {
379 #if VMDEBUG > 9
380  SDR2(cfp);
381 #endif
382 
383 #if VMDEBUG > 3
384  fprintf(stderr, " (2)");
386 #endif
387  /* stack_dump_raw(th, cfp); */
388 
389 #if VMDEBUG > 2
390  /* stack_dump_thobj(th); */
391  vm_stack_dump_each(th, th->cfp);
392 
393 #if OPT_STACK_CACHING
394  {
395  VALUE rstr;
396  rstr = rb_inspect(reg_a);
397  fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr));
398  rstr = rb_inspect(reg_b);
399  fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr));
400  }
401 #endif
402  printf
403  ("--------------------------------------------------------------\n");
404 #endif
405 }
406 
407 VALUE
409 {
410  rb_thread_t *th;
412  GetThreadPtr(self, th);
413  cfp = th->cfp;
414 
415  fprintf(stderr, "Thread state dump:\n");
416  fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
417  fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
418 
419  return Qnil;
420 }
421 
422 #if defined(HAVE_BACKTRACE)
423 # ifdef HAVE_LIBUNWIND
424 # undef backtrace
425 # define backtrace unw_backtrace
426 # elif defined(__APPLE__) && defined(__x86_64__) && defined(HAVE_LIBUNWIND_H)
427 # define UNW_LOCAL_ONLY
428 # include <libunwind.h>
429 # undef backtrace
430 int
431 backtrace(void **trace, int size)
432 {
433  unw_cursor_t cursor; unw_context_t uc;
434  unw_word_t ip;
435  int n = 0;
436 
437  unw_getcontext(&uc);
438  unw_init_local(&cursor, &uc);
439  while (unw_step(&cursor) > 0) {
440  unw_get_reg(&cursor, UNW_REG_IP, &ip);
441  trace[n++] = (void *)ip;
442  {
443  char buf[256];
444  unw_get_proc_name(&cursor, buf, 256, &ip);
445  if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) {
446  goto darwin_sigtramp;
447  }
448  }
449  }
450  return n;
451 darwin_sigtramp:
452  /* darwin's bundled libunwind doesn't support signal trampoline */
453  {
454  ucontext_t *uctx;
455  /* get _sigtramp's ucontext_t and set values to cursor
456  * http://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s
457  * http://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s
458  */
459  unw_get_reg(&cursor, UNW_X86_64_RBX, &ip);
460  uctx = (ucontext_t *)ip;
461  unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->__ss.__rax);
462  unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->__ss.__rbx);
463  unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->__ss.__rcx);
464  unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->__ss.__rdx);
465  unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->__ss.__rdi);
466  unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->__ss.__rsi);
467  unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->__ss.__rbp);
468  unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->__ss.__rsp));
469  unw_set_reg(&cursor, UNW_X86_64_R8, uctx->uc_mcontext->__ss.__r8);
470  unw_set_reg(&cursor, UNW_X86_64_R9, uctx->uc_mcontext->__ss.__r9);
471  unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->__ss.__r10);
472  unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->__ss.__r11);
473  unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->__ss.__r12);
474  unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->__ss.__r13);
475  unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->__ss.__r14);
476  unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->__ss.__r15);
477  ip = uctx->uc_mcontext->__ss.__rip;
478  if (((char*)ip)[-2] == 0x0f && ((char*)ip)[-1] == 5) {
479  /* signal received in syscall */
480  trace[n++] = (void *)ip;
481  ip = *(unw_word_t*)uctx->uc_mcontext->__ss.__rsp;
482  }
483  trace[n++] = (void *)ip;
484  unw_set_reg(&cursor, UNW_REG_IP, ip);
485  }
486  while (unw_step(&cursor) > 0) {
487  unw_get_reg(&cursor, UNW_REG_IP, &ip);
488  trace[n++] = (void *)ip;
489  }
490  return n;
491 }
492 # elif defined(BROKEN_BACKTRACE)
493 # undef HAVE_BACKTRACE
494 # define HAVE_BACKTRACE 0
495 # endif
496 #else
497 # define HAVE_BACKTRACE 0
498 #endif
499 
500 #if HAVE_BACKTRACE
501 # include <execinfo.h>
502 #elif defined(_WIN32)
503 # include <imagehlp.h>
504 # ifndef SYMOPT_DEBUG
505 # define SYMOPT_DEBUG 0x80000000
506 # endif
507 # ifndef MAX_SYM_NAME
508 # define MAX_SYM_NAME 2000
509 typedef struct {
510  DWORD64 Offset;
511  WORD Segment;
512  ADDRESS_MODE Mode;
513 } ADDRESS64;
514 typedef struct {
515  DWORD64 Thread;
516  DWORD ThCallbackStack;
517  DWORD ThCallbackBStore;
518  DWORD NextCallback;
519  DWORD FramePointer;
520  DWORD64 KiCallUserMode;
521  DWORD64 KeUserCallbackDispatcher;
522  DWORD64 SystemRangeStart;
523  DWORD64 KiUserExceptionDispatcher;
524  DWORD64 StackBase;
525  DWORD64 StackLimit;
526  DWORD64 Reserved[5];
527 } KDHELP64;
528 typedef struct {
529  ADDRESS64 AddrPC;
530  ADDRESS64 AddrReturn;
531  ADDRESS64 AddrFrame;
532  ADDRESS64 AddrStack;
533  ADDRESS64 AddrBStore;
534  void *FuncTableEntry;
535  DWORD64 Params[4];
536  BOOL Far;
537  BOOL Virtual;
538  DWORD64 Reserved[3];
539  KDHELP64 KdHelp;
540 } STACKFRAME64;
541 typedef struct {
542  ULONG SizeOfStruct;
543  ULONG TypeIndex;
544  ULONG64 Reserved[2];
545  ULONG Index;
546  ULONG Size;
547  ULONG64 ModBase;
548  ULONG Flags;
549  ULONG64 Value;
550  ULONG64 Address;
551  ULONG Register;
552  ULONG Scope;
553  ULONG Tag;
554  ULONG NameLen;
555  ULONG MaxNameLen;
556  char Name[1];
557 } SYMBOL_INFO;
558 typedef struct {
559  DWORD SizeOfStruct;
560  void *Key;
561  DWORD LineNumber;
562  char *FileName;
563  DWORD64 Address;
564 } IMAGEHLP_LINE64;
565 typedef void *PREAD_PROCESS_MEMORY_ROUTINE64;
566 typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64;
567 typedef void *PGET_MODULE_BASE_ROUTINE64;
568 typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
569 # endif
570 
571 static void
572 dump_thread(void *arg)
573 {
574  HANDLE dbghelp;
575  BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL);
576  BOOL (WINAPI *pSymCleanup)(HANDLE);
577  BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
578  DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64);
579  BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
580  BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
581  HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
582  DWORD tid = *(DWORD *)arg;
583  HANDLE ph;
584  HANDLE th;
585 
586  dbghelp = LoadLibrary("dbghelp.dll");
587  if (!dbghelp) return;
588  pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize");
589  pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup");
590  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");
591  pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64");
592  pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr");
593  pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64");
594  pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread");
595  if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 &&
596  pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) {
597  SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
598  ph = GetCurrentProcess();
599  pSymInitialize(ph, NULL, TRUE);
600  th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid);
601  if (th) {
602  if (SuspendThread(th) != (DWORD)-1) {
603  CONTEXT context;
604  memset(&context, 0, sizeof(context));
605  context.ContextFlags = CONTEXT_FULL;
606  if (GetThreadContext(th, &context)) {
607  char libpath[MAX_PATH];
608  char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
609  SYMBOL_INFO *info = (SYMBOL_INFO *)buf;
610  DWORD mac;
611  STACKFRAME64 frame;
612  memset(&frame, 0, sizeof(frame));
613 #if defined(_M_AMD64) || defined(__x86_64__)
614  mac = IMAGE_FILE_MACHINE_AMD64;
615  frame.AddrPC.Mode = AddrModeFlat;
616  frame.AddrPC.Offset = context.Rip;
617  frame.AddrFrame.Mode = AddrModeFlat;
618  frame.AddrFrame.Offset = context.Rbp;
619  frame.AddrStack.Mode = AddrModeFlat;
620  frame.AddrStack.Offset = context.Rsp;
621 #elif defined(_M_IA64) || defined(__ia64__)
622  mac = IMAGE_FILE_MACHINE_IA64;
623  frame.AddrPC.Mode = AddrModeFlat;
624  frame.AddrPC.Offset = context.StIIP;
625  frame.AddrBStore.Mode = AddrModeFlat;
626  frame.AddrBStore.Offset = context.RsBSP;
627  frame.AddrStack.Mode = AddrModeFlat;
628  frame.AddrStack.Offset = context.IntSp;
629 #else /* i386 */
630  mac = IMAGE_FILE_MACHINE_I386;
631  frame.AddrPC.Mode = AddrModeFlat;
632  frame.AddrPC.Offset = context.Eip;
633  frame.AddrFrame.Mode = AddrModeFlat;
634  frame.AddrFrame.Offset = context.Ebp;
635  frame.AddrStack.Mode = AddrModeFlat;
636  frame.AddrStack.Offset = context.Esp;
637 #endif
638 
639  while (pStackWalk64(mac, ph, th, &frame, &context, NULL,
640  NULL, NULL, NULL)) {
641  DWORD64 addr = frame.AddrPC.Offset;
642  IMAGEHLP_LINE64 line;
643  DWORD64 displacement;
644  DWORD tmp;
645 
646  if (addr == frame.AddrReturn.Offset || addr == 0 ||
647  frame.AddrReturn.Offset == 0)
648  break;
649 
650  memset(buf, 0, sizeof(buf));
651  info->SizeOfStruct = sizeof(SYMBOL_INFO);
652  info->MaxNameLen = MAX_SYM_NAME;
653  if (pSymFromAddr(ph, addr, &displacement, info)) {
654  if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath)))
655  fprintf(stderr, "%s", libpath);
656  fprintf(stderr, "(%s+0x%I64x)",
657  info->Name, displacement);
658  }
659  fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
660  memset(&line, 0, sizeof(line));
661  line.SizeOfStruct = sizeof(line);
662  if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
663  fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
664  fprintf(stderr, "\n");
665  }
666  }
667 
668  ResumeThread(th);
669  }
670  CloseHandle(th);
671  }
672  pSymCleanup(ph);
673  }
674  FreeLibrary(dbghelp);
675 }
676 #endif
677 
678 void
680 {
681 #if HAVE_BACKTRACE
682 #define MAX_NATIVE_TRACE 1024
683  static void *trace[MAX_NATIVE_TRACE];
684  int n = (int)backtrace(trace, MAX_NATIVE_TRACE);
685 #if defined(USE_ELF) && defined(HAVE_DLADDR) && !defined(__sparc)
686  rb_dump_backtrace_with_lines(n, trace);
687 #else
688  char **syms = backtrace_symbols(trace, n);
689  if (syms) {
690  int i;
691  for (i=0; i<n; i++) {
692  fprintf(stderr, "%s\n", syms[i]);
693  }
694  free(syms);
695  }
696 #endif
697 #elif defined(_WIN32)
698  DWORD tid = GetCurrentThreadId();
699  HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
700  if (th != (HANDLE)-1)
701  WaitForSingleObject(th, INFINITE);
702 #endif
703 }
704 
705 #ifdef HAVE_LIBPROCSTAT
706 #include <sys/user.h>
707 #include <sys/sysctl.h>
708 #include <sys/param.h>
709 #include <libprocstat.h>
710 # ifndef KVME_TYPE_MGTDEVICE
711 # define KVME_TYPE_MGTDEVICE 8
712 # endif
713 void
714 procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp)
715 {
716  struct kinfo_vmentry *freep, *kve;
717  int ptrwidth;
718  unsigned int i, cnt;
719  const char *str;
720 #ifdef __x86_64__
721  ptrwidth = 14;
722 #else
723  ptrwidth = 2*sizeof(void *) + 2;
724 #endif
725  fprintf(stderr, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n",
726  ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
727  "PRES", "REF", "SHD", "FL", "TP", "PATH");
728 
729 #ifdef HAVE_PROCSTAT_GETVMMAP
730  freep = procstat_getvmmap(procstat, kipp, &cnt);
731 #else
732  freep = kinfo_getvmmap(kipp->ki_pid, &cnt);
733 #endif
734  if (freep == NULL)
735  return;
736  for (i = 0; i < cnt; i++) {
737  kve = &freep[i];
738  fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
739  fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
740  fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
741  fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
742  fprintf(stderr, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
743  fprintf(stderr, "%4d ", kve->kve_resident);
744  fprintf(stderr, "%4d ", kve->kve_private_resident);
745  fprintf(stderr, "%3d ", kve->kve_ref_count);
746  fprintf(stderr, "%3d ", kve->kve_shadow_count);
747  fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
748  fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
749  "-");
750  fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-");
751  fprintf(stderr, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" :
752  kve->kve_flags & KVME_FLAG_GROWS_DOWN ? "D" : "-");
753  switch (kve->kve_type) {
754  case KVME_TYPE_NONE:
755  str = "--";
756  break;
757  case KVME_TYPE_DEFAULT:
758  str = "df";
759  break;
760  case KVME_TYPE_VNODE:
761  str = "vn";
762  break;
763  case KVME_TYPE_SWAP:
764  str = "sw";
765  break;
766  case KVME_TYPE_DEVICE:
767  str = "dv";
768  break;
769  case KVME_TYPE_PHYS:
770  str = "ph";
771  break;
772  case KVME_TYPE_DEAD:
773  str = "dd";
774  break;
775  case KVME_TYPE_SG:
776  str = "sg";
777  break;
778  case KVME_TYPE_MGTDEVICE:
779  str = "md";
780  break;
781  case KVME_TYPE_UNKNOWN:
782  default:
783  str = "??";
784  break;
785  }
786  fprintf(stderr, "%-2s ", str);
787  fprintf(stderr, "%-s\n", kve->kve_path);
788  }
789  free(freep);
790 }
791 #endif
792 
793 #if defined __linux__
794 # if defined __x86_64__ || defined __i386__
795 # define HAVE_PRINT_MACHINE_REGISTERS 1
796 # endif
797 #elif defined __APPLE__
798 # if defined __x86_64__ || defined __i386__
799 # define HAVE_PRINT_MACHINE_REGISTERS 1
800 # endif
801 #endif
802 
803 #ifdef HAVE_PRINT_MACHINE_REGISTERS
804 static int
805 print_machine_register(size_t reg, const char *reg_name, int col_count, int max_col)
806 {
807  int ret;
808  char buf[64];
809 
810 #ifdef __LP64__
811  ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%016zx", reg_name, reg);
812 #else
813  ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%08zx", reg_name, reg);
814 #endif
815  if (col_count + ret > max_col) {
816  fputs("\n", stderr);
817  col_count = 0;
818  }
819  col_count += ret;
820  fputs(buf, stderr);
821  return col_count;
822 }
823 # ifdef __linux__
824 # define dump_machine_register(reg) (col_count = print_machine_register(mctx->gregs[REG_##reg], #reg, col_count, 80))
825 # elif defined __APPLE__
826 # define dump_machine_register(reg) (col_count = print_machine_register(mctx->__ss.__##reg, #reg, col_count, 80))
827 # endif
828 
829 static void
830 rb_dump_machine_register(const ucontext_t *ctx)
831 {
832  int col_count = 0;
833  if (!ctx) return;
834 
835  fprintf(stderr, "-- Machine register context "
836  "------------------------------------------------\n");
837 
838 # if defined __linux__
839  {
840  const mcontext_t *const mctx = &ctx->uc_mcontext;
841 # if defined __x86_64__
842  dump_machine_register(RIP);
843  dump_machine_register(RBP);
844  dump_machine_register(RSP);
845  dump_machine_register(RAX);
846  dump_machine_register(RBX);
847  dump_machine_register(RCX);
848  dump_machine_register(RDX);
849  dump_machine_register(RDI);
850  dump_machine_register(RSI);
851  dump_machine_register(R8);
852  dump_machine_register(R9);
853  dump_machine_register(R10);
854  dump_machine_register(R11);
855  dump_machine_register(R12);
856  dump_machine_register(R13);
857  dump_machine_register(R14);
858  dump_machine_register(R15);
859  dump_machine_register(EFL);
860 # elif defined __i386__
861  dump_machine_register(GS);
862  dump_machine_register(FS);
863  dump_machine_register(ES);
864  dump_machine_register(DS);
865  dump_machine_register(EDI);
866  dump_machine_register(ESI);
867  dump_machine_register(EBP);
868  dump_machine_register(ESP);
869  dump_machine_register(EBX);
870  dump_machine_register(EDX);
871  dump_machine_register(ECX);
872  dump_machine_register(EAX);
873  dump_machine_register(TRAPNO);
874  dump_machine_register(ERR);
875  dump_machine_register(EIP);
876  dump_machine_register(CS);
877  dump_machine_register(EFL);
878  dump_machine_register(UESP);
879  dump_machine_register(SS);
880 # endif
881  }
882 # elif defined __APPLE__
883  {
884  const mcontext_t mctx = ctx->uc_mcontext;
885 # if defined __x86_64__
886  dump_machine_register(rax);
887  dump_machine_register(rbx);
888  dump_machine_register(rcx);
889  dump_machine_register(rdx);
890  dump_machine_register(rdi);
891  dump_machine_register(rsi);
892  dump_machine_register(rbp);
893  dump_machine_register(rsp);
894  dump_machine_register(r8);
895  dump_machine_register(r9);
896  dump_machine_register(r10);
897  dump_machine_register(r11);
898  dump_machine_register(r12);
899  dump_machine_register(r13);
900  dump_machine_register(r14);
901  dump_machine_register(r15);
902  dump_machine_register(rip);
903  dump_machine_register(rflags);
904 # elif defined __i386__
905  dump_machine_register(eax);
906  dump_machine_register(ebx);
907  dump_machine_register(ecx);
908  dump_machine_register(edx);
909  dump_machine_register(edi);
910  dump_machine_register(esi);
911  dump_machine_register(ebp);
912  dump_machine_register(esp);
913  dump_machine_register(ss);
914  dump_machine_register(eflags);
915  dump_machine_register(eip);
916  dump_machine_register(cs);
917  dump_machine_register(ds);
918  dump_machine_register(es);
919  dump_machine_register(fs);
920  dump_machine_register(gs);
921 # endif
922  }
923 # endif
924  fprintf(stderr, "\n\n");
925 }
926 #else
927 # define rb_dump_machine_register(ctx) ((void)0)
928 #endif /* HAVE_PRINT_MACHINE_REGISTERS */
929 
930 void
931 rb_vm_bugreport(const void *ctx)
932 {
933 #ifdef __linux__
934 # define PROC_MAPS_NAME "/proc/self/maps"
935 #endif
936 #ifdef PROC_MAPS_NAME
937  enum {other_runtime_info = 1};
938 #else
939  enum {other_runtime_info = 0};
940 #endif
941  const rb_vm_t *const vm = GET_VM();
942 
943  if (vm) {
944  SDR();
946  fputs("\n", stderr);
947  }
948 
950 
951 #if HAVE_BACKTRACE || defined(_WIN32)
952  fprintf(stderr, "-- C level backtrace information "
953  "-------------------------------------------\n");
955 
956 
957  fprintf(stderr, "\n");
958 #endif /* HAVE_BACKTRACE */
959 
960  if (other_runtime_info || vm) {
961  fprintf(stderr, "-- Other runtime information "
962  "-----------------------------------------------\n\n");
963  }
964  if (vm) {
965  int i;
966  VALUE name;
967  long len;
968  const int max_name_length = 1024;
969 # define LIMITED_NAME_LENGTH(s) \
970  (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)
971 
972  name = vm->progname;
973  fprintf(stderr, "* Loaded script: %.*s\n",
974  LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
975  fprintf(stderr, "\n");
976  fprintf(stderr, "* Loaded features:\n\n");
977  for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
978  name = RARRAY_AREF(vm->loaded_features, i);
979  if (RB_TYPE_P(name, T_STRING)) {
980  fprintf(stderr, " %4d %.*s\n", i,
981  LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
982  }
983  else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) {
984  const char *const type = RB_TYPE_P(name, T_CLASS) ?
985  "class" : "module";
986  name = rb_search_class_path(rb_class_real(name));
987  if (!RB_TYPE_P(name, T_STRING)) {
988  fprintf(stderr, " %4d %s:<unnamed>\n", i, type);
989  continue;
990  }
991  fprintf(stderr, " %4d %s:%.*s\n", i, type,
992  LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
993  }
994  else {
996  if (!RB_TYPE_P(klass, T_STRING)) {
997  fprintf(stderr, " %4d #<%p:%p>\n", i,
998  (void *)CLASS_OF(name), (void *)name);
999  continue;
1000  }
1001  fprintf(stderr, " %4d #<%.*s:%p>\n", i,
1002  LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
1003  (void *)name);
1004  }
1005  }
1006  fprintf(stderr, "\n");
1007  }
1008 
1009  {
1010 #ifdef PROC_MAPS_NAME
1011  {
1012  FILE *fp = fopen(PROC_MAPS_NAME, "r");
1013  if (fp) {
1014  fprintf(stderr, "* Process memory map:\n\n");
1015 
1016  while (!feof(fp)) {
1017  char buff[0x100];
1018  size_t rn = fread(buff, 1, 0x100, fp);
1019  if (fwrite(buff, 1, rn, stderr) != rn)
1020  break;
1021  }
1022 
1023  fclose(fp);
1024  fprintf(stderr, "\n\n");
1025  }
1026  }
1027 #endif /* __linux__ */
1028 #ifdef HAVE_LIBPROCSTAT
1029 # define MIB_KERN_PROC_PID_LEN 4
1030  int mib[MIB_KERN_PROC_PID_LEN];
1031  struct kinfo_proc kp;
1032  size_t len = sizeof(struct kinfo_proc);
1033  mib[0] = CTL_KERN;
1034  mib[1] = KERN_PROC;
1035  mib[2] = KERN_PROC_PID;
1036  mib[3] = getpid();
1037  if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) {
1038  perror("sysctl");
1039  }
1040  else {
1041  struct procstat *prstat = procstat_open_sysctl();
1042  fprintf(stderr, "* Process memory map:\n\n");
1043  procstat_vm(prstat, &kp);
1044  procstat_close(prstat);
1045  fprintf(stderr, "\n");
1046  }
1047 #endif /* __FreeBSD__ */
1048  }
1049 }
rb_control_frame_t * cfp
Definition: vm_core.h:708
void rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep)
Definition: vm_dump.c:185
const VALUE * ep
Definition: vm_core.h:636
#define RARRAY_LEN(a)
Definition: ruby.h:1026
void rb_bug(const char *fmt,...)
Definition: error.c:482
#define FALSE
Definition: nkf.h:174
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:38
#define VM_CFP_CNT(th, cfp)
Definition: vm_dump.c:24
static void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:28
VALUE rb_vmdebug_thread_dump_state(VALUE self)
Definition: vm_dump.c:408
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
Definition: vm_core.h:1172
static int VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp)
Definition: vm_core.h:1031
#define CLASS_OF(v)
Definition: ruby.h:453
#define T_MODULE
Definition: ruby.h:494
VALUE progname
Definition: vm_core.h:537
const VALUE * env
Definition: vm_core.h:877
struct rb_method_definition_struct *const def
Definition: method.h:61
const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
rb_thread_t * th
Definition: vm_core.h:1581
void rb_vmdebug_stack_dump_th(VALUE thval)
Definition: vm_dump.c:218
struct rb_iseq_constant_body * body
Definition: vm_core.h:395
#define MAX_POSBUF
Definition: vm_dump.c:22
#define SDR2(cfp)
Definition: vm_core.h:1415
#define PRIxVALUE
Definition: ruby.h:133
struct rb_iseq_constant_body::@196 param
parameter information
#define SDR()
Definition: vm_core.h:1414
static int VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp)
Definition: vm_core.h:1061
#define T_UNDEF
Definition: ruby.h:512
#define GET_THREAD()
Definition: vm_core.h:1513
const VALUE * iseq_encoded
Definition: vm_core.h:286
VALUE * stack
Definition: vm_core.h:706
#define RB_TYPE_P(obj, type)
Definition: ruby.h:527
const rb_iseq_t * iseq
Definition: vm_core.h:634
const rb_env_t * rb_vm_env_prev_env(const rb_env_t *env)
Definition: vm.c:739
#define val
IUnknown DWORD
Definition: win32ole.c:32
static VALUE * vm_base_ptr(const rb_control_frame_t *cfp)
#define snprintf
Definition: subst.h:6
rb_control_frame_t * cfp
Definition: vm_core.h:1582
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:525
#define TYPE(x)
Definition: ruby.h:521
int argc
Definition: ruby.c:183
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
Definition: compile.c:716
Definition: method.h:58
#define rb_str_new2
Definition: intern.h:857
#define PRIdPTRDIFF
Definition: ruby.h:159
void rb_vmdebug_debug_print_register(rb_thread_t *th)
Definition: vm_dump.c:315
static const rb_env_t * VM_ENV_ENVVAL_PTR(const VALUE *ep)
Definition: vm_core.h:1123
static VALUE vm_block_self(const struct rb_block *block)
Definition: vm_core.h:1361
void rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp, const VALUE *_pc)
Definition: vm_dump.c:344
#define TRUE
Definition: nkf.h:175
VALUE loaded_features
Definition: vm_core.h:514
void rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:146
#define VM_ENV_DATA_SIZE
Definition: vm_core.h:988
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4309
#define T_IMEMO
Definition: ruby.h:511
unsigned int env_size
Definition: vm_core.h:878
static const VALUE * vm_block_ep(const struct rb_block *block)
Definition: vm_core.h:1348
#define Qnil
Definition: ruby.h:438
unsigned int uintptr_t
Definition: win32.h:106
unsigned long VALUE
Definition: ruby.h:85
void rb_vm_bugreport(const void *ctx)
Definition: vm_dump.c:931
struct Size Size
#define OPT_STACK_CACHING
Definition: vm_opts.h:48
const char * rb_id2name(ID)
Definition: symbol.c:759
enum rb_iseq_constant_body::iseq_type type
VALUE rb_class_real(VALUE cl)
Definition: object.c:207
register unsigned int len
Definition: zonetab.h:51
#define StringValueCStr(v)
Definition: ruby.h:571
static unsigned long VM_FRAME_TYPE(const rb_control_frame_t *cfp)
Definition: vm_core.h:1025
#define RSTRING_PTR(str)
Definition: ruby.h:982
int size
Definition: encoding.c:57
void rb_print_backtrace(void)
Definition: vm_dump.c:679
#define RARRAY_AREF(a, i)
Definition: ruby.h:1040
int rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos, const rb_iseq_t *iseq, VALUE child)
Disassemble a instruction Iseq -> Iseq inspect object.
Definition: iseq.c:1402
void rb_vmdebug_thread_dump_regs(VALUE thval)
Definition: vm_dump.c:336
const struct rb_block block
Definition: vm_core.h:867
#define T_STRING
Definition: ruby.h:496
const VALUE * pc
Definition: vm_core.h:632
#define rb_dump_machine_register(ctx)
Definition: vm_dump.c:927
#define RUBY_VM_IFUNC_P(ptr)
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:646
#define T_CLASS
Definition: ruby.h:492
void rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
Definition: vm_dump.c:204
const char * name
Definition: nkf.c:208
void rb_vmdebug_stack_dump_raw_current(void)
Definition: vm_dump.c:178
size_t stack_size
Definition: vm_core.h:707
VALUE rb_inspect(VALUE)
Definition: object.c:519
#define ERR(err)
Definition: getaddrinfo.c:198
#define GC_GUARDED_PTR_REF(p)
Definition: vm_core.h:948
void rb_backtrace_print_as_bugreport(void)
Definition: vm_backtrace.c:760
#define SYMBOL_P(x)
Definition: ruby.h:382
#define feof(p)
Definition: vsnprintf.c:212
#define env
#define PRIxPTRDIFF
Definition: ruby.h:163
#define NULL
Definition: _sdbm.c:102
VALUE rb_search_class_path(VALUE)
Definition: variable.c:336
static ULONG(STDMETHODCALLTYPE AddRef)(IDispatch __RPC_FAR *This)
Definition: win32ole.c:199
free(psz)
#define bp()
Definition: vm_debug.h:25
void rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp)
Definition: vm_dump.c:373
#define LIMITED_NAME_LENGTH(s)
rb_iseq_location_t location
Definition: vm_core.h:358
#define rb_sym2str(sym)
Definition: console.c:107
VALUE rb_obj_class(VALUE)
Definition: object.c:229
#define GET_VM()
Definition: vm_core.h:1507