【Debug1】程序死机,while(1)循环,怎么办?

程序死机:停在HardFault_Handler的while(1)死循环中

问题描述

  • 程序死机,停在停在HardFault_Handler的while(1)死循环中
  • 调试日志疯狂报错:Cannot access Memory (@ 0x0000457e, Read...)。
  • 芯片内核寄存器R14(LR)显示为0xFFFFFFFD,说明异常发生在任何(线程)模式下,使用的是PSP。

原因分析:

走过的弯路

  • 手动查堆栈失败:根据PSP去Memory窗口看压栈的PC和LR,结果找出来的数据全是乱码(0x20001A6A...)。程序发生异常时,栈已经被踩坏,也可能是底层汇编的压栈动作被中断打断。
  • BFAR误导:故障报告里的BFAR显示0xE000EDF8,这是内核调试寄存器地址。

问题定位

  • Call Stack(调用栈):通过Keil自带的Call Stack窗口,直接定位到了出事前的函数调用链:network_entry->air_work_rst_dev。
  • 地址关联:发生崩溃时报错的0x457e和air_work_rst_dev函数的地址0x4543极其接近。
  • Watch(观察)窗口:在嫌疑函数air_work_rst_dev内部打断点,展开相关的全局结构体指针netdev_opt。
  • 一眼定乾坤:在Watch窗口里看到clear_rxbuf的值是0x00000000

根本原因

  • 在初始化do_netdev_opt结构体时,漏掉了对clear_rxbuf 函数指针的赋值。
  • 当air_work_rst_dev执行到netdev_opt->clear_rxbuf( netdev );时,试图调用一个空指针(跳转到0x00000000),瞬间触发硬件异常(HardFault)

该具体问题解决方案:【只针对我做的项目遇到的问题】

总结

以后遇到问题怎么Debug?

以后如果再遇到死机、跑飞、HardFault,按以下步骤:

  • 第一步:看现场
    • 打开Call Stack窗口:看看死机前最后调用的两三个函数是谁,嫌疑犯基本就在这几个函数里。
    • 打开Fault Reports:看看是 CFSR 里的哪位(如 PRECISERR 精确总线错误、UNDEFINSTR 未定义指令)在作祟,并记录下 BFAR(如果有效的话)。
  • 第二步:锁变量(Watch窗口+局部变量)
    • 在Call Stack锁定的嫌疑函数开头打断点
    • 把该函数用到的结构体、指针、关键变量全部拖进Watch窗口。
    • 重点关注指针类型:看看哪个指针变成了0x00000000、0x00000004、0x2000...(非正常数组区)、或者0x000045xx(代码区地址)
  • 第三步:看汇编(Disassembly 窗口)
    • 如果C代码里看不出来问题,去反汇编窗口
    • 跳到报错的PC地址(或者使用Show Disassembly at Address),看看崩在哪条指令。通常是LDR(加载)或STR(存储)指令。
  • 第四步:验堆栈(Memory 窗口 - 进阶)
    • 如果上述方法都找不到,再去用MSP或PSP算地址查堆栈。注意,一定要确保看到了正确的内存块,如果数据全乱,说明发生了栈溢出(Stack Overflow)。

避坑(如何不写Bug)

  1. 函数指针结构体格式必须初始化 :如果用了函数指针结构体,初始化最好用
    .成员名 = 函数名的格式,并且赋值NULL或者写个默认函数,调用前判断一下if(ptr->func != NULL)。
  2. 防御性编程 :在解引用指针(ptr->xxx)之前,一定要判断if(ptr != NULL)。
  3. 警惕数组越界:这次的乱码0x457e也可能是其他数组越界把指针踩坏了。使用数组时检查下标边界。
  4. 善用调试工具:日常开发时,编译选项坚决关闭高等级优化(用 -O0),开启Debug信息,这样单步调式才准。
  5. 多看编译警告:很多时候,把函数当成变量穿,未初始化指针,编译器会给Warning的,不要忽略它们。
相关推荐
叼烟扛炮7 小时前
[LangChain] 学习笔记(03):打破失忆症——对话机制与上下文管理
java·前端·javascript·笔记·学习·langchain
景煜拾年7 小时前
InnoAI SQL 助手
运维·数据库·笔记·sql
旖旎夜光7 小时前
【C++ 基础入门】类和对象(下):初始化列表、static 成员、友元与内部类
c++·笔记·学习
元器件BOM超人7 小时前
GD32E230C8T6 兆易创新Cortex-M23超值型MCU解析:规格参数、替代选型与常见问题
单片机·嵌入式硬件
拖累斯7 小时前
Jenkins + Python 全自动跑通「禅道任务/BUG 导出 → 月度开发考核表」
python·jenkins·bug
LONGZHIQIN7 小时前
STM32学习笔记
笔记·stm32·学习·arm
叼烟扛炮8 小时前
[LangChain] 学习笔记(04):手搓 ChatGPT 打字机——流式输出(SSE)与模型初始化选型
人工智能·笔记·chatgpt·langchain
StarsGreen8 小时前
Android 启动流程详解
android·linux·单片机·嵌入式硬件
en.en..8 小时前
AFE:模拟前端,模拟世界通往 MCU 的信号桥梁
单片机·嵌入式硬件
§ꦿCFོ༉8 小时前
嵌入式八股文—C语言入门学习(二)
c语言·学习·嵌入式·编程语言