Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rvdbg 使用手册

English

rvdbg 用一份 rvdbg.toml 管理 rustvisor 项目的烧录、调试和目标检查。连接 Lauterbach 时使用 TRACE32 PowerView;连接 StellarLINK 时使用独立运行的 openocd-stellar。镜像由项目自己的构建系统生成,rvdbg 负责把已经生成的镜像送到板子上,并帮助你确认目标的状态。

本手册面向在 macOS Apple 芯片或 Linux x86_64/aarch64 主机上使用 rvdbg 的人。rvdbg init 的板级默认值针对 SR6P6;换板前需要核对脚本、核名称、内存访问端口和一次性写入区,不能把这些默认值当作通用配置。

从你要完成的事情进入

任务阅读入口读完应能完成什么
第一次使用快速开始安装依赖,生成配置,烧录并查看状态
换镜像、调试器或核项目配置确认实际生效的镜像、后端和端口
更新程序或符号烧录与验证选择 flash/load,并正确处理多镜像
断点、单步、查看调用栈调试与交互会话接入 IDE/GDB,理解停核和复位行为
诊断当前程序查看目标检查 PC、异常、内存、时钟和验收条件
查看日志、收发数据RTT 与 FDX找到目标缓冲区,区分日志与包通信
接入脚本或 agent自动化解析 JSON、退出码和会话命令边界
操作失败排障从现象找到下一步检查

第一次阅读可按目录顺序;日常使用直接打开对应任务页。页面里的标准 Markdown 相对链接也能在 GitHub 和 Obsidian 中使用。mdBook 网站在页尾自动列出“引用此页”,可以反查哪些流程依赖当前页面。

两种后端有哪些差异?

能力TRACE32StellarLINK / OpenOCD
烧录、验证、状态、停核与继续支持支持
IDEVS Code、RustRover/LSP4IJ,通过 DAPVS Code/Cortex-Debug、GDB
普通 RAM、RTT、FDX运行中通过 AD: 访问运行中通过 MEM-AP 访问
加载调试符号rvdbg load由 GDB 读取 ELF
按 PER 名称读取寄存器reg、watch不支持;使用地址或检查文件
PRACTICEeval、cmd、do不支持
Trace 导出trace、fault --trace不支持
时钟图clock --html仅文本/JSON 时钟树

两个后端共享命令名不代表所有选项都通用。后端选择规则见配置,每种操作的限制放在对应任务页。

操作前先确认它改变什么

status、mem、fault、verify、不带 --halt 的 check 等检查命令不会为了读取而自动复位或停核;某些寄存器读取因此会被拒绝。普通 RAM 访问和有读副作用的 MMIO 也需要区分,见查看目标。

flash 会写入 Flash 并复位;reset 复位并停核;halt、go、run-until 改变运行状态。load 不写程序,但会加载符号并在需要时继续运行;IDE 接入也可能执行板级复位钩子,详见调试。

ram --write 和 FDX 发送会改变目标 RAM 或让固件执行自己的协议。cmd、do 的影响取决于 PRACTICE 内容;不能仅按 rvdbg 命令名判断它们的实际作用。

查完整参数使用 rvdbg --help 和 rvdbg <命令> --help。手册解释操作过程和判断方法,参数默认值以当前安装版本的帮助和 rvdbg init 输出为准。

本地预览、链接规则和构建检查见维护这本手册。


从安装到第一次烧录

English

本页跟踪一次 SR6P6 项目操作:主机上已有构建成功的 ELF,接好板子和调试器,生成配置,烧录,然后查看运行状态。rvdbg 不替项目编译固件。

安装 rvdbg 和所需后端

macOS Apple 芯片或 Linux 上可用 Homebrew:

brew install haoyibits/tap/rvdbg
rvdbg --version

formula 会一起安装 openocd-stellar。使用 TRACE32 仍需自行安装 PowerView 和 t32debugadapter;它们不包含在 rvdbg 里。

不使用 Homebrew 时,可以安装发布二进制:

curl -fsSL https://github.com/haoyibits/rustvisor-debug/releases/latest/download/install.sh | sh

安装脚本默认写入 ~/.local/bin。该目录需在 PATH 中;RVDBG_INSTALL_DIR 可改变目录,RVDBG_VERSION 可指定发布版本。脚本不会安装 openocd-stellar。从源码安装则在本仓库执行:

cargo install --path crates/rustvisor-debug

浏览器下载的 macOS 二进制若被 Gatekeeper 拦截,确认文件来自预期发布后,对实际二进制路径执行:

xattr -d com.apple.quarantine /path/to/rvdbg

准备调试器

TRACE32: PowerView 默认从 ~/t32 查找。若安装在别处,在配置中设置 trace32.sys。Remote API 必须使用 TCP。已有 config.t32 可写:

RCL=NETTCP
PORT=20000
REMOTEHOSTDENY

若文件未定义 RCL=,rvdbg 启动 PowerView 时会传入 TCP Remote API 参数,并限制为本机访问。已有 RCL= 时,要确保协议和端口与 trace32.rcl_port 一致。Remote API 没有认证,能连接它就能执行 PRACTICE 和主机命令,因此应保留本机访问限制。

StellarLINK: 使用 openocd-stellar,不要用缺少 Stellar 支持的普通 OpenOCD 替代。SR6P6 EVB 默认脚本是 board/sr6p6_evb.cfg。如果要用 VS Code,还需要 Cortex-Debug;直接用 GDB 则需要 arm-none-eabi-gdb。

在固件项目中生成配置

以下操作在待调试的固件项目根目录执行,不是在 rvdbg 自己的源码目录执行:

cd ~/work/rustvisor-sdk
rvdbg init
$EDITOR rvdbg.toml

init 不会覆盖已有文件。它生成 SR6P6 默认配置,请先核对 [project]:

[project]
program = "boot_diagnostic"
elf = "target/thumbv8r-none-eabihf/release/boot_diagnostic"
extra_elf = ["target/thumbv8r-none-eabihf/release/scenario-guest"]

