Rust in Everything
基于 probe-rs-tools 0.32.0

probe-rs run 跑起来了,一行日志也没有

主线位置:命令主线第五步「轮询」里的「读 RTT」。控制块怎么找、怎么校验在 RTT 控制块与通道 里讲过;本页讲找不到时命令行的反应:它不报错。

flowchart TB
  elf["parse_metadata:ELF 里有 _SEGGER_RTT 吗"] -->|有| exact["ScanRegion::Exact(地址)"]
  elf -->|没有| arg{"给了 --scan-region 吗"}
  arg -->|"没给:默认空串"| empty["Ranges(空)"]
  arg -->|给了| scan["Ram 或 Ranges:整段读出来找魔数"]
  empty --> nl["NoControlBlockLocation:不再尝试"]
  exact --> at["attach_at:读 24 字节头"]
  scan --> at
  at -->|"魔数不对"| nf["ControlBlockNotFound:下一轮再试"]
  at -->|对| ok["连上,按通道名选解码器"]
  nl --> silent["终端:没有任何 RTT 输出,也没有错误"]
  nf --> silent

现象

固件跑起来了(烧录成功、probe-rs run 没有退出),终端上却什么都没有;没有报错,Ctrl-C 后正常退出。命令行把 RTT 的两种「找不到」都当成正常状态,只打 debug 级别的日志:

// probe-rs-tools/src/bin/probe-rs/util/rtt/client.rs,try_attach_impl
            let location = match Rtt::find_control_block(core, &self.scan_region) {
                Ok(location) => location,
                Err(Error::ControlBlockNotFound) => {
                    tracing::debug!("Failed to attach - control block not found");
                    return Ok(false);
                }
                Err(Error::NoControlBlockLocation) => {
                    tracing::debug!("Failed to attach - control block location not specified");
                    self.try_attaching = false;
                    return Ok(false);
                }
                Err(error) => return Err(error),
            };

(client.rs:80)后面 attach_at 返回 ControlBlockNotFound 或 ControlBlockCorrupted 时同样只打 debug 日志。要看到它们,设 RUST_LOG=debug(命令行没给日志级别时读这个环境变量)。

同样两种错误交给库的调用方时是这样(FakeProbe 上 attach STM32L475VGTx,cargo runner 与 defmt 三件套里的固件;FakeProbe 读 RAM 得 0):

== find_rtt_control_block_in_raw_file(fw.elf) -> Some(0x20000008)
== find_rtt_control_block_in_raw_file(fw-stripped.elf) -> None
== Rtt::attach_region(Ranges(vec![])) -> Err("There is no control block location given. This usually means RTT is not present in the
firmware.")
== Rtt::attach_region(Exact(0x20000008)) -> Err("RTT control block not found in target memory.
- Make sure RTT is initialized on the target, AND that there are NO target breakpoints before RTT initialization.
- For VSCode and probe-rs-debugger users, using `halt_after_reset:true` in your `launch.json` file will prevent RTT
initialization from happening on time.
- Depending on the target, sleep modes can interfere with RTT.")

两条路

没有位置:NoControlBlockLocation,从此放弃。 parse_metadata 在 ELF 符号表里找不到 _SEGGER_RTT,就用 --scan-region 的值,而它的默认值是空串,parse_scan_region 把空串解析成空的范围列表。find_control_block 对空列表直接返回 NoControlBlockLocation,RttClient 把 try_attaching 置假,整个 run 期间不再读 RTT。--help 里写着这条规则:「If no region is specified, probe-rs will not scan and will not poll RTT.」

什么时候会没有符号:

  • ELF 被 strip 了。上面实验里 rust-objcopy --strip-all 之后 find_rtt_control_block_in_raw_file 返回 None;同时 .defmt 段也没了,就算扫到控制块,defmt 也解不了码。
  • 传给 run 的不是 ELF(--binary-format hex / bin),没有符号表可读。
  • 固件里根本没有 RTT:没依赖 defmt-rtt 或 rtt-target,或者日志走的是 semihosting、串口。

有位置但魔数不对:ControlBlockNotFound,每轮重试。 有了地址,每一轮轮询都 attach_at 一次,读到的 16 字节不是 "SEGGER RTT" 就算没找到,下一轮再来(RTT 控制块与通道)。所以这种情况会自愈:控制块一出现就连上。持续不出现的原因:

原因说明
固件停在 RTT 初始化之前报错原文的第一条。defmt-rtt 的控制块在 .data 里,启动代码拷完 .data 就有;rtt-target 0.6 的控制块是没有初值的 MaybeUninit,要等 rtt_init! 执行时才写进去。断点下在这之前、或固件在初始化前就 HardFault,都看不到
VS Code 里 haltAfterReset: true报错原文的第二条:核停在复位处,.data 还没拷(VS Code 调试配置)
芯片睡眠影响调试访问报错原文的第三条;哪些芯片会这样待实测
读到的是上一次运行的旧控制块反过来的情况:命令行在监控开始时会先清掉控制块(RTT 控制块与通道),避免连上旧的、通道配置不对的那一份

还有一种不是「没有输出」而是「输出是乱码」:通道名叫 defmt 而 ELF 里读不出 defmt 表时,原样按二进制打印(defmt 与 semihosting)。

DAP 那边多一个开关

VS Code 里还有一层:rttEnabled 默认是 false,不打开它 dap-server 根本不碰 RTT(VS Code 调试配置)。

怎么办

  1. 确认 ELF 带符号:nm <elf> | grep _SEGGER_RTT。有它,命令行用确切地址,不需要扫描。
  2. 只能用没有符号的镜像时,显式给 --scan-region ram(扫所有 RAM)或一个范围。扫描就是把整段 RAM 读出来找魔数,模拟目标上 20 KiB 是 5149 次访问(RTT 控制块与通道),范围越小越好。
  3. --list-rtt 列出通道后退出,能确认连没连上、有哪些通道。
  4. 设 RUST_LOG=debug 看是哪一种「找不到」。
  5. 固件里尽早初始化 RTT;用 defmt-rtt 的话这一条天然满足。

小结

  • RTT 找不到时命令行不报错:NoControlBlockLocation 让它整场不再尝试,ControlBlockNotFound 让它每轮重试,两者都只写 debug 日志。
  • 没有 _SEGGER_RTT 符号(strip、非 ELF、固件没有 RTT)又没给 --scan-region 时,属于前者;控制块还没初始化(断点、haltAfterReset、早期 HardFault)属于后者。
  • 带着符号运行、必要时 --scan-region,用 --list-rtt 和 RUST_LOG=debug 确认;VS Code 还要打开 rttEnabled。

💬 关联讨论

发起讨论
加载中...