diff --git a/vm_core.h b/vm_core.h index d600b0a153..a5c08d3f72 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1678,13 +1678,13 @@ VALUE rb_proc_alloc(VALUE klass); VALUE rb_proc_dup(VALUE self); /* for debug */ -extern void rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); -extern void rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *); -extern void rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); +extern bool rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); +extern bool rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *); +extern bool rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); #define SDR() rb_vmdebug_stack_dump_raw(GET_EC(), GET_EC()->cfp, stderr) #define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_EC(), (cfp), stderr) -void rb_vm_bugreport(const void *, FILE *); +bool rb_vm_bugreport(const void *, FILE *); typedef void (*ruby_sighandler_t)(int); RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 4, 5) NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const void *, const char *fmt, ...)); diff --git a/vm_dump.c b/vm_dump.c index a2e5c384be..9495ceb528 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -46,7 +46,10 @@ const char *rb_method_type_name(rb_method_type_t type); int ruby_on_ci; -static void +#define kprintf(...) if (fprintf(errout, __VA_ARGS__) < 0) goto error +#define kputs(s) if (fputs(s, errout) < 0) goto error + +static bool control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { ptrdiff_t pc = -1; @@ -140,30 +143,30 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c line = -1; } - fprintf(errout, "c:%04"PRIdPTRDIFF" ", + kprintf("c:%04"PRIdPTRDIFF" ", ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp)); if (pc == -1) { - fprintf(errout, "p:---- "); + kprintf("p:---- "); } else { - fprintf(errout, "p:%04"PRIdPTRDIFF" ", pc); + kprintf("p:%04"PRIdPTRDIFF" ", pc); } - fprintf(errout, "s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack); - fprintf(errout, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); - fprintf(errout, "%-6s", magic); + kprintf("s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack); + kprintf(ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); + kprintf("%-6s", magic); if (line) { - fprintf(errout, " %s", posbuf); + kprintf(" %s", posbuf); } if (VM_FRAME_FINISHED_P(cfp)) { - fprintf(errout, " [FINISH]"); + kprintf(" [FINISH]"); } if (0) { - fprintf(errout, " \t"); - fprintf(errout, "iseq: %-24s ", iseq_name); - fprintf(errout, "self: %-24s ", selfstr); - fprintf(errout, "%-1s ", biseq_name); + kprintf(" \t"); + kprintf("iseq: %-24s ", iseq_name); + kprintf("self: %-24s ", selfstr); + kprintf("%-1s ", biseq_name); } - fprintf(errout, "\n"); + kprintf("\n"); // additional information for CI machines if (ruby_on_ci) { @@ -171,35 +174,38 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c if (me) { if (IMEMO_TYPE_P(me, imemo_ment)) { - fprintf(errout, " me:\n"); - fprintf(errout, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type)); - fprintf(errout, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner)); + kprintf(" me:\n"); + kprintf(" called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type)); + kprintf(" owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner)); if (me->owner != me->defined_class) { - fprintf(errout, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class)); + kprintf(" defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class)); } } else { - fprintf(errout, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me)); + kprintf(" me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me)); } } - fprintf(errout, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self)); + kprintf(" self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self)); if (iseq) { if (ISEQ_BODY(iseq)->local_table_size > 0) { - fprintf(errout, " lvars:\n"); + kprintf(" lvars:\n"); for (unsigned int i=0; ilocal_table_size; i++) { const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1; - fprintf(errout, " %s: %s\n", + kprintf(" %s: %s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]), rb_raw_obj_info(buff, 0x100, argv[i])); } } } } + return true; + error: + return false; } -void +bool rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { #if 0 @@ -207,58 +213,66 @@ rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_fra const VALUE *ep = cfp->ep; VALUE *p, *st, *t; - fprintf(errout, "-- stack frame ------------\n"); + kprintf("-- stack frame ------------\n"); for (p = st = ec->vm_stack; p < sp; p++) { - fprintf(errout, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); + kprintf("%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); t = (VALUE *)*p; if (ec->vm_stack <= t && t < sp) { - fprintf(errout, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack)); + kprintf(" (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack)); } if (p == ep) - fprintf(errout, " <- ep"); + kprintf(" <- ep"); - fprintf(errout, "\n"); + kprintf("\n"); } #endif - fprintf(errout, "-- Control frame information " + kprintf("-- Control frame information " "-----------------------------------------------\n"); while ((void *)cfp < (void *)(ec->vm_stack + ec->vm_stack_size)) { control_frame_dump(ec, cfp, errout); cfp++; } - fprintf(errout, "\n"); + kprintf("\n"); + return true; + + error: + return false; } -void +bool rb_vmdebug_stack_dump_raw_current(void) { const rb_execution_context_t *ec = GET_EC(); - rb_vmdebug_stack_dump_raw(ec, ec->cfp, stderr); + return rb_vmdebug_stack_dump_raw(ec, ec->cfp, stderr); } -void +bool rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep, FILE *errout) { unsigned int i; - fprintf(errout, "-- env --------------------\n"); + kprintf("-- env --------------------\n"); while (env) { - fprintf(errout, "--\n"); + kprintf("--\n"); for (i = 0; i < env->env_size; i++) { - fprintf(errout, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]); - if (&env->env[i] == ep) fprintf(errout, " <- ep"); - fprintf(errout, "\n"); + kprintf("%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]); + if (&env->env[i] == ep) kprintf(" <- ep"); + kprintf("\n"); } env = rb_vm_env_prev_env(env); } - fprintf(errout, "---------------------------\n"); + kprintf("---------------------------\n"); + return true; + + error: + return false; } -void +bool rb_vmdebug_proc_dump_raw(rb_proc_t *proc, FILE *errout) { const rb_env_t *env; @@ -266,17 +280,21 @@ rb_vmdebug_proc_dump_raw(rb_proc_t *proc, FILE *errout) VALUE val = rb_inspect(vm_block_self(&proc->block)); selfstr = StringValueCStr(val); - fprintf(errout, "-- proc -------------------\n"); - fprintf(errout, "self: %s\n", selfstr); + kprintf("-- proc -------------------\n"); + kprintf("self: %s\n", selfstr); env = VM_ENV_ENVVAL_PTR(vm_block_ep(&proc->block)); rb_vmdebug_env_dump_raw(env, vm_block_ep(&proc->block), errout); + return true; + + error: + return false; } -void +bool rb_vmdebug_stack_dump_th(VALUE thval, FILE *errout) { rb_thread_t *target_th = rb_thread_ptr(thval); - rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp, errout); + return rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp, errout); } #if VMDEBUG > 2 @@ -325,12 +343,12 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c for (i = 0; i < argc; i++) { rstr = rb_inspect(*ptr); - fprintf(errout, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), + kprintf(" arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } for (; i < local_table_size - 1; i++) { rstr = rb_inspect(*ptr); - fprintf(errout, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), + kprintf(" local %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } @@ -347,7 +365,7 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c rstr = rb_inspect(*ptr); break; } - fprintf(errout, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), + kprintf(" stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), (ptr - ec->vm_stack)); } } @@ -365,7 +383,7 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c } #endif -void +bool rb_vmdebug_debug_print_register(const rb_execution_context_t *ec, FILE *errout) { rb_control_frame_t *cfp = ec->cfp; @@ -382,17 +400,21 @@ rb_vmdebug_debug_print_register(const rb_execution_context_t *ec, FILE *errout) } cfpi = ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size)) - cfp; - fprintf(errout, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", + kprintf(" [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", pc, (cfp->sp - ec->vm_stack), ep, cfpi); + return true; + + error: + return false; } -void +bool rb_vmdebug_thread_dump_regs(VALUE thval, FILE *errout) { - rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec, errout); + return rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec, errout); } -void +bool rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *errout) { const rb_iseq_t *iseq = cfp->iseq; @@ -402,10 +424,10 @@ rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_fr int i; for (i=0; i<(int)VM_CFP_CNT(ec, cfp); i++) { - printf(" "); + kprintf(" "); } - printf("| "); - if(0)printf("[%03ld] ", (long)(cfp->sp - ec->vm_stack)); + kprintf("| "); + if(0) kprintf("[%03ld] ", (long)(cfp->sp - ec->vm_stack)); /* printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(ec, cfp)); */ if (pc >= 0) { @@ -416,20 +438,24 @@ rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_fr } #if VMDEBUG > 3 - fprintf(errout, " (1)"); + kprintf(" (1)"); rb_vmdebug_debug_print_register(errout, ec); #endif + return true; + + error: + return false; } -void +bool rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { #if VMDEBUG > 9 - rb_vmdebug_stack_dump_raw(ec, cfp, errout); + if (!rb_vmdebug_stack_dump_raw(ec, cfp, errout)) goto errout; #endif #if VMDEBUG > 3 - fprintf(errout, " (2)"); + kprintf(" (2)"); rb_vmdebug_debug_print_register(errout, ec); #endif /* stack_dump_raw(ec, cfp); */ @@ -438,8 +464,14 @@ rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_f /* stack_dump_thobj(ec); */ vm_stack_dump_each(ec, ec->cfp, errout); - printf + kprintf ("--------------------------------------------------------------\n"); +#endif + return true; + +#if VMDEBUG > 2 + error: + return false; #endif } @@ -449,10 +481,11 @@ rb_vmdebug_thread_dump_state(FILE *errout, VALUE self) rb_thread_t *th = rb_thread_ptr(self); rb_control_frame_t *cfp = th->ec->cfp; - fprintf(errout, "Thread state dump:\n"); - fprintf(errout, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); - fprintf(errout, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep); + kprintf("Thread state dump:\n"); + kprintf("pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); + kprintf("cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep); + error: return Qnil; } @@ -746,19 +779,20 @@ dump_thread(void *arg) info->MaxNameLen = MAX_SYM_NAME; if (pSymFromAddr(ph, addr, &displacement, info)) { if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath))) - fprintf(errout, "%s", libpath); - fprintf(errout, "(%s+0x%"PRI_64_PREFIX"x)", + kprintf("%s", libpath); + kprintf("(%s+0x%"PRI_64_PREFIX"x)", info->Name, displacement); } - fprintf(errout, " [0x%p]", (void *)(VALUE)addr); + kprintf(" [0x%p]", (void *)(VALUE)addr); memset(&line, 0, sizeof(line)); line.SizeOfStruct = sizeof(line); if (pSymGetLineFromAddr64(ph, addr, &tmp, &line)) - fprintf(errout, " %s:%lu", line.FileName, line.LineNumber); - fprintf(errout, "\n"); + kprintf(" %s:%lu", line.FileName, line.LineNumber); + kprintf("\n"); } } + error: ResumeThread(th); } CloseHandle(th); @@ -783,7 +817,7 @@ rb_print_backtrace(FILE *errout) if (syms) { int i; for (i=0; i max_col) { - fputs("\n", errout); + kputs("\n"); col_count = 0; } col_count += ret; - fputs(buf, errout); + kputs(buf); return col_count; + + error: + return -1; } -static void +static bool rb_dump_machine_register(FILE *errout, const ucontext_t *ctx) { int col_count = 0; - if (!ctx) return; + if (!ctx) return true; - fprintf(errout, "-- Machine register context " + kprintf("-- Machine register context " "------------------------------------------------\n"); # if defined __linux__ @@ -1034,13 +1071,17 @@ rb_dump_machine_register(FILE *errout, const ucontext_t *ctx) # endif } # endif - fprintf(errout, "\n\n"); + kprintf("\n\n"); + return true; + + error: + return false; } #else # define rb_dump_machine_register(errout, ctx) ((void)0) #endif /* dump_machine_register */ -void +bool rb_vm_bugreport(const void *ctx, FILE *errout) { const char *cmd = getenv("RUBY_ON_BUG"); @@ -1058,8 +1099,8 @@ rb_vm_bugreport(const void *ctx, FILE *errout) { static bool crashing = false; if (crashing) { - fprintf(errout, "Crashed while printing bug report\n"); - return; + kprintf("Crashed while printing bug report\n"); + return true; } crashing = true; } @@ -1082,26 +1123,26 @@ rb_vm_bugreport(const void *ctx, FILE *errout) // If we get here, hopefully things are intact enough that // we can read these two numbers. It is an estimate because // we are reading without synchronization. - fprintf(errout, "-- Threading information " + kprintf("-- Threading information " "---------------------------------------------------\n"); - fprintf(errout, "Total ractor count: %u\n", vm->ractor.cnt); - fprintf(errout, "Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt); + kprintf("Total ractor count: %u\n", vm->ractor.cnt); + kprintf("Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt); fputs("\n", errout); } rb_dump_machine_register(errout, ctx); #if USE_BACKTRACE || defined(_WIN32) - fprintf(errout, "-- C level backtrace information " + kprintf("-- C level backtrace information " "-------------------------------------------\n"); rb_print_backtrace(errout); - fprintf(errout, "\n"); + kprintf("\n"); #endif /* USE_BACKTRACE */ if (other_runtime_info || vm) { - fprintf(errout, "-- Other runtime information " + kprintf("-- Other runtime information " "-----------------------------------------------\n\n"); } if (vm && !rb_during_gc()) { @@ -1114,16 +1155,16 @@ rb_vm_bugreport(const void *ctx, FILE *errout) name = vm->progname; if (name) { - fprintf(errout, "* Loaded script: %.*s\n", + kprintf("* Loaded script: %.*s\n", LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); - fprintf(errout, "\n"); + kprintf("\n"); } if (vm->loaded_features) { - fprintf(errout, "* Loaded features:\n\n"); + kprintf("* Loaded features:\n\n"); for (i=0; iloaded_features); i++) { name = RARRAY_AREF(vm->loaded_features, i); if (RB_TYPE_P(name, T_STRING)) { - fprintf(errout, " %4d %.*s\n", i, + kprintf(" %4d %.*s\n", i, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) { @@ -1131,26 +1172,26 @@ rb_vm_bugreport(const void *ctx, FILE *errout) "class" : "module"; name = rb_search_class_path(rb_class_real(name)); if (!RB_TYPE_P(name, T_STRING)) { - fprintf(errout, " %4d %s:\n", i, type); + kprintf(" %4d %s:\n", i, type); continue; } - fprintf(errout, " %4d %s:%.*s\n", i, type, + kprintf(" %4d %s:%.*s\n", i, type, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else { VALUE klass = rb_search_class_path(rb_obj_class(name)); if (!RB_TYPE_P(klass, T_STRING)) { - fprintf(errout, " %4d #<%p:%p>\n", i, + kprintf(" %4d #<%p:%p>\n", i, (void *)CLASS_OF(name), (void *)name); continue; } - fprintf(errout, " %4d #<%.*s:%p>\n", i, + kprintf(" %4d #<%.*s:%p>\n", i, LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass), (void *)name); } } } - fprintf(errout, "\n"); + kprintf("\n"); } { @@ -1158,7 +1199,7 @@ rb_vm_bugreport(const void *ctx, FILE *errout) { FILE *fp = fopen(PROC_MAPS_NAME, "r"); if (fp) { - fprintf(errout, "* Process memory map:\n\n"); + kprintf("* Process memory map:\n\n"); while (!feof(fp)) { char buff[0x100]; @@ -1168,7 +1209,7 @@ rb_vm_bugreport(const void *ctx, FILE *errout) } fclose(fp); - fprintf(errout, "\n\n"); + kprintf("\n\n"); } } #endif /* __linux__ */ @@ -1182,14 +1223,14 @@ rb_vm_bugreport(const void *ctx, FILE *errout) mib[2] = KERN_PROC_PID; mib[3] = getpid(); if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) { - fprintf(errout, "sysctl: %s\n", strerror(errno)); + kprintf("sysctl: %s\n", strerror(errno)); } else { struct procstat *prstat = procstat_open_sysctl(); - fprintf(errout, "* Process memory map:\n\n"); + kprintf("* Process memory map:\n\n"); procstat_vm(prstat, &kp); procstat_close(prstat); - fprintf(errout, "\n"); + kprintf("\n"); } #endif /* __FreeBSD__ */ #ifdef __APPLE__ @@ -1199,7 +1240,7 @@ rb_vm_bugreport(const void *ctx, FILE *errout) mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT; natural_t depth = 0; - fprintf(errout, "* Process memory map:\n\n"); + kprintf("* Process memory map:\n\n"); while (1) { if (vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_t)&map, &count) != KERN_SUCCESS) { @@ -1211,17 +1252,17 @@ rb_vm_bugreport(const void *ctx, FILE *errout) depth++; } else { - fprintf(errout, "%lx-%lx %s%s%s", addr, (addr+size), + kprintf("%lx-%lx %s%s%s", addr, (addr+size), ((map.protection & VM_PROT_READ) != 0 ? "r" : "-"), ((map.protection & VM_PROT_WRITE) != 0 ? "w" : "-"), ((map.protection & VM_PROT_EXECUTE) != 0 ? "x" : "-")); #ifdef HAVE_LIBPROC_H char buff[PATH_MAX]; if (proc_regionfilename(getpid(), addr, buff, sizeof(buff)) > 0) { - fprintf(errout, " %s", buff); + kprintf(" %s", buff); } #endif - fprintf(errout, "\n"); + kprintf("\n"); } addr += size; @@ -1229,9 +1270,13 @@ rb_vm_bugreport(const void *ctx, FILE *errout) } #endif } + return true; + + error: + return false; } -void +bool rb_vmdebug_stack_dump_all_threads(void) { rb_thread_t *th = NULL; @@ -1241,10 +1286,14 @@ rb_vmdebug_stack_dump_all_threads(void) // TODO: now it only shows current ractor ccan_list_for_each(&r->threads.set, th, lt_node) { #ifdef NON_SCALAR_THREAD_ID - fprintf(errout, "th: %p, native_id: N/A\n", th); + kprintf("th: %p, native_id: N/A\n", th); #else - fprintf(errout, "th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id); + kprintf("th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id); #endif - rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp, errout); + if (!rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp, errout)) goto error; } + return true; + + error: + return false; }