单片机(STM32)Debug - 基于反汇编文件的栈回溯

目录

    • 1. 栈回溯
      • 1.1 原理概述
        • 1.1.1 栈的工作原理
        • 1.1.2 根据栈内容和反汇编文件找到函数调用关系
          • (1)获取反汇编文件
          • (2)获取PC指针和各级LR指针
      • 1.2 实例-基于HardFault_Handler
        • 1.2.1 修改HardFault_Handler
        • 1.2.2 分析反汇编文件

1. 栈回溯

1.1 原理概述

1.1.1 栈的工作原理
  1. 在进入fault处理程序(Handler)前,CM3内核会将几个必须的寄存器压栈保存;
    单片机(STM32)Debug - 基于反汇编文件的栈回溯_第1张图片
  2. 栈中的PC寄存器代表着在进入Handler之前,程序所在的位置,也就是出错的那行代码;
  3. 找到出错代码后,我们还需要确定函数的调用关系
    1. 在执行出错之前已经经过了多次函数调用(A > B > C),栈内部存放了函数调用过程中的寄存器信息;
    2. 我们需要关注的是LR寄存器的内容,其存储着函数返回后执行的下一条代码的地址;
  4. 在STM32微处理器上,代码存储在Flash中,对于F103C8T6(中容量产品),Flash地址空间是0x08000000 ~ 0x0801FC00,因此程序机器码的地址必然为0x0800xxxx,从栈中提取相应地址即可(为稳妥还可以加多一条判断:该机器码的前一条应该为BL指令,即跳转指令);
    单片机(STM32)Debug - 基于反汇编文件的栈回溯_第2张图片
1.1.2 根据栈内容和反汇编文件找到函数调用关系
(1)获取反汇编文件
  1. 在Keil中添加构建后命令:fromelf --text -a -c --output=xxx.dis xxx.axf
    单片机(STM32)Debug - 基于反汇编文件的栈回溯_第3张图片 1. xxx.dis:xxx为生成的反汇编文件的名称,由用户自定义,工程构建结束后可以在工程同级目录下找到对应的反汇编文件;
    2. xxx.axf:Keil生成的可执行文件,需要基于该文件生成.dis;该文件在Linker中指定;
    单片机(STM32)Debug - 基于反汇编文件的栈回溯_第4张图片
(2)获取PC指针和各级LR指针
  1. 从栈顶开始打印各个数据,以32bit为基准,每32bit为一个寄存器的值;
  2. 首先关注进入Handler之前的PC值,其代表从哪行代码进入fault;
    单片机(STM32)Debug - 基于反汇编文件的栈回溯_第5张图片
  3. 进入引发错误的相应函数后,根据后续打印的LR(0x0800xxxx)继续分析函数调用关系即可;

1.2 实例-基于HardFault_Handler

函数调用关系:main > DebugTest > A > B > C引入除零错误

int C(int val)
{
   
    printf("Enter C()\r\n");
    return (100 / val);
}

void B()
{
   
    printf("Enter B()\r\n");
    C(0);
    printf(

你可能感兴趣的:(嵌入式学习笔记,单片机,stm32,嵌入式硬件)