把路径换成这次构建的实际产物;没有额外镜像时使用 extra_elf = []。若镜像会同时部署 hypervisor 和 Guest,应将它们一起列出,原因见多镜像烧录。

先检查工具将要操作什么

rvdbg config

检查配置路径、主镜像与额外镜像是否存在、发现了哪个探针,以及实际选择了哪个后端。两个探针都插着时默认选 TRACE32;本次想用 StellarLINK 可执行:

rvdbg --backend openocd config

config 能发现配置错误和缺失文件,但它的成功不代表 JTAG、目标供电或 Flash 操作已经通过。更改后端或核的规则见配置。

烧录并确认结果

确认镜像和目标板正确后执行:

rvdbg flash
rvdbg verify
rvdbg status

flash 会擦写并复位目标,正常完成后运行程序。verify 不带路径时检查全部已配置镜像;退出码 0 表示可加载内容与目标一致。status 显示目标在运行还是停着,停着时还会显示 PC/CPSR。

verify 一致说明镜像内容一致,不能单独证明启动成功或业务逻辑正确。需要观察日志或项目验收条件时,继续看RTT和检查文件。烧录失败时先看排障,不要用跳过验证或写 OTP 来替代定位问题。

接下来可用 rvdbg vscode 生成 IDE 配置,或直接运行 rvdbg 进入交互会话。


配置项目与选择后端

English

配置的目标是确定三件事:操作哪些镜像、通过哪个后端、连接哪个核。改配置后先运行 rvdbg config,再执行会改变目标状态的操作。

配置文件在哪里,路径相对谁?

rvdbg 从当前目录向上找最近的 rvdbg.toml。它所在的目录是项目根目录;也可以显式指定:

rvdbg --config /work/firmware/rvdbg.toml config

镜像等项目相对路径以配置目录为基准。OpenOCD 的 config 条目是交给 OpenOCD 查找的脚本名,例如 board/sr6p6_evb.cfg;额外搜索目录通过 search 添加。只写程序名的 executable/gdb 由 PATH 查找,不能把它们误当作项目内文件。

rvdbg init 是获取完整带注释模板的入口。解析器会拒绝未知段和未知键;不要在文件里保留已经改名的字段。

后端怎样选择?

按以下优先级取第一个明确选择:

  1. 命令行 --backend trace32 或 --backend openocd。
  2. [project] backend = "trace32" 或 "openocd"。
  3. 当前探针:Lauterbach 或正在运行的 PowerView 对应 TRACE32;StellarLINK 对应 OpenOCD;同时发现两者时选择 TRACE32。
rvdbg --backend openocd status
rvdbg --backend trace32 status

手动指定只决定调用哪个后端,不会让未连接的探针或未启动的服务自动变得可用。TRACE32 查看命令要求 PowerView 已运行;OpenOCD 查看命令会复用已有 Tcl 服务,否则启动一个不复位目标的实例。交互会话的连接生命周期见调试。

哪些字段值得先核对?

段关键字段决定什么
[project]elf、extra_elf、program、backend镜像集合、TRACE32 符号程序名和后端
[trace32]sys、config、host、rcl_portPowerView 安装、启动配置和 Remote API
[trace32.target]cpu、cores、mem_access、jtag_clock、dual_port目标及运行中内存访问
[trace32.flash]chip、script、args烧录脚本选择及参数
[trace32.rtos]config、menu、show_tasks可选的 RTOS 感知
[openocd]executable、config、search、commandsOpenOCD 程序和板级初始化脚本
[openocd]tcl_port、gdb_port、gdb_target、core控制连接、GDB 服务核、查看类命令用的核
[openocd]memory_ap、timeout、otp物理内存访问、操作超时及 OTP 保护范围
[rtt]symbol、control_block_address、poll_intervalRTT 控制块及轮询间隔
[fdx]symbolFDX 链接符号,默认 RUSTVISOR_FDX
[clock]例如 XOSC = "40MHz"板子决定、寄存器无法告知的输入频率

program 未填或为空时从主 ELF 文件名推导。它在 TRACE32 中标识符号程序,不是待烧录镜像路径;两个字段需要各自正确。

trace32.host 是 TRACE32 安装树中的主机平台目录名,用于定位二进制和 adapter,不是 Remote API 的网络主机地址。通常留空,由工具根据主机平台推导。

init 生成的 SR6P6 相关默认值包括:

[openocd]
executable = "openocd-stellar"
config = ["board/sr6p6_evb.cfg"]
search = []
commands = []
tcl_port = 6666
gdb_port = 3333
gdb_target = "sr6p6.k0c0.core"
gdb = "arm-none-eabi-gdb"
memory_ap = "sr6p6.axi"
timeout = 600
otp = [{ start = 0x29F87000, size = 0x1000 }]

gdb_target 选 GDB 调试的核;core 未指定时,halt、go、fault、check 等也使用它。设置另一个 core 不会同时把 IDE 的 GDB 连接切到那个核。memory_ap 是访问物理内存的 MEM-AP,不能用核名称替代。具体核名由板级 OpenOCD 脚本定义。

tcl_port 和 gdb_port 必须不同。多项目同时调试时,为各项目使用不冲突的端口,避免命令复用到另一个项目的服务。

环境变量怎样覆盖配置?

镜像覆盖对两种后端生效;TRACE32 设置的覆盖遵循其后端配置规则。优先级为环境变量、TOML、默认值。临时更换镜像时:

ELF=build/el2.elf EXTRA_ELF="build/guest.elf" rvdbg config

同样的前缀必须用于后续实际操作,或写入当前 shell 环境;只对 config 设置一次不会影响下一个命令。

变量作用及空值行为
ELF、PROJECT_ROOT覆盖主镜像或镜像解析用的项目目录;空值忽略;后者不替代 --config 选择配置文件
EXTRA_ELF按 shell 命令行规则解析镜像列表;空值明确清空列表
PROGRAM_NAMETRACE32 符号程序名;空值也生效
T32_SYS,其次 T32SYSTRACE32 安装目录;空值忽略
T32_HOST、T32_EXE、T32_BIN、T32_CONFIG、T32_DEBUG_ADAPTERTRACE32 主机平台目录及程序路径;空值忽略
T32_CPU、T32_CORES、T32_MEMACCESS、T32_JTAG_CLOCK、T32_DUALPORT目标设置;空值也生效
T32_FLASH_CHIP脚本匹配的芯片;空值忽略
T32_FLASH_SCRIPT、T32_FLASH_ARGS显式脚本及 shell 风格参数列表;空值清空
T32_RCL_PORT、T32_DAP_PORT、T32_DAP_BACKEND_PORTRemote API、DAP 对外及后端端口
T32_DAP_BACKEND_TIMEOUT、T32_TIMEOUTadapter 和 TRACE32 操作超时
RTT_SYMBOLRTT 符号;空值忽略

清空 EXTRA_ELF 会改变烧录与验证的镜像集合。尤其 TRACE32 的擦除范围由烧录脚本声明,不会因为列表缩短就自动保留其他镜像。

配置和日志放在哪里?

路径内容
<项目>/.rvdbg/history、openocd.log
<项目>/.tracebridge/PowerView 日志、工具栏脚本、时钟 HTML、trace 导出
~/.config/rvdbg/flash/本机烧录脚本库
~/.config/rvdbg/clock/本机时钟描述库

设置 XDG_CONFIG_HOME 时,本机库位于 $XDG_CONFIG_HOME/rvdbg/。受许可或保密条款限制的板级资料放本机库;仓库公开示例使用虚构寄存器,不能直接作为真实板子的配置。


烧录、加载符号与验证

English

先用配置检查确认镜像集合和后端。这里的三个命令解决不同问题:

命令使用时机目标影响
rvdbg flash程序内容需要更新写入 Flash、复位,正常完成后运行
rvdbg loadTRACE32 需要加载当前 ELF 的符号不写程序、不复位;会在需要时继续运行
rvdbg verify确认目标内容与本地 ELF 相符读取并比对,不自动停核或复位

如果重新编译改变了程序内容,load 不会把新程序写进板子。符号与目标代码不一致时,断点、PC 符号和栈解释都会失真。

多个镜像要一起声明

[project]
elf = "build/el2.elf"
extra_elf = ["build/guest.elf", "build/other-guest.elf"]

flash 一次处理主镜像和所有额外镜像;TRACE32 的 load 也加载它们的符号;不带 ELF 参数的 verify 依次检查整个集合。

TRACE32 使用 FLASH.ReProgram ALL /Erase:烧录脚本声明的扇区即使这次没有镜像写入,也可能被擦除。因此不要把 hypervisor 和 Guest 分成两次烧录来替代 extra_elf,也不要为了临时烧一个镜像而随意清空列表。

TRACE32:从脚本到运行

rvdbg flash 会在需要时启动 PowerView。烧录脚本必须支持 PREPAREONLY:它只初始化目标并声明 Flash 区域,随后由 rvdbg 执行写入。目标已处于 up 状态时,先 down,避免沿用应用留下的 MPU 等状态运行烧录算法。

主要烧录顺序是:

脚本 PREPAREONLY
FLASH.ReProgram ALL /Erase
Data.LOAD.Elf <主镜像>
Data.LOAD.Elf <额外镜像> /NoClear    # 每个额外镜像一次
FLASH.ReProgram OFF
SYStem.Down
SYStem.Up

后续设置调试环境、加载符号并在需要时运行。该路径不会自动执行本工具 verify 的逐段回读;需要确认内容时再执行 rvdbg verify。

