Remote GDB of Linux app

I’ve got a U54, five core based design. I’m running Yocto based off of SiFive’s “Unleashed” from GitHub - sifive/freedom-u-sdk: Freedom U Software Development Kit (FUSDK), 2023.04 branch. I’m following the direction from the Yocto web site:

https://docs.yoctoproject.org/dev-manual/debugging.html#using-the-gdbserver-method

Everything builds and loads as expected. I start gdbserver on the target:

root@hx40416-devboard:~# gdbserver localhost:5002 ls
Process ls created; pid = 375
Listening on port 5002

Then run riscv64-clx-linux-gdb (the GDB from the SDK) on the host:

(gdb) set sysroot debugfs
(gdb) set substitute-path /usr/src/debug debugfs/usr/src/debug
(gdb) target remote 192.168.160.93:5002
Remote debugging using 192.168.160.93:5002
Reading symbols from debugfs/bin/ls.coreutils…
Reading symbols from /home/white/debugfs/bin/.debug/ls.coreutils…
Reading symbols from debugfs/lib/ld-linux-riscv64-lp64d.so.1…
Reading symbols from debugfs/lib/.debug/ld-linux-riscv64-lp64d.so.1…
0x0000003ff7ff1da4 in _start () from debugfs/lib/ld-linux-riscv64-lp64d.so.1
(gdb)

On the target I see:

Remote debugging from host ::ffff:192.168.159.155, port 51544

On the host I continue the application:

(gdb) continue
Continuing.

At this point things are hung up. If I display the hart status using OpenOCD, all harts are halted:

0 riscv.cpu.0 riscv little riscv.cpu halted
1* riscv.cpu.1 riscv little riscv.cpu halted
2 riscv.cpu.2 riscv little riscv.cpu halted
3 riscv.cpu.3 riscv little riscv.cpu halted
4 riscv.cpu.4 riscv little riscv.cpu halted

Is there something I missed?

Thanks.

33 Debugging Tools and Techniques — The Yocto Project ® 4.3.999 documentation

This makes no mention of OpenOCD so why are you using it? And how (are you invoking it)?

I’m using OpenOCD to kick off the zeroth stage bootloader. I’ve been asked to hold off programming the one-time-programmable ROMs that normally would hold the zeroth stage bootloader. I use OpenOCD to reset/halt the processors, load the zeroth stage bootloader into L2 memory, set the PCs, then resume. After the resume the CPUs execute the zeroth stage bootloader and jump to u-boot SPL. This simulates a reboot. After I resume, I do not use OpenOCD except for querying the CPU status.

I see no change in behavior if I exit OpenOCD after kicking off the zeroth stage bootloader.

I’ve investigated this problem further and found a couple things.

First, if symbols are not loaded and I do not try to set a breakpoint then I am able to run/continue a program using gdb/gdbserver. However, setting breakpoints or even loading symbols still causes the CPUs to halt after a run/continue.

Second, OpenOCD has been setting up an SMP (“target smp”). If I do not create an SMP with OpenOCD, then only one or two of the CPUs are halted when I run gdb/gdbserver. I realize this is likely an impact of using OpenOCD to query the CPU status. With only one or two CPUs halted, I do eventually see some TTY output:

[ 220.191387] BUG: workqueue lockup - pool cpus=1 node=0 flags=0x0 nice=0 stuck for 57s!

Thanks.

Make sure the ebreakvu bit in the dcsr register is clear or otherwise an EBREAK instruction placed by gdbserver and executed in the user mode will trap into the D-mode rather than the S-mode where it would be handled by the Linux kernel. This bit is surely set by the debug firmware used by OpenOCD for total control over the target. Since you’re clearly doing low-level bring-up, I guess you’ll know how to poke at dcsr, or you can figure it out.

1 Like

Yes, that was it! OpenOCD sets three break bits in dcsr: ebreakm, ebreaks, and ebreaku. Since dcsr is only available while in debug mode, I modified OpenOCD to set the ebreak* bits to zero rather than one. I’m now able to debug a Linux application using gdbserver and gdb.

Thanks!

1 Like

OpenOCD has riscv_set_ebreak[msu] commands you can use these days (and GDB’s monitor command lets you pass through commands to OpenOCD from GDB’s command line interface).

1 Like

That works too, and without a rebuild - thanks!