How to Generate System Stack Trace?

Following is the definition of backtrace by GNU,

“A backtrace is a list of the function calls that are currently active in a thread.”

We can examine backtrace of a process by external debugger like gdb. We have following functions to get backtrace of process. Following is the code to print back trace if segmentation fault occurs.

int backtrace (void **buffer, int size):

This function gets backtrace of calling process.

char ** backtrace_symbols (void *const *buffer, int size)

This function translates information obtained from backtrace function into symbols.

void backtrace_symbols_fd (void *const *buffer, int size, int fd)

This function translates information obtained from backtrace function into symbols and writes this information to given file descriptor.

For details of above functions please check following link.
http://ftp.gnu.org/pub/old-gnu/Manuals/glibc-2.2.3/html_chapter/libc_33.html

http://www.linuxjournal.com/article/6391

We can print backtrace in signal handler for a specific signal like SIGSEGV.

A process can handle all signals except SIGKILL (09) and SIGSTOP (19).You may send SIGKILL from a process to other process.  To catch a signal, a process has to register  some function with signal number. On catching the signal, registered function is called. If no function is registered, kernel will take default action for signal.

For signals of all processes please check following link

http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html

#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <execinfo.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
char *sig[] = {“SIGHUP”/*for hangup*/,”SIGINT” /*TERMINAL INTERRUPT*/,
“SIGQUIT”/*Terminal quit*/, “SIGILL”/*Illegal instruction*/,
“SIGTRAP”/*trap*/, “SIGIOT”/*4.2 BSD*/,
“SIGBUS”/*4.2 BSD*/, “SIGFPE”/*Floating point exception*/,
“SIGKILL”/*kill that can’t be caught by process*/, “SIGUSR1″/*user defined signal*/,
“SIGSEGV”/*Invalid memory segment access*/, “SIGUSR2″/*user defined signal 2*/,
“SIGPIPE”/*broken pipe*/, “SIGALRM”/*alarm*/,
“SIGTERM”/*termination*/, “SIGSTKFLT”/*Stack Fault*/,
“SIGCHLD”/*Child process has stopped, exited, changed*/, “SIGCONT”/*Continue executing if stopped*/,
“SIGSTOP”/*that can’t be caught by process*/, “SIGTSTP”/*TERMINAL STOP signal*/,
“SIGTTIN”/*Background Process trying to read TTY*/, “SIGTTOU”/*Background Process trying to write TTY*/,
“SIGURG”/*urgent condition to socket 4.2 BSD */, “SIGXCPU”/*CPU limit exceed 4.2 BSD*/,
“SIGXFSZ”/*FILE SIZE limit exceed 4.2 BSD*/, “SIGVTALRM”/*Virtual Alarm Clock 4.2*/,
“SIGPROF”/*Profiling alarm clock 4.2 BSD*/, “SIGWINCH”/*Window size changed 4.3BSD, SUN*/,
“SIGIO”/*I/O  possible*/, “SIGPWR”/*power failure restart System V*/,
};

void print_btrace(void)
{
void *trace[50];
int tsize, counter;
char **buffer;
// get backtrace of process
tsize = backtrace(trace, 50);
//get back trace symbolsl
buffer = backtrace_symbols(trace, tsize);
if (buffer == NULL)
{
perror(“backtrace_symbols”);
return;
}
for (counter = 0; counter < tsize; counter++)
printf(“%s\n”, buffer[counter]);
//release memeory
free(buffer);
}

void print_btrace_infile(void)
{
void *trace[50];
int fd, tsize;
// opwn file in the same directory with permission 0700.
fd = open(“backtrace”, O_CREAT|O_WRONLY, S_IRWXG);
// get backtrace of process
tsize = backtrace(trace, 50);
// get symbols of process and write it to fd.
backtrace_symbols_fd(trace, tsize, fd);
//clsoe fd
close(fd);
}

void sighandler(int signum)
{
printf(“Process %d got signal %s\n”, getpid(), sig[signum – 1]);
signal(signum, SIG_DFL);
//print back trace
print_btrace();
//print back trace in file
print_btrace_infile();
kill(getpid(), signum);
}
void wait_for_signal(void)
{
printf(“Process %d waits for signal\n”,getpid());
while(1);
}
int main()
{
// register functiosn for signal handler.
signal(SIGSEGV, sighandler);
signal(SIGILL, sighandler);
signal(SIGTRAP, sighandler);
signal(SIGTERM, sighandler);
signal(SIGFPE, sighandler);
signal(SIGTSTP, sighandler);
signal(SIGSTOP, sighandler);// never be caught. just to confirm 19
signal(SIGKILL, sighandler);// never be caught. just to confirm 11
wait_for_signal();
return 0;
}
Compilation:
$ gcc -Wall -rdynamic backtrace.c  –o btrace.exe
For SIGSEGV:
$ ./btrace.exe
Process 3265 waits for signal
Now run following commands in other terminal
$ ps -ef|grep a.out
adam   3265  2554 95 03:43 pts/1    00:00:01 ./btrace.exe
$ kill -11 3265
Process 3265 got signal SIGSEGV
./ btrace.exe (print_btrace+0x1a) [0x8048842]
./ btrace.exe (sighandler+0x41) [0x80489d6]
/lib/tls/libc.so.6 [0x2dda48]
./ btrace.exe (main+0xb1) [0x8048acc]
/lib/tls/libc.so.6(__libc_start_main+0xe3) [0x2cae33]
./ btrace.exe [0x80487a1]

Segmentation fault
Now check file in same directory “backtrace”. this file will also have same backtrace.

Be Sociable, Share!

Leave a Reply