Home » Testing and Debugging » Mastering GDB Debugging: How to Set and Manage Breakpoints Effectively

Mastering GDB Debugging: How to Set and Manage Breakpoints Effectively

Debugging is a crucial part of software development. Whether you’re fixing bugs, testing, or optimizing your code, debugging tools like the GNU Debugger (GDB) can significantly improve your efficiency. One of GDB’s most powerful features is its ability to set breakpoints. Breakpoints allow developers to pause a program’s execution at specific points and analyze its state, making it easier to track down problems. In this post, we’ll cover everything you need to know about setting different breakpoints in GDB to effectively debug your programs.

What are Breakpoints in GDB?

A breakpoint is a marker that tells GDB to stop the program execution at a particular line of code. When the program hits the breakpoint, you can inspect variables, memory, and the overall program state. This helps in isolating and identifying issues in your code.

GDB offers different types of breakpoints, such as:

  1. Line Breakpoints: Stop at a specific line of code.
  2. Function Breakpoints: Stop at the beginning of a function.
  3. Conditional Breakpoints: Stop only when a specific condition is true.
  4. Watchpoints: Stop when a variable changes its value.
  5. Hardware Breakpoints: Used for low-level debugging.

lets assume we have helloworld as ARM ELF binary, then start gdb

$ arm-linux-gnueabihf-gcc -g -c -o helloworld_src/add.o helloworld_src/add.c

$ arm-linux-gnueabihf-gcc -g -o helloworld helloworld_src/helloworld.c helloworld_src/add.o  -static

Run the qemu ARM in one terminal as,

$ qemu-arm -L gcc-arm-none-eabi-10-2020-q4-major/lib -g 8090 ./helloworld

On second terminal start GDB

$ arm-none-eabi-gdb
(gdb) target remote:8090

Let’s walk through these breakpoint types and learn how to set them up.


1. Setting a Line Breakpoint

A line breakpoint stops the execution of the program at a specific line. This is the most basic type of breakpoint.

Example:
Suppose you have the following simple C code:

#include <stdio.h>

int main() {
    int a = 5;
    int b = 10;
    int result = a + b;
    printf("Result: %d\n", result);
    return 0;
}

To set a breakpoint at line 5 (where the variable result is calculated):

(gdb) break 5
Breakpoint 1 at 0x40053a: file main.c, line 5.

Now, when you run the program in GDB, it will stop at line 5, and you can inspect the values of variables a, b, and result.

Another example of Set Breakpoint using Line Number

You can set breakpoints using line number of the source code in that file, for that you must compile your binary with debugging symbols enabled, which we did using “-g” with gcc.

Check the line numbers of the source file using “li” gdb command as,

gdb) li
warning: Source file is more recent than executable.
1	#include <stdio.h>
2	
3	extern int add_two_numbers(int, int);
4	
5	int main(int argc, char **argv) {
6		int num = 0;
7		printf("helloworld\n");
8		num = add_two_numbers(3, 2);
9		printf("addition: %d\n", 3+2);
10		return 0;
(gdb) 
11	}
(gdb) 

Now, lets say you want to set breakpoint at line number 8, the type “break 8” or simply “br 8” to set breakpoint using line number i.e. “break line_number”

(gdb) br 8
Breakpoint 1 at 0x1043c: file helloworld_src/helloworld.c, line 9.
(gdb) c
Continuing.

Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:9
9		printf("addition: %d\n", 3+2);

As you can see, it set the breakpoint at the next valid statement on line number 9 and our program stopped at that line number after we pressed c i.e. continue.


2. Setting a Function Breakpoint

Sometimes, you may want to stop execution whenever a specific function is called. You can do this by setting a function breakpoint.

Example:

(gdb) break main
Breakpoint 2 at 0x40053a: file main.c, line 4.

This will pause the program when it reaches the main() function. Function breakpoints are useful for debugging larger programs where specific functions are key areas of interest.

Another example of Set Breakpoint at main

(gdb) break main
Breakpoint 1 at 0x1042e: file helloworld_src/helloworld.c, line 6.
(gdb) c
Continuing.

Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:6
warning: Source file is more recent than executable.
6		int num = 0;

3. Setting a Conditional Breakpoint

