Hi all, I'm facing a really frustrating issue: I am trying to run under debug one of the
pico-examples projects, specifically the
hello_uart.c example.
Now, I've got two debug probes in front of me:
- A Pi Pico that is flashed with the latest picoprobe binary, using the latest freshly-built openocd that is specific for the picoprobe
- A J-Link Edu mini
The Picoprobe works without a hitch: The J-Link does not. The J-Link can load the binary, single step for a bit, but it very quickly throws a HardFault exception, which I'm having real trouble debugging.
The point at which the HardFault is thrown appears to not be consistent.
Judging from the internet (and SEGGER's own website) this should work without a hitch, so I'm fairly confident I'm doing something wrong - the only trouble is, as far as I can tell, I'm doing everything by the book - would love if someone more experienced with debug probes would suggest something.
The (working) Picoprobe OpenOCD flowNow, as the title says, the OpenOCD -> picoprobe flow works perfectly. The flow works like this:
1). Open terminal A (MSYS2), and invoke
$ openocd-install/bin/openocd.exe \
-f openocd-install/share/openocd/scripts/interface/cmsis-dap.cfg \
-f openocd-install/share/openocd/scripts/interface/picoprobe.cfg -f openocd-install/share/openocd/scripts/target/rp2040.cfg
The server then duly responds:
Open On-Chip Debugger 0.11.0-g8e3c38f78 (2023-02-11-21:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Warn : Interface already configured, ignoring
adapter speed: 5000 kHz
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E66118604B1F5E21
Info : CMSIS-DAP: SWD Supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
2). Open terminal B (cmd.exe), and open GDB:
C:\Users\Maxim\prj\pi-pico-blah>arm-none-eabi-gdb.exe pico-examples-build-debug\uart\hello_uart\hello_uart.elf
Connect to the OpenOCD GDB server interface on port 3333:
(gdb) tar extended-remote :3333
Load the binary:
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x4200 lma 0x10000100
Loading section .rodata, size 0xfa0 lma 0x10004300
Loading section .binary_info, size 0x20 lma 0x100052a0
Loading section .data, size 0x22c lma 0x100052c0
Start address 0x100001e8, load size 21740
Transfer rate: 4 KB/sec, 3623 bytes/write.
(gdb)
Now, I can run the program to completion
(gdb) c
Continuing.
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000138 msp: 0x20041f00
Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
_exit (status=0)
at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_runtime/runtime.c:186
186 __breakpoint();
(gdb)
(It is expected for us to end up in
_exit, since the
main() function in this case returns after printing some text.)
The (non-working) J-Link flowThe J-Link tools however are constantly throwing HardFaults all over the place. I've tried using two tools:
I'm using the latest J-Link as of writing (version 7.84f DLLs, and version 3.28c for Ozone.)
Here is what a typical J-Link GDB server session looks like:
First, setup the server:

After launching:

This time ofcourse I don't have to open a separate OpenOCD terminal. In cmd.exe, I open the GDB client exactly the same way, exactly the same binary:
C:\Users\Maxim\prj\pi-pico-blah>arm-none-eabi-gdb.exe pico-examples-build-debug\uart\hello_uart\hello_uart.elf
And attach to the port as specified by the J-Link GDB server (port 2331):
(gdb) tar extended-remote :2331
Remote debugging using :2331
__breakpoint ()
at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_platform/include/pico/platform.h:269
269 __asm__("bkpt #0");
(gdb)
Ok, fine. I should specify at this point: I have not powered off the Pi Pico under debug: I've literally hot-swapped the SWD connectors from the Picoprobe over to the J-Link. Nothing has been power cycled. (Actually, reading this back: it *is* weird that it reports a different source line...)
So now I load the binary:
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x4200 lma 0x10000100
Loading section .rodata, size 0xfa0 lma 0x10004300
Loading section .binary_info, size 0x20 lma 0x100052a0
Loading section .data, size 0x22c lma 0x100052c0
Start address 0x100001e8, load size 21740
Transfer rate: 732 KB/sec, 3623 bytes/write.
All the numbers exactly the same, fine. Now I just continue:
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0xfffffffe in ?? ()
And there it is. We don't end up in
_exit as last time, but in a reset vector of some kind? (showing my ignorance here.)
Listing the backtrace gives
(gdb) bt
#0 0xfffffffe in ?? ()
#1 <signal handler called>
#2 0x60000200 in ?? ()
#3 0x10000264 in hold_non_core0_in_bootrom ()
at C:/Users/Maxim/prj/pi-pico-blah/pico-sdk/src/rp2_common/pico_standard_link\crt0.S:322
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
My own observationsReally interesting aside: The entry point symbol is called
_entry_point. If I put a breakpoint at
main, and print the program counter with
(gdb) p /x $sp, the value is different depending on whether the GDB server is OpenOCD or J-Link:
For the OpenOCD, upon entry to
main the stack pointer was
0x20042000:
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x4200 lma 0x10000100
Loading section .rodata, size 0xfa0 lma 0x10004300
Loading section .binary_info, size 0x20 lma 0x100052a0
Loading section .data, size 0x22c lma 0x100052c0
Start address 0x100001e8, load size 21740
Transfer rate: 4 KB/sec, 3623 bytes/write.
(gdb) i b
No breakpoints or watchpoints.
(gdb) b main
Breakpoint 1 at 0x10000364: file C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c, line 22.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) c
Continuing.
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000138 msp: 0x20041f00
Thread 1 hit Breakpoint 1, main ()
at C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c:22
22 int main() {
(gdb) p /x $sp
$1 = 0x20042000
And for the J-Link, upon entry to
main the stack pointer was
0x20041ff0:
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x4200 lma 0x10000100
Loading section .rodata, size 0xfa0 lma 0x10004300
Loading section .binary_info, size 0x20 lma 0x100052a0
Loading section .data, size 0x22c lma 0x100052c0
Start address 0x100001e8, load size 21740
Transfer rate: 758 KB/sec, 3623 bytes/write.
(gdb) c
Continuing.
Thread 2 hit Breakpoint 1, main ()
at C:/Users/Maxim/prj/pi-pico-blah/pico-examples/uart/hello_uart/hello_uart.c:22
22 int main() {
(gdb) p /x $sp
$3 = 0x20041ff0
(That is, assuming that I can get to
main before it throws an exception.)