四个 Fault 全部采集现场:MemManage/BusFault/UsageFault 由空死循环升级
原状:HardFault 已有崩溃采集,但 MemManage / BusFault / UsageFault 仍是空
while(1) —— 这三类故障发生时日志完全静默,且因 SHCSR 默认未使能,实际会
被升级成 HardFault,报告出笼统的 "HARDFAULT"、看不出根因。
改动:
- Src/stm32f4xx_it.c:三个 Handler 升级为手工 __asm 版(取 MSP/PSP 帧指针)
-> B 到 per-fault C 入口 fault_entry_{mem,bus,usage} -> hard_fault_report()。
hard_fault_report 增加 tag 参数,日志统一为
"[ERR] <TAG> PC=.. LR=.. xPSR=.. R0-R3=.. CFSR=.. HFSR=..[/BFAR][/MMFAR]"。
生成实体经 #define X X_Gen 改名保留,链接器各移除 2 字节(.map 已验)。
三个各带独立锚点 MEMFAULT/BUSFAULT/USAGEFAULT-ANCHOR。
- 新增 fault_handler_enable()(USER CODE BEGIN 1 区):使能 SHCSR 的
MEMFAULTENA/BUSFAULTENA/USGFAULTENA。声明入 Inc/stm32f4xx_it.h,调用在
app_main_init() 第一行(纯寄存器写,不依赖日志/时钟)。
- 刻意不启用 CCR.UNALIGN_TRP / CCR.DIV_0_TRP:会把普通 bug 升级成死机,
对本项目弊大于利(说明写进函数注释)。
实现约束(本轮踩坑):ARMCC 的 __asm 块取不到 C 的数据符号(ADR r1, xxx_tag
报 A1516E: Bad symbol,去 static 也无效),也无法给 C 函数传字符串参数,
故故障名必须由 C 侧 per-fault 入口带上。
配套:
- check_cubemx_survival.py:新增 fault-handlers-3 / fault-handler-enable 两项,
UNPROTECTED_LEGACY 清掉三个 Fault(WARN 2->1),清单 16 -> 18 项。
- AGENTS.md:新增"4 个 Fault 全部采集"条目;ARMCC 汇编条目补 A1516E 第 3 坑;
校验标记补 [ERR](四个 Fault 日志都以它开头 -> 一律判 FAIL,刻意)。
- 看门狗设计说明.md:§6.1 补 4 条 Fault 标记与 @test 禁项关系;
§10.2 L3 清单与四个 Fault 采集小节;§11 结论表与变更记录。
- 待处理内容.md:新增 N-03d(已完成),N-03c 补第二次重生成结论。
验证:@build 0 错误 0 警告(Flash +156 B,RAM 无变化);pre-commit 13 钩子
全通过;审计 18 通过 / 1 警告 / 0 失败。
This commit is contained in:
@@ -96,20 +96,51 @@ CHECKS = [
|
||||
must_contain=[
|
||||
"HARD-FAULT-ANCHOR", # 手工锚点注释,重生成后会消失
|
||||
"__asm void HardFault_Handler", # 手工汇编 Handler
|
||||
"hard_fault_report", # 跳转目标
|
||||
"fault_entry_hard", # 跳转目标(C 侧带故障名)
|
||||
],
|
||||
must_not_contain=["HardFault_Handler(void)\r\n{\r\n while (1)"],
|
||||
hint="HardFault_Handler 须为手工汇编版(取 MSP/PSP 交 hard_fault_report),"
|
||||
hint="HardFault_Handler 须为手工汇编版(取 MSP/PSP 交 fault_entry_hard),"
|
||||
"生成实体改名 HardFault_Handler_Gen。被打回空 while(1) 后死机将完全静默。"
|
||||
"恢复后补回 `HARD-FAULT-ANCHOR` 锚点注释。",
|
||||
),
|
||||
# ⚠ 2026-09-29:MemManage / BusFault / UsageFault 三个也升级为崩溃采集。
|
||||
# 模板形态与 HardFault 相同(整函数重写、函数体外无标记区)→ 同一套方案:
|
||||
# 生成区整函数替换 + 独立锚点 + `#define X X_Gen` 改名保留生成实体。
|
||||
# 由一项统一检查(同文件、同 kind),避免 4 条重复项。
|
||||
dict(
|
||||
id="fault-handlers-3",
|
||||
kind="wholefile",
|
||||
path="Src/stm32f4xx_it.c",
|
||||
must_contain=[
|
||||
"MEMFAULT-ANCHOR",
|
||||
"BUSFAULT-ANCHOR",
|
||||
"USAGEFAULT-ANCHOR",
|
||||
"__asm void MemManage_Handler",
|
||||
"__asm void BusFault_Handler",
|
||||
"__asm void UsageFault_Handler",
|
||||
"fault_entry_mem",
|
||||
"fault_entry_bus",
|
||||
"fault_entry_usage",
|
||||
],
|
||||
hint="MemManage/BusFault/UsageFault 须为手工汇编版(各跳 fault_entry_* 打故障名)。"
|
||||
"被打回空 while(1) 后这三类故障会被升级成 HardFault 且看不出根因。",
|
||||
),
|
||||
dict(
|
||||
id="fault-handler-enable",
|
||||
kind="protected",
|
||||
path="Src/stm32f4xx_it.c",
|
||||
region="1",
|
||||
must_contain=["fault_handler_enable", "SCB_SHCSR_MEMFAULTENA_Msk"],
|
||||
hint="MemManage/BusFault/UsageFault 默认**禁用**,须在 SHCSR 置使能位才会独立触发;"
|
||||
"否则它们被升级成 HardFault、日志只显示 HARDFAULT。"
|
||||
),
|
||||
dict(
|
||||
id="hardfault-report-impl",
|
||||
kind="protected",
|
||||
path="Src/stm32f4xx_it.c",
|
||||
region="0",
|
||||
must_contain=["hard_fault_report", "CFSR"],
|
||||
hint="HardFault 现场报告实现(打印 PC/LR/xPSR/CFSR/HFSR/BFAR/MMFAR)"
|
||||
hint="崩溃现场报告实现(打印 PC/LR/xPSR/CFSR/HFSR/BFAR/MMFAR)"
|
||||
"须在 USER CODE BEGIN 0 区内(生成区内的标准保护位)。",
|
||||
),
|
||||
# ---------------- P1:FreeRTOS 加固 ----------------
|
||||
@@ -368,14 +399,6 @@ UNPROTECTED_LEGACY = [
|
||||
("timeSyncTask 手工定义(不在 .ioc FREERTOS.Tasks01 里)", r"timeSyncTask_attributes"),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Src/stm32f4xx_it.c",
|
||||
[
|
||||
("MemManage_Handler 仍为空 while(1),死机静默", r"void MemManage_Handler\(void\)"),
|
||||
("BusFault_Handler 仍为空 while(1),死机静默", r"void BusFault_Handler\(void\)"),
|
||||
("UsageFault_Handler 仍为空 while(1),死机静默", r"void UsageFault_Handler\(void\)"),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user