diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | error.c | 108 | ||||
-rw-r--r-- | signal.c | 6 | ||||
-rw-r--r-- | vm.c | 2 | ||||
-rw-r--r-- | vm_core.h | 3 | ||||
-rw-r--r-- | vm_dump.c | 141 |
6 files changed, 233 insertions, 37 deletions
@@ -1,3 +1,13 @@ +Sun May 25 12:46:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * error.c (rb_bug_context): new function to report bug with + context. + + * vm_dump.c (rb_vm_bugreport): accepts `ucontext_t` argument to + dump machine regisiters. based on [GH-584]. + + * signal.c (sigbus, sigsegv): dump machine regisiters if available. + Sun May 25 12:32:42 2014 Tanaka Akira <akr@fsij.org> * test/lib/minitest/unit.rb: Sort leaked threads and tempfiles. @@ -292,41 +292,78 @@ rb_bug_reporter_add(void (*func)(FILE *, void *), void *data) return 1; } -static void -report_bug(const char *file, int line, const char *fmt, va_list args) +/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */ +#define REPORT_BUG_BUFSIZ 256 +static FILE * +bug_report_file(const char *file, int line) { - /* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */ - char buf[256]; + char buf[REPORT_BUG_BUFSIZ]; FILE *out = stderr; - int len = err_position_0(buf, 256, file, line); + int len = err_position_0(buf, sizeof(buf), file, line); if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len || (ssize_t)fwrite(buf, 1, len, (out = stdout)) == (ssize_t)len) { + return out; + } + return NULL; +} + +static void +bug_report_begin(FILE *out, const char *fmt, va_list args) +{ + char buf[REPORT_BUG_BUFSIZ]; - fputs("[BUG] ", out); - vsnprintf(buf, 256, fmt, args); - fputs(buf, out); - snprintf(buf, 256, "\n%s\n\n", ruby_description); - fputs(buf, out); + fputs("[BUG] ", out); + vsnprintf(buf, sizeof(buf), fmt, args); + fputs(buf, out); + snprintf(buf, sizeof(buf), "\n%s\n\n", ruby_description); + fputs(buf, out); +} - rb_vm_bugreport(); +#define bug_report_begin(out, fmt) do { \ + va_list args; \ + va_start(args, fmt); \ + bug_report_begin(out, fmt, args); \ + va_end(args); \ +} while (0) - /* call additional bug reporters */ - { - int i; - for (i=0; i<bug_reporters_size; i++) { - struct bug_reporters *reporter = &bug_reporters[i]; - (*reporter->func)(out, reporter->data); - } +static void +bug_report_end(FILE *out) +{ + /* call additional bug reporters */ + { + int i; + for (i=0; i<bug_reporters_size; i++) { + struct bug_reporters *reporter = &bug_reporters[i]; + (*reporter->func)(out, reporter->data); } - fprintf(out, REPORTBUG_MSG); } + fprintf(out, REPORTBUG_MSG); +} + +#define report_bug(file, line, fmt, ctx) do { \ + FILE *out = bug_report_file(file, line); \ + if (out) { \ + bug_report_begin(out, fmt); \ + rb_vm_bugreport(ctx); \ + bug_report_end(out); \ + } \ +} while (0) \ + +NORETURN(static void die(void)); +static void +die(void) +{ +#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80 + _set_abort_behavior( 0, _CALL_REPORTFAULT); +#endif + + abort(); } void rb_bug(const char *fmt, ...) { - va_list args; const char *file = NULL; int line = 0; @@ -335,17 +372,28 @@ rb_bug(const char *fmt, ...) line = rb_sourceline(); } - va_start(args, fmt); - report_bug(file, line, fmt, args); - va_end(args); + report_bug(file, line, fmt, NULL); -#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80 - _set_abort_behavior( 0, _CALL_REPORTFAULT); -#endif + die(); +} - abort(); +void +rb_bug_context(const void *ctx, const char *fmt, ...) +{ + const char *file = NULL; + int line = 0; + + if (GET_THREAD()) { + file = rb_sourcefile(); + line = rb_sourceline(); + } + + report_bug(file, line, fmt, ctx); + + die(); } + void rb_bug_errno(const char *mesg, int errno_arg) { @@ -394,11 +442,7 @@ rb_async_bug_errno(const char *mesg, int errno_arg) void rb_compile_bug(const char *file, int line, const char *fmt, ...) { - va_list args; - - va_start(args, fmt); - report_bug(file, line, fmt, args); - va_end(args); + report_bug(file, line, fmt, NULL); abort(); } @@ -507,9 +507,11 @@ typedef RETSIGTYPE (*sighandler_t)(int); #ifdef USE_SIGALTSTACK typedef void ruby_sigaction_t(int, siginfo_t*, void*); #define SIGINFO_ARG , siginfo_t *info, void *ctx +#define SIGINFO_CTX ctx #else typedef RETSIGTYPE ruby_sigaction_t(int); #define SIGINFO_ARG +#define SIGINFO_CTX 0 #endif #ifdef USE_SIGALTSTACK @@ -776,7 +778,7 @@ sigbus(int sig SIGINFO_ARG) #if defined __APPLE__ CHECK_STACK_OVERFLOW(); #endif - rb_bug("Bus Error" MESSAGE_FAULT_ADDRESS); + rb_bug_context(SIGINFO_CTX, "Bus Error" MESSAGE_FAULT_ADDRESS); } #endif @@ -813,7 +815,7 @@ sigsegv(int sig SIGINFO_ARG) segv_received = 1; ruby_disable_gc_stress = 1; - rb_bug("Segmentation fault" MESSAGE_FAULT_ADDRESS); + rb_bug_context(SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS); } #endif @@ -2376,7 +2376,7 @@ extern VALUE *rb_gc_register_stack_start; static VALUE sdr(void) { - rb_vm_bugreport(); + rb_vm_bugreport(NULL); return Qnil; } @@ -836,7 +836,8 @@ extern void rb_vmdebug_debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp #define SDR() rb_vmdebug_stack_dump_raw(GET_THREAD(), GET_THREAD()->cfp) #define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_THREAD(), (cfp)) -void rb_vm_bugreport(void); +void rb_vm_bugreport(const void *); +NORETURN(void rb_bug_context(const void *, const char *fmt, ...)); /* functions about thread/vm execution */ RUBY_SYMBOL_EXPORT_BEGIN @@ -789,8 +789,145 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp) } #endif +#if defined __linux__ +# if defined __x86_64__ || defined __i386__ +# define HAVE_PRINT_MACHINE_REGISTERS 1 +# endif +#elif defined __APPLE__ +# if defined __x86_64__ || defined __i386__ +# define HAVE_PRINT_MACHINE_REGISTERS 1 +# endif +#endif + +#ifdef HAVE_PRINT_MACHINE_REGISTERS +static int +print_machine_register(size_t reg, const char *reg_name, int col_count, int max_col) +{ + int ret; + char buf[64]; + +#ifdef __LP64__ + ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%016zx", reg_name, reg); +#else + ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%08zx", reg_name, reg); +#endif + if (col_count + ret > max_col) { + fputs("\n", stderr); + col_count = 0; + } + col_count += ret; + fputs(buf, stderr); + return col_count; +} +# ifdef __linux__ +# define dump_machine_register(reg) (col_count = print_machine_register(mctx->gregs[REG_##reg], #reg, col_count, 80)) +# elif defined __APPLE__ +# define dump_machine_register(reg) (col_count = print_machine_register(mctx->__ss.__##reg, #reg, col_count, 80)) +# endif + +static void +rb_dump_machine_register(const ucontext_t *ctx) +{ + int col_count = 0; + if (!ctx) return; + + fprintf(stderr, "-- Machine register context " + "------------------------------------------------\n"); + +# if defined __linux__ + { + const mcontext_t *const mctx = &ctx->uc_mcontext; +# if defined __x86_64__ + dump_machine_register(RIP); + dump_machine_register(RBP); + dump_machine_register(RSP); + dump_machine_register(RAX); + dump_machine_register(RBX); + dump_machine_register(RCX); + dump_machine_register(RDX); + dump_machine_register(RDI); + dump_machine_register(RSI); + dump_machine_register(R8); + dump_machine_register(R9); + dump_machine_register(R10); + dump_machine_register(R11); + dump_machine_register(R12); + dump_machine_register(R13); + dump_machine_register(R14); + dump_machine_register(R15); + dump_machine_register(EFL); +# elif defined __i386__ + dump_machine_register(GS); + dump_machine_register(FS); + dump_machine_register(ES); + dump_machine_register(DS); + dump_machine_register(EDI); + dump_machine_register(ESI); + dump_machine_register(EBP); + dump_machine_register(ESP); + dump_machine_register(EBX); + dump_machine_register(EDX); + dump_machine_register(ECX); + dump_machine_register(EAX); + dump_machine_register(TRAPNO); + dump_machine_register(ERR); + dump_machine_register(EIP); + dump_machine_register(CS); + dump_machine_register(EFL); + dump_machine_register(UESP); + dump_machine_register(SS); +# endif + } +# elif defined __APPLE__ + { + const mcontext_t mctx = ctx->uc_mcontext; +# if defined __x86_64__ + dump_machine_register(rax); + dump_machine_register(rbx); + dump_machine_register(rcx); + dump_machine_register(rdx); + dump_machine_register(rdi); + dump_machine_register(rsi); + dump_machine_register(rbp); + dump_machine_register(rsp); + dump_machine_register(r8); + dump_machine_register(r9); + dump_machine_register(r10); + dump_machine_register(r11); + dump_machine_register(r12); + dump_machine_register(r13); + dump_machine_register(r14); + dump_machine_register(r15); + dump_machine_register(rip); + dump_machine_register(rflags); +# elif defined __i386__ + dump_machine_register(eax); + dump_machine_register(ebx); + dump_machine_register(ecx); + dump_machine_register(edx); + dump_machine_register(edi); + dump_machine_register(esi); + dump_machine_register(ebp); + dump_machine_register(esp); + dump_machine_register(ss); + dump_machine_register(eflags); + dump_machine_register(eip); + dump_machine_register(cs); + dump_machine_register(ds); + dump_machine_register(es); + dump_machine_register(fs); + dump_machine_register(gs); +# endif + } +# endif + fprintf(stderr, "\n\n"); +} +#else +# define rb_dump_machine_register(ctx) ((void)0) +#endif /* HAVE_PRINT_MACHINE_REGISTERS */ + void -rb_vm_bugreport(void) +rb_vm_bugreport(const void *ctx) { #ifdef __linux__ # define PROC_MAPS_NAME "/proc/self/maps" @@ -820,6 +957,8 @@ rb_vm_bugreport(void) fputs("\n", stderr); } + rb_dump_machine_register(ctx); + #if HAVE_BACKTRACE || defined(_WIN32) fprintf(stderr, "-- C level backtrace information " "-------------------------------------------\n"); |