Essential GDB Commands Reference
Automate repetitive setup with .gdbinit and master the core command set — free linux kernel development course
Typing set sysroot ... every single time you start a debug session gets old fast. This lecture in our free embedded systems course shows how to automate that setup with GDB command files, then walks through the command set you’ll reach for constantly: breakpoints, stepping, and inspection commands — finishing with a real walkthrough of running a program to its first meaningful breakpoint.
Keywords
What You Will Learn
- How GDB loads command files, and in what order
- Why recent GDB versions refuse to auto-load a local
.gdbinit, and how to override it safely - The core breakpoint, stepping, and information commands you’ll use every session
- A real “running to main()” walkthrough over a remote gdbserver session
Prerequisites
- Completed the previous lecture on connecting GDB and gdbserver, including sysroot setup
- A working remote debug session (network or serial) to practice against
GDB Command Files
Some setup — sysroot, breakpoints you always want, custom print formats — needs to happen at the start of every single session. Rather than retyping it, put those commands in a text file and let GDB read it automatically. GDB looks for startup commands in this order:
$HOME/.gdbinit— your personal, global defaults.gdbinitin the current working directory — per-project overrides- Any file passed explicitly with the
-xcommand-line option
Modern GDB refuses to auto-load a .gdbinit from the current directory by default, purely as a security precaution — a malicious project could otherwise ship a .gdbinit that runs arbitrary commands the moment you open GDB inside it. You can allow a specific directory by adding a line like this to your global $HOME/.gdbinit:
add-auto-load-safe-path /home/dev/projects/ep_sensor/.gdbinit
Or disable the check entirely (not recommended on a shared or multi-user machine):
set auto-load safe-path /
A cleaner habit for day-to-day work is to skip auto-loading altogether and pass the file explicitly with -x, which has the side benefit of reminding you exactly which command file is in effect:
$ arm-linux-gnueabihf-gdb -x ep_debug.gdbinit ./ep_sensor_reader
A typical project command file bundles your sysroot and a starting breakpoint:
# ep_debug.gdbinit
set sysroot /home/dev/buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot
target remote 192.168.1.50:2345
break main
Both Yocto and Buildroot can also generate a starter file for you automatically — Buildroot, for instance, writes a ready-made sysroot command to output/staging/usr/share/buildroot/gdbinit that you can copy into your own project file rather than typing the path from memory.
Breakpoint Commands
| Command | Shorthand | What it does |
|---|---|---|
break <location> | b <location> | Set a breakpoint on a function name, line number, or file:line (e.g. main, 42, sensor.c:42) |
info break | i b | List all current breakpoints |
delete break <N> | d b <N> | Delete breakpoint number N |
Running and Stepping Commands
| Command | Shorthand | What it does |
|---|---|---|
run | r | Load a fresh copy and start execution — does not work in a remote gdbserver session |
continue | c | Resume execution from a breakpoint |
Ctrl-C | — | Interrupt/pause the running program |
step | s | Execute one source line, stepping into any function called |
next | n | Execute one source line, stepping over function calls |
finish | — | Run until the current function returns |
Information Commands
| Command | Shorthand | What it does |
|---|---|---|
backtrace | bt | List the current call stack |
info threads | — | List all threads in the program |
info libs | — | List shared libraries loaded and their symbol status |
print <variable> | p <variable> | Print the current value of a variable, e.g. p raw_adc |
list | — | Show source lines around the current program counter |
Hands-On: Running to a Breakpoint Remotely
When gdbserver loads a program, it stops execution at the very first CPU instruction — before the C runtime has even set up the environment for main(). If you try to single-step immediately at that point, GDB complains:
(gdb) step
Cannot find bounds of current function
That message is expected, not a bug — the program counter is sitting in hand-written startup assembly with no source mapping. The fix is to set a breakpoint on main() and continue past the startup code rather than stepping through it instruction by instruction:
(gdb) break main
Breakpoint 1 at 0x104a4: file ep_sensor_reader.c, line 12.
(gdb) continue
Continuing.
Breakpoint 1, main (argc=1, argv=0xbefffe14) at ep_sensor_reader.c:12
12 printf("Starting sensor reader\n");
If at this point you instead see a warning like this:
warning: Could not load shared library symbols for 2 libraries,
e.g. /lib/libc.so.6.
it means you skipped set sysroot from the previous lecture — go back and set it before continuing, or the rest of the session will be missing shared library symbol information.
Common Mistakes and Troubleshooting
- Typing
runin a remote session — either errors immediately or hangs silently on older GDB; usebreak main+continueinstead. - Single-stepping before main() — produces “Cannot find bounds of current function”; set a breakpoint on
mainand continue past the startup assembly. - Auto-load refused — a local
.gdbinitsilently not loading is a security feature, not a bug; use-xoradd-auto-load-safe-path. - Forgetting the shorthand forms exist — muscle memory for
b,c,s,n,bt,pspeeds up every session considerably.
Best Practices
- Keep a per-project
.gdbinitwith sysroot and the connection command pre-baked, loaded explicitly with-x. - Set a breakpoint on
main()as your default first move in every remote session, rather than trying to step from the very first instruction. - Use
info breakperiodically in long sessions to keep track of accumulated breakpoints you may have forgotten about.
Summary and Key Takeaways
- GDB loads
$HOME/.gdbinit, then a local.gdbinit(if explicitly allowed), then any-xfile — use-xfor reliable, visible project setup. - Breakpoints (
break/b), stepping (step/next/continue), and inspection (print/backtrace/list) form the core toolkit for every session. - gdbserver halts at the very first instruction — always set a breakpoint on
main()andcontinuerather than stepping from the start.
Conclusion
With command files handling the repetitive setup and the core command set under your fingers, remote debugging stops feeling like a chore and starts being just another tool in the workflow. The next lecture in this free linux development course moves from applications to the trickier territory of shared libraries, source path resolution, attaching to already-running processes, and debugging forks and threads.
FAQ
Why won’t GDB load the .gdbinit in my project folder?
Recent GDB versions block auto-loading a local .gdbinit as a security measure. Either add it to your global add-auto-load-safe-path list or load it explicitly with gdb -x file.gdbinit.
What’s the difference between step and next?
step follows execution into any function call on the current line; next executes the whole call as one step and stays at the current level, which is usually what you want unless you specifically need to debug inside that function.
Why do I get Cannot find bounds of current function right after connecting?
gdbserver halts the program at its very first CPU instruction, in startup assembly with no source mapping. Set a breakpoint on main and continue instead of stepping immediately.
Can I put breakpoints in my .gdbinit file?
Yes — a line like break main works exactly the same inside a command file as typed interactively, and is one of the most common things people automate.
Is set auto-load safe-path / safe to use?
It disables a security check meant to stop a malicious project’s .gdbinit from running arbitrary commands. It’s fine on a personal single-user machine but not recommended on shared systems.
Continue the Free Linux Kernel Development Course
Next: debugging shared libraries and locating source code for GDB.
Browse All Lectures Join EmbeddedPathashala
2 Comments