Introduction

I’m in the position that I have to debug a program that is running alongside multiple other programs which emulate portions of the complete system so that you can run tests on a desktop PC. That means I can’t just start the program from the command line and be done with it: everything is started in proper order by a script. It’s not possible to inject a debugger into the middle of that process without disturbing it, so I have to attach the debugger after the process is already running - which I had never done before. That means I get to document something new that I’ve learned!

FYI, these steps are for Linux.

Basic Concept

At its simplest, all you need to do to use gdb on an already running program is use the -p command line option like this:

gdb -p

But there’s a difficulty: you need the PID (Process ID) which is a number. On Linux, you can get this with ps:

ps -aux

That produces output that looks something like this:

      PID    PPID    PGID     WINPID   TTY         UID    STIME COMMAND
      198     162     198      27012  pty0      197609 21:36:06 /usr/bin/ps
      162     161     162      24660  pty0      197609 21:35:52 /usr/bin/bash
      161       1     161       6984  ?         197609 21:35:52 /usr/bin/mintty

That’s output from ps on git bash on Windows. On Linux it will be different, but fundamentally you’re looking for the PID so that you can use it with gdb.

Of course, the program that you’re attempting to debug must be compiled with the proper switches to allow for debugging or this won’t work.

Scripting gdb

One of the nice aspects of gdb is that you can avoid having to type all the commands that you want to use by putting them in a text file and passing it to gdb on the command line. This is very useful when you’re attaching to a running process because you may want to catch some transient behavior. You can do this with the -x command line:

gdb -x gdb_cmds.txt

gdb_cmds.txt needs only be a text file that contains the commands you want to execute in gdb.

Catching Program Startup

If you want to catch some startup behavior of your program you’ll need to generate a script that’s looking for the process to start to catch the pid and then immediately start gdb. I’ve used a bash script to do this, and below is a distillation of one that I’ve used before:

# Loop until ps shows the program running and grab the pid

while [ -z "$pid" ] ; do
    pid=$(ps -aux | grep -v grep | grep <program name> | tr -s ' ' | cut-d' ' -f 2)
	sleep .5
done

gdb -p "$pid" -x gdb_cmds.txt

Obviously ‘program name’ is the name of your program. You can adjust the sleep to be more responsive if you need to catch the program doing something at startup. The big ol’ command that assigns the pid variable is processing the output of ps to find the program and massage it to return only the pid number. You can also use the gdb_cmds.txt file to immediately upon startup set a breakpoint in your desired location and then start the program executing immediately - keep in mind that gdb will halt the program when it attaches to it. This may be undesirable if your program needs to communicate with anything that isn’t halted by a debuger.