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>
|
Sun May 25 12:32:42 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* test/lib/minitest/unit.rb: Sort leaked threads and tempfiles.
|
* test/lib/minitest/unit.rb: Sort leaked threads and tempfiles.
|
||||||
|
90
error.c
90
error.c
@ -292,25 +292,44 @@ rb_bug_reporter_add(void (*func)(FILE *, void *), void *data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
|
||||||
report_bug(const char *file, int line, const char *fmt, va_list args)
|
#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[REPORT_BUG_BUFSIZ];
|
||||||
char buf[256];
|
|
||||||
FILE *out = stderr;
|
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 ||
|
if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len ||
|
||||||
(ssize_t)fwrite(buf, 1, len, (out = stdout)) == (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);
|
fputs("[BUG] ", out);
|
||||||
vsnprintf(buf, 256, fmt, args);
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
fputs(buf, out);
|
fputs(buf, out);
|
||||||
snprintf(buf, 256, "\n%s\n\n", ruby_description);
|
snprintf(buf, sizeof(buf), "\n%s\n\n", ruby_description);
|
||||||
fputs(buf, out);
|
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)
|
||||||
|
|
||||||
|
static void
|
||||||
|
bug_report_end(FILE *out)
|
||||||
|
{
|
||||||
/* call additional bug reporters */
|
/* call additional bug reporters */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -320,13 +339,31 @@ report_bug(const char *file, int line, const char *fmt, va_list args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
void
|
||||||
rb_bug(const char *fmt, ...)
|
rb_bug(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
|
||||||
const char *file = NULL;
|
const char *file = NULL;
|
||||||
int line = 0;
|
int line = 0;
|
||||||
|
|
||||||
@ -335,17 +372,28 @@ rb_bug(const char *fmt, ...)
|
|||||||
line = rb_sourceline();
|
line = rb_sourceline();
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(args, fmt);
|
report_bug(file, line, fmt, NULL);
|
||||||
report_bug(file, line, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80
|
die();
|
||||||
_set_abort_behavior( 0, _CALL_REPORTFAULT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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
|
void
|
||||||
rb_bug_errno(const char *mesg, int errno_arg)
|
rb_bug_errno(const char *mesg, int errno_arg)
|
||||||
{
|
{
|
||||||
@ -394,11 +442,7 @@ rb_async_bug_errno(const char *mesg, int errno_arg)
|
|||||||
void
|
void
|
||||||
rb_compile_bug(const char *file, int line, const char *fmt, ...)
|
rb_compile_bug(const char *file, int line, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
report_bug(file, line, fmt, NULL);
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
report_bug(file, line, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
6
signal.c
6
signal.c
@ -507,9 +507,11 @@ typedef RETSIGTYPE (*sighandler_t)(int);
|
|||||||
#ifdef USE_SIGALTSTACK
|
#ifdef USE_SIGALTSTACK
|
||||||
typedef void ruby_sigaction_t(int, siginfo_t*, void*);
|
typedef void ruby_sigaction_t(int, siginfo_t*, void*);
|
||||||
#define SIGINFO_ARG , siginfo_t *info, void *ctx
|
#define SIGINFO_ARG , siginfo_t *info, void *ctx
|
||||||
|
#define SIGINFO_CTX ctx
|
||||||
#else
|
#else
|
||||||
typedef RETSIGTYPE ruby_sigaction_t(int);
|
typedef RETSIGTYPE ruby_sigaction_t(int);
|
||||||
#define SIGINFO_ARG
|
#define SIGINFO_ARG
|
||||||
|
#define SIGINFO_CTX 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SIGALTSTACK
|
#ifdef USE_SIGALTSTACK
|
||||||
@ -776,7 +778,7 @@ sigbus(int sig SIGINFO_ARG)
|
|||||||
#if defined __APPLE__
|
#if defined __APPLE__
|
||||||
CHECK_STACK_OVERFLOW();
|
CHECK_STACK_OVERFLOW();
|
||||||
#endif
|
#endif
|
||||||
rb_bug("Bus Error" MESSAGE_FAULT_ADDRESS);
|
rb_bug_context(SIGINFO_CTX, "Bus Error" MESSAGE_FAULT_ADDRESS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -813,7 +815,7 @@ sigsegv(int sig SIGINFO_ARG)
|
|||||||
|
|
||||||
segv_received = 1;
|
segv_received = 1;
|
||||||
ruby_disable_gc_stress = 1;
|
ruby_disable_gc_stress = 1;
|
||||||
rb_bug("Segmentation fault" MESSAGE_FAULT_ADDRESS);
|
rb_bug_context(SIGINFO_CTX, "Segmentation fault" MESSAGE_FAULT_ADDRESS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
2
vm.c
2
vm.c
@ -2376,7 +2376,7 @@ extern VALUE *rb_gc_register_stack_start;
|
|||||||
static VALUE
|
static VALUE
|
||||||
sdr(void)
|
sdr(void)
|
||||||
{
|
{
|
||||||
rb_vm_bugreport();
|
rb_vm_bugreport(NULL);
|
||||||
return Qnil;
|
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 SDR() rb_vmdebug_stack_dump_raw(GET_THREAD(), GET_THREAD()->cfp)
|
||||||
#define SDR2(cfp) rb_vmdebug_stack_dump_raw(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 */
|
/* functions about thread/vm execution */
|
||||||
RUBY_SYMBOL_EXPORT_BEGIN
|
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
|
#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
|
void
|
||||||
rb_vm_bugreport(void)
|
rb_vm_bugreport(const void *ctx)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# define PROC_MAPS_NAME "/proc/self/maps"
|
# define PROC_MAPS_NAME "/proc/self/maps"
|
||||||
@ -820,6 +957,8 @@ rb_vm_bugreport(void)
|
|||||||
fputs("\n", stderr);
|
fputs("\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rb_dump_machine_register(ctx);
|
||||||
|
|
||||||
#if HAVE_BACKTRACE || defined(_WIN32)
|
#if HAVE_BACKTRACE || defined(_WIN32)
|
||||||
fprintf(stderr, "-- C level backtrace information "
|
fprintf(stderr, "-- C level backtrace information "
|
||||||
"-------------------------------------------\n");
|
"-------------------------------------------\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user