Skip to content

Debug the boards with GDB

This section requires the embedXcode+ edition and a board with a built-in or with an optional external hardware debugger compatible with GDB.

This section applies for all the boards compatible with GDB, using a proprietary or open-source driver like MSPDebug, Texane ST-Link or OpenOCD .

For more information about GDB,

For more information about the drivers,

Configure specific boards

Some boards require a specific hardware or software configuration before debugging.

Platform Board Debugger
Adafruit Feather nRF52832 and nRF52840 Segger J-Link
  Feather M0 and M4 Segger J-Link
Arduino Arduino Due Segger J-Link
  Arduino M0 Pro Built-in
Espressif ESP32 ESP-Prog
LaunchPad LaunchPad CC3200 WiFi Built-in
Seeeduino Xiao M0 Segger J-Link

Configure the LaunchPad CC3200 WiFi

The LaunchPad CC3200 WiFi requires a specific hardware configuration.

  • Unplug the LaunchPad CC3200 WiFi board.

  • Remove the wire from JTAG J8 (emulator side) to SOP 2 (CC3200) side.

  • Place the TCK J8 jumper.

  • Place the SOP 2 jumper.

Debugging requires TCK and SOP 2 jumpers placed on

  • Plug the LaunchPad CC3200 WiFi board.

The project is uploaded into SRAM and is lost in case the power is disconnected. For more information,

  • Please refer to Upload to LaunchPad CC3200 WiFi.

The Segger J-Link provides a JTAG 2x10 2.54 mm 0.1" connector while the Adafruit Feather nRF52832 and nRF52840 feature a 2x5 1.27 mm 0.05" SWD connector.

The Adafruit Feather nRF52832 only provisions the pads, but the SWD connector needs to be soldered.

The Segger J-Link Edu mini provides the same 2x5 1.27 mm 0.05" SWD connector as the Adafruit Feather nRF52840.

  • Just use the 10-way flat cable provided with the Segger J-Link Edu mini.

If the software suite for the Segger J-Link isn't installed,

Because the Adafruit Feather nRF52 boards run on FreeRTOS, J-Link requires specific plug-ins. Ozone manages FreeRTOS better than the command-line J-Link utility and is thus strongly recommended.

The Adafruit Feather M0 exposes the SWD signals through SWCLK and SWDIO pads and the Adafruit Feather M4 through a 2x5 0.05" connector.

Cables and pins should be soldered to connect the Segger J-Link programmer-debugger.

Example of SWD implementation for the Feather M4 board, front and rear

For more information on how to prepare the boards,

The Segger J-Link provides a JTAG 2x10 2.54 mm 0.1" connector while the Arduino Due features a 2x5 1.27 mm 0.05" SWD connector.

If the software suite for the Segger J-Link isn't installed,

Arduino Due, SWD to JTAG adaptor, Segger J-Link

The Seeeduino Xiao M0 exposes the SWD signals through SWCLK and SWDIO pads.

Cables and pins should be soldered to connect the Segger J-Link programmer-debugger.

For more information,

Select the USB Port for the Arduino M0 Pro

  • Connect the USB cable to the Programmer USB Port is order to perform debugging. The native USB port doesn't feature debugging.

  • Use the USB Programming port

Connect the ESP-Prog to the ESP32 board

The ESP-Prog provides a PROG 2x3 2.54 mm 0.1" connector and a JTAG 2x5 2.54 mm 0.1" connector.

  • Ensure OpenOCD for ESP32 has been installed. Otherwise, follow the procedure Install the OpenOCD driver for ESP32 .

  • Follow the table at Configure Other JTAG Interface and connect power +3.3V and Ground, JTAG TMS, TDI, TCK, TDO and RESET, serial TXD and RXD pins of the board to the corresponding pins of the ESP-Prog programmer-debugger.

  • Open a Terminal and launch the command

% sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver

This command prevents macOS from enumerating all the ports of the ESP-Prog programmer-debugger as serial ports.

  • Connect the external programmer to the USB port.

In case the following message is displayed on the serial console,

Brownout detector was triggered
  • Power the ESP32 board through the +5V pin instead of the +3.3V pin.

The ESP32 board requires up to 400 mA and may exceed what a standard USB port can deliver.

  • Power the ESP32 board with an external power supply.

At the end of the session,

  • Open a Terminal and launch the command
% sudo kextload -b com.FTDI.driver.FTDIUSBSerialDriver

This command allows macOS to automatically enumerate all the ports as serial ports again.

To check whether the FTDI driver is loaded,

  • Open a Terminal and launch the command
% kextstat | grep FTDI

For more information on the ESP-Prog,

For more information on debugging the ESP32,

Accept incoming connection

For the Arduino M0 Pro board, some of the utilities used for debugging may prompt a window for authorisation.

  • Click on Allow to proceed.

Some Segger J-Link debug probes can power the board directly and re-route a serial console.

Some Segger J-Link debug probes can power the board with +5 V (300mA maximum, pin 19), while the logic level is set through VTref (target reference voltage, pin 1).

  • On the main Makefile, set the variable JLINK_POWER to 1.
