17 #include <sys/types.h>
20 # include <sys/wait.h>
21 # include <sys/syscall.h>
24 #ifndef WVCRASH_USE_SIGALTSTACK
25 # define WVCRASH_USE_SIGALTSTACK 1
31 # include <execinfo.h>
35 static const char *argv0 = program_invocation_short_name;
37 static const char *argv0 =
"UNKNOWN";
40 #if WVCRASH_USE_SIGALTSTACK
41 static const size_t altstack_size = 1048576;
42 static char altstack[altstack_size];
46 static const int buffer_size = 2048 + wvcrash_ring_buffer_size;
48 static char desc[buffer_size];
51 static void wr(
int fd,
const char *str)
53 write(fd, str, strlen(str));
58 static void wrn(
int fd,
int num)
92 static void wra(
int fd,
const void *addr)
94 const unsigned int ptrbitsshift = (
sizeof(ptrdiff_t) << 3) - 4;
95 char digits[] =
"0123456789ABCDEF";
98 for (
int shift=ptrbitsshift; shift>=0; shift-=4)
99 write(fd, &digits[(((ptrdiff_t)addr)>>shift)&0xF], 1);
103 static void wvcrash_real(
int sig,
int fd, pid_t pid)
105 static void *trace[64];
106 static char *signame = strsignal(sig);
115 wr(fd,
" dying on signal ");
125 static char pid_str[32];
126 wr(fd,
"\nProcess ID: ");
127 snprintf(pid_str,
sizeof(pid_str),
"%d", getpid());
130 wr(fd,
"\nParent's process ID: ");
131 snprintf(pid_str,
sizeof(pid_str),
"%d", getppid());
136 #if WVCRASH_USE_SIGALTSTACK
138 const void *last_real_stack_frame;
141 last_real_stack_frame = __builtin_frame_address(0);
142 if (last_real_stack_frame == NULL
143 || last_real_stack_frame < &altstack[0]
144 || last_real_stack_frame >= &altstack[altstack_size])
146 last_real_stack_frame = __builtin_frame_address(1);
147 if (last_real_stack_frame == NULL
148 || last_real_stack_frame < &altstack[0]
149 || last_real_stack_frame >= &altstack[altstack_size])
151 last_real_stack_frame = __builtin_frame_address(2);
152 if (last_real_stack_frame == NULL
153 || last_real_stack_frame < &altstack[0]
154 || last_real_stack_frame >= &altstack[altstack_size])
156 last_real_stack_frame = __builtin_frame_address(3);
157 if (last_real_stack_frame == NULL
158 || last_real_stack_frame < &altstack[0]
159 || last_real_stack_frame >= &altstack[altstack_size])
161 last_real_stack_frame = __builtin_frame_address(4);
162 if (last_real_stack_frame == NULL
163 || last_real_stack_frame < &altstack[0]
164 || last_real_stack_frame >= &altstack[altstack_size])
166 last_real_stack_frame = __builtin_frame_address(5);
167 if (last_real_stack_frame == NULL
168 || last_real_stack_frame < &altstack[0]
169 || last_real_stack_frame >= &altstack[altstack_size])
171 last_real_stack_frame = NULL;
174 if (last_real_stack_frame != NULL)
176 wr(fd,
"\nLast real stack frame: ");
177 wra(fd, last_real_stack_frame);
178 const void *top_of_stack = WvTaskMan::current_top_of_stack();
179 wr(fd,
"\nTop of stack: ");
180 wra(fd, top_of_stack);
181 size_t stack_size = size_t(top_of_stack) - size_t(last_real_stack_frame);
182 wr(fd,
"\nStack size: ");
183 wrn(fd,
int(stack_size));
184 size_t stack_size_limit = WvTaskMan::current_stacksize_limit();
185 if (stack_size_limit > 0)
187 wr(fd,
"\nStack size rlimit: ");
188 wrn(fd,
int(stack_size_limit));
189 if (stack_size > stack_size_limit)
190 wr(fd,
" DEFINITE STACK OVERFLOW");
191 else if (stack_size + 16384 > stack_size_limit)
192 wr(fd,
" PROBABLE STACK OVERFLOW");
203 while ((ring = wvcrash_ring_buffer_get()) != NULL)
208 wr(fd,
"\nRing buffer:\n");
216 const char *assert_msg = wvcrash_read_assert();
217 if (assert_msg && assert_msg[0])
219 wr(fd,
"\nAssert:\n");
226 const char *will_msg = wvcrash_read_will();
227 if (will_msg && will_msg[0])
229 wr(fd,
"\nLast Will and Testament:\n");
235 if (WvCrashInfo::in_stream_state != WvCrashInfo::UNUSED
236 && WvCrashInfo::in_stream)
238 const char *state = NULL;
239 switch (WvCrashInfo::in_stream_state)
241 case WvCrashInfo::UNUSED:
244 case WvCrashInfo::PRE_SELECT:
245 state =
"\nStream in pre_select: ";
247 case WvCrashInfo::POST_SELECT:
248 state =
"\nStream in post_select: ";
250 case WvCrashInfo::EXECUTE:
251 state =
"\nStream in execute: ";
257 static char ptr_str[32];
258 snprintf(ptr_str,
sizeof(ptr_str),
"%p", WvCrashInfo::in_stream);
259 ptr_str[
sizeof(ptr_str) - 1] =
'\0';
262 wr(fd, WvCrashInfo::in_stream_id && WvCrashInfo::in_stream_id[0]
263 ? WvCrashInfo::in_stream_id :
"unknown stream");
270 wr(fd,
"\nBacktrace:\n");
271 backtrace_symbols_fd(trace,
272 backtrace(trace,
sizeof(trace)/
sizeof(trace[0])), fd);
280 struct timespec ts = { 0, 100*1000*1000 };
282 for (i=0; i < 100; ++i)
284 if (waitpid(pid, NULL, WNOHANG) == pid)
286 nanosleep(&ts, NULL);
298 signal(sig, SIG_DFL);
310 void wvcrash(
int sig)
315 signal(sig, SIG_DFL);
316 wr(2,
"\n\nwvcrash: crashing!\n");
330 for (
int count = 5; count < 15; count++)
334 wvcrash_real(sig, 2, 0);
339 wvcrash_real(sig, 2, 0);
344 fcntl(0, F_SETFD, 0);
346 execlp(
"wvcrash",
"wvcrash", NULL);
349 wr(2,
"wvcrash: can't exec wvcrash binary "
350 "- writing to wvcrash.txt!\n");
351 execlp(
"dd",
"dd",
"of=wvcrash.txt", NULL);
353 wr(2,
"wvcrash: can't exec dd to write to wvcrash.txt!\n");
359 wvcrash_real(sig, fds[1], pid);
368 static void wvcrash_setup_alt_stack()
370 #if WVCRASH_USE_SIGALTSTACK
375 ss.ss_size = altstack_size;
377 if (ss.ss_sp == NULL || sigaltstack(&ss, NULL))
378 fprintf(stderr,
"Failed to setup sigaltstack for wvcrash: %s\n",
380 #endif //WVCRASH_USE_SIGALTSTACK
383 void wvcrash_add_signal(
int sig)
385 #if WVCRASH_USE_SIGALTSTACK
386 struct sigaction act;
388 memset(&act,0,
sizeof(act));
389 act.sa_handler = wvcrash;
390 sigfillset(&act.sa_mask);
391 act.sa_flags = SA_ONSTACK | SA_RESTART;
393 if (sigaction(sig, &act, NULL))
394 fprintf(stderr,
"Failed to setup wvcrash handler for signal %d: %s\n",
395 sig, strerror(errno));
397 signal(sig, wvcrash);
398 #endif //WVCRASH_USE_SIGALTSTACK
402 extern void __wvcrash_init_buffers(
const char *program_name);
404 void wvcrash_setup(
const char *_argv0,
const char *_desc)
407 argv0 = basename(_argv0);
408 __wvcrash_init_buffers(argv0);
411 strncpy(desc, _desc, buffer_size);
412 desc[buffer_size - 1] =
'\0';
417 wvcrash_setup_alt_stack();
419 wvcrash_add_signal(SIGSEGV);
420 wvcrash_add_signal(SIGBUS);
421 wvcrash_add_signal(SIGABRT);
422 wvcrash_add_signal(SIGFPE);
423 wvcrash_add_signal(SIGILL);
426 #elif defined(_WIN32)
430 #include <imagehlp.h>
432 inline char* last_part(
char* in)
434 int len = strlen(in);
438 if (*tmp ==
'/' || *tmp ==
'\\')
454 int backtrace(CONTEXT &ctx)
456 HANDLE hProcess = (HANDLE)GetCurrentProcess();
457 HANDLE hThread = (HANDLE)GetCurrentThread();
459 SymInitialize(hProcess, NULL, TRUE);
462 memset(&sf, 0,
sizeof(STACKFRAME));
464 sf.AddrPC.Offset = ctx.Eip;
465 sf.AddrPC.Mode = AddrModeFlat;
466 sf.AddrFrame.Offset = ctx.Ebp;
467 sf.AddrFrame.Mode = AddrModeFlat;
468 sf.AddrStack.Offset = ctx.Esp;
469 sf.AddrStack.Mode = AddrModeFlat;
471 fprintf(stderr,
"Generating stack trace......\n");
472 fprintf(stderr,
"%3s %16s:%-10s %32s:%3s %s\n",
"Num",
"Module",
"Addr",
"Filename",
"Line",
"Function Name");
474 while (StackWalk(IMAGE_FILE_MACHINE_I386,
480 SymFunctionTableAccess,
484 if (sf.AddrPC.Offset == 0)
488 IMAGEHLP_MODULE modinfo;
489 memset(&modinfo, 0,
sizeof(IMAGEHLP_MODULE));
490 modinfo.SizeOfStruct =
sizeof(IMAGEHLP_MODULE);
491 SymGetModuleInfo(hProcess, sf.AddrPC.Offset, &modinfo);
496 memset(buffer, 0,
sizeof(buffer));
497 PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL)buffer;
498 sym->SizeOfStruct =
sizeof(IMAGEHLP_SYMBOL);
499 sym->MaxNameLength =
sizeof(buffer) -
sizeof(IMAGEHLP_SYMBOL) + 1;
500 SymGetSymFromAddr(hProcess, sf.AddrPC.Offset, &disp, sym);
504 SymSetOptions(SYMOPT_LOAD_LINES);
506 memset(&line, 0,
sizeof(IMAGEHLP_LINE));
507 line.SizeOfStruct =
sizeof(IMAGEHLP_LINE);
508 SymGetLineFromAddr(hProcess, sf.AddrPC.Offset, &disp2, &line);
511 fprintf(stderr,
"%3d. %16s:0x%08X %32s:%-3d %s\n",
513 modinfo.LoadedImageName[0]?modinfo.LoadedImageName:
"unknown",
514 (DWORD)sf.AddrPC.Offset,
515 (line.FileName && line.FileName[0])?last_part(line.FileName):
"unknown",
516 (line.FileName && line.FileName[0])?line.LineNumber:0,
517 sym->Name[0]?sym->Name:
"unknown");
520 SymCleanup(hProcess);
526 static void exception_desc(FILE *file,
unsigned exception,
527 unsigned data1,
unsigned data2)
538 "invalid memory read from address 0x%08X",
543 "invalid memory write to address 0x%08X",
548 "invalid memory access (unknown type %d) at address 0x%08X",
556 fprintf(file,
"integer division by zero");
560 fprintf(file,
"unknown exception (data1=0x%08X, data2=0x%08X)");
565 static LONG WINAPI ExceptionFilter(
struct _EXCEPTION_POINTERS * pExceptionPointers )
572 unsigned more_unknown;
576 ExceptionInfo *info = *(ExceptionInfo **)pExceptionPointers;
581 if (info->exception==0x80000003)
583 fprintf(stderr,
"Preparing to debug!\n");
584 return EXCEPTION_CONTINUE_SEARCH;
587 fprintf(stderr,
"--------------------------------------------------------\n");
588 fprintf(stderr,
"Exception 0x%08X:\n ", info->exception);
589 exception_desc(stderr, info->exception, info->data1, info->data2);
590 fprintf(stderr,
"\n at instruction 0x%08X in thread 0x%08X\n", info->ip, GetCurrentThreadId());
591 backtrace(*pExceptionPointers->ContextRecord);
592 fprintf(stderr,
"--------------------------------------------------------\n");
595 return EXCEPTION_EXECUTE_HANDLER;
598 static bool have_global_exception_handler =
false;
599 void setup_console_crash()
601 if (!have_global_exception_handler)
603 SetUnhandledExceptionFilter(ExceptionFilter);
604 have_global_exception_handler =
true;
608 void wvcrash(
int sig) {}
609 void wvcrash_setup(
const char *_argv0,
const char *_desc) {}
613 void wvcrash(
int sig) {}
614 void wvcrash_add_signal(
int sig) {}
615 void wvcrash_setup(
const char *_argv0,
const char *_desc) {}