report bug with machine regisiters
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46106 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
c1b5b93b3f
commit
82f4c4d4d7
10
ChangeLog
10
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.
|
||||
|
118
error.c
118
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) {
|
||||
|
||||
fputs("[BUG] ", out);
|
||||
vsnprintf(buf, 256, fmt, args);
|
||||
fputs(buf, out);
|
||||
snprintf(buf, 256, "\n%s\n\n", ruby_description);
|
||||
fputs(buf, out);
|
||||
|
||||
rb_vm_bugreport();
|
||||
|
||||
/* 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);
|
||||
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, sizeof(buf), fmt, args);
|
||||
fputs(buf, out);
|
||||
snprintf(buf, sizeof(buf), "\n%s\n\n", ruby_description);
|
||||
fputs(buf, out);
|
||||
}
|
||||
|
||||
#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)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
abort();
|
||||
die();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
6
signal.c
6
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
|
||||
|
||||
|
2
vm.c
2
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
141
vm_dump.c
141
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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user