GDB + OpenOCD Setup - Notes for Later
Here’s some instructions I’m writing to my future self on setting up GDB and OpenOCD. I don’t set up GDB and OpenOCD too frequently, so I want to leave myself a few breadcrumbs for the next time it happens. I probably wouldn’t have bothered in the first place if I hadn’t had issues connecting to the OpenOCD instance that st-util
hosts on this new Ubuntu machine. Lots of issues with flash loader support in the OSSW version of STLink, apparently.
In any case - here are some instructions for future me on setting up OpenOCD. I’m running Ubuntu 20.04 here, but it looks like results don’t vary widely across Linux distros.
Configure OpenOCD first
OpenOCD is the right place to start your setup. It’s what manages the physical connection between your computer and your microcontroller. You’ll want to do the typical installation song and dance:
$ sudo apt-get install openocd
And then you’ll want to start an openocd.cfg
file in your project directory.
You’ll want to leverage some of the built-in config files that are bundled with OpenOCD. As per the project setup guide, these files are located at /usr/share/openocd/scripts
on most Linux systems, and that’s where I was able to find them:
nreilly@banoodler:~/projects/bfunc/sw_embedded/bfunc_rev1$ ll /usr/share/openocd/scripts/
total 88
drwxr-xr-x 11 root root 4096 May 4 06:33 ./
drwxr-xr-x 5 root root 4096 May 4 06:33 ../
-rw-r--r-- 1 root root 1601 Feb 10 13:53 bitsbytes.tcl
drwxr-xr-x 2 root root 20480 May 4 06:33 board/
drwxr-xr-x 5 root root 4096 May 4 06:33 chip/
drwxr-xr-x 2 root root 4096 May 4 06:33 cpld/
drwxr-xr-x 3 root root 4096 May 4 06:33 cpu/
drwxr-xr-x 2 root root 4096 May 4 06:33 fpga/
drwxr-xr-x 3 root root 4096 May 4 06:33 interface/
-rw-r--r-- 1 root root 787 Feb 10 13:53 mem_helper.tcl
-rw-r--r-- 1 root root 4563 Feb 10 13:53 memory.tcl
-rw-r--r-- 1 root root 1648 Feb 10 13:53 mmr_helpers.tcl
drwxr-xr-x 2 root root 12288 May 4 06:33 target/
drwxr-xr-x 2 root root 4096 May 4 06:33 test/
drwxr-xr-x 2 root root 4096 May 4 06:33 tools/
Since we’re trying to establish a physical connection first thing, we want to first define an interface to the debugger and the microcontroller, so naturally, the interfaces
directory should be our first stop:
nreilly@banoodler:~$ ll /usr/share/openocd/scripts/interface/
total 136
drwxr-xr-x 3 root root 4096 May 4 06:33 ./
drwxr-xr-x 11 root root 4096 May 4 06:33 ../
-rw-r--r-- 1 root root 190 Feb 10 13:53 altera-usb-blaster2.cfg
-rw-r--r-- 1 root root 215 Feb 10 13:53 altera-usb-blaster.cfg
-rw-r--r-- 1 root root 96 Feb 10 13:53 arm-jtag-ew.cfg
-rw-r--r-- 1 root root 102 Feb 10 13:53 at91rm9200.cfg
-rw-r--r-- 1 root root 484 Feb 10 13:53 buspirate.cfg
-rw-r--r-- 1 root root 195 Feb 10 13:53 calao-usb-a9260.cfg
-rw-r--r-- 1 root root 115 Feb 10 13:53 chameleon.cfg
-rw-r--r-- 1 root root 218 Feb 10 13:53 cmsis-dap.cfg
-rw-r--r-- 1 root root 63 Feb 10 13:53 dummy.cfg
-rw-r--r-- 1 root root 75 Feb 10 13:53 estick.cfg
-rw-r--r-- 1 root root 331 Feb 10 13:53 flashlink.cfg
drwxr-xr-x 2 root root 4096 May 4 06:33 ftdi/
-rw-r--r-- 1 root root 268 Feb 10 13:53 jlink.cfg
-rw-r--r-- 1 root root 354 Feb 10 13:53 jtag_vpi.cfg
-rw-r--r-- 1 root root 258 Feb 10 13:53 nds32-aice.cfg
-rw-r--r-- 1 root root 84 Feb 10 13:53 opendous.cfg
-rw-r--r-- 1 root root 96 Feb 10 13:53 openjtag.cfg
-rw-r--r-- 1 root root 114 Feb 10 13:53 osbdm.cfg
-rw-r--r-- 1 root root 371 Feb 10 13:53 parport.cfg
-rw-r--r-- 1 root root 296 Feb 10 13:53 parport_dlc5.cfg
-rw-r--r-- 1 root root 1183 Feb 10 13:53 raspberrypi2-native.cfg
-rw-r--r-- 1 root root 991 Feb 10 13:53 raspberrypi-native.cfg
-rw-r--r-- 1 root root 155 Feb 10 13:53 rlink.cfg
-rw-r--r-- 1 root root 156 Feb 10 13:53 stlink-v1.cfg
-rw-r--r-- 1 root root 488 Feb 10 13:53 stlink-v2-1.cfg
-rw-r--r-- 1 root root 484 Feb 10 13:53 stlink-v2.cfg
-rw-r--r-- 1 root root 554 Feb 10 13:53 sysfsgpio-raspberrypi.cfg
-rw-r--r-- 1 root root 349 Feb 10 13:53 ti-icdi.cfg
-rw-r--r-- 1 root root 162 Feb 10 13:53 ulink.cfg
-rw-r--r-- 1 root root 1600 Feb 10 13:53 usb-jtag.cfg
-rw-r--r-- 1 root root 221 Feb 10 13:53 usbprog.cfg
-rw-r--r-- 1 root root 82 Feb 10 13:53 vsllink.cfg
I’m using an ST-Link V2 debug probe, so I’ll want the config file that maps to that probe: stlink-v2.cfg
. I add this as the first line to my openocd.cfg
file:
source [find interface/stlink-v2.cfg]
Then I call openocd
from the directory in which the file is locate. openocd
pulls in its configs from openocd.cfg
, and then promptly complains that additional settings are needed:
nreilly@banoodler:~/projects/bfunc/sw_embedded/bfunc_rev1$ openocd
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Error: An adapter speed is not selected in the init script. Insert a call to adapter_khz or jtag_rclk to proceed.
This is no big deal - openocd
needs some more info about the physical connection between the debugger and the target microcontroller. This is as simple as adding another line for the target MCU config, which you can find in the /usr/share/openocd/scripts/target
directory. I’m using an STM32F072 microcontroller, so I chose the stm32f0x.cfg
file, and added it to openocd.cfg
:
source [find interface/stlink-v2.cfg]
source [find target/stm32f0x.cfg]
Firing this up yields us the result we’re looking for - some debugger info, API versions, breakpoint info from the target chip, and even the voltage detected by the debugger. We’re in business!
nreilly@banoodler:~/projects/bfunc/sw_embedded/bfunc_rev1$ openocd
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v29 API v2 SWIM v7 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.237616
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
It’s worth pointing out that there’s a ton of useful information in stm32f0x.cfg
. It’s worth a quick perusal so you can see what’s happening at the debug protocol level. It will make you say a quiet “thank you” to the apps engineer who got it cranking for you.
Use gdb-multiarch
I originally tried installing arm-none-eabi-gdb
, but that’s apparently no longer needed thanks to gdb-multiarch
. I was able to install gdb-multiarch
the typical way:
$ sudo apt-get install gdb-multiarch
And then start a quick .gdbinit
script in the same project directory in which I stored openocd.cfg
.
file "./build/bfunc_rev1.elf"
target extended-remote :3333
load
break main
continue
This takes care of a few things for you:
file "./build/bfunc_rev1.elf"
loads up your symbol table, and helps you use friendly, human-readable function names when you’re debugging.target extended-remote :3333
tellsgdb-multiarch
that it’s connecting to a different CPU to debug.extended-remote
is a particular operating mode that allows GDB some flexibility in connecting to, and disconnecting from, the remote machine. The:3333
just specifies the port through which GDB talks to OpenOCD.load
takes care of loading the various memory sections of the target into GDB’s memory.break main
sets a breakpoint at themain
entry point of your C program. This can cause you some grief if you are trying to look at the early boot process that happens beforemain
is entered. I’ll need to figure out a clever way around this if I ever need to do bootloader stuff again.