Its great if your program runs as expected but what if it doesn't? It may crash or return an error when you least expect. Breakpoints are a great way to stop the execution of your code so you can inspect how you got a certain place in your code and with what state. There are two primary ways I use breakpoints:

  1. to stop when a function is called.
  2. to stop at a particular line of code.

Once stopped, we can use backtrace and the Micro Trace Buffer to see our current state and how we got there.

If the steps below don't work, make sure you compiled your binary with symbols. (-ggdb for gcc)


To add a breakpoint where you want it to stop use break. For example, to break at the function mp_hal_stdin_rx_chr in CircuitPython you would type:

(gdb) break mp_hal_stdin_rx_chr
Breakpoint 1 at 0x1730c: file mphalport.c, line 141.

If you want to break close to a particular source code line you can give the filename and line number instead. For example, with file mphalport.c and line 150 it'd be:

(gdb) break mphalport.c:150
Breakpoint 2 at 0x1739a: file mphalport.c, line 150.

Breaking by line can get fuzzy if you enabled optimizations while compiling because the compiler may rework the underlying machine code for efficiency and inadvertantly mix code for different source lines. With GCC, you can make sure and compile with -O0 (letter O and zero) to disable optimizations.

Once you add a breakpoint the program will be stopped there everytime its reached. To view the existing breakpoints do:

(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x0001730c in mp_hal_stdin_rx_chr at mphalport.c:141
2       breakpoint     keep y   0x0001739a in mp_hal_stdin_rx_chr at mphalport.c:150

To delete a single breakpoint, such as 1:

(gdb) delete 1

To delete all breakpoints:

(gdb) delete


We'll cover how to inspect state in just a bit but lets just reiterate how to get back going. As before, if you want to load a new version (hopefully fixed) you can do:

(gdb) load
(gdb) monitor reset init
(gdb) continue

(No init with JLink.)

If you just want to keep going you can simply do:

(gdb) continue

Additionally if you just want to go another little bit you can do:

  • step executes one more source code line and goes into functions
  • next executes one more source code line but skips going into functions
  • finish executes until the function finishes

More info about control is here.

Last updated on Aug 11, 2017 Published on Oct 12, 2016