Featured image of post GDB - Not an exhaustive guide

GDB - Not an exhaustive guide

A comprehensive guide to GDB (GNU Debugger) with essential commands and debugging techniques

Introduction

GDB (GNU Debugger) is a powerful debugging tool for programs written in C, C++, and other languages. This guide covers essential GDB commands and techniques for effective debugging.

Compilation for Debugging

To use GDB, compile your program with debugging information:

1
2
3
4
5
# Add -g flag for debugging information
g++ -g program.cpp -o program

# Optional: disable optimization for better debugging
g++ -g -O0 program.cpp -o program

Basic GDB Commands

Starting GDB

1
2
3
4
5
6
7
8
# Start GDB with a program
gdb program

# Start with core dump
gdb program core

# Attach to running process
gdb -p <PID>

Running and Stopping

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Start program execution
(gdb) run [args]
(gdb) r [args]

# Continue execution
(gdb) continue
(gdb) c

# Execute next line (step over)
(gdb) next
(gdb) n

# Step into function
(gdb) step
(gdb) s

# Step out of current function
(gdb) finish

# Execute until line number/function
(gdb) until <line_num>
(gdb) until <function>

Breakpoints

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Set breakpoint at function
(gdb) break function_name
(gdb) b function_name

# Set breakpoint at line
(gdb) break file:line
(gdb) b 45

# Set conditional breakpoint
(gdb) break file:line if condition
(gdb) b 45 if i == 100

# List breakpoints
(gdb) info breakpoints
(gdb) i b

# Delete breakpoint
(gdb) delete <breakpoint_num>
(gdb) d 1

# Enable/disable breakpoint
(gdb) enable <breakpoint_num>
(gdb) disable <breakpoint_num>

Examining State

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Print variable value
(gdb) print variable
(gdb) p variable

# Print array elements
(gdb) p array[0]@length
(gdb) p *array@length

# Print in different format
(gdb) p/x variable  # hex
(gdb) p/t variable  # binary
(gdb) p/c variable  # character

# Display variable (auto-update)
(gdb) display variable
(gdb) undisplay <display_num>

# Examine memory
(gdb) x/nfu addr
# n: number of units
# f: format (x,d,u,o,t,a,c,s,i)
# u: unit size (b,h,w,g)

Advanced Features

Watchpoints

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Watch variable for changes
(gdb) watch variable
(gdb) watch *pointer

# Watch expression
(gdb) watch expression

# Watch for reads
(gdb) rwatch variable

# Watch for reads/writes
(gdb) awatch variable

Backtrace and Frame Navigation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Show call stack
(gdb) backtrace
(gdb) bt

# Show detailed frame info
(gdb) info frame
(gdb) i f

# Select frame
(gdb) frame <number>
(gdb) f <number>

# Move up/down stack
(gdb) up
(gdb) down

Thread Debugging

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# List threads
(gdb) info threads

# Switch thread
(gdb) thread <thread_num>

# Apply command to all threads
(gdb) thread apply all bt

# Set break on all threads
(gdb) break file:line thread all

Practical Examples

Example 1: Debugging Segmentation Fault

1
2
3
4
5
6
// buggy.cpp
int main() {
    int* ptr = nullptr;
    *ptr = 42;  // Segmentation fault
    return 0;
}

Debugging session:

1
2
3
4
5
6
7
8
$ g++ -g buggy.cpp -o buggy
$ gdb buggy
(gdb) run
Program received signal SIGSEGV
(gdb) bt
#0 main () at buggy.cpp:3
(gdb) print ptr
$1 = 0x0

Example 2: Conditional Breakpoint

1
2
3
4
5
6
7
8
9
// loop.cpp
int main() {
    for(int i = 0; i < 1000; i++) {
        if(i * i > 5000) {
            // Break here when condition met
        }
    }
    return 0;
}

Debugging session:

1
2
3
4
5
(gdb) break 4 if i * i > 5000
(gdb) run
Breakpoint 1, main () at loop.cpp:4
(gdb) print i
$1 = 71

GDB TUI Mode

GDB’s Text User Interface provides a more visual debugging experience:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Start GDB in TUI mode
gdb -tui program

# Toggle TUI mode
(gdb) tui enable
(gdb) tui disable

# Switch layouts
(gdb) layout src      # source only
(gdb) layout regs     # registers and source
(gdb) layout asm      # disassembly

Best Practices

  1. Debugging Strategy:

    • Start with a hypothesis
    • Use appropriate breakpoints
    • Check variable values systematically
    • Keep track of program flow
  2. Performance:

    • Use conditional breakpoints judiciously
    • Remove unnecessary breakpoints
    • Consider watchpoints impact
  3. Core Dumps:

    • Enable core dumps: ulimit -c unlimited
    • Analyze crashes post-mortem
    • Save debugging sessions for reference

Common GDB Commands Cheat Sheet

Command Description Example
run Start program run arg1 arg2
break Set breakpoint break main
print Print value print variable
next Step over next
step Step into step
continue Continue execution continue
backtrace Show call stack bt
info Show information info breakpoints
watch Set watchpoint watch variable

Conclusion

GDB is an essential tool for C/C++ developers. While it has a steep learning curve, mastering these basic commands and techniques will significantly improve your debugging efficiency. Remember to compile with debugging symbols and use appropriate commands based on your debugging needs.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy