π― Learn to trace, inspect, and fix C programs like a professional using the gdb tool.
π§ What is gdb?
gdb (GNU Debugger) is a powerful tool that lets you:
β Pause execution of a program
β Inspect variables and memory
β Step through code line-by-line
β Set breakpoints at any point
β Trace bugs like segmentation faults
It's essential for C programmers β especially for runtime errors like crashes, invalid memory access, and logic bugs.
π§° Getting Started with gdb
π οΈ Step 1: Compile with g flag
β Purpose:
The -g flag tells the compiler to include debugging information in the compiled binary (myprogram). This debugging info maps source code lines to machine instructions, including:
Variable names
Line numbers
Function boundaries
Stack frames
π Why It's Important:
Without -g, the binary will run, but gdb wonβt be able to give meaningful debugging information like variable values or exact source code lines.
This includes debugging information in the executable:
gcc -g program.c -o programπ Without -g, gdb wonβt show variable names or source code lines.
π Step 2: Launch gdb
β Purpose:
This launches the GNU Debugger with your compiled binary (myprogram). In this interactive tool, you can:
Set breakpoints at specific lines or functions
Step through code line-by-line (
next,step)Inspect variables and memory
View the call stack when crashes or errors occur
Find segmentation faults and other bugs
gdb ./programThis will open an interactive terminal prompt like:
(gdb)π§Ύ Resultant Outcome:
Action | Outcome |
|---|---|
Compile with | Creates a binary with full debug symbols |
Launch | Opens a debugging environment |
Set breakpoints | Pauses execution at desired points to inspect program state |
Step execution | Helps you trace code logic, loops, and function calls line-by-line |
Inspect variables | See the actual values of variables at runtime |
Crash detection | Find exact location of segmentation faults, buffer overflows, etc. |
π Final Outcome:
Using these steps, you gain fine-grained control over your program's execution and can diagnose even complex bugs effectively. It turns your compiled program into an interactive, debuggable environment.
π§ Common gdb Commands (Must Know)
π οΈ Command | π‘ Purpose |
|---|---|
| Starts executing your program |
| Sets a breakpoint at the |
| Sets a breakpoint at line number 15 |
| Runs next line (without entering functions) |
| Steps into functions line-by-line |
| Continues execution until next breakpoint |
| Prints the value of variable |
| Lists source code lines |
| Shows the function call stack |
| Exits gdb |
π― Sample Debugging Workflow
Letβs debug this simple C program with a bug:
<div class="infographic-cgdb">
<style>
.infographic-cgdb {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--code-bg: #1e1e2e;
--code-text: #d4d4e0;
--syn-keyword: #c586c0;
--syn-func: #dcdcaa;
--syn-string: #ce9178;
--syn-comment: #6a9955;
--err: #e2695f;
--err-soft: #3a1f1d;
}
.infographic-cgdb[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--code-bg: #0d0d14;
--code-text: #d4d4e0;
}
.infographic-cgdb {
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
background: var(--paper);
color: var(--ink);
font-family: 'Inter', -apple-system, sans-serif;
padding: 0 clamp(1rem, 4vw, 2.25rem) 1.25rem;
}
.infographic-cgdb *, .infographic-cgdb *::before, .infographic-cgdb *::after {
box-sizing: border-box;
}
.infographic-cgdb h1 {
font-family: 'Fraunces', Georgia, serif;
font-weight: 600;
font-size: clamp(1.3rem, 3.5vw, 1.6rem);
margin: 1.25rem 0 0.2rem;
text-align: center;
}
.infographic-cgdb .subhead { color: var(--ink-soft); font-size: 0.82rem; margin-bottom: 1rem; text-align: center; }
.infographic-cgdb .code-panel {
background: var(--code-bg);
color: var(--code-text);
border-radius: 8px;
padding: 0.55rem 0;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.74rem;
line-height: 1.55;
margin-bottom: 0.8rem;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.infographic-cgdb .code-line {
display: flex;
white-space: pre;
padding: 0 0.7rem;
transition: background 0.3s, box-shadow 0.3s;
}
.infographic-cgdb .code-line .ln { color: var(--ink-soft); width: 1.6rem; flex-shrink: 0; text-align: right; margin-right: 0.6rem; }
.infographic-cgdb .code-line.is-current {
background: rgba(91, 141, 239, 0.22);
box-shadow: inset 3px 0 0 var(--accent);
}
.infographic-cgdb .code-line.is-crash {
background: var(--err-soft, rgba(226,105,95,0.18));
box-shadow: inset 3px 0 0 var(--err);
}
.infographic-cgdb .syn-keyword { color: var(--syn-keyword); }
.infographic-cgdb .syn-func { color: var(--syn-func); }
.infographic-cgdb .syn-string { color: var(--syn-string); }
.infographic-cgdb .locals-row {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 0.9rem;
flex-wrap: wrap;
}
.infographic-cgdb .local-chip {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.75rem;
padding: 0.3rem 0.6rem;
border-radius: 6px;
border: 1px solid var(--line);
background: var(--paper-alt);
color: var(--ink-soft);
transition: border-color 0.3s, background 0.3s, color 0.3s;
}
.infographic-cgdb .local-chip.is-known { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.infographic-cgdb .term {
background: var(--code-bg);
color: var(--code-text);
border-radius: 8px;
padding: 0.7rem 0.9rem;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.76rem;
line-height: 1.55;
white-space: pre-wrap;
min-height: 9rem;
max-height: 13rem;
overflow-y: auto;
margin-bottom: 0.9rem;
}
.infographic-cgdb .term .prompt { color: #7fdb8a; }
.infographic-cgdb .term .crash-line { color: var(--err); font-weight: 700; }
.infographic-cgdb .controls { display: flex; justify-content: center; gap: 0.5rem; }
.infographic-cgdb .ctrl-btn {
all: unset; cursor: pointer;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.8rem; font-weight: 600;
padding: 0.45rem 1rem;
border-radius: 999px;
background: var(--accent);
color: #fff;
}
.infographic-cgdb .ctrl-btn:hover { opacity: 0.88; }
.infographic-cgdb .ctrl-btn:disabled { opacity: 0.5; cursor: default; }
.infographic-cgdb .ctrl-btn.secondary { background: var(--paper-alt); color: var(--ink); border: 1px solid var(--line); }
.infographic-cgdb .takeaway {
font-size: 0.82rem; color: var(--ink-soft);
margin-top: 1.3rem; border-top: 1px solid var(--line); padding-top: 0.9rem;
}
.infographic-cgdb .takeaway strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-cgdb * { transition: none !important; }
}
</style>
<h1>π οΈ Stepping Through gdb</h1>
<p class="subhead">Click through the exact same session, command by command.</p>
<div class="code-panel" id="gdb-code">
<span class="code-line" data-ln="1"><span class="ln">1</span><span>#include <stdio.h></span></span>
<span class="code-line" data-ln="2"><span class="ln">2</span><span> </span></span>
<span class="code-line" data-ln="3"><span class="ln">3</span><span><span class="syn-keyword">int</span> <span class="syn-func">divide</span>(<span class="syn-keyword">int</span> a, <span class="syn-keyword">int</span> b) {</span></span>
<span class="code-line" data-ln="4"><span class="ln">4</span><span> <span class="syn-keyword">int</span> result = a / b;</span></span>
<span class="code-line" data-ln="5"><span class="ln">5</span><span> <span class="syn-keyword">return</span> result;</span></span>
<span class="code-line" data-ln="6"><span class="ln">6</span><span>}</span></span>
<span class="code-line" data-ln="7"><span class="ln">7</span><span> </span></span>
<span class="code-line" data-ln="8"><span class="ln">8</span><span><span class="syn-keyword">int</span> <span class="syn-func">main</span>() {</span></span>
<span class="code-line" data-ln="9"><span class="ln">9</span><span> <span class="syn-keyword">int</span> x = 10;</span></span>
<span class="code-line" data-ln="10"><span class="ln">10</span><span> <span class="syn-keyword">int</span> y = 0;</span></span>
<span class="code-line" data-ln="11"><span class="ln">11</span><span> <span class="syn-keyword">int</span> z = <span class="syn-func">divide</span>(x, y);</span></span>
<span class="code-line" data-ln="12"><span class="ln">12</span><span> <span class="syn-func">printf</span>(<span class="syn-string">"Result: %d\n"</span>, z);</span></span>
<span class="code-line" data-ln="13"><span class="ln">13</span><span> <span class="syn-keyword">return</span> 0;</span></span>
<span class="code-line" data-ln="14"><span class="ln">14</span><span>}</span></span>
</div>
<div class="locals-row">
<span class="local-chip" id="loc-x">x = ?</span>
<span class="local-chip" id="loc-y">y = ?</span>
<span class="local-chip" id="loc-a">a = ?</span>
<span class="local-chip" id="loc-b">b = ?</span>
</div>
<div class="term" id="gdb-term"></div>
<div class="controls">
<button class="ctrl-btn" id="gdb-next">βΆ Next command</button>
<button class="ctrl-btn secondary" id="gdb-restart">β² Restart</button>
</div>
<p class="takeaway"><strong>step</strong> goes inside a function call; <strong>next</strong> runs it as one unit. Use step when you need to see what's happening inside divide() β which is exactly how you'd catch b = 0 before the crash.</p>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-cgdb')
|| document.querySelector('.infographic-cgdb');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
function $(sel) { return wrapper.querySelector(sel); }
const codeLines = wrapper.querySelectorAll('.code-line[data-ln]');
const term = $('#gdb-term');
const nextBtn = $('#gdb-next');
const restartBtn = $('#gdb-restart');
const locX = $('#loc-x'), locY = $('#loc-y'), locA = $('#loc-a'), locB = $('#loc-b');
function highlightLine(ln, crash) {
codeLines.forEach(l => {
l.classList.remove('is-current', 'is-crash');
if (l.dataset.ln === String(ln)) l.classList.add(crash ? 'is-crash' : 'is-current');
});
}
function setLocal(el, val) {
el.textContent = el.id.slice(4) + ' = ' + val;
el.classList.add('is-known');
}
function appendTerm(cmd, output, isCrash) {
const cmdLine = '<span class="prompt">(gdb)</span> ' + cmd;
const outLine = isCrash ? '<span class="crash-line">' + output + '</span>' : output;
term.innerHTML += (term.innerHTML ? '\n' : '') + cmdLine + (output ? '\n' + outLine : '');
term.scrollTop = term.scrollHeight;
}
const STEPS = [
{ cmd: 'break main', out: 'Breakpoint 1 at 0x1149: file buggy.c, line 9.' },
{ cmd: 'run', out: 'Starting program: /home/user/buggy \n\nBreakpoint 1, main () at buggy.c:9\n9\t int x = 10;', line: 9 },
{ cmd: 'next', out: '10\t int y = 0;', line: 10, setLocal: () => setLocal(locX, 10) },
{ cmd: 'next', out: '11\t int z = divide(x, y);', line: 11, setLocal: () => setLocal(locY, 0) },
{ cmd: 'print x', out: '$1 = 10' },
{ cmd: 'print y', out: '$2 = 0' },
{ cmd: 'step', out: 'divide (a=10, b=0) at buggy.c:4\n4\t int result = a / b;', line: 4, setLocal: () => { setLocal(locA, 10); setLocal(locB, 0); } },
{ cmd: 'print a', out: '$3 = 10' },
{ cmd: 'print b', out: '$4 = 0' },
{ cmd: 'next', out: '\nProgram received signal SIGFPE, Arithmetic exception.\n0x0000555555555149 in divide (a=10, b=0) at buggy.c:4\n4\t int result = a / b;', line: 4, crash: true }
];
let idx = 0;
function runStep() {
if (idx >= STEPS.length) return;
const s = STEPS[idx];
appendTerm(s.cmd, s.out, s.crash);
if (s.line) highlightLine(s.line, s.crash);
if (s.setLocal) s.setLocal();
idx++;
if (idx >= STEPS.length) {
nextBtn.disabled = true;
nextBtn.textContent = 'β Session complete';
}
}
function restart() {
idx = 0;
term.innerHTML = '';
highlightLine(null, false);
[locX, locY, locA, locB].forEach(el => { el.textContent = el.id.slice(4) + ' = ?'; el.classList.remove('is-known'); });
nextBtn.disabled = false;
nextBtn.textContent = 'βΆ Next command';
}
nextBtn.addEventListener('click', runStep);
restartBtn.addEventListener('click', restart);
restart();
})();
</script>Youβll now clearly see where and why it crashed: division by zero.
π¬ Advanced gdb Features
watch xPauses program execution whenever variable x is modified.
break 20 if x > 100Breaks only if the condition is true β powerful for loops or large input cases.
π If your program crashes and generates a core dump file:
gdb ./program coreThis helps post-mortem analysis β you can inspect the exact line and variable states at crash time.
β οΈ gdb vs printf Debugging
β
Use | π§ Use |
|---|---|
You want to see quick variable output | Program crashes unexpectedly |
Code is simple & small | You need to step through logic flow |
For beginner tracing | Deep memory/pointer issues involved |
π§ͺ Bonus: gdb Shortcuts
π Alias | π Meaning |
|---|---|
| next |
| step |
| continue |
| quit |
| backtrace |
| print variable |
π Real-World Debugging with gdb
Scenario: A program crashes on user input.
Steps:
Compile with
gReproduce the crash under
gdbUse
break,step,print, andbacktraceLocate null pointer or logic flaw
Fix the source, recompile, retest!