HardFault分析

segger官方也有hardFault相关的文档和代码,去这个页面ctrl+F搜索hardfault,可以看到文档和相关代码:https://www.segger.com/downloads/application-notes/

参考keil官方文档和相关代码 apnt209 :http://www.keil.com/appnotes/docs/apnt_209.asp

以及一个开源的hardFault诊断工具CMBackTrace :https://github.com/armink/CmBacktrace

 

最主要的是,找到 Cortex - M3 Technical Reference Manual。

原来只知道有stm32的datasheet和参考手册,根本不知道还有这个手册。。

大概《cortex M3权威指南》翻译的大部分内容,都是从这本书上来的。

我只是用这个手册翻了一下,找到一些寄存器的定义。

(因为这些寄存器的定义在stm32的参考手册里是没有的,属于ARM公司规定的CMSIS范畴,不是芯片范畴的)

 

还有一个是stm32官方出示的一个“hardFault诊断”手册,其实跟apnt209差不多。地址:http://www.stmcu.org/search/?q=hardfault&m=

 

最后我总结一下我在apnt209中截取的一部分:

思路就是在hardFault的ISR中,添加一个死循环,当系统运行到这里时,说明出现了hardfault异常。

下面是apnt209配套的软件工程:

 1 /******************************************************************************
 2  * @file     HardFault_Handler.c
 3  * @brief    HardFault handler example
 4  * @version  V1.00
 5  * @date     10. July 2017
 6  ******************************************************************************/
 7 /*
 8  * Copyright (c) 2017 ARM Limited. All rights reserved.
 9  *
10  * SPDX-License-Identifier: Apache-2.0
11  *
12  * Licensed under the Apache License, Version 2.0 (the License); you may
13  * not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  * www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 #include "RTE_Components.h"             // Component selection
26 #include CMSIS_device_header            // Include device header file from
27 #include "stdio.h"                      // include stdio library for printf output
28 #include "project_configuration.h"      // Header file for test case configuration
29 
30 #if HARDFAULT_HANDLER == 1
31 
32 void HardFault_Handler_C(unsigned long * svc_args, unsigned int lr_value);
33 
34 // HardFault handler wrapper in assembly language.
35 // It extracts the location of stack frame and passes it to the handler written
36 // in C as a pointer. We also extract the LR value as second parameter.
37 __asm void HardFault_Handler(void)
38 {
39     TST    LR, #4     ;测试LR寄存器的bit2是否为1
40     ITE    EQ
41     MRSEQ  R0, MSP    ;如果LR的bit2是0,表示在发生HardFault之前,程序使用的是主进程堆栈Main Stack
42     MRSNE  R0, PSP    ;否则LR的bit2是1,说明在发生HF之前,程序使用是进程堆栈Process Stack
43     MOV    R1, LR
44     B      __cpp(HardFault_Handler_C)  ;把栈的值放入R0,把LR的值放入R1,调用C函数
45 }
46 
47 
48 // HardFault handler in C, with stack frame location and LR value extracted
49 // from the assembly wrapper as input parameters
50 void HardFault_Handler_C(unsigned long * hardfault_args, unsigned int lr_value)  //hardfault_args存的是栈的值,lr_value是LR的值
51 {
52     unsigned long stacked_r0;
53     unsigned long stacked_r1;
54     unsigned long stacked_r2;
55     unsigned long stacked_r3;
56     unsigned long stacked_r12;
57     unsigned long stacked_lr;
58     unsigned long stacked_pc;
59     unsigned long stacked_psr;
60     unsigned long cfsr;
61     unsigned long bus_fault_address;
62     unsigned long memmanage_fault_address;
63 
64     bus_fault_address       = SCB->BFAR;   //BusFaultAddrReg
65     memmanage_fault_address = SCB->MMFAR;  //MemManageAddrReg
66     cfsr                    = SCB->CFSR;   //ConfigerableFaultStatusReg
67 
68     stacked_r0  = ((unsigned long) hardfault_args[0]);  //Stack指向地址的内容,按照自动进栈出栈时的顺序
69     stacked_r1  = ((unsigned long) hardfault_args[1]);
70     stacked_r2  = ((unsigned long) hardfault_args[2]);
71     stacked_r3  = ((unsigned long) hardfault_args[3]);
72     stacked_r12 = ((unsigned long) hardfault_args[4]);
73     stacked_lr  = ((unsigned long) hardfault_args[5]);
74     stacked_pc  = ((unsigned long) hardfault_args[6]);
75     stacked_psr = ((unsigned long) hardfault_args[7]);
76 
77     printf ("[HardFault]\n");
78     printf ("- Stack frame:\n");
79     printf (" R0  = %x\n", stacked_r0);
80     printf (" R1  = %x\n", stacked_r1);
81     printf (" R2  = %x\n", stacked_r2);
82     printf (" R3  = %x\n", stacked_r3);
83     printf (" R12 = %x\n", stacked_r12);
84     printf (" LR  = %x\n", stacked_lr);
85     printf (" PC  = %x\n", stacked_pc);  //注意这个是在HardFault发生前的PC地址,说明运行到这里发生HF【定位HF发生的指令】
86     printf (" PSR = %x\n", stacked_psr);
87     printf ("- FSR/FAR:\n");
88     printf (" CFSR = %x\n", cfsr);
89     printf (" HFSR = %x\n", SCB->HFSR);  //HardFaultStatusReg
90     printf (" DFSR = %x\n", SCB->DFSR);  //DebugFaultStatusReg
91     printf (" AFSR = %x\n", SCB->AFSR);  //Auxiliary Fault Status Reg 附加的..具体看Cortex M3 Technical Reference Manual
92     if (cfsr & 0x0080) printf (" MMFAR = %x\n", memmanage_fault_address);
93     if (cfsr & 0x8000) printf (" BFAR = %x\n", bus_fault_address);
94     printf ("- Misc\n");
95     printf (" LR/EXC_RETURN= %x\n", lr_value);
96 
97     while(1); // endless loop
98 }
99 #endif

 

 

所有的诊断过程都是类似的,根据LR的bit2判断进入HardFault前是哪个Stack

确定了Stack,就读取Stack指向地址处的几个寄存器,这几个寄存器在每次发生中断和异常都会自动的压栈出栈

从里面读出PC,PC指向的地址,就是发生异常的地址。

 

这个地址可以用工具add2line,得到函数名,而不是机器码的地址。。。

这部分可以看上边提到的BackTrace开源工具。

它可以回溯包含发生hardfault函数的,所有的函数调用关系!

 

 

keil工具,定性(哪种hardfault)和定位(哪个指令)

 

 

 

 

 

参考:http://blog.csdn.net/zhzht19861011/article/details/8645661

posted @ 2017-12-07 15:56  为民除害  阅读(3563)  评论(0编辑  收藏  举报