Without running GDB, but only the program itself.
edit: i've already seen such program but i can't figure how to do that myself :(
Without running GDB, but only the program itself.
edit: i've already seen such program but i can't figure how to do that myself :(
Tommie deserves credit for solving this.
I've detached his answer from GDB by using the somewhat standard backtrace
utility from <execinfo.h>
.
static void dumpstack(void){
static void *backbuf[ 50 ];
int levels;
levels = backtrace( backbuf, 50 );
backtrace_symbols_fd( backbuf, levels, STDERR_FILENO );
return;
}
You can try opening a file and writing instead of STDERR_FILENO
, but I'd avoid such heavy lifting in a crashed process.
On my system, the output looks like this:
Shadow:code dkrauss$ ./dumpy
0 dumpy 0x0000000100000d81 dumpstack + 25
1 dumpy 0x0000000100000d18 signal_handler + 47
2 libSystem.B.dylib 0x00007fff86b1766a _sigtramp + 26
3 ??? 0x0000000000000000 0x0 + 0
4 dumpy 0x0000000100000a18 start + 52
FATAL: Segmentation Fault
So, it doesn't give file name + line number, but it does give function name + code offset, which you can translate easily enough.
Hmmm... you could try doing it this way...
struct sigaction g_sigact;
void panic(const char *fmt, ...){
char buf[PANICBUF_LEN];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, "%s\n", buf);
exit(-1);
}
void init_signals(void){
g_sigact.sa_handler = signal_handler;
sigemptyset(&g_sigact.sa_mask);
g_sigact.sa_flags = 0;
sigaction(SIGINT, &g_sigact, (struct sigaction *)NULL);
sigaddset(&g_sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &g_sigact, (struct sigaction *)NULL);
sigaddset(&g_sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &g_sigact, (struct sigaction *)NULL);
sigaddset(&g_sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &g_sigact, (struct sigaction *)NULL);
sigaddset(&g_sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &g_sigact, (struct sigaction *)NULL);
sigaddset(&g_sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &g_sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig){
if (sig == SIGHUP) g_keepRunning = 0;
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if ((sig == SIGQUIT || (sig == SIGKILL) || (sig == SIGINT)) ;
}
static void dumpstack(void){
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
char dbx[160];
sprintf(dbx, "echo -ne 'detach\n' | gdb --eval-command=where --pid=%d > %d.dump", getpid(), getpid());
system(dbx);
return;
}
When a segmentation fault is trapped, dumpstack
gets invoked and prints the most recent stack-trace up to the point when it segmentation faulted and gets redirected to a file with a numeric pid of the process....
Why exactly do you not want to run gdb? You can detect the location of segfaults very easily if you use it.