mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Dump backtraces to an arbitrary stream
This commit is contained in:
parent
acd44902b9
commit
ac244938e8
9 changed files with 265 additions and 236 deletions
264
vm_dump.c
264
vm_dump.c
|
@ -47,7 +47,7 @@ const char *rb_method_type_name(rb_method_type_t type);
|
|||
int ruby_on_ci;
|
||||
|
||||
static void
|
||||
control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
||||
control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout)
|
||||
{
|
||||
ptrdiff_t pc = -1;
|
||||
ptrdiff_t ep = cfp->ep - ec->vm_stack;
|
||||
|
@ -140,30 +140,30 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
|
|||
line = -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
|
||||
fprintf(errout, "c:%04"PRIdPTRDIFF" ",
|
||||
((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp));
|
||||
if (pc == -1) {
|
||||
fprintf(stderr, "p:---- ");
|
||||
fprintf(errout, "p:---- ");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc);
|
||||
fprintf(errout, "p:%04"PRIdPTRDIFF" ", pc);
|
||||
}
|
||||
fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack);
|
||||
fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
|
||||
fprintf(stderr, "%-6s", magic);
|
||||
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);
|
||||
if (line) {
|
||||
fprintf(stderr, " %s", posbuf);
|
||||
fprintf(errout, " %s", posbuf);
|
||||
}
|
||||
if (VM_FRAME_FINISHED_P(cfp)) {
|
||||
fprintf(stderr, " [FINISH]");
|
||||
fprintf(errout, " [FINISH]");
|
||||
}
|
||||
if (0) {
|
||||
fprintf(stderr, " \t");
|
||||
fprintf(stderr, "iseq: %-24s ", iseq_name);
|
||||
fprintf(stderr, "self: %-24s ", selfstr);
|
||||
fprintf(stderr, "%-1s ", biseq_name);
|
||||
fprintf(errout, " \t");
|
||||
fprintf(errout, "iseq: %-24s ", iseq_name);
|
||||
fprintf(errout, "self: %-24s ", selfstr);
|
||||
fprintf(errout, "%-1s ", biseq_name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
|
||||
// additional information for CI machines
|
||||
if (ruby_on_ci) {
|
||||
|
@ -171,26 +171,26 @@ 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(stderr, " me:\n");
|
||||
fprintf(stderr, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type));
|
||||
fprintf(stderr, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner));
|
||||
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));
|
||||
if (me->owner != me->defined_class) {
|
||||
fprintf(stderr, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class));
|
||||
fprintf(errout, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class));
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me));
|
||||
fprintf(errout, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me));
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self));
|
||||
fprintf(errout, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self));
|
||||
|
||||
if (iseq) {
|
||||
if (ISEQ_BODY(iseq)->local_table_size > 0) {
|
||||
fprintf(stderr, " lvars:\n");
|
||||
fprintf(errout, " lvars:\n");
|
||||
for (unsigned int i=0; i<ISEQ_BODY(iseq)->local_table_size; i++) {
|
||||
const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1;
|
||||
fprintf(stderr, " %s: %s\n",
|
||||
fprintf(errout, " %s: %s\n",
|
||||
rb_id2name(ISEQ_BODY(iseq)->local_table[i]),
|
||||
rb_raw_obj_info(buff, 0x100, argv[i]));
|
||||
}
|
||||
|
@ -200,83 +200,83 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
|
|||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
||||
rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout)
|
||||
{
|
||||
#if 0
|
||||
VALUE *sp = cfp->sp;
|
||||
const VALUE *ep = cfp->ep;
|
||||
VALUE *p, *st, *t;
|
||||
|
||||
fprintf(stderr, "-- stack frame ------------\n");
|
||||
fprintf(errout, "-- stack frame ------------\n");
|
||||
for (p = st = ec->vm_stack; p < sp; p++) {
|
||||
fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
|
||||
fprintf(errout, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p);
|
||||
|
||||
t = (VALUE *)*p;
|
||||
if (ec->vm_stack <= t && t < sp) {
|
||||
fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack));
|
||||
fprintf(errout, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack));
|
||||
}
|
||||
|
||||
if (p == ep)
|
||||
fprintf(stderr, " <- ep");
|
||||
fprintf(errout, " <- ep");
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "-- Control frame information "
|
||||
fprintf(errout, "-- Control frame information "
|
||||
"-----------------------------------------------\n");
|
||||
while ((void *)cfp < (void *)(ec->vm_stack + ec->vm_stack_size)) {
|
||||
control_frame_dump(ec, cfp);
|
||||
control_frame_dump(ec, cfp, errout);
|
||||
cfp++;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_stack_dump_raw_current(void)
|
||||
{
|
||||
const rb_execution_context_t *ec = GET_EC();
|
||||
rb_vmdebug_stack_dump_raw(ec, ec->cfp);
|
||||
rb_vmdebug_stack_dump_raw(ec, ec->cfp, stderr);
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep)
|
||||
rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep, FILE *errout)
|
||||
{
|
||||
unsigned int i;
|
||||
fprintf(stderr, "-- env --------------------\n");
|
||||
fprintf(errout, "-- env --------------------\n");
|
||||
|
||||
while (env) {
|
||||
fprintf(stderr, "--\n");
|
||||
fprintf(errout, "--\n");
|
||||
for (i = 0; i < env->env_size; i++) {
|
||||
fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]);
|
||||
if (&env->env[i] == ep) fprintf(stderr, " <- ep");
|
||||
fprintf(stderr, "\n");
|
||||
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");
|
||||
}
|
||||
|
||||
env = rb_vm_env_prev_env(env);
|
||||
}
|
||||
fprintf(stderr, "---------------------------\n");
|
||||
fprintf(errout, "---------------------------\n");
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_proc_dump_raw(rb_proc_t *proc)
|
||||
rb_vmdebug_proc_dump_raw(rb_proc_t *proc, FILE *errout)
|
||||
{
|
||||
const rb_env_t *env;
|
||||
char *selfstr;
|
||||
VALUE val = rb_inspect(vm_block_self(&proc->block));
|
||||
selfstr = StringValueCStr(val);
|
||||
|
||||
fprintf(stderr, "-- proc -------------------\n");
|
||||
fprintf(stderr, "self: %s\n", selfstr);
|
||||
fprintf(errout, "-- proc -------------------\n");
|
||||
fprintf(errout, "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));
|
||||
rb_vmdebug_env_dump_raw(env, vm_block_ep(&proc->block), errout);
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_stack_dump_th(VALUE thval)
|
||||
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);
|
||||
rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp, errout);
|
||||
}
|
||||
|
||||
#if VMDEBUG > 2
|
||||
|
@ -295,7 +295,7 @@ vm_base_ptr(const rb_control_frame_t *cfp)
|
|||
}
|
||||
|
||||
static void
|
||||
vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
||||
vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout)
|
||||
{
|
||||
int i, argc = 0, local_table_size = 0;
|
||||
VALUE rstr;
|
||||
|
@ -321,17 +321,17 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c
|
|||
{
|
||||
const VALUE *ptr = ep - local_table_size;
|
||||
|
||||
control_frame_dump(ec, cfp);
|
||||
control_frame_dump(ec, cfp, errout);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
rstr = rb_inspect(*ptr);
|
||||
fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
|
||||
(void *)ptr++);
|
||||
fprintf(errout, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
|
||||
(void *)ptr++);
|
||||
}
|
||||
for (; i < local_table_size - 1; i++) {
|
||||
rstr = rb_inspect(*ptr);
|
||||
fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
|
||||
(void *)ptr++);
|
||||
fprintf(errout, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
|
||||
(void *)ptr++);
|
||||
}
|
||||
|
||||
ptr = vm_base_ptr(cfp);
|
||||
|
@ -347,13 +347,13 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c
|
|||
rstr = rb_inspect(*ptr);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
|
||||
fprintf(errout, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
|
||||
(ptr - ec->vm_stack));
|
||||
}
|
||||
}
|
||||
else if (VM_FRAME_FINISHED_P(cfp)) {
|
||||
if (ec->vm_stack + ec->vm_stack_size > (VALUE *)(cfp + 1)) {
|
||||
vm_stack_dump_each(ec, cfp + 1);
|
||||
vm_stack_dump_each(ec, cfp + 1, errout);
|
||||
}
|
||||
else {
|
||||
/* SDR(); */
|
||||
|
@ -366,7 +366,7 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c
|
|||
#endif
|
||||
|
||||
void
|
||||
rb_vmdebug_debug_print_register(const rb_execution_context_t *ec)
|
||||
rb_vmdebug_debug_print_register(const rb_execution_context_t *ec, FILE *errout)
|
||||
{
|
||||
rb_control_frame_t *cfp = ec->cfp;
|
||||
ptrdiff_t pc = -1;
|
||||
|
@ -382,18 +382,18 @@ rb_vmdebug_debug_print_register(const rb_execution_context_t *ec)
|
|||
}
|
||||
|
||||
cfpi = ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size)) - cfp;
|
||||
fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
|
||||
fprintf(errout, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n",
|
||||
pc, (cfp->sp - ec->vm_stack), ep, cfpi);
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_thread_dump_regs(VALUE thval)
|
||||
rb_vmdebug_thread_dump_regs(VALUE thval, FILE *errout)
|
||||
{
|
||||
rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec);
|
||||
rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec, errout);
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc)
|
||||
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;
|
||||
|
||||
|
@ -416,27 +416,27 @@ rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_fr
|
|||
}
|
||||
|
||||
#if VMDEBUG > 3
|
||||
fprintf(stderr, " (1)");
|
||||
rb_vmdebug_debug_print_register(ec);
|
||||
fprintf(errout, " (1)");
|
||||
rb_vmdebug_debug_print_register(errout, ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
|
||||
rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout)
|
||||
{
|
||||
#if VMDEBUG > 9
|
||||
SDR2(cfp);
|
||||
rb_vmdebug_stack_dump_raw(ec, cfp, errout);
|
||||
#endif
|
||||
|
||||
#if VMDEBUG > 3
|
||||
fprintf(stderr, " (2)");
|
||||
rb_vmdebug_debug_print_register(ec);
|
||||
fprintf(errout, " (2)");
|
||||
rb_vmdebug_debug_print_register(errout, ec);
|
||||
#endif
|
||||
/* stack_dump_raw(ec, cfp); */
|
||||
|
||||
#if VMDEBUG > 2
|
||||
/* stack_dump_thobj(ec); */
|
||||
vm_stack_dump_each(ec, ec->cfp);
|
||||
vm_stack_dump_each(ec, ec->cfp, errout);
|
||||
|
||||
printf
|
||||
("--------------------------------------------------------------\n");
|
||||
|
@ -444,14 +444,14 @@ rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_f
|
|||
}
|
||||
|
||||
VALUE
|
||||
rb_vmdebug_thread_dump_state(VALUE self)
|
||||
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(stderr, "Thread state dump:\n");
|
||||
fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp);
|
||||
fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep);
|
||||
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);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -664,6 +664,11 @@ typedef void *PGET_MODULE_BASE_ROUTINE64;
|
|||
typedef void *PTRANSLATE_ADDRESS_ROUTINE64;
|
||||
# endif
|
||||
|
||||
struct dump_thead_arg {
|
||||
DWORD tid;
|
||||
FILE *errout;
|
||||
};
|
||||
|
||||
static void
|
||||
dump_thread(void *arg)
|
||||
{
|
||||
|
@ -675,7 +680,8 @@ dump_thread(void *arg)
|
|||
BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *);
|
||||
BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *);
|
||||
HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD);
|
||||
DWORD tid = *(DWORD *)arg;
|
||||
DWORD tid = ((struct dump_thead_arg *)arg)->tid;
|
||||
FILE *errout = ((struct dump_thead_arg *)arg)->errout;
|
||||
HANDLE ph;
|
||||
HANDLE th;
|
||||
|
||||
|
@ -740,16 +746,16 @@ 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(stderr, "%s", libpath);
|
||||
fprintf(stderr, "(%s+0x%"PRI_64_PREFIX"x)",
|
||||
fprintf(errout, "%s", libpath);
|
||||
fprintf(errout, "(%s+0x%"PRI_64_PREFIX"x)",
|
||||
info->Name, displacement);
|
||||
}
|
||||
fprintf(stderr, " [0x%p]", (void *)(VALUE)addr);
|
||||
fprintf(errout, " [0x%p]", (void *)(VALUE)addr);
|
||||
memset(&line, 0, sizeof(line));
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
if (pSymGetLineFromAddr64(ph, addr, &tmp, &line))
|
||||
fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, " %s:%lu", line.FileName, line.LineNumber);
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,27 +770,30 @@ dump_thread(void *arg)
|
|||
#endif
|
||||
|
||||
void
|
||||
rb_print_backtrace(void)
|
||||
rb_print_backtrace(FILE *errout)
|
||||
{
|
||||
#if USE_BACKTRACE
|
||||
#define MAX_NATIVE_TRACE 1024
|
||||
static void *trace[MAX_NATIVE_TRACE];
|
||||
int n = (int)backtrace(trace, MAX_NATIVE_TRACE);
|
||||
#if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)) && defined(HAVE_DLADDR) && !defined(__sparc)
|
||||
rb_dump_backtrace_with_lines(n, trace);
|
||||
rb_dump_backtrace_with_lines(n, trace, errout);
|
||||
#else
|
||||
char **syms = backtrace_symbols(trace, n);
|
||||
if (syms) {
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
fprintf(stderr, "%s\n", syms[i]);
|
||||
fprintf(errout, "%s\n", syms[i]);
|
||||
}
|
||||
free(syms);
|
||||
}
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &tid);
|
||||
struct dump_thead_arg arg = {
|
||||
.tid = GetCurrentThreadId(),
|
||||
.errout = errout,
|
||||
};
|
||||
HANDLE th = (HANDLE)_beginthread(dump_thread, 0, &arg);
|
||||
if (th != (HANDLE)-1)
|
||||
WaitForSingleObject(th, INFINITE);
|
||||
#endif
|
||||
|
@ -796,21 +805,21 @@ rb_print_backtrace(void)
|
|||
|
||||
#if defined __linux__
|
||||
# if defined(__x86_64__) || defined(__i386__)
|
||||
# define dump_machine_register(reg) (col_count = print_machine_register(mctx->gregs[REG_##reg], #reg, col_count, 80))
|
||||
# define dump_machine_register(reg) (col_count = print_machine_register(errout, mctx->gregs[REG_##reg], #reg, col_count, 80))
|
||||
# elif defined(__aarch64__) || defined(__arm__) || defined(__riscv) || defined(__loongarch64)
|
||||
# define dump_machine_register(reg, regstr) (col_count = print_machine_register(reg, regstr, col_count, 80))
|
||||
# define dump_machine_register(reg, regstr) (col_count = print_machine_register(errout, reg, regstr, col_count, 80))
|
||||
# endif
|
||||
#elif defined __APPLE__
|
||||
# if defined(__aarch64__)
|
||||
# define dump_machine_register(reg, regstr) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), regstr, col_count, 80))
|
||||
# define dump_machine_register(reg, regstr) (col_count = print_machine_register(errout, mctx->MCTX_SS_REG(reg), regstr, col_count, 80))
|
||||
# else
|
||||
# define dump_machine_register(reg) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), #reg, col_count, 80))
|
||||
# define dump_machine_register(reg) (col_count = print_machine_register(errout, mctx->MCTX_SS_REG(reg), #reg, col_count, 80))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef dump_machine_register
|
||||
static int
|
||||
print_machine_register(size_t reg, const char *reg_name, int col_count, int max_col)
|
||||
print_machine_register(FILE *errout, size_t reg, const char *reg_name, int col_count, int max_col)
|
||||
{
|
||||
int ret;
|
||||
char buf[64];
|
||||
|
@ -818,21 +827,21 @@ print_machine_register(size_t reg, const char *reg_name, int col_count, int max_
|
|||
|
||||
ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%.*" PRIxSIZE, reg_name, size_width, reg);
|
||||
if (col_count + ret > max_col) {
|
||||
fputs("\n", stderr);
|
||||
fputs("\n", errout);
|
||||
col_count = 0;
|
||||
}
|
||||
col_count += ret;
|
||||
fputs(buf, stderr);
|
||||
fputs(buf, errout);
|
||||
return col_count;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_dump_machine_register(const ucontext_t *ctx)
|
||||
rb_dump_machine_register(FILE *errout, const ucontext_t *ctx)
|
||||
{
|
||||
int col_count = 0;
|
||||
if (!ctx) return;
|
||||
|
||||
fprintf(stderr, "-- Machine register context "
|
||||
fprintf(errout, "-- Machine register context "
|
||||
"------------------------------------------------\n");
|
||||
|
||||
# if defined __linux__
|
||||
|
@ -1025,14 +1034,14 @@ rb_dump_machine_register(const ucontext_t *ctx)
|
|||
# endif
|
||||
}
|
||||
# endif
|
||||
fprintf(stderr, "\n\n");
|
||||
fprintf(errout, "\n\n");
|
||||
}
|
||||
#else
|
||||
# define rb_dump_machine_register(ctx) ((void)0)
|
||||
# define rb_dump_machine_register(errout, ctx) ((void)0)
|
||||
#endif /* dump_machine_register */
|
||||
|
||||
void
|
||||
rb_vm_bugreport(const void *ctx)
|
||||
rb_vm_bugreport(const void *ctx, FILE *errout)
|
||||
{
|
||||
const char *cmd = getenv("RUBY_ON_BUG");
|
||||
if (cmd) {
|
||||
|
@ -1049,7 +1058,7 @@ rb_vm_bugreport(const void *ctx)
|
|||
{
|
||||
static bool crashing = false;
|
||||
if (crashing) {
|
||||
fprintf(stderr, "Crashed while printing bug report\n");
|
||||
fprintf(errout, "Crashed while printing bug report\n");
|
||||
return;
|
||||
}
|
||||
crashing = true;
|
||||
|
@ -1067,32 +1076,32 @@ rb_vm_bugreport(const void *ctx)
|
|||
const rb_execution_context_t *ec = rb_current_execution_context(false);
|
||||
|
||||
if (vm && ec) {
|
||||
SDR();
|
||||
rb_backtrace_print_as_bugreport();
|
||||
fputs("\n", stderr);
|
||||
rb_vmdebug_stack_dump_raw(ec, ec->cfp, errout);
|
||||
rb_backtrace_print_as_bugreport(errout);
|
||||
fputs("\n", 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(stderr, "-- Threading information "
|
||||
fprintf(errout, "-- Threading information "
|
||||
"---------------------------------------------------\n");
|
||||
fprintf(stderr, "Total ractor count: %u\n", vm->ractor.cnt);
|
||||
fprintf(stderr, "Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt);
|
||||
fputs("\n", stderr);
|
||||
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);
|
||||
fputs("\n", errout);
|
||||
}
|
||||
|
||||
rb_dump_machine_register(ctx);
|
||||
rb_dump_machine_register(errout, ctx);
|
||||
|
||||
#if USE_BACKTRACE || defined(_WIN32)
|
||||
fprintf(stderr, "-- C level backtrace information "
|
||||
fprintf(errout, "-- C level backtrace information "
|
||||
"-------------------------------------------\n");
|
||||
rb_print_backtrace();
|
||||
rb_print_backtrace(errout);
|
||||
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
#endif /* USE_BACKTRACE */
|
||||
|
||||
if (other_runtime_info || vm) {
|
||||
fprintf(stderr, "-- Other runtime information "
|
||||
fprintf(errout, "-- Other runtime information "
|
||||
"-----------------------------------------------\n\n");
|
||||
}
|
||||
if (vm && !rb_during_gc()) {
|
||||
|
@ -1105,16 +1114,16 @@ rb_vm_bugreport(const void *ctx)
|
|||
|
||||
name = vm->progname;
|
||||
if (name) {
|
||||
fprintf(stderr, "* Loaded script: %.*s\n",
|
||||
fprintf(errout, "* Loaded script: %.*s\n",
|
||||
LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
if (vm->loaded_features) {
|
||||
fprintf(stderr, "* Loaded features:\n\n");
|
||||
fprintf(errout, "* Loaded features:\n\n");
|
||||
for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
|
||||
name = RARRAY_AREF(vm->loaded_features, i);
|
||||
if (RB_TYPE_P(name, T_STRING)) {
|
||||
fprintf(stderr, " %4d %.*s\n", i,
|
||||
fprintf(errout, " %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)) {
|
||||
|
@ -1122,26 +1131,26 @@ rb_vm_bugreport(const void *ctx)
|
|||
"class" : "module";
|
||||
name = rb_search_class_path(rb_class_real(name));
|
||||
if (!RB_TYPE_P(name, T_STRING)) {
|
||||
fprintf(stderr, " %4d %s:<unnamed>\n", i, type);
|
||||
fprintf(errout, " %4d %s:<unnamed>\n", i, type);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, " %4d %s:%.*s\n", i, type,
|
||||
fprintf(errout, " %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(stderr, " %4d #<%p:%p>\n", i,
|
||||
fprintf(errout, " %4d #<%p:%p>\n", i,
|
||||
(void *)CLASS_OF(name), (void *)name);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, " %4d #<%.*s:%p>\n", i,
|
||||
fprintf(errout, " %4d #<%.*s:%p>\n", i,
|
||||
LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
|
||||
(void *)name);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1149,17 +1158,17 @@ rb_vm_bugreport(const void *ctx)
|
|||
{
|
||||
FILE *fp = fopen(PROC_MAPS_NAME, "r");
|
||||
if (fp) {
|
||||
fprintf(stderr, "* Process memory map:\n\n");
|
||||
fprintf(errout, "* Process memory map:\n\n");
|
||||
|
||||
while (!feof(fp)) {
|
||||
char buff[0x100];
|
||||
size_t rn = fread(buff, 1, 0x100, fp);
|
||||
if (fwrite(buff, 1, rn, stderr) != rn)
|
||||
if (fwrite(buff, 1, rn, errout) != rn)
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fprintf(stderr, "\n\n");
|
||||
fprintf(errout, "\n\n");
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
@ -1173,14 +1182,14 @@ rb_vm_bugreport(const void *ctx)
|
|||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) {
|
||||
perror("sysctl");
|
||||
fprintf(errout, "sysctl: %s\n", strerror(errno));
|
||||
}
|
||||
else {
|
||||
struct procstat *prstat = procstat_open_sysctl();
|
||||
fprintf(stderr, "* Process memory map:\n\n");
|
||||
fprintf(errout, "* Process memory map:\n\n");
|
||||
procstat_vm(prstat, &kp);
|
||||
procstat_close(prstat);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
#ifdef __APPLE__
|
||||
|
@ -1190,7 +1199,7 @@ rb_vm_bugreport(const void *ctx)
|
|||
mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT;
|
||||
natural_t depth = 0;
|
||||
|
||||
fprintf(stderr, "* Process memory map:\n\n");
|
||||
fprintf(errout, "* 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) {
|
||||
|
@ -1202,17 +1211,17 @@ rb_vm_bugreport(const void *ctx)
|
|||
depth++;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%lx-%lx %s%s%s", addr, (addr+size),
|
||||
fprintf(errout, "%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(stderr, " %s", buff);
|
||||
fprintf(errout, " %s", buff);
|
||||
}
|
||||
#endif
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(errout, "\n");
|
||||
}
|
||||
|
||||
addr += size;
|
||||
|
@ -1227,14 +1236,15 @@ rb_vmdebug_stack_dump_all_threads(void)
|
|||
{
|
||||
rb_thread_t *th = NULL;
|
||||
rb_ractor_t *r = GET_RACTOR();
|
||||
FILE *errout = stderr;
|
||||
|
||||
// TODO: now it only shows current ractor
|
||||
ccan_list_for_each(&r->threads.set, th, lt_node) {
|
||||
#ifdef NON_SCALAR_THREAD_ID
|
||||
fprintf(stderr, "th: %p, native_id: N/A\n", th);
|
||||
fprintf(errout, "th: %p, native_id: N/A\n", th);
|
||||
#else
|
||||
fprintf(stderr, "th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id);
|
||||
fprintf(errout, "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);
|
||||
rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp, errout);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue