GDB 调试指南
本文档介绍如何使用 GDB 调试 ARCS SDK 应用程序,包括环境配置、调试方式和常用命令。
Tip
使用 J-Link 对 flash 进行烧录、擦除和回读,见 J-Link 烧录工具。 本文档侧重调试环境搭建与 GDB 用法。
Note
ARCS SDK 使用 RISC-V 架构的 Nuclei 工具链,调试时需要使用对应的 GDB 工具。
调试概述
GDB(GNU Debugger)是一个功能强大的调试工具,支持断点、单步执行、变量查看等调试功能。在嵌入式开发中,通常使用 GDB 配合 JTAG/SWD 调试器进行远程调试。
支持的调试方式
JTAG 调试:通过 JTAG 接口连接调试器
远程 GDB 调试:使用 GDB Server 进行远程调试
命令行调试:使用 GDB 命令行界面进行调试
环境准备
安装调试工具
确认工具链安装
确保已按照 快速入门 中的步骤安装了 Nuclei 工具链,并**在当前 shell 中导出工具链路径**:
export NUCLEI_TOOLCHAIN_PATH=~/.listenai/gcc
Important
build.sh内部虽然会 export 该变量,但那只在其自身进程内有效,不会传给 你的交互 shell。若不手动导出,后续${NUCLEI_TOOLCHAIN_PATH}/bin/...会展开成/bin/...并报没有那个文件或目录。建议写入
~/.bashrc以免每次重设。安装 GDB 运行依赖
Nuclei GDB 链接的是
libtinfo.so.5与libncursesw.so.5,而 Ubuntu 24.04 仅提供 v6 且仓库已移除 v5,需从 22.04 归档安装:cd /tmp B=http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses curl -fsSLO $B/libtinfo5_6.3-2ubuntu0.2_amd64.deb curl -fsSLO $B/libncursesw5_6.3-2ubuntu0.2_amd64.deb sudo apt install -y ./libtinfo5_6.3-2ubuntu0.2_amd64.deb \ ./libncursesw5_6.3-2ubuntu0.2_amd64.deb
Note
两个包都要装,只装
libtinfo5会接着报libncursesw.so.5缺失。 二者 SONAME 与系统自带的 v6 不同,可以共存,不影响其它程序。未安装时的现象:
riscv64-unknown-elf-gdb: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory
安装 J-Link 软件
从 J-LINK 下载对应平台的 J-Link 软件包进行安装,推荐安装 V7.98 及以上版本。
安装完成后,检查 J-Link 是否正常安装:
JLinkGDBServerCLExe --version配置 J-Link 设备支持
J-Link 需要设备描述文件才能识别芯片。SDK 在
tools/jlink/下提供了这些文件 (来自芯片原厂,含 ARCS 与 VenusA),部署到 J-Link 的固定搜索目录即可:rm -rf ~/.config/SEGGER/JLinkDevices mkdir -p ~/.config/SEGGER/JLinkDevices cp -r tools/jlink/. ~/.config/SEGGER/JLinkDevices/
Important
JLinkExe只从~/.config/SEGGER/JLinkDevices/读取设备描述,不支持-JLinkDevicesXMLPath参数,也不读取当前工作目录。仓库里的tools/jlink/必须拷贝到该目录才会生效。部署后目录结构:
~/.config/SEGGER/JLinkDevices/ ├── JLinkDevices.xml 设备描述 ├── Devices/Arcs/flashloader.elf ARCS 烧写算法 ├── Devices/Venusa/flashloader.elf VenusA 烧写算法 └── scripts/jtagscan0.JLinkScript JTAG 链扫描脚本 scripts/jtagscan1.JLinkScript验证设备是否被识别(应输出
Connected to target):JLinkGDBServerCLExe -device VENUSA -if cJTAG -speed 4000 -port 2331 \ -jlinkscriptfile ~/.config/SEGGER/JLinkDevices/scripts/jtagscan0.JLinkScript
验证 GDB 工具
检查 GDB 工具是否可用:
${NUCLEI_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-gdb --version
应该看到类似以下输出:
GNU gdb (GDB) 13.2.90.20230712-git Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
硬件要求
Important
需要 J-Link 仿真器 V11 或更高版本。
准备调试文件
编译时需要生成包含调试信息的 ELF 文件:
./build.sh -C -S samples/helloworld -DBOARD=arcs_evb
Important
切换 sample 或板型时必须加 -C``(清理构建目录)。``build/ 中残留的
CMake 缓存记录了上一个工程的源码路径,不清理会报:
CMake Error: The source ".../helloworld/CMakeLists.txt" does not match
the source ".../<上一个工程>/CMakeLists.txt" used to generate cache.
编译成功后,在 build 目录下会生成:
helloworld:包含调试符号的可执行文件helloworld.bin:用于烧录的二进制文件
Note
默认情况下,SDK 编译生成的 ELF 文件已包含调试信息(-g 选项)。
开始调试
硬件连接
将 J-Link 仿真器连接到开发板。ARCS 与 VenusA 接线相同,均为 cJTAG 2 线:
J-Link 引脚 |
目标板引脚 |
说明 |
|---|---|---|
SWCLK |
PA00 |
cJTAG TCK |
SWDIO |
PA01 |
cJTAG TMS |
GND |
GND |
地线 |
VTref |
3.3V |
参考电压 |
Warning
VTref 必须接。 J-Link 依赖该引脚检测目标电压,未接会直接报无法识别目标。
接口速率固定 4000 kHz,不要使用自适应速率。
PA00/PA01 的 Function 0(复位默认功能)就是 cJTAG,芯片上电即可调试,固件侧不需要 任何”使能 JTAG”的代码。若工程启用的驱动占用了这两个引脚,见 调试口引脚占用(全板型通用)。
调试步骤
完整的 GDB 调试流程如下:
启动 J-Link GDB Server
# 调试 AP 核(Core0),监听 2331 JLinkGDBServerCLExe -device VENUSA -if cJTAG -speed 4000 -port 2331 \ -jlinkscriptfile ~/.config/SEGGER/JLinkDevices/scripts/jtagscan0.JLinkScript # 调试 CP 核(Core1),监听 3331 JLinkGDBServerCLExe -device VENUSA -if cJTAG -speed 4000 -port 3331 \ -jlinkscriptfile ~/.config/SEGGER/JLinkDevices/scripts/jtagscan1.JLinkScript
ARCS 芯片把
-device换成ARCS即可,其余相同。接了多个探针时用-select USB=<序列号>指定,序列号可通过echo ShowEmuList | JLinkExe -NoGui 1查询。成功启动后会输出
Connected to target,随后停在Waiting for GDB connection...。Important
停在
Waiting for GDB connection...是正常状态,不是卡死。 GDB Server 会持续占用该终端等待客户端接入,请保持它不关闭,在新终端中 继续下一步。Important
两颗芯片的 sample 默认运行核相反,照抄示例调另一颗芯片会连错核:
板型
默认核
JLinkScript
端口
venusa_rd_evbAP(Core0)
jtagscan02331
arcs_evbCP(Core1)
jtagscan13331
连接后用
p/x $mhartid自检:AP 为0x0,CP 为0x1。值不符说明 JLinkScript 选错了。另需确保 ELF 与目标芯片一致 —— 用
arcs_evb编出的 ELF 连到 VenusA 上,寄存器能读但符号地址全错,断点会下到无效位置。启动 GDB 并加载 ELF 文件
在另一个终端中启动 GDB:
${NUCLEI_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-gdb build/helloworld
启动后会进入 GDB 命令行界面:
GNU gdb (GDB) 13.2.90.20230712-git ... Reading symbols from build/helloworld... (gdb)
连接到 GDB Server
在 GDB 命令行中连接到 J-Link GDB Server:
(gdb) target remote localhost:2331
Note
如果 GDB Server 运行在其他机器上,将
localhost替换为对应的 IP 地址默认端口为 2331,如果使用其他端口,请相应修改
加载程序到目标设备
连接成功后,将程序加载到目标设备:
(gdb) load Loading section .text, size 0x1234 lma 0x20000000 ... Start address 0x20000000, load size 4660 Transfer rate: 1165 bytes/sec, 1165 bytes/write.
开始调试
设置断点并运行程序:
(gdb) break main Breakpoint 1 at 0x20000a34: file main.c, line 15. (gdb) continue Continuing.
快速调试脚本
为了简化调试流程,可以创建一个 .gdbinit 文件来自动执行常用命令:
# 连接到 GDB Server
target remote localhost:2331
Note
出于安全考虑,GDB 可能不会自动加载当前目录的 .gdbinit 文件。可以在用户主目录的 ~/.gdbinit 中添加:
set auto-load safe-path /
目标核心与 JLinkScript 选择
ARCS 与 VenusA 均为双核 RISC-V,两个核心挂在同一条 JTAG 链的不同 TAP 上,
必须加载对应的 JLinkScript,否则报 CPU-TAP not found in JTAG chain。
目标核 |
JLinkScript |
GDB 端口 |
JTAG IDCODE |
|
|---|---|---|---|---|
AP(Core0) |
|
2331 |
|
0 |
CP(Core1) |
|
3331 |
|
1 |
Important
只有调试 CP 核时用 jtagscan1,其余一律用 jtagscan0 —— 包括烧录、
读 flash、读寄存器。
自动判定当前工程跑在哪个核:
grep -E "CONFIG_(ARCS|VENUSA)_(AP|CP)_CORE=y" build/.config
Note
两颗芯片的默认核相反:ARCS 的 sample 默认运行在 CP 核,
VenusA 的 sample 默认运行在 AP 核(CONFIG_HARTID 默认 0)。
连接后可用 p/x $mhartid 确认实际所在核心。
启动 GDB Server 时按上表选择对应的 -jlinkscriptfile 与 -port。
双核调试
CP(Core1)由 AP 通过 CMN_SYSCFG.SW_RESET_CFG1 控制,寄存器地址 0x43100010:
写入值 |
作用 |
|---|---|
|
把 CP 摁在复位里 |
|
释放 CP 正常运行 |
只调试 AP 时,建议先把 CP 摁住,避免其在后台运行干扰:
(gdb) monitor memU32 0x43100010 = 0xCAFE000A
双核联调顺序:
先起 AP 会话,下载固件,停在
_startresume AP,由它释放 CP
再起 CP 会话 attach 接入(只加载符号,不重复下载固件)
SDK 侧对应实现见 soc/venusa/soc.c 的 venusa_start_cp()。
调试口引脚占用(全板型通用)
PA00/PA01 的 Function 0(复位默认功能)本就是 cJTAG TCK/TMS,芯片上电即可调试, 固件侧不需要任何”使能 JTAG”的代码。会导致 J-Link 掉线的只有一种情况:板级 pinmux 把这两个引脚复用成了别的功能。
关键在于 lisa_xxx_pinmux() 这类板级函数只在对应驱动被启用时才执行。
samples/helloworld 这类最小工程既不启用 GPIOA 也不启用 PWM,两个函数都不会被
调用,PA00/PA01 一直停在 cJTAG 上——所以按前面的流程接好线就能直接调试。
一旦工程启用了会占用调试口的驱动,就会出现典型现象:上电瞬间能连上,固件跑起来
立刻掉线,或直接报 CPU could not be halted。
各板型的占用情况:
板型 |
抢 PA00 的函数 |
抢 PA01 的函数 |
重写代价 |
|---|---|---|---|
|
|
|
背光调节 + 屏复位 |
|
|
|
摄像头复位 + 外放 |
|
|
无 |
外放 |
解决办法是按 SDK 惯例在应用代码里重写对应的 weak 函数(各 sample 处理引脚 共用时都采用这种做法):
#include "IOMuxManager.h"
/* 覆盖板级默认:保住 PA00/PA01 的 cJTAG 功能 */
void lisa_gpioa_pinmux(void)
{
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 0, CSK_IOMUX_FUNC_DEFAULT); /* cjtag_tck */
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 1, CSK_IOMUX_FUNC_DEFAULT); /* cjtag_tms */
}
Important
重写时必须保留原函数里其它引脚的配置,只去掉占用 PA00/PA01 的那几行。
arcs_evb 尤其要注意:lisa_gpioa_pinmux() 里还有 TP_INT(PA24)、
TP_RST(PA25)、PA_EN(PA27) 三行,漏掉会导致触摸失效;而且它的 PA00 是被
lisa_pwm_pinmux() 占的,需要同时重写两个函数。
venusa_rd_evb 最简单,原函数只有 PA_EN 一行,重写不会丢失其它配置。
Note
代价是被占引脚的原功能失效:venusa_rd_evb 上是功放使能(无音频输出),
arcs_evb 上是背光和屏复位。这是引脚复用的物理必然,软件绕不开。
venusa_rd_evb 另有硬件层面的共用:PA00 经 J53 跳线三选一接 PA_EN /
摄像头 PWDN / LCD_RST,PA01 经 H6 焊桥接 TP_INT。详见
boards/venusa_rd_evb/README.md。
Note
CP 进入深睡后调试器掉线:CP 深睡时 Debug Module 时钟被关。置位
0x43100088 处 N300_CORE1_CTRL 的 core1_override_dm_sleep 位,
可让 DM 在深睡时保持可访问。
RTT 日志
SEGGER RTT(Real-Time Transfer)通过调试器读写目标 RAM 传输日志:目标端只是往 RAM 写字节,J-Link 在后台把数据搬到主机。它不占用 UART 引脚,吞吐远高于 串口,对实时性的干扰也小得多,适合串口被业务占用、引脚不够,或波特率不足以承载 日志量的场景。
RTT 是 lisa_log 的一个后端,开启后与 console(UART)后端并存,两路同时 输出,不需要修改任何业务代码。ARCS 与 VenusA 均已支持。
开启方式
在工程 prj.conf 中加两行:
CONFIG_LOG=y
CONFIG_LOG_BACKEND_SEGGER_RTT=y
CONFIG_LOG_BACKEND_SEGGER_RTT 会自动 select SUPPORT_SEGGER_RTT。可调项
位于 menuconfig 的 Third-party Modules → SEGGER RTT Support:
配置项 |
默认 |
说明 |
|---|---|---|
|
1024 |
目标→主机缓冲区字节数,占用 SRAM |
|
16 |
主机→目标缓冲区字节数 |
|
2 |
缓冲区满时:0=丢弃,1=截断,2=阻塞 |
Warning
默认的模式 2 保证日志不丢,但主机没有读取时缓冲区写满会阻塞在
SEGGER_RTT_Write() 上。量产固件若要常开 RTT 后端,应改为 0 或 1。
开启后 SRAM 多占用约 BUFFER_SIZE_UP + BUFFER_SIZE_DOWN + 168 字节。
读取日志
连接参数
RTT 日志跟着固件走:固件跑在哪个核,就连那个核。先确认当前工程的核:
grep -E "^CONFIG_(HARTID|.*_(AP|CP)_CORE)=" build/.config
# CONFIG_ARCS_CP_CORE=y
# CONFIG_HARTID=1 → CP 核
两颗芯片的默认核相反:ARCS 默认 CP,VenusA 默认 AP。下表为使用默认内存分区时的连接参数:
芯片 / 核 |
|
JLinkScript |
端口 |
|---|---|---|---|
VenusA / AP(默认) |
|
|
2331 |
VenusA / CP |
|
|
3331 |
ARCS / CP(默认) |
|
|
3331 |
ARCS / AP |
|
|
2331 |
Tip
可用日志中的 hartid 自检读到的是哪个核:0 为 AP、1 为 CP。
与预期不符说明搜索范围或 JLinkScript 指向了另一个核。
操作步骤
下面以 ARCS / CP 核(默认配置)为例,其它组合按上表替换 -device、
JLinkScript 与端口。端口在终端 1 与终端 3 各出现一次,必须同时改。
终端 1 —— 启动 GDB Server,保持运行:
JLinkGDBServerCLExe -device Arcs -if cJTAG -speed 4000 -port 3331 \
-jlinkscriptfile ~/.config/SEGGER/JLinkDevices/scripts/jtagscan1.JLinkScript
终端 2 —— 挂上 RTT 客户端,等待数据:
JLinkRTTClient
终端 3 —— GDB Server 连接时会 halt 内核,需放行才有日志产生。这一步还要告知 J-Link 控制块所在的 SRAM 区域,取值为该核镜像的 SRAM 分区,从构建产物 读出:
grep -E "^CONFIG_MEM_SRAM_(BASE|SIZE)=" build/.config
# CONFIG_MEM_SRAM_BASE=0x20010000
# CONFIG_MEM_SRAM_SIZE=0x00024800
两个值依次填入 SetRTTSearchRanges:
${NUCLEI_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-gdb -q -batch \
-ex 'target remote localhost:3331' \
-ex 'monitor exec SetRTTSearchRanges 0x20010000 0x24800' \
-ex 'monitor reset' \
-ex 'continue' \
build/helloworld
终端 2 随即输出:
I/elog [00:00:00.048 1 elog_async] EasyLogger V2.2.99 is initialize success.
I/logger_sample [00:00:00.049 1 main] Hello, world!
Tip
时间戳后面那一位是产生该日志的核(mhartid):0 为 AP、
1 为 CP。上面输出中为 1,说明读到的是 CP 核的日志。连错核时终端 2
不会有任何输出,而不会显示另一个核的内容——每个核的 RTT 缓冲区是独立的。
也可在终端 3 的 GDB 中用 p/x $mhartid 直接确认当前连接的核。
Important
必须先启动终端 2,再执行终端 3。RTT 缓冲区读一次即清空,启动日志只在 复位那一刻产生;顺序反了会错过,需要再复位一次。
Note
终端 3 的 GDB 在
continue后会一直阻塞,这是正常的——它在等目标停下来。 确认日志已输出后Ctrl-C退出即可,目标与 RTT 都会继续运行。末尾的 ELF 可省略,但带上后能直接看出内核停在哪,排查时有用。
GDB Server 不要加
-singlerun,否则 GDB 断开时它会退出并带走 19021 上的 RTT 服务。
双核工程
RTT 需在每个镜像的 prj.conf 中单独开启,只在需要观察的核上开即可,
另一个核走 UART 或下面的 IPC 转发。两个核都开启时,必须按上一节指定搜索范围,
否则可能读到另一个核的日志。
SRAM 占用
每个开启 RTT 的核占用 BUFFER_SIZE_UP + BUFFER_SIZE_DOWN + 168 字节。SRAM 分区
较小的核需调小缓冲区,否则链接失败:
region `SRAM' overflowed by 736 bytes
调小 CONFIG_SEGGER_RTT_BUFFER_SIZE_UP 即可。VenusA CP 核仅 40 KB,默认 1 KB
的上行缓冲区放不下。
在一个终端看两个核的日志
一次只能连接一个核。需要同时观察两个核时,用 lisa_log 的 IPC 后端在固件侧汇聚:
# CP 核镜像
CONFIG_LOG_BACKEND_IPC_WRITER=y
# AP 核镜像
CONFIG_LOG_BACKEND_IPC_READER=y
CONFIG_LOG_BACKEND_SEGGER_RTT=y
对端日志带 [REMOTE] 前缀。两个后端可对调,哪个核便于接调试器就让哪个作
READER。需要工程已启用 AMP IPC。
Note
IPC 汇聚方式未在实板验证,仅依据 system/log/Kconfig 与
system/log/lisa_log_backend_ipc.c 的实现说明。
常见问题
现象 |
处理 |
|---|---|
终端 2 停在 |
ARCS 漏了 |
|
19021 同时只允许一个客户端, |
|
终端 3 的端口与终端 1 不一致 |
|
|
|
JLinkScript 选错,按上表核对 |
日志重复出现两遍 |
复位了两次,属正常 |
目标核跑飞、软复位无法恢复 |
断电重上电。切勿用 |
确认固件是否真的在输出
工具链有问题时,可绕开 RTT 工具直接读控制块,判断是固件问题还是工具问题:
# 取控制块地址
${NUCLEI_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-nm build/helloworld | grep _SEGGER_RTT
# 20011f00 B _SEGGER_RTT
JLinkExe -NoGui 1 -Device Arcs -IF cJTAG -Speed 4000 -AutoConnect 1 -JTAGConf -1,-1 \
-JLinkScriptFile ~/.config/SEGGER/JLinkDevices/scripts/jtagscan1.JLinkScript <<'EOF'
mem8 20011F00 0x10
exit
EOF
看到 "SEGGER RTT" 魔数即说明固件已正常初始化 RTT,问题在主机侧:
20011F00 = 53 45 47 47 45 52 20 52 54 54 00 00 00 00 00 00
S E G G E R R T T
Warning
JLinkRTTLogger 不能用于 ARCS/VenusA——该工具不支持 cJTAG,
-If cJTAG 会报 Could not parse target interface。请使用上面的
GDB Server + JLinkRTTClient 方式。
Note
读取 RISC-V cJTAG 需 J-Link 软件 V9.46 及以上,旧版会误识别为 ARM7。
常用 GDB 命令
本节介绍嵌入式调试中最常用的 GDB 命令。完整的 GDB 命令参考请查阅 参考资料。
基本调试命令
命令 |
说明 |
|---|---|
|
在 main 函数设置断点 |
|
在 main.c 第 25 行设置断点 |
|
查看所有断点 |
|
删除编号为 1 的断点 |
|
继续执行 |
|
单步执行(不进入函数) |
|
单步执行(进入函数) |
|
执行完当前函数并返回 |
查看变量和内存
(gdb) print variable_name # 打印变量值(简写: p)
(gdb) print /x variable_name # 以十六进制打印
(gdb) x/10xw 0x20000000 # 查看内存(10个字,十六进制)
(gdb) display variable_name # 每次停止时自动显示变量
调用栈和寄存器
(gdb) backtrace # 显示调用栈(简写: bt)
(gdb) info locals # 显示局部变量
(gdb) info registers # 显示所有寄存器
(gdb) print $pc # 打印程序计数器
实用命令
(gdb) list # 查看源代码(简写: l)
(gdb) info threads # 显示所有线程(RTOS 环境)
(gdb) help # 显示帮助信息
(gdb) quit # 退出 GDB(简写: q)
调试示例
以调试 helloworld 示例为例,展示完整的调试流程:
编译项目
./build.sh -C -S samples/helloworld -DBOARD=arcs_evb
启动 J-Link GDB Server
参考 开始调试
JLinkGDBServerCLExe -device ARCS -if cJTAG -speed 4000 -port 2331 -jlinkscriptfile $HOME/.config/SEGGER/JLinkDevices/scripts/arcs/jtagscan1.JLinkScript
启动 GDB 并调试
${NUCLEI_TOOLCHAIN_PATH}/bin/riscv64-unknown-elf-gdb build/helloworld
在 GDB 中执行:
(gdb) target remote localhost:2331 (gdb) break main (gdb) continue (gdb) next # 单步执行 (gdb) print variable_name # 查看变量 (gdb) backtrace # 查看调用栈 (gdb) info registers # 查看寄存器
常见调试场景
内存问题调试
(gdb) x/10xw $sp # 查看栈顶内存
(gdb) x/20i $pc # 查看当前指令
(gdb) watch *0x20001000 # 监视内存变化
函数调用跟踪
(gdb) break func_name
(gdb) backtrace # 查看调用栈
(gdb) info args # 查看函数参数
(gdb) finish # 执行完函数
调试技巧
条件断点和监视点
条件断点只在满足条件时才停止,监视点可以监视变量或内存的变化:
(gdb) break main.c:30 if counter > 100 # 条件断点
(gdb) watch variable_name # 监视变量变化
(gdb) watch *(int *)0x20000100 # 监视内存地址
查看汇编代码
对于底层调试,可以查看汇编代码:
(gdb) disassemble main # 反汇编 main 函数
(gdb) disassemble /m main # 混合显示源码和汇编
(gdb) stepi # 汇编级单步执行
常见问题
找不到调试符号
问题现象:
Reading symbols from build/helloworld... (No debugging symbols found)
解决方法:
确保编译时包含调试信息(
-g选项)检查是否误用了
.bin文件而非.elf文件
无法连接到 GDB Server
问题现象:
(gdb) target remote localhost:2331 localhost:2331: Connection refused.
解决方法:
确认 J-Link GDB Server 已正确启动
检查端口号是否正确(默认 2331)
检查防火墙设置
确认 J-Link 仿真器已正确连接到开发板
断点无法命中
可能原因:
代码被优化掉(使用
-O0编译选项禁用优化)断点位置不正确
程序未正确加载到目标设备
解决方法:
(gdb) info breakpoints # 检查断点状态 (gdb) break *0x20000a34 # 使用绝对地址设置断点
程序执行位置与源代码不对应
解决方法:
确保 ELF 文件与烧录的 BIN 文件版本一致
重新编译并烧录程序
检查是否有多个版本的源文件
查看变量显示 optimized out
问题原因:
编译优化导致变量被优化掉。
解决方法:
使用
-O0编译选项禁用优化(仅用于调试)在 CMakeLists.txt 中添加:
add_compile_options(-O0 -g)
CPU-TAP not found in JTAG chain
启动 GDB Server 时漏了
-jlinkscriptfile。ARCS/VenusA 是双 TAP 链, 必须加载 JLinkScript,见 目标核心与 JLinkScript 选择。设备名无法识别
The selected device "VENUSA" is unknown to this software version.
tools/jlink/未部署到~/.config/SEGGER/JLinkDevices/,或部署不完整。 按 环境准备 重新拷贝。固件一跑起来 J-Link 就掉线
工程启用的某个驱动把 PA00/PA01 复用走了,典型表现是上电瞬间能连、固件跑起来 立刻掉线,或报
CPU could not be halted。见 调试口引脚占用(全板型通用)。断点不够用
代码 XIP 跑在 flash 里时,软件断点(
ebreak)无法写入,只能用硬件断点。 实测硬件断点为 4 个 —— J-Link 报告HW instruction/data BPs: 4, 芯片官方文档给出的保守值是 2 个。用尽后需先删除已有断点,或把待调试的函数 放到 SRAM 里执行。另外 J-Link 报告
Support set/clr BPs while running: No,增删断点需先暂停目标。探针识别不到
lsusb | grep -i segger # 确认 USB 枚举 id -nG | grep plugdev # 确认用户组 ls /etc/udev/rules.d/*jlink* # 确认 udev 规则
在虚拟机中使用时,需先把 J-Link 设备从宿主机直通给虚拟机。
强杀 J-Link 进程后出现各种诡异报错
若上一次会话被超时强杀,探针可能残留异常状态,随后出现
Could not start CPU core、JTAG communication error、cJTAG is not supported by the connected probe、USB 反复重新枚举等现象。这些是偶发的残留效应,并非稳定故障。处理顺序:直接重试通常即恢复; 目标核被留在 halt 导致程序不运行时用
cskburn --chip-id复位芯片; 探针仍不响应则拔插 USB。Tip
遇到这类报错先重复 2~3 次确认是否稳定复现,不要当作真实缺陷排查。
参考资料
GDB 文档
GDB 官方文档 - GDB 完整用户手册
GDB 快速参考卡片 - 常用命令速查(PDF)
RISC-V 相关
RISC-V GDB 使用指南 - RISC-V 工具链文档
Nuclei RISC-V 工具链 - Nuclei 官方工具链文档
J-Link 文档
J-Link / J-Trace 用户手册 - J-Link 官方用户手册
J-Link GDB Server 文档 - GDB Server 配置和使用
ARCS SDK 相关
ARCS SDK 快速入门:快速入门