脚本选择先看显式 script,否则用 chip,为空时用 trace32.target.cpu 匹配。候选先查本机 rvdbg/flash 库,再查 TRACE32 安装目录的 demo/*/flash:

rvdbg chips SR6P6
rvdbg flash --chip SR6P6
rvdbg flash --script '~~/demo/arm/flash/my_chip.cmm'

自动匹配要求脚本有合适的 ; @Chip: 和 PREPAREONLY 支持。精确匹配优先于通配符,更具体的通配符优先;仍然歧义时应明确指定脚本。若脚本接受 CPU= 且配置没有提供,rvdbg 会补充芯片参数。其他参数通过 [trace32.flash] args 指定。

flash、load 不会抢占正在运行的 PRACTICE 脚本;遇到 PowerView is busy 时按排障处理。

StellarLINK:写入、回读和运行

正常过程是 reset init,逐镜像执行 flash write_image erase,通过 memory_ap 回读可加载段并比对,最后 reset run。

rvdbg --backend openocd flash
rvdbg --backend openocd flash --no-run

--no-run 使烧录后目标保持停着;--no-verify 跳过烧录后的比对。两者以及 --write-otp 都只适用于 OpenOCD;TRACE32 的 --chip、--script 则不能用于 OpenOCD。

一般保留默认验证。发生差异时退出码为 3,先核对报告中的镜像、地址和读回内容,不应把跳过验证当作修复。

OTP 为什么会阻止烧录?

写入之前,工具先检查镜像中落入 openocd.otp 范围的内容。和目标相同则无需更改;不同则拒绝写入,除非显式使用 --write-otp。即便允许写入,需要将某一位从 0 改为 1 的请求仍会被拒绝,因为 OTP 不能擦除。

SR6P6 默认范围是存放启动记录的 UTEST:start = 0x29F87000、size = 0x1000。保护范围来自项目配置,并不自动覆盖所有芯片的一次性区域。--no-verify 不关闭 OTP 检查。

收到 OTP 差异后,先判断是不是选错镜像、启动记录变更或保护范围设置错误。只有确实计划永久改变该区域时,才由操作者决定使用 --write-otp。

单独核对板子上是什么

rvdbg verify
rvdbg verify build/el2.elf
rvdbg --backend trace32 verify --t32

比对的是 ELF PT_LOAD 段中的文件内容及其加载地址 LMA(p_paddr),不是初始化后 RAM 的全部运行状态。启动时复制到 RAM 的初始化数据因此在其加载位置比对;BSS 和业务状态应使用检查文件。

verify 无路径时检查配置中的全部镜像,显式给路径时只检查该 ELF。发现不一致时报告差异并返回 3;读取或解析失败返回 1。

TRACE32 的 --t32 额外使用 Data.LOAD.Elf /DIFF /PHYSLOAD /NoRegister /NosYmbol /NoClear 交叉比对,不改目标内存、PC 和已加载符号。

内容匹配后,继续用状态与项目检查确认程序运行到了预期位置,再接入IDE 调试。


调试与交互会话

English

本页从已经部署的程序进入调试。先确认本地镜像与目标内容一致,并确保 ELF 含调试信息;单纯拥有 .elf 后缀不代表其中有源码行号。

先选择是否改变目标状态

命令行为
rvdbg status查看状态,不自动停核
rvdbg attach不复位地连接目标,保留原有运行/停止状态
rvdbg halt停下所选核
rvdbg go继续所选核
rvdbg reset复位芯片并停在复位向量
rvdbg run-until <符号或地址>从停核状态运行到临时硬件断点
rvdbg downTRACE32:执行 SYStem.Down

使用 TRACE32 查看或控制目标前,PowerView 必须已经运行。rvdbg open 启动或复用 PowerView;需要加载符号时使用 rvdbg load,注意它会在目标停着时继续运行。

运行到检查点的示例:

rvdbg halt
rvdbg run-until rustvisor_boot_main --timeout 30
rvdbg status

符号需要在实际镜像中存在,且控制流之后确实能到达。目标原本已经运行时,run-until 不会先替你停核。停在其他位置时返回 3;超时不等于目标已经停止。StellarLINK 超时时目标继续运行,工具尽可能移除临时断点;下一步先检查状态。OpenOCD 路径使用 A32 硬件断点,不应直接套用于不同指令集的目标。

VS Code

rvdbg vscode

命令向项目的 .vscode/launch.json、tasks.json 合并配置,保留已有条目,修改前备份为 *.bak.<时间戳>。在 Run and Debug 中选择相应后端:

配置连接方式启动前准备与行为
TRACE32: Attach隐藏任务启动 rvdbg DAP 代理PowerView 已运行,符号已加载
StellarLINK: AttachCortex-Debug 接入 rvdbg debug 的 GDB server先烧录;SR6P6 板级脚本在 GDB 连接时会复位核

因此不能仅凭配置名中的 “Attach” 推断它保留现场。需要保存故障现场时,先用查看目标记录状态,再决定是否开启 IDE 会话。

TRACE32 的 Restart 由代理通过 Remote API 复位并继续运行。代理对 Locals 请求返回空列表,以避开部分 t32debugadapter 在 FreeRTOS 中断帧上的崩溃;寄存器、调用栈、监视表达式、断点和单步使用对应调试功能。

生成文件包含 rvdbg 和配置文件的绝对路径。项目搬家或工具安装位置改变后,重新执行 rvdbg vscode。

RustRover / JetBrains(TRACE32)

安装 LSP4IJ 插件后执行:

rvdbg rustrover

命令生成 .run/TRACE32 Attach.run.xml。选择 TRACE32: Attach 并启动 Debug,LSP4IJ 启动 DAP 代理并连接。此流程不提供 StellarLINK 配置;StellarLINK 使用 VS Code/Cortex-Debug 或 GDB。

第一个终端保持服务运行:

rvdbg --backend openocd debug

第二个终端加载实际主镜像并连接,下面的端口采用默认值:

arm-none-eabi-gdb build/el2.elf -ex 'target extended-remote :3333'

默认 GDB 断开后服务结束;rvdbg debug --keep 保持运行直到 Ctrl-C。如果复用已有交互会话的 OpenOCD,服务生命周期归原会话管理。额外镜像符号在手工 GDB 会话中需要自行加载;生成的 VS Code 配置会为 extra_elf 添加符号加载命令。

gdb_target 决定 GDB 调试哪个核;查看命令的 core 可以另设,见配置。外部命令停核、继续运行会影响同一个核上的 GDB 调试,不要把它们当作彼此隔离的会话。

多条命令:进入交互会话

不带子命令运行 rvdbg。下面是示意交互,提示符中的后端和状态以实际连接为准:

$ rvdbg
rvdbg [...]> status
rvdbg [...]> halt
rvdbg [...]> fault
rvdbg [...]> mem my_buffer 4
rvdbg [...]> go
rvdbg [...]> quit

会话提供 help [命令]、Tab 补全、backend trace32|openocd、reconnect 和 quit/exit。换探针后用 reconnect 重新检测。历史写入 .rvdbg/history。Ctrl-C 结束等待中的 RTT、FDX 或 run-until,保留会话;命令失败也不会直接退出。

StellarLINK 会话保持一个 OpenOCD 供命令与 GDB 共用。TRACE32 的查看命令、ram 和 fdx 共用首次使用时建立的连接;失败后丢弃,下一条命令重新连接,失败命令不会自动重试。flash、load、open 等另行管理连接。

TRACE32 自定义操作

rvdbg eval 'Register(PC)'
rvdbg cmd 'Break.Set my_function /Program /Onchip'
rvdbg do scripts/trace_setup.cmm

eval 求值,cmd 执行 PRACTICE 命令,do 运行脚本并等待结束。脚本出错停止时工具会收尾并报告;脚本停在对话框或 STOP 时留给操作者处理。命令或脚本能做什么取决于内容,包括改变寄存器、复位和烧录。

Trace 的配置和导出见查看目标;IDE 无源码、端口或脚本繁忙问题见排障。


查看目标与执行检查

English

先明确要观察的是运行状态、故障现场、程序内容还是业务条件。查看类命令不会为了满足读取条件而自动停核;check --halt 是需要明确选择的例外。

TRACE32 查看命令要求已有 PowerView;StellarLINK 优先复用 Tcl 端口上的 OpenOCD,否则启动不复位目标的实例。连接失败先看排障,不要直接复位仍有诊断价值的现场。

从状态到异常现场

rvdbg status
rvdbg halt
rvdbg status
rvdbg fault

第一条观察当前运行状态;halt 是显式改变目标状态的步骤。核停着时,status 显示 PC、符号偏移与解码后的 CPSR。fault 面向 AArch32 Hyp 异常,报告向量、HSR、HDFAR/HIFAR、ELR_hyp 及 SPSR_hyp;它不把任何停核都视为一次有效 Hyp 故障。

StellarLINK 的核心及协处理器寄存器读取要求核停着,Hyp 寄存器还要求核停在 EL2。停在 Guest EL1 后报错,并不证明 Hyp 寄存器没有值;需要在 hypervisor 内的合适断点取得现场。TRACE32 对部分 EL1 下的 Hyp 协处理器读取可以改用 HC15:,StellarLINK 没有同等替代。

记录结果后是否 go、reset 或重新部署,由当前诊断任务决定;这些操作见调试。

读一个值还是读一片 RAM?

命令适用对象单位与限制
mem <地址或符号> [个数]少量 32 位内存值;TRACE32 地址访问类;受支持的协处理器地址默认读 1 个 32 位字
ram <地址或符号> [个数]已知有效的普通 RAM 缓冲区批量 32 位字,地址需对齐;不能用于 MMIO/协处理器
ram <地址或符号> --write <值…>向普通 RAM 写入 32 位字改变目标内存,操作前确认所有权和地址
reg <名字…>TRACE32 PER 寄存器或字段名称区分大小写,可能需要完整路径
rvdbg mem my_buffer 4
rvdbg ram my_buffer 64 --json
rvdbg --backend trace32 reg HSR HSCTLR.C

ram 在运行中通过 TRACE32 AD: 或 StellarLINK MEM-AP 访问,不经过逐个寄存器表达式求值。地址和长度检查不能证明这片区域确实是普通 RAM;应由项目内存布局确认。目标正在更新的多字缓冲区也不保证是同一时刻的一致快照,需要固件协议或显式停核配合。

写入示例只用于自己控制的普通 RAM:

rvdbg ram my_buffer --write 0x12345678 0

MMIO 应用 mem 或项目检查文件,并先确认该寄存器的读取语义。工具没有执行写命令,不代表“读清除”类寄存器不会被硬件改变。

TRACE32 的 reg 通过 PER 定义解析名字和字段,再由 PowerView 读取值。重名且地址不同会列出候选路径;用完整路径消歧。watch 可打开 PER.Watch 窗口,需要支持该功能的 PowerView 版本,窗口本身不代替记录验收结果。

用 check 把人工判断写下来

把检查文件放在被测项目中,例如 checks/boot.toml。以下假定项目确实有 idle_loop 符号:

description = "Stopped at the idle loop"

[[check]]
name = "PC is in the idle loop"
read = { core = "PC" }
expect = { in_symbol = "idle_loop" }
rvdbg check checks/boot.toml --dry-run
rvdbg check checks/boot.toml --halt

--dry-run 解析名字和符号,不读取目标值;它检查文件能否解析,不证明目标满足条件。--halt 在需要读取核心/协处理器寄存器时先停核,结束后保持停着;如果要继续,显式执行 rvdbg go。

读取方式后端
read = { addr = "AD:0x..." }两者;地址和访问类必须适用于对应后端
read = { core = "PC" }两者,需要停核
read = { clock = "CORE" }两者,需要可用的时钟描述
read = { reg = "SCTRL" }TRACE32 PER
read = { expr = "..." }TRACE32 PRACTICE

数值条件包括 eq、ne、nonzero、range、in_symbol、one_of;适用的比较可带 mask。eq、ne、one_of 可用 "sym:名称+偏移" 表示符号地址。variants = ["debug"] 限制某项只在指定变体运行:

rvdbg check checks/boot.toml --variant debug --json

全部条件满足返回 0,已执行但条件不满足返回 3,无法执行检查返回 1。公开的检查文件示例展示更多语法,其中寄存器和值是虚构的,开头仍使用 tracebridge 命令示例;在 rvdbg 中使用 rvdbg check,并替换为项目自己的条件。

verify 回答目标的加载内容与 ELF 是否一致;check 回答当前观察值是否满足条件。二者配合使用,具体镜像比对规则见烧录与验证。

时钟树:先提供板子知道的输入

rvdbg clock
rvdbg clock XOSC=40MHz
rvdbg --backend trace32 clock --html

时钟描述通过 --tree 文件 指定,或从本机 rvdbg/clock 库按配置芯片匹配。[clock] 提供寄存器中不存在的信息,例如晶振频率;命令参数可临时提供输入。

输出同时显示当前源、频率和计算依据。off 表示关闭;? 表示输入或源未知;警告如 not locked 来自描述文件规则。相关寄存器读取失败时对应时钟显示错误并返回 1。工具读取到的是该次查询的寄存器值,结果是否正确也取决于描述公式和板级输入是否正确。

--html 仅 TRACE32 支持,生成 .tracebridge/clock.html,可在浏览器查看模块关系和当前有效路径。新增芯片描述可参考虚构时钟示例,真实芯片公式依据其手册编写,并遵守资料许可。

Trace:导出已经录下的内容(TRACE32)

rvdbg 不配置 ETM 和板级 trace 硬件。先用项目自己的脚本配置,再运行到目标位置,最后在核停着时导出:

rvdbg halt
rvdbg do scripts/trace_setup.cmm
rvdbg run-until batch_done --timeout 30
rvdbg trace --last 3000 --json > trace.json

脚本和符号需要来自实际项目。fault --trace 可把最新记录附在异常报告后。工具读取 PowerView 已记录的数据并重新查询符号,原始导出在 .tracebridge/trace.ad;周期列需要周期精确的 trace 配置,不能由普通地址记录推断周期数。


RTT 日志与 FDX 通信

English

RTT 和 FDX 都通过目标 RAM 与运行中的固件交换数据,不要求先停核。TRACE32 使用运行中内存访问,通常需要 dual_port = "ON";StellarLINK 使用配置中的 MEM-AP。二者都要求固件实现并初始化相应缓冲区,主机命令不会替固件创建协议。

需求使用什么
连续查看字符日志,或终端输入RTT 通道 0
向镜像发送一个包并等待约定回答FDX
直接检查普通 RAMmem / ram

RTT:先找到控制块

rvdbg rtt
rvdbg rtt --output-only
rvdbg rtt --replay

默认按 _SEGGER_RTT 符号找到控制块。--output-only 不转发键盘输入;--replay 先将上行通道读偏移设为零,以便显示缓冲区中已有内容,不能理解为回放全部历史日志。退出用 Ctrl-C,终端设置会恢复。

配置与临时覆盖示例:

[rtt]
symbol = "_SEGGER_RTT"
control_block_address = ""
poll_interval = 0.02
rvdbg rtt --symbol _SEGGER_RTT --poll 0.02
rvdbg rtt --cb 0x60000000 --output-only

最后一条的地址只是语法示例,必须替换成项目真实控制块地址。--cb 绕过符号查找,不能绕过固件尚未初始化、地址不可读或缓存一致性问题。TRACE32 还需正确的符号程序名 project.program。持续等待时按排障逐项确认。

FDX:链接属于一个镜像

rustvisor 使用 FDX BufferE 链接,默认符号是 RUSTVISOR_FDX。同一静态区域内相邻存放发往目标和发往主机的两个通道。主机通过 RAM 读写它们,因此两种后端都能使用。

rvdbg fdx
rvdbg fdx --guest 0

第一条默认选主 ELF;--guest 0 选 project.extra_elf 的第一个镜像,不是 VMID 0 或硬件核 0。交互终端把输入的每一行当作一个包,收到的包逐行显示。目标复位后重新打开链接时终端会重新跟上。

--symbol 可选择其他符号;--address 直接给地址,跳过 ELF 符号查找。符号和镜像选择规则与项目配置一致,地址必须指向实际有效的 FDX 链接。

脚本收发与超时

下面的消息是协议示例,仅适用于实现了这些消息的镜像:

rvdbg fdx --send "boot single" --expect "ok boot" --timeout 10 --json

工具先按顺序发送全部 --send 包,再按顺序等待 --expect 包。重复选项可以发送或等待多个包。--timeout 分别约束等待链接打开、发送空间及每个期望包的等待,不能理解为整条命令的总时间上限。期望包没有按时到达时返回 3。

FDX 只提供传输,消息的含义由固件定义;一个字符串可能触发启动、测量或状态修改。--json 只改变输出形式,不改变这些作用。脚本怎样判断结果见自动化。

谁拥有缓冲区?

同一 FDX 链接同一时刻只能由一个主机程序驱动。不要同时让板级 runner、rvdbg fdx 和 PowerView FDX.* 窗口使用它。RTT 也应避免多个读者竞争同一个通道的读偏移。

rvdbg fdx --close 将链接标成关闭;它用于板子保持复位、RAM 还残留上次打开状态的特定场景,会修改 RAM,不是通用的“断开主机连接”按钮。不要在固件或 runner 正在使用链接时执行。


脚本、JSON 与 AI agent

English

自动化首先要区分两种调用:一次性命令靠进程退出码判断;长期管道会话靠每条命令的结束记录判断。二者都应固定配置与镜像,记录 rvdbg 版本,并为等待操作设置期限。

一次性命令:先检查退出码

rvdbg status --json
rvdbg verify --json
rvdbg check checks/boot.toml --variant debug --json

把 --json 放在命令参数后面,尤其 cmd、eval、do 这类接收剩余文本的命令。查看命令的典型结果封装如下,result 的具体字段随命令而变:

{"command":"ram","ok":true,"exit_code":0,"result":{"symbol":null,"address":"0x60000000","words":[1],"hex":["0x00000001"]}}

这是格式示例,不是一次板上读取结果。--json 并不保证任意命令、任意失败阶段都只在 stdout 输出 JSON;配置加载失败等早期错误仍可能只有 stderr。不要把 stderr 合并进待解析的 JSON。

退出码含义脚本应如何处理
0命令完成、条件满足再按需要解析结果
1执行失败保存错误,区分配置、连接和读取问题
2用法错误修正参数,不重试目标操作
3已执行但结果不符合预期保存差异或失败条件,不能当作连接失败

返回 3 的场景包括 verify 不一致、check 条件未满足、run-until 停在其他位置,以及 FDX 期望包超时。不要无条件重试 flash、reset 或协议消息;重试会再次改变目标。

一个只读取状态的 Python 示例:

import json
import subprocess

completed = subprocess.run(
    ["rvdbg", "status", "--json"],
    capture_output=True, text=True, timeout=15,
)
if completed.returncode != 0:
    raise SystemExit(completed.stderr or completed.stdout)
report = json.loads(completed.stdout)
if not report["ok"]:
    raise SystemExit(report)
print(report["result"])

对于可能返回 3 的命令,先保存 stdout 中的结构化报告,再按退出码分类。烧录的超时预算应覆盖实际 Flash 耗时,不能照搬上面的 15 秒。

多条命令:NDJSON 管道会话

rvdbg --json 在 stdin 来自管道而非终端时启用机器会话:

printf '%s\n' 'status' 'quit' | rvdbg --json

首先输出 ready 记录,再逐行执行命令,并在每条命令自己的输出后追加 end 记录。以下省略了命令结果,值仅作示意:

{"ready":true,"version":"0.1.25","config":"/work/project/rvdbg.toml","backend":"openocd","reason":"..."}
{"end":"status","ok":true,"exit_code":0,"error":null}
{"end":"quit","ok":true,"exit_code":0,"error":null}

ready: true 表示进入协议循环,不代表目标检查成功;还需要检查 backend、连接信息和实际命令结果。未能确定后端时 backend 可以为 null。

客户端按下面的顺序驱动:

  1. 启动进程,读取 ready,确认版本、配置路径和后端符合预期。
  2. 写一条命令并 flush;持续收集输出,直到对应 end。
  3. 以该记录的 ok、exit_code、error 判断结果,再决定下一条操作。
  4. 最后发送 quit 或关闭 stdin,等待进程退出并收集 stderr。

查看命令、ram 和 FDX 单次收发提供结构化输出;flash、load 等仍可能输出进度文本。机器客户端应把这些文本保存为日志,并识别已约定的 JSON 记录,不能假定每一行都是同一结构。持续交互的 rtt/裸 fdx 不适合作为普通请求插入该循环;FDX 使用带超时的单次收发模式,见通信。

会话读到 EOF 后可以返回 0,即使之前某条命令失败。 所以 shell 管道最后成功不能证明所有检查成功,必须消费每个 end。会话还会在命令失败后继续接收输入;若失败后不应继续执行,客户端需要等 end 后再决定,而不是预先把整段破坏性流程全部写入。

客户端也应为启动、每条命令和进程退出设置超时,并持续处理 stderr,避免日志管道填满。连接丢失后先检查目标状态,不要直接重放先前命令。

与 rustvisor-sdk 板级 runner 配合

当前 SDK 集成使用已安装的 rvdbg(至少 0.1.24,或 runner 支持的 RVDBG 路径覆盖),通过 rvdbg --json 通信,每次烧录使用一个会话。镜像通过 ELF、EXTRA_ELF、PROGRAM_NAME 选择;具体测试计划仍属于 SDK 的 runner。

编写自己的 runner 时,把 ready/end 协议和命令结果作为接口,不解析带颜色的人类表格。记录镜像、配置、版本和检查报告,才能区分“内容写入一致”“检查满足”和“业务运行正确”。现有 Rust 库集成说明见开发者后端文档,它与 SDK 当前通过子进程调用的路径不同。

AI agent 使用哪一层?

rvdbg skill
rvdbg skill --dir /path/to/agent/skills

默认安装到 $CLAUDE_CONFIG_DIR/skills 或 ~/.claude/skills,升级 rvdbg 后重新安装以更新说明。该 skill 说明命令选择、后端限制,以及目标状态变更的确认要求;不要让 agent 自动添加 --write-otp。

TRACE32 通用断点、单步、调用栈和交互调试可配合 Lauterbach t32mcp;烧录、专用诊断、验证、时钟和 RAM/FDX 流程由 rvdbg 提供。它们共享同一个 PowerView,PRACTICE 脚本同一时间只能运行一个。StellarLINK 使用 rvdbg 与 GDB 路径,详见调试。

如果为 agent 配置免确认规则,依据操作影响和实际参数限制范围。check 可带 --halt,ram 可带 --write,不能仅用宽泛命令前缀把所有调用当作只读。


按现象排障

English

先保留报错和现场,再判断故障在配置、服务、探针还是目标。rvdbg config 显示工具准备操作什么;rvdbg status 查看当前状态。不要先复位再试图恢复已经消失的异常现场。

没发现探针,或者选错后端

现象: no probe found,或命令实际走了另一种调试器。

运行 rvdbg config,检查检测到的 USB 探针、PowerView 和配置中的固定后端。两种探针同时存在时默认 TRACE32;本次要用 StellarLINK,使用 rvdbg --backend openocd ...。交互会话插拔探针后执行 reconnect。

明确指定后端只跳过自动选择,不能证明物理连接可用。成功标准是实际后端命令能读取目标状态。规则见配置。

TRACE32 端口有响应,但 rvdbg 连不上

现象: no PowerView on RCL port ...、not a usable TRACE32 RCL endpoint,或启动后一直未就绪。

  • 尚未启动 PowerView:执行 rvdbg open,随后再运行查看命令。
  • 已有 config.t32 定义 RCL=:确认是 NETTCP,PORT= 与 trace32.rcl_port 一致。
  • 端口已占用但协议不对:确认监听者确实是预期 PowerView,避免把其他服务当作 Remote API。
  • 启动失败:查看 <项目>/.tracebridge/powerview.log,核对安装目录和启动配置。

不要为了排障移除本机访问限制。连接设置见快速开始,启动路径见配置。

OpenOCD 起不来,或复用了别的会话

检查 rvdbg config 中的 executable、板级脚本、Tcl/GDB 端口,随后查看 .rvdbg/openocd.log。确认安装的是 openocd-stellar,脚本存在,目标已供电,探针连接正确。

rvdbg 会优先复用 Tcl 端口上已有的 OpenOCD。多个项目不能无意共享同一组端口;也不要仅因端口冲突就结束不明来源的调试服务。为项目设置独立端口,重新建立所需会话,见配置。

命令或选项只支持 TRACE32

现象: ... is available with TRACE32 only,或选项被提示只适用于一个后端。

先确认这次是不是有意使用 OpenOCD。reg 的 PER 名称、PRACTICE、trace、时钟 HTML 都没有直接的 StellarLINK 对应。寄存器可改用项目确认过的地址或检查文件,不能把 PER 名称当作物理地址。功能对照见手册入口,读取方式见查看目标。

运行中读不到核心或 Hyp 寄存器

现象: ... can only be read while the core is halted,或停在 Guest 时仍无法读 Hyp 寄存器。

读取内存和读取核心状态有不同条件。需要停核时显式执行 rvdbg halt,或对检查选择 --halt。StellarLINK 还需要核当前处于 Hyp/EL2;应在 hypervisor 的合适断点停下。不要把当前在 EL1 造成的不可读误判为异常寄存器全零。诊断后 check --halt 不会自动继续,见查看目标。

PowerView is busy

flash、load、reset、do 会拒绝覆盖正在运行的 PRACTICE 脚本。脚本可能来自其他工具,也可能停在对话框、STOP 或错误位置。先到 PowerView 确认脚本用途,等它结束;确实需要放弃时由操作者结束脚本,再执行原命令。

调大超时不会解除脚本栈冲突。共享服务的规则见调试。

烧录超时、验证差异或 OTP 拒绝

现象下一步
烧录确实还在进行核对 trace32.operation_timeout / openocd.timeout;TRACE32 同时看 AREA 输出
verify 返回 3保存首个差异地址,核对本地镜像、加载地址和本次完整镜像集合
另一个镜像消失核对 extra_elf,尤其 TRACE32 的全范围擦除行为
OTP 内容不同核对启动记录和保护范围;确定是否原本就不应更改该区域

不要将 --no-verify 或 --write-otp 作为通用重试选项。操作顺序和保护规则见烧录。

IDE 只有汇编、没有源码,或断点不对

确认 IDE 加载的 ELF 与板子一致,再检查 ELF 是否有 DWARF 行号。Rust release profile 可启用 debug = true 并重新构建;这会改变构建产物,构建后按正常流程核对或重新部署,不能直接假定新 ELF 与旧目标一致。

TRACE32 需要加载正确符号;GDB 需要读取正确 ELF 和额外镜像符号。项目移动后重新生成 IDE 配置。TRACE32 Locals 为空是代理的既定行为,见调试。

RTT 无输出,或者 FDX 等不到回答

RTT 先确认固件已经执行初始化,再核对符号/地址和 TRACE32 程序名。给出 --cb 只绕过符号定位,不能修复错误控制块。

FDX 先确认选择的是主镜像还是 --guest N,再确认固件确实实现了发送的消息。结束其他 runner/终端对同一链接的占用;检查期望包内容与超时。不要向不明链接反复发送会改变目标的命令。缓冲区和超时含义见RTT 与 FDX。

脚本显示成功,但其中一个检查失败

如果使用 rvdbg --json 管道会话,检查每条命令的 end 记录。会话最终退出码 0 仅说明输入循环正常结束,不能覆盖某条命令返回的 3。若只按进程退出码判断,应改用一次性命令,或实现会话协议的逐条结果判断。


维护这本手册

English

中文正文按任务平铺在 docs/guide/cn/,对应英文页面放在 docs/guide/en/。中英文各是一本独立的 mdBook,各有自己的 SUMMARY.md 和 book.toml;根目录的 README.md 是 GitHub 和 Obsidian 中的语言入口,site/ 存放网站首页的语言选择页。一个短主题使用一个文件;只有出现多个需要独立持续维护的长主题时,才考虑增加目录。README.md 提供任务入口,SUMMARY.md 维护 mdBook 阅读顺序,二者都不应替代正文。

从一次操作往前写

每篇先交代适用项目、后端、镜像及起终点。主线依次说明前提、命令、目标影响、预期结果和失败后下一步。后端差异放在发生差异的位置,不要求用户拼接两套完整教程。

命令第一次出现时解释它改变什么。特别区分烧录、复位、停核、加载符号、运行中 RAM 访问和固件消息。普通 RAM 示例不能推广到 MMIO;示例地址、符号、协议消息和虚构寄存器要明确说明需要替换。

CLI 默认值、选项及行为先核对当前实现,再修改手册。主要依据是 CLI 定义、初始化模板、配置解析、会话协议及对应后端。网页链接的 main 跟随仓库主线;排查特定发布版本时,应切到对应 tag/commit 核对。

源码和模拟测试说明实现及预期,不说明某次板上操作已通过。声称上板验证时,应给日期、镜像、后端、判据和记录位置;本手册的命令与输出示例不作为实测记录。

正文链接与自动反向链接

使用标准 Markdown 相对文件链接,例如 [配置](configuration.md),便于 GitHub、mdBook 和 Obsidian 共同阅读。每个行为保留一个主要解释位置,其他页面在需要处引用它。不要为增加关系数量而互相堆链接。

把 docs/guide/ 作为 Obsidian vault 打开,使用 Markdown 链接格式即可查看编辑器反向链接。mdBook 构建时由仓库的 tools/docs/links.py 解析正文链接,在页面末尾添加“引用此页”;只修改构建内容,不回写 Markdown,也不把生成的反向链接再次算入引用关系。

新正文页必须加入 SUMMARY.md。工具会检查遗漏、重复收录、文件是否存在,以及链接目标是否属于手册。指向手册之外的源码、示例或旧文档时,使用仓库网页链接,避免生成网站后相对路径失效。参考式链接也可使用,代码块和行内代码中的示例链接不计入引用。

中英文保持相同文件名和内容覆盖,每页提供双向语言切换。指向另一种语言(../en/…)的链接只用于语言切换:工具检查目标存在,但不生成反向链接。其他链接都留在本书之内。

本地构建与检查

在本仓库根目录执行,文档依赖只用于构建手册,不是 rvdbg 运行依赖。需要 Python 3.10+ 和 mdBook 0.5.4:

cargo install mdbook --version 0.5.4 --locked
python3 -m venv target/docs-venv
. target/docs-venv/bin/activate
python -m pip install -r tools/docs/requirements.txt
python -m unittest discover -s tools/docs -p 'test_*.py'
tools/docs/build.sh

build.sh 把两本手册和语言选择页构建到 target/guide/,并检查所有生成的链接:语言入口为 index.html,中文打开 cn/index.html,英文打开 en/index.html。需要自动重建预览一本时执行 mdbook serve docs/guide/cn --open(此时语言切换链接指向另一本,serve 不会构建它)。网站地址是 https://rvdbg.docs.haoyichen.com,CI 从 main 自动部署;本地部署在 build.sh 之后执行 cd docs && npx wrangler deploy。启动 mdBook 时应保持虚拟环境激活,因为它通过 python3 调用预处理器。构建过程的依赖机制见 mdBook 预处理器说明。

交稿前检查目录、页面间跳转、反向链接和长表格显示,并执行 git diff --check。HTML 检查确认生成文件和片段链接有效;它不验证外部网站可达性,也不代替实际操作命令的板级验证。