如何根据HardFault中断抛出的寄存器值排查数组越界

Gitee仓库

bash 复制代码
git clone https://gitee.com/banana-peel-x/freedom-learn.git

项目场景:

实习的时候遇到了函数不可重入问题,场景是上位机与MCU通过udp协议通信,控制MCU测试不同的功能项,频率为1s/次。其中测试CAN老化功能时,需要每秒让CAN控制器进入LoopBack模式,自发自收后上传。测试时偶发跑死,串口抛出异常。

根因:是由于在其他的task里会控制can的模式,在udp的钩子函数里(我的task)里也需要切换can的模式,自测没有问题是两者偶尔各自控制一下硬件没有影响,压测会出现同时控制can,出现HardFault。


问题描述

从本科做项目开始,排查Bug主要靠直觉,小代码量绰绰有余。对于代码量很大的程序却很低效。最后靠部门大佬帮忙解决,大佬一通操作直接看起了汇编,近来吃不好睡不香,故捡起来琢磨一下大佬的排查方法。

首先改进启动文件,startup_stm32f103xb.s:通常出现HardFault异常后会进入HardFault_Handler中断,这里弃用HardFault_Handler函数,改用hard_fault_handler_c函数。
常规

c 复制代码
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP

改进

c 复制代码
HardFault_Handler\
                PROC
                MOVS    r0, #4
                MOV     r1, lr
                TST     r0, r1
                BEQ     stacking_used_MSP
                MRS     r0, psp
                B       get_LR_and_branch
stacking_used_MSP
                MRS     r0, msp
get_LR_and_branch
                MOV     r1, lr
                IMPORT  hard_fault_handler_c
                BL       hard_fault_handler_c  
                ENDP

在hard_fault_handler_c函数中通过Uart抛出寄存器的值

c 复制代码
void hard_fault_handler_c(unsigned int * hardfault_args, unsigned lr_value)
{
  unsigned int stacked_r0;
  unsigned int stacked_r1;
  unsigned int stacked_r2;
  unsigned int stacked_r3;
  unsigned int stacked_r12;
  unsigned int stacked_lr;
  unsigned int stacked_pc;
  unsigned int stacked_psr;
  stacked_r0 = ((unsigned long) hardfault_args[0]);
  stacked_r1 = ((unsigned long) hardfault_args[1]);
  stacked_r2 = ((unsigned long) hardfault_args[2]);
  stacked_r3 = ((unsigned long) hardfault_args[3]);
  stacked_r12 = ((unsigned long) hardfault_args[4]);
  stacked_lr = ((unsigned long) hardfault_args[5]);
  stacked_pc = ((unsigned long) hardfault_args[6]);
  stacked_psr = ((unsigned long) hardfault_args[7]);

  printf ("[Hard fault handler]\r\n");
  printf ("R0 = %x\r\n", stacked_r0);
  printf ("R1 = %x\r\n", stacked_r1);
  printf ("R2 = %x\r\n", stacked_r2);
  printf ("R3 = %x\r\n", stacked_r3);
  printf ("R12 = %x\r\n", stacked_r12);
  printf ("Stacked LR = %x\r\n", stacked_lr);
  printf ("Stacked PC = %x\r\n", stacked_pc);
  printf ("Stacked PSR = %x\r\n", stacked_psr);
  printf ("Current LR = %x\r\n", lr_value);

  while(1); // endless loop
}

复制代码
发生异常后,可以通过串口抛出的值快速定位问题,KEIL在不破坏现场的情况下进入Debug模式。
当中断或者异常发生时,内核会将xPSR、PC、LR、R12、R3、R2、R1、R0这些寄存器按照顺序依次存入堆栈,这些寄存器中的值是中断/异常发生前一刻的值。
    故抛出的PC寄存器存的就是被中断打断的指令的下一条指令地址,所以我们同个定位PC寄存器中地址所指向的代码,就可以精准定位或定位在问题代码附近。

原因分析:

根据Stacked PC = 8002e8c,在汇编中查找抛出异常前代码运行位置,可以看出StackFlow_50ms函数中数组越界。



相关推荐
Wave8452 小时前
STM32--智能小车
stm32·单片机·嵌入式硬件
wdfk_prog5 小时前
[Linux]学习笔记系列 -- lib/timerqueue.c Timer Queue Management 高精度定时器的有序数据结构
linux·c语言·数据结构·笔记·单片机·学习·安全
充哥单片机设计8 小时前
【STM32项目开源】基于STM32的智能家居环境(空气质量)检测系统
stm32·单片机·嵌入式硬件
夜月yeyue9 小时前
ART 加速器、流水线与指令预测的关系详解
linux·服务器·c语言·单片机·嵌入式硬件·性能优化·嵌入式高阶技巧
糖糖单片机设计11 小时前
硬件开发_基于物联网的生态环境检测系统
stm32·单片机·嵌入式硬件·物联网·51单片机
A9better11 小时前
嵌入式开发学习日志35——stm32之超声波测距
stm32·单片机·嵌入式硬件·学习
Janspran11 小时前
监控系统1 - 项目框架 | 线程邮箱
网络·单片机·嵌入式硬件·硬件架构
常州晟凯电子科技11 小时前
海思Hi3516CV610/Hi3516CV608开发笔记之环境搭建和SDK编译
人工智能·笔记·嵌入式硬件·物联网
qq_3975623112 小时前
STC8H8K64,使用0.96寸oled屏幕. 进行硬件iic和硬件spi驱动(spi开启DMA)---(代码)
单片机·嵌入式硬件
弘毅 失败的 mian12 小时前
STM32 GPIO实战:LED与按键控制
经验分享·笔记·stm32·单片机·嵌入式硬件