GDB Cheatsheet

Threads

Use this GDB reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Listing and Switching

gdb gives every thread a number in the current inferior and a global id.num identifier. The * marks the one your commands apply to.

(gdb) info threads
  Id   Target Id                        Frame
* 1    Thread 0x7ffff7d8a740 (LWP 4711) "prog" main () at prog.c:61
  2    Thread 0x7ffff7589640 (LWP 4712) "worker" __futex_abstimed_wait ()
  3    Thread 0x7ffff6d88640 (LWP 4713) "worker" poll () from /lib/libc.so.6

(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff7589640 (LWP 4712))]
#0  __futex_abstimed_wait_common64 () at futex-internal.c:57
(gdb) bt
CommandEffect
info threadslist every thread with its current frame
info threads 2 4-6only those thread numbers
thread Nswitch to thread N
thread 1.3thread 3 of inferior 1, the global form
thread name readername the current thread for readability
thread find workerfind threads whose name or target id matches a regex
p $_threadthe current thread number
p $_gthreadits global number
p $_inferior_thread_counthow many threads exist
info inferiorslist processes, not threads
inferior 2switch process, for a forked child

Selecting a thread changes what bt, info locals, p, and the registers refer to. Breakpoints stay global unless you scope them with thread N.

Running a Command on Every Thread

This is how you triage a hang or a deadlock. One command, every stack.

(gdb) thread apply all bt
(gdb) thread apply all -s bt          # skip threads where it errors
(gdb) thread apply all bt 6           # only 6 frames each, much shorter
(gdb) thread apply 2-5 p errno
(gdb) taas bt                         # short for thread apply all -s
(gdb) tfaas info locals               # thread apply all -s frame apply all -s
CommandExpands to
thread apply all CMDrun CMD in every thread
thread apply all -s CMDsame, silently skipping threads where it fails
taas CMDthread apply all -s CMD
tfaas CMDthread apply all -s frame apply all -s CMD
frame apply all CMDrun CMD in every frame of the current thread
# the one-liner that diagnoses most hangs
gdb -q -p 4711 -batch -ex "thread apply all bt full" > hang.txt

Read the output looking for two things: several threads blocked in pthread_mutex_lock, and which thread holds a lock while waiting on something else. taas bt 8 keeps the output short enough to actually read.

Freezing the Scheduler

By default a step in one thread lets the others run, so the program can stop somewhere else entirely. set scheduler-locking fixes the focus.

ModeBehavior
offany thread may run at any time
ononly the current thread runs when you resume, new threads are held at entry
stepacts like on while stepping, off for continue, until, finish
replayacts like on in replay mode, off otherwise, the default
(gdb) set scheduler-locking on      # nobody else moves while I step
(gdb) show scheduler-locking
(gdb) set schedule-multiple on      # resume all inferiors, not just this one
(gdb) set print thread-events off   # stop the create and exit chatter

scheduler-locking on makes stepping deterministic, and it also deadlocks you if the thread you are stepping waits on a lock another thread must release. The symptom is a next that never returns. Set it back to off and continue.

(gdb) b worker.c:40 thread 3        # only when thread 3 gets there
(gdb) watch counter thread 3        # hardware watchpoints only
(gdb) info breakpoints              # the thread scope shows in the What column

Non-Stop Mode

In the default all-stop mode every thread freezes at every stop. Non-stop mode stops only the thread that hit the event and leaves the rest running, which matters for a server you cannot afford to pause.

# in .gdbinit, this must be set before the program runs
set non-stop on
(gdb) continue&         # resume in the background, prompt comes back
(gdb) interrupt         # stop the current thread only
(gdb) interrupt -a      # stop every thread
(gdb) info threads      # running threads show "(running)"
(gdb) thread 4
(gdb) bt

Non-stop mode has to be enabled before running or attaching. In non-stop mode continue resumes only the current thread, and every execution command takes the & suffix to run in the background so you keep the prompt.

Fork and Exec

SettingValuesEffect
set follow-fork-modeparent (default), childwhich side gdb follows
set detach-on-forkon (default), offoff keeps both under gdb
set follow-exec-modesame (default), newreuse the inferior or make a new one
catch fork / catch vfork / catch exec—stop at the event itself
(gdb) set follow-fork-mode child
(gdb) set detach-on-fork off
(gdb) run
(gdb) info inferiors
  Num  Description       Connection           Executable
* 1    process 4711      1 (native)           /home/me/prog
  2    process 4718      1 (native)           /home/me/prog
(gdb) inferior 1                # go back to the parent
(gdb) detach inferior 2

With detach-on-fork off both processes stay stopped under gdb, so a parent that would normally wait on its child now sits still while you inspect the child. That is the setup for debugging a fork plus exec server, and it is also how you accidentally hang a program that expects its child to finish quickly.

For a daemon that double-forks past you, it is usually easier to let it start and attach to the final pid than to follow it through two forks.