定位Fault方法

定位ARM Hard Fault 的方法

 

1,  Keil的话,可以做如下操作:

先将fault中断函数的内容改为:

 

HardFault_Handler\

                PROC

                ;EXPORT  HardFault_Handler         [WEAK]

                ;B                  .

                                IMPORT hard_fault_handler_c  

                                TST LR, #4  

                                ITE EQ  

                                MRSEQ R0, MSP  

                                MRSNE R0, PSP  

                                B hard_fault_handler_c  

                ENDP

 

 

然后在源程序里添加下面的函数代码:

// hard fault handler in C,  

// with stack frame location as input parameter  

void hard_fault_handler_c(unsigned int * hardfault_args)  

{  

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]\n");  

printf ("R0 = %x\n", stacked_r0);  

printf ("R1 = %x\n", stacked_r1);  

printf ("R2 = %x\n", stacked_r2);  

printf ("R3 = %x\n", stacked_r3);  

printf ("R12 = %x\n", stacked_r12);  

printf ("LR = %x\n", stacked_lr);  

printf ("PC = %x\n", stacked_pc);  

printf ("PSR = %x\n", stacked_psr);  

printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));  

printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));  

printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));  

printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));  

printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));  

 

   

while(1)

{

        ;;

}

 

}  

 

如果使用调试器,则可以在第一个printf处设置断点.没有的话看串口打印结果

通过查看stacked_lr的内容可以知道程序运行到哪个位置出现fault

然后查看编译后汇编代码,可以知道源程序是哪个函数哪一步出现问题,

配合其它寄存器的内容来分析找出原因

 

 

2IAR的话,startup_ewarm.c文件中的FaultISR()函数的内容改为:

volatile unsigned int stacked_r0;  

volatile unsigned int stacked_r1;  

volatile unsigned int stacked_r2;  

volatile unsigned int stacked_r3;  

volatile unsigned int stacked_r12;  

volatile unsigned int stacked_lr;  

volatile unsigned int stacked_pc;  

volatile unsigned int stacked_psr;  

 

//unsigned long cc;

 

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]\n");  

printf ("R0 = %x\n", stacked_r0);  

printf ("R1 = %x\n", stacked_r1);  

printf ("R2 = %x\n", stacked_r2);  

printf ("R3 = %x\n", stacked_r3);  

printf ("R12 = %x\n", stacked_r12);  

printf ("LR = %x\n", stacked_lr);  

printf ("PC = %x\n", stacked_pc);  

printf ("PSR = %x\n", stacked_psr);  

printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));  

printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));  

printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));  

printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));  

printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));  

 

   

  while(1)

  {

          ;;

  }

如果使用调试器,则可以在第一个printf处设置断点.没有的话看串口打印结果

通过查看stacked_lr的内容可以知道程序运行到哪个位置出现fault

然后查看编译后汇编代码,可以知道源程序是哪个函数哪一步出现问题,

配合其它寄存器的内容来分析找出原因

另一种方法:
    默认的HardFaudler 处理方法不是死循环么?将它改成BX LR直接返回的形式。然后再这条语句打个断点,一旦在断点中停下来,说明出错了,然后再返回,就可以返回到出错的位置的下一条语句哪里。
_asm void wait()
{
    BX lr  //BX无条件转移指令
}


void HardFault_Handler(void)
{
    wait();
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Segmentation fault(段错误)是一种常见的程序错误,通常是由于访问了无效的内存地址或者内存越界导致的。定位Segmentation fault问题可以通过以下几个步骤来进行: 1. 编译选项:在编译程序时,可以使用一些选项来帮助定位Segmentation fault问题。例如,在gcc编译器中,可以使用"-g"选项来生成调试信息,使用"-fsanitize=address"选项来检测内存错误。 2. 调试工具:使用调试工具可以帮助我们逐步执行程序并查看变量的值,以便找到引发Segmentation fault的原因。常用的调试工具有gdb(GNU调试器)和valgrind。 - 使用gdb:可以通过在命令行中输入"gdb <可执行文件名>"来启动gdb调试器。然后可以使用"run"命令来运行程序,并在Segmentation fault发生时暂停程序的执行。使用"backtrace"命令可以查看函数调用栈,定位到引发错误的代码行。 - 使用valgrind:可以通过在命令行中输入"valgrind <可执行文件名>"来运行程序,并检测内存错误。valgrind会输出详细的错误信息,包括引发Segmentation fault的代码行。 3. 代码审查:仔细检查代码,特别是涉及指针操作和数组访问的地方。常见的引发Segmentation fault的原因包括: - 空指针引用:使用了一个未初始化或者已经释放的指针。 - 内存越界:访问了数组或者其他数据结构的越界位置。 - 野指针:使用了一个已经释放的指针。 - 栈溢出:函数调用过深导致栈空间不足。 以上是定位Segmentation fault问题的一般步骤和方法,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值