Debugging with gdb – CMPSC 311 Lecture
Debugging: Purpose & Context
Debugging = locating, understanding, and removing faults in software.
Frequently the most complicated and time-consuming activity in development.
Goal: discover where real program behaviour diverges from intended behaviour and correct it.
Continuous process: confirm the program is actually "doing what you think it is doing".
First-Line Techniques
Printing / Logging
Insert temporary output statements to reveal values/state.
Example (C):
printf("My variable value is %d", myvar);Pros: quick, works everywhere.
Cons: intrusive, must be removed or disabled later, produces large output, limited visibility.
## Assertions (Logic / Program Guards)
Provided by C via
#include <assert.h>.Syntax:
assert(expression);– program aborts ifexpressionis false.Enforces contractual assumptions about inputs, return values, pointer validity, etc.
Typical uses:
assert(i >= 0);– non-negative loop/index.assert(ptr != NULL);– pointer validity.assert((ptr = malloc(100)) != NULL);– allocation succeeded.assert(func(10,20));– boolean function returned true/non-zero.Active only when compiled without
-DNDEBUG; they disappear in release builds, so never place side-effects inside.
Demonstration Code (Factorial)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int factorial(int i) {
assert(i >= 0);
if (i <= 1) return i;
return factorial(i-1) * i;
}
int main(int argc, char **argv) {
int i = 5;
if (argc > 1) i = atoi(argv[1]);
printf("Factorial of %d: %d\n", i, factorial(i));
return 0;
}
Compile with symbols:
gcc -g debugging.c -o debugging.Sample runs:
./debugging→Factorial of 5: 120./debugging 4→Factorial of 4: 24./debugging -1→ assertion failure (stops at runtime).
Mathematical definition enforced by the code: n! = n \times (n-1)! with base case 0! = 1 (here coded as \le 1).
The Debugger Environment
A debugger executes the target program in a controlled sandbox where you can:
Start/attach, halt, resume, step through code/instructions.
Inspect or modify state (registers, memory, variables, environment).
Automate via conditions & scripts.
Linux/Unix mainstream: GNU gdb. (Apple & LLVM world: lldb).
Launching gdb
Terminal:
gdb <program>(does not start the program yet).Can also be integrated into editors/IDEs, e.g., Emacs → Tools → Debugger (GDB).
Basic prompt features:
helporhelp <command>– built-in manual.Tab-completion, command abbreviations (e.g.,
lforlist).
Running the Program
run(aliasr) actually begins execution.Pass arguments exactly as on shell:
r 12.
After normal termination gdb prints [Inferior … exited normally] and drops back to prompt.
Inspecting Source
list(aliasl) shows 10 source lines surrounding a locus.list 4– centered around line 4 of current file.list main– shows function main.
Breakpoints
Pause execution at specified locations.
Set:
break <function>orbreak <line>— aliasb.Delete:
delete <num>ord.Each breakpoint auto-numbered; visible with
info breakpoints.
Conditional Breakpoints:
Add condition later:
cond <bp#> <expr>.Inline:
b <loc> if <expr>.Example:
b 7→ Breakpoint 1 at line 7.cond 1 i<=1— only stops wheni <= 1.
Saving / Restoring:
save breakpoints <file>– writes gdb commands.source <file>– re-load their definitions.
Watchpoints (Data Breakpoints)
Trigger when a variable’s value changes, independent of code location.
watch <variable>.Hardware vs software implementation; may be limited in number.
Example flow:
(gdb) watch i (gdb) continue Hardware watchpoint 2: i Old value = 5 New value = 4
Stack & Frames
where(aliasbacktrace/bt) – full call stack with line numbers.up,down– navigate frames.p iprints localiin current frame.Use to inspect callers/callees during recursion.
Examining Data
Printing Variables
print <var>orpshows value in default format.Format override:
p/<fmt> <var>where fmt is one of:ooctal,xhex,dsigned dec,uunsigned dec,tbinary,ffloat,aaddress,iinstruction,sstring.Example outputs:
p/x values→{0x1, 0x2, 0x3, 0x4}p/f val2→2.45678.
## Examining Raw Memory
Command:
x/[num][fmt][size] <address>.[num]= repeat count,[fmt]= print code as above,[size]=b(1),h(2),w(4),g(8 bytes).Examples:
x buf(default word/hex):0xefefefef.x/8xb buf– 8 bytes, hex byte-wise:ef ef ef ef ef ef ef ef.x/xg buf– one 8-byte giant word.x &buf– show pointer stored in stack variablebuf.
Stepping Through Execution
Four primary flow-control commands (all can be abbreviated):
next(n) – executes the current source line; does not enter called functions.step(s) – executes current line and does enter called functions.continue(c) – resumes until next breakpoint, watchpoint, or program exit.finish(fin) – continues until current function returns, then stops in caller.
Integrated Example Walk-Through
Workflow summary using factorial program:
Set breakpoints before run:
(gdb) b factorial(gdb) b 20(line inmain)
(gdb) run 3– program stops atmain’s breakpoint.(gdb) continue– runs tofactorialbreakpoint.Use
n,s,cto step/descend/continue through recursive calls.Observe
where,p i,up/downto watch changing argument values.Confirm expected output
Factorial of 3: 6, program exits normally.
Compiler & Build Considerations
Always compile with debug symbols for full gdb power:
gcc -g ....Optimisation (
-O2,-O3) may reorder/remove code → stepping looks odd; turn it off during heavy debugging or accept discrepancies.Assertion removal with
-DNDEBUGmay shift line numbers; keep assertions enabled while debugging.
Connections & Practical Implications
Printing/logging & assertions provide front-line defense and lightweight sanity checks even after release.
Symbolic debuggers (gdb/lldb) deliver:
Fine-grained control → faster root-cause identification vs printf-spamming.
Reproducibility: breakpoints/watchpoints scripts create deterministic sessions.
Ethical & professional obligation: deliver robust, well-tested code; knowledge of debugging tools is essential.
Real-world relevance: techniques apply to low-level OS dev, embedded systems, performance tuning, security analysis (reverse engineering uses same stack/backtrace methods).
Quick gdb Command Reference (Cheat Sheet)
Startup & Help
gdb prog,help,quit.
Execution
run [args],attach <pid>,kill.
Breakpoints
b <loc>,cond <bp#> <expr>,d <bp#>,info b,save breakpoints.
Watchpoints
watch <expr>,rwatch(read),awatch(access).
Flow
n,s,c,fin,until <loc>.
Stack
where,bt,frame,up,down.
Data
p[/fmt] expr,set var <expr> = <value>,x/[nfmt][size] addr.
Source
list,disassemble.
Misc
info <topic>,set pagination off,display expr(auto-print each stop).
These bullet-style notes compile every key detail from the lecture slides and transcripts, offering a stand-alone study reference for CMPSC 311’s unit on debugging and gdb usage.