A conditional breakpoint stops the program only when a specified condition is true. This is helpful when you’re interested in debugging only under certain conditions, rather than pausing the program every time it hits the breakpoint.

Example:

(gdb) break 5 if a == 5

In this example, the program will stop at line 5 only if the value of a is 5.


4. Using Watchpoints

A watchpoint is a special type of breakpoint that stops the program whenever the value of a specific variable changes. This is useful for tracking down bugs where the root cause may be an unexpected change in a variable’s value.

Example:

(gdb) watch a
Watchpoint 3: a

The program will now stop whenever the value of a changes.


5. Setting Hardware Breakpoints

While most breakpoints in GDB are software breakpoints, GDB also allows you to set hardware breakpoints, which are especially useful in embedded systems or low-level debugging. These breakpoints are set directly in the CPU’s hardware, allowing for faster debugging without modifying the code in memory.

To set a hardware breakpoint:

(gdb) hbreak 5

This sets a breakpoint at line 5 using hardware instead of software.


Setting Breakpoint using Memory Address

First, we need to check the memory address using objdump as,

$ arm-linux-gnueabihf-objdump -D helloworld > helloworld_objdump.txt

then, we can check the address of main and code inside by reading from helloworld_object.txt as

00010424 <main>:
   10424:       b580            push    {r7, lr}
   10426:       b084            sub     sp, #16
   10428:       af00            add     r7, sp, #0
   1042a:       6078            str     r0, [r7, #4]
   1042c:       6039            str     r1, [r7, #0]
   1042e:       2300            movs    r3, #0
   10430:       60fb            str     r3, [r7, #12]
   10432:       4b08            ldr     r3, [pc, #32]   ; (10454 <main+0x30>)
   10434:       447b            add     r3, pc
   10436:       4618            mov     r0, r3
   10438:       f008 fc90       bl      18d5c <_IO_puts>
   1043c:       2105            movs    r1, #5
   1043e:       4b06            ldr     r3, [pc, #24]   ; (10458 <main+0x34>)
   10440:       447b            add     r3, pc
   10442:       4618            mov     r0, r3
   10444:       f004 faac       bl      149a0 <_IO_printf>
   10448:       2300            movs    r3, #0
   1044a:       4618            mov     r0, r3
   1044c:       3710            adds    r7, #16
   1044e:       46bd            mov     sp, r7
   10450:       bd80            pop     {r7, pc}
   10452:       bf00            nop
   10454:       00039950        andeq   r9, r3, r0, asr r9
   10458:       00039950        andeq   r9, r3, r0, asr r9

As we can see above, we have a code where its printing using printf, and address is, 0x00043c , so we can set the breakpoint at this address using “star zero x” and then address as,

(gdb) br *0x0001043c
Breakpoint 1 at 0x1043c: file helloworld_src/helloworld.c, line 9.

Now, if we do continue, we can see our program stopped just before printf,

(gdb) c
Continuing.

Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:9
warning: Source file is more recent than executable.
9		printf("addition: %d\n", 3+2);

Managing Breakpoints

Once you’ve set several breakpoints, you may want to list, disable, or remove them.

  • List all breakpoints:
  (gdb) info breakpoints

This will show you all the breakpoints you have set.

  • Disable a breakpoint (without deleting it):
  (gdb) disable 1
  • Remove a breakpoint:
  (gdb) delete 1
  • Re-enable a breakpoint:
  (gdb) enable 1

These commands help you manage your breakpoints during long debugging sessions, making it easier to toggle on and off as needed.


Why Use Breakpoints in GDB?

Breakpoints allow you to pause the execution of your program and inspect its state at any given moment. This gives you deeper insights into what your program is doing behind the scenes and helps you quickly identify issues like incorrect variable values or unexpected control flow.

Debugging without breakpoints can be like searching for a needle in a haystack, especially in larger projects. By using breakpoints effectively, you can narrow down issues faster and with more precision.


Setting different types of breakpoints in GDB is essential for effective debugging. By learning how to use line, function, conditional, and watch breakpoints, you can gain more control over the debugging process, saving time and improving the quality of your code. Whether you are tracking down a tricky bug or optimizing your program, breakpoints will always be your best friend in GDB.

Start using breakpoints today and see how much faster and more efficient your debugging process can become.

Leave a Comment