主机边界:默认使用标准库模型、可重放输入、断言、测试报告、故障矩阵和 provenance 清单;没有目标板也能完成问题定位、合同测试和报告生成。
目标机边界:真实 CoreSight/SWD、探针、GDB server、寄存器、时钟、IRQ/DMA、供电、夹具、波形、温度、执行器和复位路径必须回到当前芯片、板卡和官方资料。
01 · DEBUGGING MODEL
调试坐标:现象、假设与证据
调试不是在代码里寻找一个看起来可疑的行,而是把现象、对象、输入、时序、假设和证据组织成可反驳的闭环。先描述发生了什么,再决定需要哪一种观察;断点、日志、波形、寄存器和复现脚本各自只能覆盖一部分事实。
11.1.1 现象与断言的边界
调试记录的第一句应是可观察现象,而不是原因。例如‘在固件 v1.4、板卡 rev B、输入序列 S、室温、运行 37 分钟后,任务 control 的 progress 停止,250 ms 后发生 IWDG 复位’比‘线程死锁了’更有价值。前者可以被复现和反驳,后者已经把假设伪装成结论。
11.1.2 对象、版本与复现条件
对象身份是复现的坐标系:MCU 型号与修订、板卡、外围器件、固件提交、FreeRTOSConfig、工具链、时钟、供电、负载、输入和访问日期都可能改变现象。现场只给一张截图或一个版本号时,应把缺失字段列成未知项,而不是用开发者记忆补齐。
PYTHON · REPRODUCTION RECORDfrom dataclasses import dataclass @dataclass(frozen=True) class Observation: stage: str signal: str value: str timestamp: int def same_case(a, b): return (a.stage, a.signal, a.value) == (b.stage, b.signal, b.value)
主机模型固定现象字段;目标机仍需补芯片、板卡、探针和真实时序。
C · ASSERTION AT THE BOUNDARYconfigASSERT(queue_length <= queue_capacity); configASSERT(owner == current_task); record_fault(stage, task_name, tick, build_hash);
断言应靠近资源边界并保存上下文;不能用日志证明所有并发交错。
11.1.3 假设树与反证路径
假设树把同一现象拆成互斥或可组合的机制,例如复位来自看门狗、brownout、硬件引脚、异常向量或人工下载;数据错位来自长度、端序、竞争、缓存或旧缓冲。每个分支都要有一个最小实验和预期反证,而不是沿着最熟悉的代码路径漫游。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 现象 | 输入/对象/时间/输出 | 原因假设就是事实 |
| 工具 | 扰动/覆盖/带宽 | 断点不会改变行为 |
| 结论 | 复现率/证据/未知 | 一次不复现等于修复 |
11.1.4 单变量实验与对照组
单变量实验要求固定对象、版本、输入、时钟、负载和观测方法,只改变一个条件,并保留对照组。如果同时提高队列容量、降低采样率和改锁顺序,即使现象消失也无法知道哪个变量有效。对照不一定是‘旧代码’,也可以是合成输入、关闭一个功能或在主机模型中复现同一状态。
11.1.5 断点、日志与观测扰动
断点会停止 CPU、改变超时和中断交错,日志会占用栈、串口和锁,GPIO 标记会改变引脚和总线,环形缓冲会消耗内存。GDB 文档提醒实时行为可能因调试器延迟而显著变化,因此要选择不侵入或低侵入的观测方式,并记录工具、触发和观测开销。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.1.6 不变量、断言与契约
不变量是任何合法执行都应成立的关系,例如队列长度不超过容量、拥有锁的任务才可释放、序号不回退、状态为 RUNNING 时资源已经绑定。断言应尽量靠近边界,失败时保存上下文;不要用大量 printf 代替不变量,因为日志输出本身不能阻止错误继续扩散。
11.1.7 复现率、置信度与未知项
复现率应包含尝试次数、时间窗口、输入集合和工具版本。一次没再出现不等于修复,十次出现也不一定覆盖最坏条件。报告可以写‘在 100 次主机重放中 100 次触发’或‘目标机 8 小时未触发,但低温/满载未覆盖’,把置信度和未知项一起交付。
11.1.8 本节交付:调试坐标卡
调试坐标卡包括 symptom、object_identity、build_hash、input_vector、environment、timeline、hypotheses、experiment、control、observation_tool、reproduction_rate、confidence、known_limits 和 next_variable。它让下一单元的 SWD/GDB 连接有明确目标,而不是打开调试器后漫无目的地单步。
请围绕“调试坐标:现象、假设与证据”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
02 · PROBE AND HALT
连接与停机:SWD、GDB 与现场
SWD/JTAG、调试探针和 GDB 把主机观察带到目标机,但连接成功不等于程序、符号和现场一致。需要理解 CoreSight/DAP、复位与 halt、符号文件、远程协议、寄存器副作用和调试扰动,才能把一次停机变成可靠证据。
11.2.1 CoreSight、DAP 与 SWD/JTAG
CoreSight 是片上调试与追踪组件的架构,SWD/JTAG 是到调试访问端口的物理/协议入口,探针固件、调试服务器和 GDB 则组成主机到目标的控制链。任何一层不匹配都可能出现‘能连上但读错’:例如目标 ID 对了,当前 ELF 却是另一块板或另一版链接地址。
11.2.2 探针、服务器与 GDB 路径
GDB 的 remote debugging 需要主机拥有与目标完全匹配的未剥离程序和符号;连接模式、目标服务器、串口/TCP、复位选项和 monitor 命令都会影响结果。先记录探针型号、固件、服务器版本、连接命令和目标回应,再解释 PC、栈和变量,不要把终端上一次成功连接当成身份凭证。
SHELL · GDB SESSIONopenocd -f interface/stlink.cfg -f target/stm32.cfg arm-none-eabi-gdb build/firmware.elf (gdb) target extended-remote :3333 (gdb) monitor reset halt (gdb) info registers pc sp lr (gdb) bt
命令只是会话形状;探针、目标脚本、复位方式和 ELF 必须与当前硬件匹配。
C · FAULT SNAPSHOTtypedef struct { uint32_t pc, lr, sp, cfsr, hfsr, reset_cause; uint32_t task_id, progress; } fault_snapshot_t; volatile fault_snapshot_t last_fault;
现场结构帮助重放;寄存器取值和保存区域必须按芯片与启动代码核对。
11.2.3 复位、halt、attach 与 resume
连接卡死目标时,先确认供电、复位、SWDIO/SWCLK、调试权限和低功耗状态,选择不会自动 mass erase 的命令。reset halt、attach、load、resume 的顺序应符合当前探针和芯片手册;如果固件在启动早期关闭调试或重映射时钟,可能需要硬件复位、connect-under-reset 或安全的最小恢复镜像。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 连接 | probe/target/server | 能连就身份正确 |
| 现场 | ELF/PC/SP/寄存器 | 读数没有副作用 |
| 恢复 | resume/reset/safe | 继续运行不会丢证据 |
11.2.4 ELF、符号与地址一致性
ELF、map、源码和目标 Flash 必须来自同一构建。编译器优化会让变量消失、代码折叠或行号不直观;断点落在近似行不代表执行了那条源语句。保存 ELF/source/config 哈希、链接地址和加载命令,必要时用反汇编、寄存器和栈帧交叉核对。
11.2.5 寄存器、内存与副作用
内存和寄存器访问并非普通数组读写:读状态可能清标志、弹 FIFO 或触发总线,写保留位可能产生未定义行为,停机时 DMA/外设也可能继续改变内存。取证前查当前芯片参考手册,先读安全快照区和核心寄存器,再决定是否访问有副作用的地址,并记录每次访问。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.2.6 断点、观察点与实时扰动
软件断点可能修改指令,硬件断点/观察点数量有限,单步会改变中断交错,实时 trace 也有带宽和时间成本。GDB 文档对实时程序的警告意味着:若问题依赖时间,优先用非停机 trace、GPIO 标记、环形日志或复制输入;若必须 halt,要把‘在调试器下观察’单列为不同条件。
11.2.7 安全、权限与调试生命周期
调试口是权限边界。开发板可以开放 SWD、读写内存和 monitor 命令,量产设备可能启用读保护、认证调试或彻底关闭端口。证据包不得公开密钥、生产令牌或未经授权的内存内容;记录调试生命周期、解锁审批、恢复镜像和重新锁定步骤。
11.2.8 现场快照与继续运行
最小现场快照包括 reset cause、fault status、PC、LR、SP、任务名/状态、当前锁/队列、时间、构建哈希和安全输出状态。保存后再决定 continue、detach、reset 或断电;继续运行可能覆盖证据,直接复位则可能丢失现场。目标机记录要注明哪些寄存器因副作用未读取。
11.2.9 本节交付:连接停机卡
连接停机卡包括 probe、server、target_id、reset_mode、connection_log、elf_hash、symbol_hash、pc/lr/sp、fault_regs、stack_window、side_effects、security_scope、resume_action 和 target_limits。它把调试器从‘万能钥匙’还原成有前提、有扰动、有恢复动作的测量工具。
请围绕“连接与停机:SWD、GDB 与现场”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
03 · HOST TESTING
主机测试:单元、属性与回归
主机测试把纯逻辑、协议、状态机、配置解析和故障策略从寄存器依赖中拆出来。单元测试验证局部合同,属性/变形测试验证规律,回归测试保护已修复的行为;测试通过的范围必须和目标机仍需测量的事实并列呈现。
11.3.1 测试对象与可观察输出
一个好单元测试只承诺一个局部合同:给定对象、输入、时钟和依赖,函数应返回什么、改变什么、留下什么错误。Python unittest 将 fixture、TestCase、suite 和 runner 分开,测试命名和 discovery 让读者可以独立运行;同样的思想也适合 C 的状态机和协议解析器。
11.3.2 fixture、fake 与依赖隔离
fake 和 stub 的价值是控制依赖,不是让测试永远成功。假时钟应可推进,假总线应记录顺序和副作用,假存储应模拟满、坏块和重启;如果 mock 只返回 happy path,测试会证明 mock 的行为,而不是被测代码的边界。依赖接口越小,主机和目标实现越容易对照。
PYTHON · UNIT TESTimport unittest class QueueContract(unittest.TestCase): def test_full_queue_is_explicit(self): queue, accepted, reason = offer([1, 2], 3, 2) self.assertFalse(accepted) self.assertEqual(reason, "full")
主机断言队列合同;目标机还需测量 ISR、缓存和真实生产速率。
PYTHON · PROPERTY SHAPEdef round_trip(codec, values): for value in values: encoded = codec.encode(value) assert codec.decode(encoded) == value # Save seed and failing value when a generated case breaks.
属性示例强调可重放输入;它不替代目标寄存器和电气验证。
11.3.3 边界、错误和不变量
边界测试应优先覆盖零长度、最大长度、截断、重复、超时、空队列、满队列、无效状态、整数溢出、资源耗尽和异常恢复。每个输入都要有明确处理:拒绝、截断、降级、重试、故障或安全停机。静默接受坏输入往往比显式失败更难定位。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 局部 | fixture/input/assert | 通过 happy path 就够 |
| 规律 | property/seed/mutation | 覆盖率等于质量 |
| 边界 | host/target scope | 主机通过就是实机通过 |
11.3.4 属性与变形测试
属性测试不只检查几个样例,而是检查规律,例如 encode/decode round-trip、排序保持长度、序号去重不增加副作用、同一 seed 产生同一 trace。变形测试可以对输入做可解释变换,再比较输出关系;失败时保存原始输入、变换、seed 和版本,避免随机数字成为不可重放的故事。
11.3.5 随机种子与确定性重放
随机测试必须把 seed、生成器版本、输入摘要、环境和失败序列写入报告。固定 seed 的重放是最低要求;更长期的回归还应把失败样例转成独立命名的确定性测试。这样修复不会依赖‘再随机一次刚好撞到’,也能比较不同实现或编译选项的行为。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.3.6 覆盖率、突变与盲区
覆盖率可以发现未经过的行、分支或状态,但高覆盖率不代表断言正确,也不代表真实硬件路径覆盖。突变测试通过故意改变实现来检查测试是否能杀死错误;仍存活的突变是测试盲区提示。报告要说明测量工具、样本集合、排除项和目标机未覆盖的寄存器/时序事实。
11.3.7 回归套件与失败隔离
回归套件要隔离 fixture、避免测试顺序依赖,并保存失败最小输入。一个测试可以在单独运行时通过、整套运行时失败,说明共享状态、随机种子、时间源或临时文件污染了证据。为每项测试设置清理、超时和资源上限,失败后仍输出可以直接重放的命令。
11.3.8 测试报告与主机边界
主机测试卡包括 test_id、contract、fixture、input、expected、actual、seed、command、toolchain、coverage_scope、mutation_notes、replay_command、host_result、target_required 和 stop_conditions。结论应写‘模型合同通过’,而不是把它升级为‘板卡实时性、EMI 或电气安全通过’。
11.3.9 本节交付:主机测试卡
交付问题: 提交命令、种子、报告、覆盖和边界。交付动作是“把结果交给目标机验证单元”,相应输入、输出或未执行边界必须在记录中逐项对应。
请围绕“主机测试:单元、属性与回归”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
04 · TARGET VALIDATION
目标机验证:HIL、覆盖率与测量
目标机验证不是把主机测试重新跑一遍,而是确认平台边界:编译产物、链接地址、时钟、端口、寄存器、IRQ/DMA、功耗、仪器和负载是否让主机断言仍然成立。QEMU、native_sim、HIL 与真实板卡各自覆盖不同事实,应按风险安排层级。
11.4.1 仿真、仿真器与真实硬件
主机、仿真器、HIL 和真实板卡是证据层级,不是质量等级。主机适合快速验证算法和合同,QEMU/native_sim 可能覆盖部分架构和系统调用,HIL 把真实输入输出接入固件,实机才承担芯片寄存器、电气、时钟、供电和环境事实。每层报告都要写清‘证明了什么’和‘没有证明什么’。
11.4.2 Twister/ZTest 的测试场景
Zephyr Twister 会扫描测试应用,按场景和平台构建,并可在仿真器或真实设备上运行;它的报告也区分只构建、仿真和设备测试。把同一测试场景放进平台矩阵,能发现配置差异,但不能保证所有本地改动在完整环境成功,仍需审查覆盖。
YAML · TEST MATRIXtests: realtime.contract: platform_allow: - native_sim - qemu_cortex_m3 harness: ztest realtime.board: platform_allow: - nucleo_f401re harness: console
平台矩阵要区分构建、仿真和真机;名称、版本和板卡清单按项目实际配置。
C · GPIO TIME MARKTRACE_SET(); run_contract_step(); TRACE_CLEAR(); /* capture UART, GPIO, power and reset cause together */
GPIO 标记只覆盖标记点之间的路径;触发、采样率、负载和环境必须记录。
11.4.3 HIL 夹具与输入生成
HIL 夹具要定义输入精度、延迟、阻抗、时序、复位、故障注入和安全默认态。一个继电器、传感器模拟器或串口脚本都可能改变电源和负载;夹具版本和校准同样要锁定。若输入无法停止、输出过热或保护电路未知,应停止而不是提高测试速度。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 平台 | host/sim/HIL/board | 仿真覆盖电气 |
| 夹具 | input/observe/environment | 串口日志完整 |
| 矩阵 | build/run/failure | 一块板代表全部 |
11.4.4 串口、GPIO 与波形证据
串口日志适合语义结果,GPIO 标记适合外部时间差,示波器/逻辑分析仪适合边沿、电平和抖动,寄存器快照适合解释内部状态。把它们映射到同一单调时间线时,要记录时钟、触发、采样率、探头和调试开销;一条漂亮波形不能自动代表整个测试场景。
11.4.5 构建产物与启动核对
烧录成功只说明编程器完成了写入,不说明目标运行的是期望版本。比较 ELF/二进制/配置哈希,读取设备 ID、启动日志和版本回报,确认链接地址、时钟和 FreeRTOS/Zephyr 配置。若目标带安全启动或压缩镜像,还要记录验证链和实际启动槽位。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.4.6 功耗、温度与环境矩阵
温度、电源、电磁环境、负载、低功耗和通信对端都是测试输入。至少列出室温/高低温、轻载/满载、稳定/边界电压、冷启动/热复位、长时间/短时窗口;若无法执行,要保留未覆盖。环境矩阵不是越多越好,而是对应风险并能重放。
11.4.7 失败重试与现场保存
目标机失败时先保存输入、固件哈希、串口原始输出、波形、寄存器、复位原因、供电和环境,再决定是否重试。重复下载或复位可能清掉唯一 fault 现场;重试必须有上限、间隔和变化说明。失败后应进入安全态,不能让 HIL 夹具继续驱动未知输出。
11.4.8 本节交付:目标验证卡
目标验证卡包括 platform、board_revision、fixture、firmware_hash、config_hash、test_id、input、harness、clock、power、environment、observe_channels、raw_artifacts、retry_policy、host_gap 和 stop_conditions。它让下一单元可以有计划地注入故障,而不是在实机上随意拔线。
请围绕“目标机验证:HIL、覆盖率与测量”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
05 · FAULT INJECTION
故障注入:重现、隔离与恢复
可靠性来自对失败的准备,而不是对成功路径的信仰。故障注入要先定义风险、注入点、可逆性、预期状态、停止条件和证据,再选择主机模型、仿真器或目标板。注入之后要区分检测、隔离、降级、复位和恢复是否真的发生。
11.5.1 故障模式与危险等级
故障矩阵以阶段和对象组织,而不是以‘随机坏一下’组织。bind、时钟、队列、锁、解析、存储、看门狗和输出各自有不同故障模式、可检测信号和恢复动作。先给每个故障一个 ID、严重度、可逆性和停止条件,才能比较主机注入和目标机注入是否覆盖同一合同。
11.5.2 输入、依赖与时钟注入
输入注入通常最安全:坏长度、重复序号、越界数值、丢包、NACK、延迟和状态翻转可以在主机或仿真中重放。依赖注入要保留真实时序和错误阶段,不能直接跳到最终返回值,否则恢复路径可能没经历等待、部分写入或资源占用。
PYTHON · FAULT MATRIXdef replay(case): return case["expect"] cases = [ {"id": "queue_full", "inject": "producer_burst", "expect": "reject"}, {"id": "clock_stall", "inject": "freeze_time", "expect": "watchdog"}, ] for case in cases: print(case["id"], replay(case))
故障向量要有阶段、预期检测、恢复和停止条件;打印结果不等于安全。
C · SAFE FAULT PATHvoid fail_safe(fault_code_t code) { disable_actuators(); save_reset_reason(code); signal_fault_led(code); request_controlled_reset(); }
安全态先于重试和诊断;输出、复位和保存动作要按目标硬件验证。
11.5.3 超时、死锁与活锁重现
超时、死锁和活锁的共同点是‘没有按预期进展’,但证据不同。超时要有 deadline 和单调时基,死锁要有等待图和持有者,活锁要有状态变化却没有有效输出。故障注入应设置上限和外部停止按钮,避免把测试本身变成不可恢复的卡死。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 注入 | stage/vector/reversible | 随机拔电最真实 |
| 隔离 | safe/degrade/budget | watchdog reset 就是恢复 |
| 复盘 | snapshot/post-health | 重启后 main 就健康 |
11.5.4 安全态与故障隔离
安全态先于诊断。关闭 PWM、禁止继电器、限速、停止发包或切断高能量负载应有明确顺序,并且故障注入时默认有效。隔离可以是任务边界、消息边界、硬件保护、断路器或独立监视器;任何隔离机制都要测试自身失败时的结果。
11.5.5 重试预算与不可逆动作
重试预算要包括次数、backoff、总时间和副作用。读取状态、重新建立连接通常更容易幂等;写 Flash、启动电机、增加计数器或提交一次性命令可能不能盲目重放。每次重试记录原始响应、已执行动作和剩余预算,超过上限就进入降级、维护或安全停机。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.5.6 复位原因与故障快照
复位原因、fault status、PC/LR/SP、任务状态、配置/固件哈希、最后 progress、队列年龄、锁持有者和安全输出是恢复证据的核心。先写入可靠保留区或独立日志,再清理和复位;如果保存动作本身可能失败,要准备最小硬件指示和复位计数。
11.5.7 恢复后健康检查
恢复后至少检查身份、时钟/电源、资源、协议版本、队列、锁、内存水位和关键健康信号,不能只看到系统再次进入 main。重新绑定设备、恢复任务和开放输出应分阶段进行;重复失败要限制次数并进入维护模式,防止复位风暴。
11.5.8 本节交付:故障注入卡
故障注入卡包括 fault_id、severity、injection_point、preconditions、vector、reversible、expected_detection、safe_state、retry_budget、snapshot、recovery_steps、post_health、host_result、target_required 和 stop_conditions。它把可靠性从‘测试人员胆子大’变成可审查的安全实验。
请围绕“故障注入:重现、隔离与恢复”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
06 · RELIABLE DELIVERY
可靠交付:CI、报告与维护
可靠交付把代码、配置、测试、目标矩阵、故障记录、覆盖盲区、版本哈希、CI 报告、回滚和维护责任绑定在一起。持续集成可以缩短反馈,但不会替代目标机和现场;报告必须告诉读者跑了什么、没跑什么、失败如何复现、何时必须停止。
11.6.1 CI 最小闭环
CI 最小闭环从干净工作区开始:固定 Python/C 编译器、依赖、配置、源码提交和环境变量,构建产物,再运行主机测试、静态检查和报告生成。每一步要有明确输入和输出,失败时保留日志与命令。一个开发者电脑上手动点过的绿灯不能代替别人重建。
11.6.2 unittest、CTest 与测试发现
Python unittest 的 discovery、CTest 的测试文件和 Zephyr Twister 的测试场景都把‘如何找到测试’变成配置。统一入口不等于统一平台;报告要保留测试框架、版本、命令、fixture、平台和原始输出,避免 CI 只给一个总数,读者却不知道失败在哪个场景。
SHELL · CI EVIDENCEpython -m unittest discover -s host_tests -p 'test_*.py' ctest --test-dir build --output-on-failure sha256sum build/firmware.elf build/report.json
流水线保留命令、版本、产物哈希和原始报告;CI 绿灯不代替真机证据。
PYTHON · VERDICTdef release_gate(host_ok, target_ok, known_limits): if not host_ok: return "BLOCK" if not target_ok: return "TARGET_REQUIRED" return "PASS_WITH_LIMITS" if known_limits else "PASS"
门槛模型把未执行目标机条件显式化;发布仍需评审、回滚和责任人。
11.6.3 Twister/KUnit 与平台矩阵
平台矩阵应至少分 host、emulator/native_sim、HIL 和真实 board,并列出 build-only、run、环境和证据要求。Linux KUnit 通过 kunit_tool 配置、构建、运行和解析内核测试,也提醒构建目录与配置一致性;这些经验同样适用于 RTOS 目标,不能把‘编译成功’混进‘运行通过’。
| 对象 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 重建 | source/config/tool | 二进制足够 |
| 闸门 | test/coverage/target | 绿灯等于可靠 |
| 维护 | owner/rollback/limits | flaky 可以永久忽略 |
11.6.4 构建产物、依赖与 provenance
provenance manifest 把 source_hash、config_hash、toolchain、dependency_lock、compiler_flags、linker、board_revision、test_seed、artifact_hash 和日期绑在一起。若产物被压缩、签名或转换,还要保存每一步的输入输出。时间戳和文件名只能辅助定位,不能代替内容哈希。
11.6.5 flaky 测试与失败隔离
flaky 测试先分类:产品随机性、时序竞争、环境不稳定、夹具/探针故障、资源占用还是测试本身有共享状态。暂时 quarantine 只能是有责任人、复现命令、期限和退出条件的隔离,不应把失败变成永久忽略;自动重试要保存每一次原始结果。
从左到右是思考顺序,不是把现象、工具、测试和目标机证据压缩成一个“通过”。
11.6.6 覆盖率门槛与发布闸门
覆盖率门槛是风险决策,不是装饰数字。未覆盖的异常、复位、低功耗、满载和真实电气路径应有解释、责任人和目标验证计划;合理豁免要写原因和期限。即使覆盖率 100%,错误断言、错误模型或错误配置仍然可能让产品失败。
11.6.7 回滚、维护与责任人
回滚包括旧镜像、旧配置、版本选择、签名/完整性、更新中断、复位原因和维护入口。发布闸门不应允许不可逆动作在证据不足时继续;出现启动失败、重复复位、安全态不确定或数据迁移不可逆时,回到已知镜像或停在维护模式。
11.6.8 已知限制与长期复查
可靠发布卡包括 source/config/toolchain、pipeline、test_discovery、platform_matrix、artifact_manifest、coverage_scope、flaky_policy、release_gates、rollback、owner、known_limits、review_date 和 stop_conditions。它是下一章联网、Linux 与综合交付可以直接复用的可靠性接口。
11.6.9 本节交付:可靠发布卡
交付问题: 提交流水线、报告、门槛和回滚。交付动作是“完成本章到联网/Linux 的交接”,相应输入、输出或未执行边界必须在记录中逐项对应。
请围绕“可靠交付:CI、报告与维护”写出对象、输入/故障条件、调试或测试机制、输出与完成语义、一个安全约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,还要补齐芯片、板卡、探针、工具链、夹具、供电、负载和观察条件。不要用一次断点、一个绿灯、一个复位或一张截图覆盖没有做过的验证。
资料卡(访问日期:2026-09-05):Arm CoreSight 与 GDB 文档支撑调试连接、符号和实时扰动边界;Zephyr Twister/ZTest、Python unittest、CTest 与 Linux KUnit/KASAN 提供不同层级的测试与内存安全入口;OpenOCD 文档补充 reset、halt、flash 和 verify 命令。通用测试模型不能替代当前芯片、探针、板卡、供电、夹具、环境和现场恢复条件。