JLINK_POWER = 1

For more information,

Additionally, some Segger J-Link debug probes feature VCOM and re-route a serial console through J-Link Tx (pin 5) and J-Link RX (pin 17).

This feature is only valid with SWD and is disabled by default. To enable it,

  • Connect the Segger J-Link debug probe.

  • Launch JLinkConfig.

  • Select the debug probe and call the contectual menu Configure.

  • Click on Enable below Virtual COM-Port, then on OK.

  • Power-cycle the debug probe.

Alternatively,

  • Open a Terminal window,

  • Launch the following commands after the J-Link> prompt.

% JLinkExe

J-Link>vcom enable
The new configuration applies after power cycling the debug probe.

J-Link>exit

If the probe has the serial number 123456789, the serial port is re-routed to /dev/tty.usbmodem000123456789.

  • Just open a Terminal window and launch the follwing command with the correct speed.
% screen /dev/tty.usbmodem000123456789 9600

To disable it,

  • Proceed as before, but select Disable below Virtual COM-Port instead.

Alternatively,

  • Open a Terminal window,

  • Launch the following commands after the J-Link> prompt.

% JLinkExe

J-Link>vcom disable
The new configuration applies after power cycling the debug probe.

J-Link>exit

For more information,

Launch a debugging session

Before launching a debugging session, select the connection, either though a USB cable or over-the-air through WiFi or Ethernet over USB.

To launch a debugging session,

  • Select the Debug target and press Run.

Some boards require the entire project to be built with specific parameters. For example, the Adafruit Feather nRF52840 needs optimisation turned off and additional low-level libraries. For those boards,

  • Select the Clean target and press Run.

  • Select the Debug target and press Run.

embedXcode builds and links the project, uploads it to the board, open a first Terminal window for the serial console, and then opens two Terminal windows for debugging.

Identify two Terminal windows

The first Terminal window hosts the server. The server connects to the board and answers the requests from the debugger.

The second Terminal window is the client, actually the active debugger. It downloads all the breakpoints defined previously and starts running the project.

The client can't run without a valid server.

Run and stop the sketch execution

Here are the most common commands to run, stop and continue the execution of the sketch in a debugging session:

  • Enter the commands after the (gdb) prompt and validate it by pressing the Enter key.
(gdb) 

When the debugger stops,

  • Type continue or c to continue till the next breakpoint.
(gdb) continue
(gdb) c

To run the sketch one step to the next line of code to be executed, including the sub-functions called by the current function,

  • Type step or simply s.
(gdb) step
(gdb) s

To run the sketch to the next line of the current function, without stopping at the sub-functions,

  • Type next or simply n.
(gdb) next
(gdb) n

To repeat the last entered command,

  • Press Enter.

To stop the sketch,

  • Press Ctrl+C.

To list the breakpoints defined and loaded,

  • Type info break.
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x000044b2 in loop() at embed1.ino:115
    breakpoint already hit 2 times
        silent
        printf "i = %d\n",i
        echo Blink\n
2       breakpoint     keep y   0x00004468 in blink(uint8_t, uint8_t, uint16_t) at LocalLibrary.cpp:25
    breakpoint already hit 2 times
(gdb)

For more information about the GDB commands,

Perform common debugging tasks

Change the value of a variable

To get the value of a variable,

  • Type the command print and the name of the variable.
(gdb) print i
$1 = 7 '\a'

To change the value of a variable,

  • Type first the command set variable or set var, then the name of the variable and the = sign, and finally the new value.
(gdb) set var i = 4
(gdb) print i
$2 = 4 '\004'

Display the registers

To display the registers,

  • Type the command info registers or i r.
(gdb) info registers
r0             0x20002708   536880904
r1             0x20002708   536880904
r2             0x0  0
r3             0x200026f8   536880888
r4             0x651    1617
r5             0xffffffff   -1
r6             0xffffffff   -1
r7             0xffffffff   -1
r8             0xffffffff   -1
r9             0xffffffff   -1
r10            0xffffffff   -1
r11            0xffffffff   -1
r12            0x0  0
sp             0x20002f20   0x20002f20
lr             0x637    1591
pc             0x652    0x652 <loop()+2>
xPSR           0x61000000   1627389952

The example above comes from the MSP432P401R.

To display all the registers,

  • Type the command info all-registers or i all-r.

Display the call stack

To display the stack of the calls,

  • Type the command backtrace or bt.
(gdb) backtrace
#0  blink (pin=43 '+', times=2 '\002', ms=500) at LocalLibrary.cpp:25
#1  0x000044c8 in loop () at embed1.ino:115
#2  0x0000444e in main () at main.cpp:164

The blink() function is called by the function loop(), and loop() is called by the main function main().

The backtrace command also provides the details of the parameters and values passed by loop() on to blink().

Here, values are pin=43, times=2, ms=500.

(gdb) print RED_LED
$1 = 43 '+'

Value 43 does correspond to constant RED_LED.

Display specific layouts

To enable GDB Text User Interface with a layout for source,

  • Type the command layout src or tui enable.
