Ruby: vm_dump.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

vm_dump.c
1/**********************************************************************
2
3 vm_dump.c -
4
5 $Author$
6
7 Copyright (C) 2004-2007 Koichi Sasada
8
9**********************************************************************/
10
11#include "ruby/internal/config.h"
12
13#ifdef HAVE_UCONTEXT_H
14# include <ucontext.h>
15#endif
16
17#ifdef __APPLE__
18# ifdef HAVE_LIBPROC_H
19# include <libproc.h>
20# endif
21# include <mach/vm_map.h>
22# include <mach/mach_init.h>
23# ifdef __LP64__
24# define vm_region_recurse vm_region_recurse_64
25# endif
26/* that is defined in sys/queue.h, and conflicts with
27 * ccan/list/list.h */
28# undef LIST_HEAD
29#endif
30
31#include "addr2line.h"
32#include "gc.h"
33#include "internal.h"
34#include "internal/variable.h"
35#include "internal/vm.h"
36#include "iseq.h"
37#include "vm_core.h"
38#include "ractor_core.h"
39
40#define MAX_POSBUF 128
41
42#define VM_CFP_CNT(ec, cfp) \
43 ((rb_control_frame_t *)((ec)->vm_stack + (ec)->vm_stack_size) - \
44 (rb_control_frame_t *)(cfp))
45
46const char *rb_method_type_name(rb_method_type_t type);
47int ruby_on_ci;
48
49static void
50control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
51{
52 ptrdiff_t pc = -1;
53 ptrdiff_t ep = cfp->ep - ec->vm_stack;
54 char ep_in_heap = ' ';
55 char posbuf[MAX_POSBUF+1];
56 int line = 0;
57 const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
58 VALUE tmp;
59 const rb_iseq_t *iseq = NULL;
60 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
61
62 if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
63 ep = (ptrdiff_t)cfp->ep;
64 ep_in_heap = 'p';
65 }
66
67 switch (VM_FRAME_TYPE(cfp)) {
68 case VM_FRAME_MAGIC_TOP:
69 magic = "TOP";
70 break;
71 case VM_FRAME_MAGIC_METHOD:
72 magic = "METHOD";
73 break;
74 case VM_FRAME_MAGIC_CLASS:
75 magic = "CLASS";
76 break;
77 case VM_FRAME_MAGIC_BLOCK:
78 magic = "BLOCK";
79 break;
80 case VM_FRAME_MAGIC_CFUNC:
81 magic = "CFUNC";
82 break;
83 case VM_FRAME_MAGIC_IFUNC:
84 magic = "IFUNC";
85 break;
86 case VM_FRAME_MAGIC_EVAL:
87 magic = "EVAL";
88 break;
89 case VM_FRAME_MAGIC_RESCUE:
90 magic = "RESCUE";
91 break;
92 case VM_FRAME_MAGIC_DUMMY:
93 magic = "DUMMY";
94 break;
95 case 0:
96 magic = "------";
97 break;
98 default:
99 magic = "(none)";
100 break;
101 }
102
103 if (0) {
104 tmp = rb_inspect(cfp->self);
105 selfstr = StringValueCStr(tmp);
106 }
107 else {
108 selfstr = "";
109 }
110
111 if (cfp->iseq != 0) {
112#define RUBY_VM_IFUNC_P(ptr) IMEMO_TYPE_P(ptr, imemo_ifunc)
113 if (RUBY_VM_IFUNC_P(cfp->iseq)) {
114 iseq_name = "<ifunc>";
115 }
116 else if (SYMBOL_P((VALUE)cfp->iseq)) {
117 tmp = rb_sym2str((VALUE)cfp->iseq);
118 iseq_name = RSTRING_PTR(tmp);
119 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
120 line = -1;
121 }
122 else {
123 if (cfp->pc) {
124 iseq = cfp->iseq;
125 pc = cfp->pc - ISEQ_BODY(iseq)->iseq_encoded;
126 iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
127 line = rb_vm_get_sourceline(cfp);
128 if (line) {
129 snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(iseq)), line);
130 }
131 }
132 else {
133 iseq_name = "<dummy_frame>";
134 }
135 }
136 }
137 else if (me != NULL) {
138 iseq_name = rb_id2name(me->def->original_id);
139 snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
140 line = -1;
141 }
142
143 fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
144 ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp));
145 if (pc == -1) {
146 fprintf(stderr, "p:---- ");
147 }
148 else {
149 fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
150 }
151 fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack);
152 fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
153 fprintf(stderr, "%-6s", magic);
154 if (line) {
155 fprintf(stderr, " %s", posbuf);
156 }
157 if (VM_FRAME_FINISHED_P(cfp)) {
158 fprintf(stderr, " [FINISH]");
159 }
160 if (0) {
161 fprintf(stderr, " \t");
162 fprintf(stderr, "iseq: %-24s ", iseq_name);
163 fprintf(stderr, "self: %-24s ", selfstr);
164 fprintf(stderr, "%-1s ", biseq_name);
165 }
166 fprintf(stderr, "\n");
167
168 // additional information for CI machines
169 if (ruby_on_ci) {
170 char buff[0x100];
171
172 if (me) {
173 if (IMEMO_TYPE_P(me, imemo_ment)) {
174 fprintf(stderr, " me:\n");
175 fprintf(stderr, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type));
176 fprintf(stderr, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner));
177 if (me->owner != me->defined_class) {
178 fprintf(stderr, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class));
179 }
180 }
181 else {
182 fprintf(stderr, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me));
183 }
184 }
185
186 fprintf(stderr, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self));
187
188 if (iseq) {
189 if (ISEQ_BODY(iseq)->local_table_size > 0) {
190 fprintf(stderr, " lvars:\n");
191 for (unsigned int i=0; i<ISEQ_BODY(iseq)->local_table_size; i++) {
192 const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1;
193 fprintf(stderr, " %s: %s\n",
194 rb_id2name(ISEQ_BODY(iseq)->local_table[i]),
195 rb_raw_obj_info(buff, 0x100, argv[i]));
196 }
197 }
198 }
199 }
200}
201
202void
203rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
204{
205#if 0
206 VALUE *sp = cfp->sp;
207 const VALUE *ep = cfp->ep;
208 VALUE *p, *st, *t;
209
210 fprintf(stderr, "-- stack frame ------------\n");
211 for (p = st = ec->vm_stack; p < sp; p++) {
212 fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
213
214 t = (VALUE *)*p;
215 if (ec->vm_stack <= t && t < sp) {
216 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack));
217 }
218
219 if (p == ep)
220 fprintf(stderr, " <- ep");
221
222 fprintf(stderr, "\n");
223 }
224#endif
225
226 fprintf(stderr, "-- Control frame information "
227 "-----------------------------------------------\n");
228 while ((void *)cfp < (void *)(ec->vm_stack + ec->vm_stack_size)) {
229 control_frame_dump(ec, cfp);
230 cfp++;
231 }
232 fprintf(stderr, "\n");
233}
234
235void
236rb_vmdebug_stack_dump_raw_current(void)
237{
238 const rb_execution_context_t *ec = GET_EC();
239 rb_vmdebug_stack_dump_raw(ec, ec->cfp);
240}
241
242void
243rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep)
244{
245 unsigned int i;
246 fprintf(stderr, "-- env --------------------\n");
247
248 while (env) {
249 fprintf(stderr, "--\n");
250 for (i = 0; i < env->env_size; i++) {
251 fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]);
252 if (&env->env[i] == ep) fprintf(stderr, " <- ep");
253 fprintf(stderr, "\n");
254 }
255
256 env = rb_vm_env_prev_env(env);
257 }
258 fprintf(stderr, "---------------------------\n");
259}
260
261void
262rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
263{
264 const rb_env_t *env;
265 char *selfstr;
266 VALUE val = rb_inspect(vm_block_self(&proc->block));
267 selfstr = StringValueCStr(val);
268
269 fprintf(stderr, "-- proc -------------------\n");
270 fprintf(stderr, "self: %s\n", selfstr);
271 env = VM_ENV_ENVVAL_PTR(vm_block_ep(&proc->block));
272 rb_vmdebug_env_dump_raw(env, vm_block_ep(&proc->block));
273}
274
275void
276rb_vmdebug_stack_dump_th(VALUE thval)
277{
278 rb_thread_t *target_th = rb_thread_ptr(thval);
279 rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp);
280}
281
282#if VMDEBUG > 2
283
284/* copy from vm.c */
285static const VALUE *
286vm_base_ptr(const rb_control_frame_t *cfp)
287{
288 const rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
289 const VALUE *bp = prev_cfp->sp + ISEQ_BODY(cfp->iseq)->local_table_size + VM_ENV_DATA_SIZE;
290
291 if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_METHOD) {
292 bp += 1;
293 }
294 return bp;
295}
296
297static void
298vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
299{
300 int i, argc = 0, local_table_size = 0;
301 VALUE rstr;
302 VALUE *sp = cfp->sp;
303 const VALUE *ep = cfp->ep;
304
305 if (VM_FRAME_RUBYFRAME_P(cfp)) {
306 const rb_iseq_t *iseq = cfp->iseq;
307 argc = ISEQ_BODY(iseq)->param.lead_num;
308 local_table_size = ISEQ_BODY(iseq)->local_table_size;
309 }
310
311 /* stack trace header */
312
313 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD||
314 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP ||
315 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK ||
316 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS ||
317 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC ||
318 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC ||
319 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL ||
320 VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_RESCUE)
321 {
322 const VALUE *ptr = ep - local_table_size;
323
324 control_frame_dump(ec, cfp);
325
326 for (i = 0; i < argc; i++) {
327 rstr = rb_inspect(*ptr);
328 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
329 (void *)ptr++);
330 }
331 for (; i < local_table_size - 1; i++) {
332 rstr = rb_inspect(*ptr);
333 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
334 (void *)ptr++);
335 }
336
337 ptr = vm_base_ptr(cfp);
338 for (; ptr < sp; ptr++, i++) {
339 switch (TYPE(*ptr)) {
340 case T_UNDEF:
341 rstr = rb_str_new2("undef");
342 break;
343 case T_IMEMO:
344 rstr = rb_str_new2("imemo"); /* TODO: can put mode detail information */
345 break;
346 default:
347 rstr = rb_inspect(*ptr);
348 break;
349 }
350 fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
351 (ptr - ec->vm_stack));
352 }
353 }
354 else if (VM_FRAME_FINISHED_P(cfp)) {
355 if (ec->vm_stack + ec->vm_stack_size > (VALUE *)(cfp + 1)) {
356 vm_stack_dump_each(ec, cfp + 1);
357 }
358 else {
359 /* SDR(); */
360 }
361 }
362 else {
363 rb_bug("unsupported frame type: %08lx", VM_FRAME_TYPE(cfp));
364 }
365}
366#endif
367
368void
369rb_vmdebug_debug_print_register(const rb_execution_context_t *ec)
370{
371 rb_control_frame_t *cfp = ec->cfp;
372 ptrdiff_t pc = -1;
373 ptrdiff_t ep = cfp->ep - ec->vm_stack;
374 ptrdiff_t cfpi;
375
376 if (VM_FRAME_RUBYFRAME_P(cfp)) {
377 pc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
378 }
379
380 if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
381 ep = -1;
382 }
383
384 cfpi = ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size)) - cfp;
385 fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
386 pc, (cfp->sp - ec->vm_stack), ep, cfpi);
387}
388
389void
390rb_vmdebug_thread_dump_regs(VALUE thval)
391{
392 rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec);
393}
394
395void
396rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc)
397{
398 const rb_iseq_t *iseq = cfp->iseq;
399
400 if (iseq != 0) {
401 ptrdiff_t pc = _pc - ISEQ_BODY(iseq)->iseq_encoded;
402 int i;
403
404 for (i=0; i<(int)VM_CFP_CNT(ec, cfp); i++) {
405 printf(" ");
406 }
407 printf("| ");
408 if(0)printf("[%03ld] ", (long)(cfp->sp - ec->vm_stack));
409
410 /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(ec, cfp)); */
411 if (pc >= 0) {
412 const VALUE *iseq_original = rb_iseq_original_iseq((rb_iseq_t *)iseq);
413
414 rb_iseq_disasm_insn(0, iseq_original, (size_t)pc, iseq, 0);
415 }
416 }
417
418#if VMDEBUG > 3
419 fprintf(stderr, " (1)");
420 rb_vmdebug_debug_print_register(ec);
421#endif
422}
423
424void
425rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp
426#if OPT_STACK_CACHING
427 , VALUE reg_a, VALUE reg_b
428#endif
429 )
430{
431#if VMDEBUG > 9
432 SDR2(cfp);
433#endif
434
435#if VMDEBUG > 3
436 fprintf(stderr, " (2)");
437 rb_vmdebug_debug_print_register(ec);
438#endif
439 /* stack_dump_raw(ec, cfp); */
440
441#if VMDEBUG > 2
442 /* stack_dump_thobj(ec); */
443 vm_stack_dump_each(ec, ec->cfp);
444
445#if OPT_STACK_CACHING
446 {
447 VALUE rstr;
448 rstr = rb_inspect(reg_a);
449 fprintf(stderr, " sc reg A: %s\n", StringValueCStr(rstr));
450 rstr = rb_inspect(reg_b);
451 fprintf(stderr, " sc reg B: %s\n", StringValueCStr(rstr));
452 }
453#endif
454 printf
455 ("--------------------------------------------------------------\n");
456#endif
457}
458
459 VALUE
460rb_vmdebug_thread_dump_state(VALUE self)
461{
462 rb_thread_t *th = rb_thread_ptr(self);
463 rb_control_frame_t *cfp = th->ec->cfp;
464
465 fprintf(stderr, "Thread state dump:\n");
466 fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
467 fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
468
469 return Qnil;
470}
471
472#if defined __APPLE__
473# if __DARWIN_UNIX03
474# define MCTX_SS_REG(reg) __ss.__##reg
475# else
476# define MCTX_SS_REG(reg) ss.reg
477# endif
478#endif
479
480#if defined(HAVE_BACKTRACE)
481# define USE_BACKTRACE 1
482# ifdef HAVE_LIBUNWIND
483# undef backtrace
484# define backtrace unw_backtrace
485# elif defined(__APPLE__) && defined(HAVE_LIBUNWIND_H)
486# define UNW_LOCAL_ONLY
487# include <libunwind.h>
488# include <sys/mman.h>
489# undef backtrace
490int
491backtrace(void **trace, int size)
492{
493 unw_cursor_t cursor; unw_context_t uc;
494 unw_word_t ip;
495 int n = 0;
496
497 unw_getcontext(&uc);
498 unw_init_local(&cursor, &uc);
499# if defined(__x86_64__)
500 while (unw_step(&cursor) > 0) {
501 unw_get_reg(&cursor, UNW_REG_IP, &ip);
502 trace[n++] = (void *)ip;
503 {
504 char buf[256];
505 unw_get_proc_name(&cursor, buf, 256, &ip);
506 if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) {
507 goto darwin_sigtramp;
508 }
509 }
510 }
511 return n;
512darwin_sigtramp:
513 /* darwin's bundled libunwind doesn't support signal trampoline */
514 {
515 ucontext_t *uctx;
516 char vec[1];
517 int r;
518 /* get previous frame information from %rbx at _sigtramp and set values to cursor
519 * https://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s
520 * https://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s
521 */
522 unw_get_reg(&cursor, UNW_X86_64_RBX, &ip);
523 uctx = (ucontext_t *)ip;
524 unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->MCTX_SS_REG(rax));
525 unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->MCTX_SS_REG(rbx));
526 unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->MCTX_SS_REG(rcx));
527 unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->MCTX_SS_REG(rdx));
528 unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->MCTX_SS_REG(rdi));
529 unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->MCTX_SS_REG(rsi));
530 unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->MCTX_SS_REG(rbp));
531 unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->MCTX_SS_REG(rsp)));
532 unw_set_reg(&cursor, UNW_X86_64_R8, uctx->uc_mcontext->MCTX_SS_REG(r8));
533 unw_set_reg(&cursor, UNW_X86_64_R9, uctx->uc_mcontext->MCTX_SS_REG(r9));
534 unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->MCTX_SS_REG(r10));
535 unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->MCTX_SS_REG(r11));
536 unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->MCTX_SS_REG(r12));
537 unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->MCTX_SS_REG(r13));
538 unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->MCTX_SS_REG(r14));
539 unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->MCTX_SS_REG(r15));
540 ip = uctx->uc_mcontext->MCTX_SS_REG(rip);
541
542 /* There are 4 cases for SEGV:
543 * (1) called invalid address
544 * (2) read or write invalid address
545 * (3) received signal
546 *
547 * Detail:
548 * (1) called invalid address
549 * In this case, saved ip is invalid address.
550 * It needs to just save the address for the information,
551 * skip the frame, and restore the frame calling the
552 * invalid address from %rsp.
553 * The problem is how to check whether the ip is valid or not.
554 * This code uses mincore(2) and assume the address's page is
555 * incore/referenced or not reflects the problem.
556 * Note that High Sierra's mincore(2) may return -128.
557 * (2) read or write invalid address
558 * saved ip is valid. just restart backtracing.
559 * (3) received signal in user space
560 * Same as (2).
561 * (4) received signal in kernel
562 * In this case saved ip points just after syscall, but registers are
563 * already overwritten by kernel. To fix register consistency,
564 * skip libc's kernel wrapper.
565 * To detect this case, just previous two bytes of ip is "\x0f\x05",
566 * syscall instruction of x86_64.
567 */
568 r = mincore((const void *)ip, 1, vec);
569 if (r || vec[0] <= 0 || memcmp((const char *)ip-2, "\x0f\x05", 2) == 0) {
570 /* if segv is caused by invalid call or signal received in syscall */
571 /* the frame is invalid; skip */
572 trace[n++] = (void *)ip;
573 ip = *(unw_word_t*)uctx->uc_mcontext->MCTX_SS_REG(rsp);
574 }
575
576 trace[n++] = (void *)ip;
577 unw_set_reg(&cursor, UNW_REG_IP, ip);
578 }
579 while (unw_step(&cursor) > 0) {
580 unw_get_reg(&cursor, UNW_REG_IP, &ip);
581 trace[n++] = (void *)ip;
582 }
583 return n;
584
585# else /* defined(__arm64__) */
586 /* Since Darwin arm64's _sigtramp is implemented as normal function,
587 * unwind can unwind frames without special code.
588 * https://github.com/apple/darwin-libplatform/blob/215b09856ab5765b7462a91be7076183076600df/src/setjmp/generic/sigtramp.c
589 */
590 while (unw_step(&cursor) > 0) {
591 unw_get_reg(&cursor, UNW_REG_IP, &ip);
592 // Strip Arm64's pointer authentication.
593 // https://developer.apple.com/documentation/security/preparing_your_app_to_work_with_pointer_authentication
594 // I wish I could use "ptrauth_strip()" but I get an error:
595 // "this target does not support pointer authentication"
596 trace[n++] = (void *)(ip & 0x7fffffffffffull);
597 }
598 return n;
599# endif
600}
601# elif defined(BROKEN_BACKTRACE)
602# undef USE_BACKTRACE
603# define USE_BACKTRACE 0
604# endif
605#else
606# define USE_BACKTRACE 0
607#endif
608
609#if USE_BACKTRACE
610# include <execinfo.h>
611#elif defined(_WIN32)
612# include <imagehlp.h>
613# ifndef SYMOPT_DEBUG
614# define SYMOPT_DEBUG 0x80000000
615# endif
616# ifndef MAX_SYM_NAME
617# define MAX_SYM_NAME 2000
618typedef struct {
619 DWORD64 Offset;
620 WORD Segment;
621 ADDRESS_MODE Mode;
622} ADDRESS64;
623typedef struct {
624 DWORD64 Thread;
625 DWORD ThCallbackStack;
626 DWORD ThCallbackBStore;
627 DWORD NextCallback;
628 DWORD FramePointer;
629 DWORD64 KiCallUserMode;
630 DWORD64 KeUserCallbackDispatcher;
631 DWORD64 SystemRangeStart;
632 DWORD64 KiUserExceptionDispatcher;
633 DWORD64 StackBase;
634 DWORD64 StackLimit;
635 DWORD64 Reserved[5];
636} KDHELP64;
637typedef struct {
638 ADDRESS64 AddrPC;
639 ADDRESS64 AddrReturn;
640 ADDRESS64 AddrFrame;
641 ADDRESS64 AddrStack;
642 ADDRESS64 AddrBStore;
643 void *FuncTableEntry;
644 DWORD64 Params[4];
645 BOOL Far;
646 BOOL Virtual;
647 DWORD64 Reserved[3];
648 KDHELP64 KdHelp;
649} STACKFRAME64;
650typedef struct {
651 ULONG SizeOfStruct;
652 ULONG TypeIndex;
653 ULONG64 Reserved[2];
654 ULONG Index;
655 ULONG Size;
656 ULONG64 ModBase;
657 ULONG Flags;
658 ULONG64 Value;
659 ULONG64 Address;
660 ULONG Register;
661 ULONG Scope;
662 ULONG Tag;
663 ULONG NameLen;
664 ULONG MaxNameLen;
665 char Name[1];
666} SYMBOL_INFO;
667typedef struct {
668 DWORD SizeOfStruct;
669 void *Key;
670 DWORD LineNumber;
671 char *FileName;
672 DWORD64 Address;
673} IMAGEHLP_LINE64;
674typedef void *PREAD_PROCESS_MEMORY_ROUTINE64;
675typedef void *PFUNCTION_TABLE_ACCESS_ROUTINE64;
676typedef void *PGET_MODULE_BASE_ROUTINE64;
677typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
678# endif
679
680static void
681dump_thread(void *arg)
682{
683 HANDLE dbghelp;
684 BOOL (WINAPI *pSymInitialize)(HANDLE, const char *, BOOL);
685 BOOL (WINAPI *pSymCleanup)(HANDLE);
686 BOOL (WINAPI *pStackWalk64)(DWORD, HANDLE, HANDLE, STACKFRAME64 *, void *, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
687 DWORD64 (WINAPI *pSymGetModuleBase64)(HANDLE, DWORD64);
688 BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
689 BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
690 HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
691 DWORD tid = *(DWORD *)arg;
692 HANDLE ph;
693 HANDLE th;
694
695 dbghelp = LoadLibrary("dbghelp.dll");
696 if (!dbghelp) return;
697 pSymInitialize = (BOOL (WINAPI *)(HANDLE, const char *, BOOL))GetProcAddress(dbghelp, "SymInitialize");
698 pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(dbghelp, "SymCleanup");
699 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");
700 pSymGetModuleBase64 = (DWORD64 (WINAPI *)(HANDLE, DWORD64))GetProcAddress(dbghelp, "SymGetModuleBase64");
701 pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *))GetProcAddress(dbghelp, "SymFromAddr");
702 pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *))GetProcAddress(dbghelp, "SymGetLineFromAddr64");
703 pOpenThread = (HANDLE (WINAPI *)(DWORD, BOOL, DWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread");
704 if (pSymInitialize && pSymCleanup && pStackWalk64 && pSymGetModuleBase64 &&
705 pSymFromAddr && pSymGetLineFromAddr64 && pOpenThread) {
706 SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
707 ph = GetCurrentProcess();
708 pSymInitialize(ph, NULL, TRUE);
709 th = pOpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, FALSE, tid);
710 if (th) {
711 if (SuspendThread(th) != (DWORD)-1) {
712 CONTEXT context;
713 memset(&context, 0, sizeof(context));
714 context.ContextFlags = CONTEXT_FULL;
715 if (GetThreadContext(th, &context)) {
716 char libpath[MAX_PATH];
717 char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
718 SYMBOL_INFO *info = (SYMBOL_INFO *)buf;
719 DWORD mac;
720 STACKFRAME64 frame;
721 memset(&frame, 0, sizeof(frame));
722#if defined(_M_AMD64) || defined(__x86_64__)
723 mac = IMAGE_FILE_MACHINE_AMD64;
724 frame.AddrPC.Mode = AddrModeFlat;
725 frame.AddrPC.Offset = context.Rip;
726 frame.AddrFrame.Mode = AddrModeFlat;
727 frame.AddrFrame.Offset = context.Rbp;
728 frame.AddrStack.Mode = AddrModeFlat;
729 frame.AddrStack.Offset = context.Rsp;
730#else /* i386 */
731 mac = IMAGE_FILE_MACHINE_I386;
732 frame.AddrPC.Mode = AddrModeFlat;
733 frame.AddrPC.Offset = context.Eip;
734 frame.AddrFrame.Mode = AddrModeFlat;
735 frame.AddrFrame.Offset = context.Ebp;
736 frame.AddrStack.Mode = AddrModeFlat;
737 frame.AddrStack.Offset = context.Esp;
738#endif
739
740 while (pStackWalk64(mac, ph, th, &frame, &context, NULL,
741 NULL, NULL, NULL)) {
742 DWORD64 addr = frame.AddrPC.Offset;
743 IMAGEHLP_LINE64 line;
744 DWORD64 displacement;
745 DWORD tmp;
746
747 if (addr == frame.AddrReturn.Offset || addr == 0 ||
748 frame.AddrReturn.Offset == 0)
749 break;
750
751 memset(buf, 0, sizeof(buf));
752 info->SizeOfStruct = sizeof(SYMBOL_INFO);
753 info->MaxNameLen = MAX_SYM_NAME;
754 if (pSymFromAddr(ph, addr, &displacement, info)) {
755 if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath)))
756 fprintf(stderr, "%s", libpath);
757 fprintf(stderr, "(%s+0x%"PRI_64_PREFIX"x)",
758 info->Name, displacement);
759 }
760 fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
761 memset(&line, 0, sizeof(line));
762 line.SizeOfStruct = sizeof(line);
763 if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
764 fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
765 fprintf(stderr, "\n");
766 }
767 }
768
769 ResumeThread(th);
770 }
771 CloseHandle(th);
772 }
773 pSymCleanup(ph);
774 }
775 FreeLibrary(dbghelp);
776}
777#endif
778
779void
780rb_print_backtrace(void)
781{
782#if USE_BACKTRACE
783#define MAX_NATIVE_TRACE 1024
784 static void *trace[MAX_NATIVE_TRACE];
785 int n = (int)backtrace(trace, MAX_NATIVE_TRACE);
786#if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)) && defined(HAVE_DLADDR) && !defined(__sparc)
787 rb_dump_backtrace_with_lines(n, trace);
788#else
789 char **syms = backtrace_symbols(trace, n);
790 if (syms) {
791 int i;
792 for (i=0; i<n; i++) {
793 fprintf(stderr, "%s\n", syms[i]);
794 }
795 free(syms);
796 }
797#endif
798#elif defined(_WIN32)
799 DWORD tid = GetCurrentThreadId();
800 HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
801 if (th != (HANDLE)-1)
802 WaitForSingleObject(th, INFINITE);
803#endif
804}
805
806#ifdef HAVE_LIBPROCSTAT
807#include "missing/procstat_vm.c"
808#endif
809
810#if defined __linux__
811# if defined __x86_64__ || defined __i386__ || defined __aarch64__ || defined __arm__ || defined __riscv
812# define HAVE_PRINT_MACHINE_REGISTERS 1
813# endif
814#elif defined __APPLE__
815# if defined __x86_64__ || defined __i386__ || defined __aarch64__
816# define HAVE_PRINT_MACHINE_REGISTERS 1
817# endif
818#endif
819
820#ifdef HAVE_PRINT_MACHINE_REGISTERS
821static int
822print_machine_register(size_t reg, const char *reg_name, int col_count, int max_col)
823{
824 int ret;
825 char buf[64];
826 static const int size_width = sizeof(size_t) * CHAR_BIT / 4;
827
828 ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%.*" PRIxSIZE, reg_name, size_width, reg);
829 if (col_count + ret > max_col) {
830 fputs("\n", stderr);
831 col_count = 0;
832 }
833 col_count += ret;
834 fputs(buf, stderr);
835 return col_count;
836}
837# ifdef __linux__
838# if defined(__x86_64__) || defined(__i386__)
839# define dump_machine_register(reg) (col_count = print_machine_register(mctx->gregs[REG_##reg], #reg, col_count, 80))
840# elif defined(__aarch64__) || defined(__arm__) || defined(__riscv)
841# define dump_machine_register(reg, regstr) (col_count = print_machine_register(reg, regstr, col_count, 80))
842# endif
843# elif defined __APPLE__
844# if defined(__aarch64__)
845# define dump_machine_register(reg, regstr) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), regstr, col_count, 80))
846# else
847# define dump_machine_register(reg) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), #reg, col_count, 80))
848# endif
849# endif
850
851static void
852rb_dump_machine_register(const ucontext_t *ctx)
853{
854 int col_count = 0;
855 if (!ctx) return;
856
857 fprintf(stderr, "-- Machine register context "
858 "------------------------------------------------\n");
859
860# if defined __linux__
861 {
862 const mcontext_t *const mctx = &ctx->uc_mcontext;
863# if defined __x86_64__
864 dump_machine_register(RIP);
865 dump_machine_register(RBP);
866 dump_machine_register(RSP);
867 dump_machine_register(RAX);
868 dump_machine_register(RBX);
869 dump_machine_register(RCX);
870 dump_machine_register(RDX);
871 dump_machine_register(RDI);
872 dump_machine_register(RSI);
873 dump_machine_register(R8);
874 dump_machine_register(R9);
875 dump_machine_register(R10);
876 dump_machine_register(R11);
877 dump_machine_register(R12);
878 dump_machine_register(R13);
879 dump_machine_register(R14);
880 dump_machine_register(R15);
881 dump_machine_register(EFL);
882# elif defined __i386__
883 dump_machine_register(GS);
884 dump_machine_register(FS);
885 dump_machine_register(ES);
886 dump_machine_register(DS);
887 dump_machine_register(EDI);
888 dump_machine_register(ESI);
889 dump_machine_register(EBP);
890 dump_machine_register(ESP);
891 dump_machine_register(EBX);
892 dump_machine_register(EDX);
893 dump_machine_register(ECX);
894 dump_machine_register(EAX);
895 dump_machine_register(TRAPNO);
896 dump_machine_register(ERR);
897 dump_machine_register(EIP);
898 dump_machine_register(CS);
899 dump_machine_register(EFL);
900 dump_machine_register(UESP);
901 dump_machine_register(SS);
902# elif defined __aarch64__
903 dump_machine_register(mctx->regs[0], "x0");
904 dump_machine_register(mctx->regs[1], "x1");
905 dump_machine_register(mctx->regs[2], "x2");
906 dump_machine_register(mctx->regs[3], "x3");
907 dump_machine_register(mctx->regs[4], "x4");
908 dump_machine_register(mctx->regs[5], "x5");
909 dump_machine_register(mctx->regs[6], "x6");
910 dump_machine_register(mctx->regs[7], "x7");
911 dump_machine_register(mctx->regs[18], "x18");
912 dump_machine_register(mctx->regs[19], "x19");
913 dump_machine_register(mctx->regs[20], "x20");
914 dump_machine_register(mctx->regs[21], "x21");
915 dump_machine_register(mctx->regs[22], "x22");
916 dump_machine_register(mctx->regs[23], "x23");
917 dump_machine_register(mctx->regs[24], "x24");
918 dump_machine_register(mctx->regs[25], "x25");
919 dump_machine_register(mctx->regs[26], "x26");
920 dump_machine_register(mctx->regs[27], "x27");
921 dump_machine_register(mctx->regs[28], "x28");
922 dump_machine_register(mctx->regs[29], "x29");
923 dump_machine_register(mctx->sp, "sp");
924 dump_machine_register(mctx->fault_address, "fault_address");
925# elif defined __arm__
926 dump_machine_register(mctx->arm_r0, "r0");
927 dump_machine_register(mctx->arm_r1, "r1");
928 dump_machine_register(mctx->arm_r2, "r2");
929 dump_machine_register(mctx->arm_r3, "r3");
930 dump_machine_register(mctx->arm_r4, "r4");
931 dump_machine_register(mctx->arm_r5, "r5");
932 dump_machine_register(mctx->arm_r6, "r6");
933 dump_machine_register(mctx->arm_r7, "r7");
934 dump_machine_register(mctx->arm_r8, "r8");
935 dump_machine_register(mctx->arm_r9, "r9");
936 dump_machine_register(mctx->arm_r10, "r10");
937 dump_machine_register(mctx->arm_sp, "sp");
938 dump_machine_register(mctx->fault_address, "fault_address");
939# elif defined __riscv
940 dump_machine_register(mctx->__gregs[REG_SP], "sp");
941 dump_machine_register(mctx->__gregs[REG_S0], "s0");
942 dump_machine_register(mctx->__gregs[REG_S1], "s1");
943 dump_machine_register(mctx->__gregs[REG_A0], "a0");
944 dump_machine_register(mctx->__gregs[REG_A0+1], "a1");
945 dump_machine_register(mctx->__gregs[REG_A0+2], "a2");
946 dump_machine_register(mctx->__gregs[REG_A0+3], "a3");
947 dump_machine_register(mctx->__gregs[REG_A0+4], "a4");
948 dump_machine_register(mctx->__gregs[REG_A0+5], "a5");
949 dump_machine_register(mctx->__gregs[REG_A0+6], "a6");
950 dump_machine_register(mctx->__gregs[REG_A0+7], "a7");
951 dump_machine_register(mctx->__gregs[REG_S2], "s2");
952 dump_machine_register(mctx->__gregs[REG_S2+1], "s3");
953 dump_machine_register(mctx->__gregs[REG_S2+2], "s4");
954 dump_machine_register(mctx->__gregs[REG_S2+3], "s5");
955 dump_machine_register(mctx->__gregs[REG_S2+4], "s6");
956 dump_machine_register(mctx->__gregs[REG_S2+5], "s7");
957 dump_machine_register(mctx->__gregs[REG_S2+6], "s8");
958 dump_machine_register(mctx->__gregs[REG_S2+7], "s9");
959 dump_machine_register(mctx->__gregs[REG_S2+8], "s10");
960 dump_machine_register(mctx->__gregs[REG_S2+9], "s11");
961# endif
962 }
963# elif defined __APPLE__
964 {
965 const mcontext_t mctx = ctx->uc_mcontext;
966# if defined __x86_64__
967 dump_machine_register(rax);
968 dump_machine_register(rbx);
969 dump_machine_register(rcx);
970 dump_machine_register(rdx);
971 dump_machine_register(rdi);
972 dump_machine_register(rsi);
973 dump_machine_register(rbp);
974 dump_machine_register(rsp);
975 dump_machine_register(r8);
976 dump_machine_register(r9);
977 dump_machine_register(r10);
978 dump_machine_register(r11);
979 dump_machine_register(r12);
980 dump_machine_register(r13);
981 dump_machine_register(r14);
982 dump_machine_register(r15);
983 dump_machine_register(rip);
984 dump_machine_register(rflags);
985# elif defined __i386__
986 dump_machine_register(eax);
987 dump_machine_register(ebx);
988 dump_machine_register(ecx);
989 dump_machine_register(edx);
990 dump_machine_register(edi);
991 dump_machine_register(esi);
992 dump_machine_register(ebp);
993 dump_machine_register(esp);
994 dump_machine_register(ss);
995 dump_machine_register(eflags);
996 dump_machine_register(eip);
997 dump_machine_register(cs);
998 dump_machine_register(ds);
999 dump_machine_register(es);
1000 dump_machine_register(fs);
1001 dump_machine_register(gs);
1002# elif defined __aarch64__
1003 dump_machine_register(x[0], "x0");
1004 dump_machine_register(x[1], "x1");
1005 dump_machine_register(x[2], "x2");
1006 dump_machine_register(x[3], "x3");
1007 dump_machine_register(x[4], "x4");
1008 dump_machine_register(x[5], "x5");
1009 dump_machine_register(x[6], "x6");
1010 dump_machine_register(x[7], "x7");
1011 dump_machine_register(x[18], "x18");
1012 dump_machine_register(x[19], "x19");
1013 dump_machine_register(x[20], "x20");
1014 dump_machine_register(x[21], "x21");
1015 dump_machine_register(x[22], "x22");
1016 dump_machine_register(x[23], "x23");
1017 dump_machine_register(x[24], "x24");
1018 dump_machine_register(x[25], "x25");
1019 dump_machine_register(x[26], "x26");
1020 dump_machine_register(x[27], "x27");
1021 dump_machine_register(x[28], "x28");
1022 dump_machine_register(lr, "lr");
1023 dump_machine_register(fp, "fp");
1024 dump_machine_register(sp, "sp");
1025# endif
1026 }
1027# endif
1028 fprintf(stderr, "\n\n");
1029}
1030#else
1031# define rb_dump_machine_register(ctx) ((void)0)
1032#endif /* HAVE_PRINT_MACHINE_REGISTERS */
1033
1034void
1035rb_vm_bugreport(const void *ctx)
1036{
1037 const char *cmd = getenv("RUBY_ON_BUG");
1038 if (cmd) {
1039 char buf[0x100];
1040 snprintf(buf, sizeof(buf), "%s %"PRI_PIDT_PREFIX"d", cmd, getpid());
1041 int r = system(buf);
1042 if (r == -1) {
1043 snprintf(buf, sizeof(buf), "Launching RUBY_ON_BUG command failed.");
1044 }
1045 }
1046
1047 // Thread unsafe best effort attempt to stop printing the bug report in an
1048 // infinite loop. Can happen with corrupt Ruby stack.
1049 {
1050 static bool crashing = false;
1051 if (crashing) {
1052 fprintf(stderr, "Crashed while printing bug report\n");
1053 return;
1054 }
1055 crashing = true;
1056 }
1057
1058#ifdef __linux__
1059# define PROC_MAPS_NAME "/proc/self/maps"
1060#endif
1061#ifdef PROC_MAPS_NAME
1062 enum {other_runtime_info = 1};
1063#else
1064 enum {other_runtime_info = 0};
1065#endif
1066 const rb_vm_t *const vm = GET_VM();
1067 const rb_execution_context_t *ec = rb_current_execution_context(false);
1068
1069 if (vm && ec) {
1070 SDR();
1071 rb_backtrace_print_as_bugreport();
1072 fputs("\n", stderr);
1073 }
1074
1075 rb_dump_machine_register(ctx);
1076
1077#if USE_BACKTRACE || defined(_WIN32)
1078 fprintf(stderr, "-- C level backtrace information "
1079 "-------------------------------------------\n");
1080 rb_print_backtrace();
1081
1082
1083 fprintf(stderr, "\n");
1084#endif /* USE_BACKTRACE */
1085
1086 if (other_runtime_info || vm) {
1087 fprintf(stderr, "-- Other runtime information "
1088 "-----------------------------------------------\n\n");
1089 }
1090 if (vm && !rb_during_gc()) {
1091 int i;
1092 VALUE name;
1093 long len;
1094 const int max_name_length = 1024;
1095# define LIMITED_NAME_LENGTH(s) \
1096 (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)
1097
1098 name = vm->progname;
1099 if (name) {
1100 fprintf(stderr, "* Loaded script: %.*s\n",
1101 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
1102 fprintf(stderr, "\n");
1103 }
1104 if (vm->loaded_features) {
1105 fprintf(stderr, "* Loaded features:\n\n");
1106 for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
1107 name = RARRAY_AREF(vm->loaded_features, i);
1108 if (RB_TYPE_P(name, T_STRING)) {
1109 fprintf(stderr, " %4d %.*s\n", i,
1110 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
1111 }
1112 else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) {
1113 const char *const type = RB_TYPE_P(name, T_CLASS) ?
1114 "class" : "module";
1115 name = rb_search_class_path(rb_class_real(name));
1116 if (!RB_TYPE_P(name, T_STRING)) {
1117 fprintf(stderr, " %4d %s:<unnamed>\n", i, type);
1118 continue;
1119 }
1120 fprintf(stderr, " %4d %s:%.*s\n", i, type,
1121 LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
1122 }
1123 else {
1124 VALUE klass = rb_search_class_path(rb_obj_class(name));
1125 if (!RB_TYPE_P(klass, T_STRING)) {
1126 fprintf(stderr, " %4d #<%p:%p>\n", i,
1127 (void *)CLASS_OF(name), (void *)name);
1128 continue;
1129 }
1130 fprintf(stderr, " %4d #<%.*s:%p>\n", i,
1131 LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
1132 (void *)name);
1133 }
1134 }
1135 }
1136 fprintf(stderr, "\n");
1137 }
1138
1139 {
1140#ifdef PROC_MAPS_NAME
1141 {
1142 FILE *fp = fopen(PROC_MAPS_NAME, "r");
1143 if (fp) {
1144 fprintf(stderr, "* Process memory map:\n\n");
1145
1146 while (!feof(fp)) {
1147 char buff[0x100];
1148 size_t rn = fread(buff, 1, 0x100, fp);
1149 if (fwrite(buff, 1, rn, stderr) != rn)
1150 break;
1151 }
1152
1153 fclose(fp);
1154 fprintf(stderr, "\n\n");
1155 }
1156 }
1157#endif /* __linux__ */
1158#ifdef HAVE_LIBPROCSTAT
1159# define MIB_KERN_PROC_PID_LEN 4
1160 int mib[MIB_KERN_PROC_PID_LEN];
1161 struct kinfo_proc kp;
1162 size_t len = sizeof(struct kinfo_proc);
1163 mib[0] = CTL_KERN;
1164 mib[1] = KERN_PROC;
1165 mib[2] = KERN_PROC_PID;
1166 mib[3] = getpid();
1167 if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) {
1168 perror("sysctl");
1169 }
1170 else {
1171 struct procstat *prstat = procstat_open_sysctl();
1172 fprintf(stderr, "* Process memory map:\n\n");
1173 procstat_vm(prstat, &kp);
1174 procstat_close(prstat);
1175 fprintf(stderr, "\n");
1176 }
1177#endif /* __FreeBSD__ */
1178#ifdef __APPLE__
1179 vm_address_t addr = 0;
1180 vm_size_t size = 0;
1181 struct vm_region_submap_info map;
1182 mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT;
1183 natural_t depth = 0;
1184
1185 fprintf(stderr, "* Process memory map:\n\n");
1186 while (1) {
1187 if (vm_region_recurse(mach_task_self(), &addr, &size, &depth,
1188 (vm_region_recurse_info_t)&map, &count) != KERN_SUCCESS) {
1189 break;
1190 }
1191
1192 if (map.is_submap) {
1193 // We only look at main addresses
1194 depth++;
1195 }
1196 else {
1197 fprintf(stderr, "%lx-%lx %s%s%s", addr, (addr+size),
1198 ((map.protection & VM_PROT_READ) != 0 ? "r" : "-"),
1199 ((map.protection & VM_PROT_WRITE) != 0 ? "w" : "-"),
1200 ((map.protection & VM_PROT_EXECUTE) != 0 ? "x" : "-"));
1201#ifdef HAVE_LIBPROC_H
1202 char buff[PATH_MAX];
1203 if (proc_regionfilename(getpid(), addr, buff, sizeof(buff)) > 0) {
1204 fprintf(stderr, " %s", buff);
1205 }
1206#endif
1207 fprintf(stderr, "\n");
1208 }
1209
1210 addr += size;
1211 size = 0;
1212 }
1213#endif
1214 }
1215}
1216
1217void
1218rb_vmdebug_stack_dump_all_threads(void)
1219{
1220 rb_thread_t *th = NULL;
1221 rb_ractor_t *r = GET_RACTOR();
1222
1223 // TODO: now it only shows current ractor
1224 ccan_list_for_each(&r->threads.set, th, lt_node) {
1225#ifdef NON_SCALAR_THREAD_ID
1226 fprintf(stderr, "th: %p, native_id: N/A\n", th);
1227#else
1228 fprintf(stderr, "th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id);
1229#endif
1230 rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp);
1231 }
1232}
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
T_IMEMO
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition value_type.h:67
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
T_MODULE
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
T_UNDEF
#define T_UNDEF
Old name of RUBY_T_UNDEF.
Definition value_type.h:82
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
T_CLASS
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
rb_bug
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
rb_obj_class
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:191
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:601
rb_class_real
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:181
rb_sym2str
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:943
rb_id2name
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:960
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition cxxanyargs.hpp:56
PRI_PIDT_PREFIX
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
Definition pid_t.h:38
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:583
RSTRING_PTR
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
__sFILE
Definition vsnprintf.c:160
rb_callable_method_entry_struct
Definition method.h:62
rb_control_frame_struct
Definition vm_core.h:818
rb_env_t
Definition vm_core.h:1150
rb_execution_context_struct
Definition vm_core.h:899
rb_iseq_struct
Definition vm_core.h:526
rb_proc_t
Definition vm_core.h:1137
rb_ractor_struct
Definition ractor_core.h:105
rb_thread_struct
Definition vm_core.h:984
rb_vm_struct
Definition vm_core.h:615
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375