aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--error.c108
-rw-r--r--signal.c6
-rw-r--r--vm.c2
-rw-r--r--vm_core.h3
-rw-r--r--vm_dump.c141
6 files changed, 233 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 9c9d9a871c..f8232f48e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/error.c b/error.c
index 4a1cd8aeff..71375c3bea 100644
--- a/error.c
+++ b/error.c
@@ -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();
}
diff --git a/signal.c b/signal.c
index e24cc755c5..5af01fe087 100644
--- a/signal.c
+++ b/signal.c
@@ -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
diff --git a/vm.c b/vm.c
index 1fa76af3fd..40eceeae9f 100644
--- a/vm.c
+++ b/vm.c
@@ -2376,7 +2376,7 @@ extern VALUE *rb_gc_register_stack_start;
static VALUE
sdr(void)
{
- rb_vm_bugreport();
+ rb_vm_bugreport(NULL);
return Qnil;
}
diff --git a/vm_core.h b/vm_core.h
index 07fc60ab83..0883f66ed5 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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
diff --git a/vm_dump.c b/vm_dump.c
index 97abccfc74..c2cb0ce898 100644
--- a/vm_dump.c
+++ b/vm_dump.c
@@ -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");