(gdb) layout src
(gdb) tui enable

The resulting screen displays

   ┌──LocalLibrary.cpp─────────────────────────────────────────────────────────┐
   │22          // Code                                                        │
   │23          void blinkLED(uint8_t pin, uint8_t times, uint16_t ms, bool lev│
   │24          {                                                              │
   │25              for (uint8_t i = 0; i < times; i++)                        │26              {                                                          │
B+>27                  digitalWrite(pin, level ? HIGH : LOW);                 │28                  delay(ms >> 1);                                        │29                  digitalWrite(pin, level ? LOW : HIGH);                 │30                  delay(ms >> 1);                                        │31              }                                                          │
   │32          }                                                              │
   │                                                                           │
   │                                                                           │
   └───────────────────────────────────────────────────────────────────────────┘
extended-r Remote target In: blinkLED                       L27   PC: 0x800022e 
(gdb) 

To display a layout for assembler,

  • Type the command layout asm.
(gdb) layout asm

The resulting screen displays

 ┌───────────────────────────────────────────────────────────────────────────┐
>0x8000236 <blinkLED(unsigned char, unsigned char, unsigned short, bool)+30>
 0x8000238 <blinkLED(unsigned char, unsigned char, unsigned short, bool)+32>
 0x800023c <blinkLED(unsigned char, unsigned char, unsigned short, bool)+36>
 0x800023e <blinkLED(unsigned char, unsigned char, unsigned short, bool)+38>
 0x8000240 <blinkLED(unsigned char, unsigned char, unsigned short, bool)+40>
 0x8000244 <blinkLED(unsigned char, unsigned char, unsigned short, bool)+44>
 0x8000246 <blinkLED(unsigned char, unsigned char, unsigned short, bool)+46>
 0x800024a <blinkLED(unsigned char, unsigned char, unsigned short, bool)+50>
 0x800024c <blinkLED(unsigned char, unsigned char, unsigned short, bool)+52>
 0x800024e <blinkLED(unsigned char, unsigned char, unsigned short, bool)+54>
 0x8000252 <initVariant()>                                                  
 0x8000254 <premain()>                                                      
 0x8000256 <premain()+2>                                                    
 └───────────────────────────────────────────────────────────────────────────┘
extended-r Remote target In: blinkLED                       L28   PC: 0x8000236 
(gdb) 

To display also the registers,

  • Type the command layout regs.
(gdb) layout regs

The resulting screen displays

┌──Register group: general─────────────────────────────────────────────────────┐
│r0             0x5                 5                                          │
│r1             0x1d                29                                         │
│r2             0x21                33                                         │
│r3             0x200001f8          536871416                                  │
│r4             0x0                 0                                          │
│r5             0x0                 0                                          │
└──────────────────────────────────────────────────────────────────────────────┘
B+>0x80002b0 <loop()+16>   ldr    r0, [pc, #28]   ; (0x80002d0 <loop()+48>)   │0x80002b2 <loop()+18>   movs   r3, #1                                      │
   │0x80002b4 <loop()+20>   ldrb   r0, [r0, #0]                                │
   │0x80002b6 <loop()+22>   movw   r2, #333        ; 0x14d                     │0x80002ba <loop()+26>   movs   r1, #3                                      │
   │0x80002bc <loop()+28>   bl     0x8000218 <blinkLED(unsigned char, unsigned │
   └───────────────────────────────────────────────────────────────────────────┘
extended-r Remote target In: loop                           L130  PC: 0x80002b0 
(gdb) 

For more information on the GDB Text User Interface,

Get help

To display the help,

  • Type the command help or h.
(gdb) help
List of classes of commands:

aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands

Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.

End and quit a debugging session

To end and quit the debugging session,

  • On the client window, type monitor shutdown to close the server.
(gdb) monitor shutdown
shutdown command invoked
(gdb) 
  • On the client window, type quit or simply q or press ctrl-D, and confirm by y.
(gdb) quit

(gdb) q
A debugging session is active.

    Inferior 1 [Remote target] will be killed.

Quit anyway? (y or n) y

If the server hasn't already been terminated,

  • On the server window, press Ctrl+C to stop the server.
Info : halted: PC: 0x00000422
Info : dropped 'gdb' connection
^C

$
  • Always quit and close the two Terminal windows: the active debugging session and the server session.

End and quit a debugging session on the Intel Edison board

On the Intel Edison board, terminating the debugging session closes the remote server.

  • On the client window, type quit or simply q or press ctrl-D, and confirm by y.
(gdb) quit
(gdb) q
A debugging session is active.

    Inferior 1 [process 376] will be killed.

Quit anyway? (y or n) y

    Inferior 1 [Remote target] will be killed.

Quit anyway? (y or n) y

The client automatically stops the remote server.

Process /home/root/Projects/e_edison_yocto/embeddedcomputing created; pid = 376
Listening on port 1234
Remote debugging from host 192.168.1.14
Killing all inferiors
*** Done
  • Always quit and close the two Terminal windows: the active debugging session and the server session.