39

I'm wondering if it's possible to launch an application via GDB, on a SegFault write the backtrace to a file (to look at later), and then exit GDB all without any user input.

I'm running an application from a shell script in an infinite loop (so if it crashes it reloads) on OS boot from a non-interactive session. The application is crashing in a non-reproducible way so I need a backtrace from the crash to debug the issue. Ideally, I'd just modify the shell script to include the GDB debugging + backtracing functionality and preserve the automatic restarting of the application following a crash.

Is this possible to do?

Matt Razza
  • 3,524
  • 2
  • 25
  • 29
  • 2
    http://www.commandlinefu.com/commands/view/4039/print-stack-trace-of-a-core-file-without-needing-to-enter-gdb-interactively – A. K. Nov 24 '13 at 18:32
  • 2
    Can you not enable core files on your system and get the backtrace that way? It seems a lot easier than a gdb loop. – Mark B Nov 24 '13 at 18:41
  • `so I need a backtrace from the crash to debug the issue.` - I have not found an answer why you cannot analyze a core file from a crash? Is it because it is quite big? –  Nov 25 '13 at 18:09

4 Answers4

47

Thanks to Aditya Kumar; acceptable solution:

gdb -batch -ex "run" -ex "bt" ${my_program} 2>&1 | grep -v ^"No stack."$

If the program needs arguments:

gdb -batch -ex "run" -ex "bt" --args ${my_program} param1 param2 \
                              param3 ... 2>&1 | grep -v ^"No stack."$
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Matt Razza
  • 3,524
  • 2
  • 25
  • 29
3
gdb --batch -q <debuged_executable> <core_file> -ex bt  
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
brane
  • 585
  • 6
  • 20
  • 1
    This needs `-ex run` too. Also, `-q` is not necessary with `-batch`. From `man dgb`, section `-q`: *»These messages are also suppressed in batch mode.«* – Socowi Aug 29 '21 at 09:56
2

This works with gdb 7.6:

My test program that causes a core dump if it is given a command line parameter:

int a(int argc)
{
  if (argc > 1) {
    int *p = 0;
    *p = *p +1;
    return  *p;
  }
  else {
    return 0;
  }
}

int b(int argc)
{
  return a(argc);
}

int main(int argc, char *argv[])
{
  int res = b(argc);
  return res;
}

My python script my_check.py:

def my_signal_handler (event):
  if (isinstance(event, gdb.SignalEvent)):
    log_file_name = "a.out.crash." + str(gdb.selected_inferior().pid) + ".log"
    gdb.execute("set logging file " + log_file_name )
    gdb.execute("set logging on")
    gdb.execute("set logging redirect on")
    gdb.execute("thread apply all bt")
    gdb.execute("q")

gdb.events.stop.connect(my_signal_handler)
gdb.execute("set confirm off")
gdb.execute("set pagination off")
gdb.execute("r")
gdb.execute("q")

So, first I run a.out and there is no crash. No log files are created:

gdb -q -x my_check.py --args ./a.out >/dev/null

Next I run a.out and give it one parameter:

>gdb -q -x my_check.py --args ./a.out 1 >/dev/null

And this is a crash report:

>cat a.out.crash.13554.log

Thread 1 (process 13554):
#0  0x0000000000400555 in a (argc=2) at main.cpp:5
#1  0x000000000040058a in b (argc=2) at main.cpp:15
#2  0x00000000004005a3 in main (argc=2, argv=0x7fffffffe198) at main.cpp:20
1

Alternatively to just storing the backtrace, you could put ulimit -c unlimited in front of your infinite loop in your shell script. The result will be that every time your program segfaults, it will write a core dump into a file which on my system is just called core but on other systems might include the process id. If the program segfaults (you see this from its exit status being equal to 139) then just move the core file to a safe location using a unique name (for example using timestamps). With these core files and gdb you can then do even more than just look at the backtrace. Thus I guess using them might even be more useful to you.

josch
  • 6,716
  • 3
  • 41
  • 49