Debug Linux Kernel with OpenOCD & GDB

Hi all,

I’m trying to set up target debug of the Linux kernel using GDB & OpenOCD of the HiFive Unmatched. I’m running an Ubuntu 20.04 host. I’m using the stock build from the SiFive freedom-u-sdk github with just two additions to the build/conf/local.conf:

KERNEL_IMAGETYPES += " vmlinux "
EXTRA_IMAGEDEPENDS += " gdb-cross-${TARGET_ARCH} "

Kernel debug seemed to be enabled when I checked with menuconfig. I built the “demo-coreip-cli” image and wrote to the SD card and booted the system. All seemed to go well. I launched OpenOCD that I built from ‘git clone GitHub - riscv/riscv-openocd: Fork of OpenOCD that has RISC-V support’:

openocd -c ‘bindto 0.0.0.0’ -f ./openocd_hifive_unleashed.cfg

I obtained the openocd_hifive_unleashed.cfg from zephyr/openocd_hifive_unleashed.cfg at main · zephyrproject-rtos/zephyr · GitHub. I did modify one line of the script to add “-rtos linux”:

$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 0x4000 -work-area-backup 1 -rtos linux

I then launched a devshell to get access to the cross-compiled GDB:

MACHINE=unmatched bitbake -c devshell linux-mainline

From the devshell I launch GDB:

riscv64-oe-linux-gdb /…/build/tmp-glibc/deploy/images/unmatched/vmlinux

Once in GDB I attached to OpenOCD:

target extended-remote localhost:3333

At this point I am attached and the target is halted but I am unable to resolve symbols. This is what I see after entering the “target command” above:

Remote debugging using localhost:3333
0x0000000080004aaa in ?? ()

At the OpenOCD console I see this:

Error: Cannot compute linux virt2phys translation

I put most of the above steps together from pieces gathered here and there. Is there some step I’m missing or some web page that tells me the proper way to debug the Linux kernel using OpenOCD & GDB? Or is there some other debugger I should be using?

Thanks,
Michael

$_TARGETNAME.0 is hart 0 which is the MMU-less S core rather than one of the four MMU-capable U cores, and thus parked in M-mode not doing anything. Have you tried switching cores via thread 1 up to 4? When I used OpenOCD to debug FreeBSD on the Unmatched in the past I omitted hart 0 entirely from the config and just started from 1.

That worked - thank you. Is there a way to set a breakpoint and have it survive a reset? I’m trying this:

(gdb) b smp_init (I’ve also tried “b start_kernel”)
(gdb) cont
(telnet) reset

The breakpoint is never hit although GDB remains attached; I’ve tried this with and without SMP enabled. If I halt the processor after boot and insert a breakpoint, that seems to work.

Thanks,
Michael

Would something like this work via gdb:

monitor reset halt (or reset init?)
b smp_init
cont

How can you use OpenOCD to debug FreeBSD? Could you please give me some advise. My problem is OpenOCD Failed to read memory. And I want to use OpenOCD to debug the kernel.Thanks !!!

I gave up on a pure GDB solution and went with FreedomStudio. I was able to get FreedomStudio to work with u-boot SPL, u-boot, & pre-MMU Linux. It may also be able to work with post-MMU Linux but I haven’t had a need for that yet so I haven’t tried. I can tell you what I did to get get pre-MMU Linux to work when loaded by u-boot; maybe that will help you with BSD. Again, this may be modified for other scenarios but I haven’t had a need to try.

  1. Add a GDB dependency to the Yocto build, e.g. DEPENDS:append:foo-devboard = " gdb-cross-${TARGET_ARCH}".
  2. Build with the following additional configuration flags: CONFIG_GDB_SCRIPTS CONFIG_DEBUG_INFO
  3. Launch a devshell, e.g. MACHINE=foo-devboard bitbake -c devshell linux-mainline
  4. Lauch FreedomStudio from outside the devshell. Otherwise I’ve had FreedomStudio file selector act funny when loading a source file.
  5. In FreedomStudio, add a “GDB Hardware Debugging” debug configuration. Leave as default unless otherwise noted:
  • In the Main tab, set C/C++ application to the vmlinux path, e.g.:
    /home/white/sifive/riscv-sifive/build/tmp-glibc/deploy/images/foo-devboard/vmlinux
  • In the Debugger tab, set the GDB command to the path returned from the command “which riscv64-oe-linux-gdb” in the devshell, e.g.:
    /home/white/sifive/riscv-sifive/build/tmp-glibc/work/foo_devboard-oe-linux/linux-mainline/5.13.x+gitAUTOINC+f7eb8f60ca-r0/recipe-sysroot-native/usr/bin/riscv64-oe-linux/riscv64-oe-linux-gdb
  • In the Debugger tab, set the remote target:
    JTAG Device: OpenOCD (via socket)
    GDB Connection String: localhost:3333
  • In the Startup tab add the following initialization commands:
    monitor reset halt
    monitor bp [Linux kernel load address] 8 hw
    continue
    monitor rbp all
  • In the Startup tab de-select “Load image” and “Load symbols”
  • In the Startup tab add the following run commands, for a Linux kernel load address of 0x80240000 my symbol offset was 0x100240000, e.g.:
    add-symbol-file /home/white/sifive/riscv-sifive/build/tmp-glibc/deploy/images/foo-devboard/vmlinux -o [symbol offset]
  • In the Source tab add a Path Mapping, e.g.:
    /usr/src/kernel - /home/white/sifive/riscv-sifive/build/tmp-glibc/work-shared/foo-devboard/kernel-source
  1. Run the new debug configuration.

When you run this debug configuration, it will reset your platform, let the u-boots run, then halt on the Linux entry point.

I used the OpenOCD configuration mentioned earlier in this thread.

Don’t try to dump memory with the FreedomStudio GUI as it’ll disconnected from OpenOCD. Instead use “monitor mdw” from the FreedomStudio gdb shell.

When single stepping through code, gdb frequently disconnects from OpenOCD. The system is still in a halted state and you can re-connect using another debug configuration. This is the previous GDB configuration without the initialization commands. In FreedomStudio, add a “GDB Hardware Debugging” debug configuration. Leave as default unless otherwise noted:

  • In the Main tab, set C/C++ application to the vmlinux path, e.g.:
    /home/white/sifive/riscv-sifive/build/tmp-glibc/deploy/images/foo-devboard/vmlinux
  • In the Debugger tab, set the GDB command to the path returned from the command “which riscv64-oe-linux-gdb” in the devshell, e.g.:
    /home/white/sifive/riscv-sifive/build/tmp-glibc/work/foo_devboard-oe-linux/linux-mainline/5.13.x+gitAUTOINC+f7eb8f60ca-r0/recipe-sysroot-native/usr/bin/riscv64-oe-linux/riscv64-oe-linux-gdb
  • In the Debugger tab, set the remote target:
    JTAG Device: OpenOCD (via socket)
    GDB Connection String: localhost:3333
  • In the Startup tab de-select “Load image” and “Load symbols”
  • In the Startup tab add the following run commands, for a Linux kernel load address of 0x80240000 my symbol offset was 0x100240000, e.g.:
    add-symbol-file /home/white/sifive/riscv-sifive/build/tmp-glibc/deploy/images/foo-devboard/vmlinux -o [symbol offset]
  • In the Source tab add a Path Mapping, e.g.:
    /usr/src/kernel - /home/white/sifive/riscv-sifive/build/tmp-glibc/work-shared/foo-devboard/kernel-source

Hope this helps.