0

I am writing an infrastructure code which should log backtrack of my crashed C program exactly as gdb does, but without using gdb specially. For that I have written a crash signal handler to log just before exitting.

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void crash_signal_handler(int sig) 
{
    void* backtrace_array[10];
    size_t size;
    char** symbols;

    size = backtrace(backtrace_array, 10);
    symbols = backtrace_symbols(backtrace_array, size);

    int fd = fileno(stdout);  // Use stdout file descriptor

    fprintf(stderr, "Program crashed. Backtrace:\n");
    backtrace_symbols_fd(backtrace_array, size, fd);

    free(symbols);
    exit(1);
}

int main() {
    signal(SIGSEGV, crash_signal_handler);
    //Intentionally trigger a segmentation fault for testing
    int* ptr = NULL;
    *ptr = 42;
}

However, its backtrace is no where similar to what we see in GDB when the program crashes, and we run bt command.

/home/ravi#  ./a.out 
Program crashed. Backtrace:
./a.out(crash_signal_handler+0x35)[0x55931304e27e]
/lib/x86_64-linux-gnu/libc.so.6(+0x43090)[0x7fbf3155f090]
./a.out(main+0x3a)[0x55931304e335]    -----> no line number shown, file name is also a.out it should be source file name where it crashed
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7fbf31540083]
./a.out(_start+0x2e)[0x55931304e18e]
/home/ravi#  

ideally it should show the line number and name of the source file like below

(gdb) r
Starting program: /home/root# a.out 

**Program received signal SIGSEGV, Segmentation fault.
0x000055555555513d in main () at sample.c:7
7       *ptr = 42;
(gdb) bt
#0  0x000055555555513d in main () at sample.c:7
(gdb)** q
A debugging session is active.

    Inferior 1 [process 1567493] will be killed.

Quit anyway? (y or n) y
/home/root#

Is there any way to update the code and achieve this? This will be helpful to debug the large source code based C program if it crashed in production environment.

Also, it is ok to write a signal handler to log to backtrack and add that feature in the production code? I know we can not permanently keep symbols in production code, but during testing phase it can be ok. Or anything better can be done ? Any suggestion are welcome.

  • 3
    See [this answer](https://stackoverflow.com/a/1925461/1983398), but you might want to consider creating core-files instead. – ssbssa Jun 21 '23 at 09:24

2 Answers2

1

If you want source line info (and source info), you'll need to take the addresses in the backtrace and look them up in the debug symbols in the executable. That's not easy to do, and will generally require invoking an external program like addr2line to do the heavy lifting.

You can find an open-source example here

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

For that I have written a crash signal handler to log just before exitting.

Note that neither backtrace, nor backtrace_symbols are async-signal safe.

Calling them from a SIGSEGV handler is bound to end in tears as soon as you crash due to heap corruption.

You will likely be much better off using libunwind, which at least aims to be async-signal safe.

You will then have to use async-signal-safe symbolizer to translate addresses into symbol names, and an async-signal-safe debuginfo decoder to translate these addresses into file/line info.

Writing either of these is very far from trivial.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362