mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Support for generating core/register/thread-info dump on fault exceptions
							parent
							
								
									e0d79ff16a
								
							
						
					
					
						commit
						29348d823d
					
				| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
;/*
 | 
			
		||||
; * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
 | 
			
		||||
; *
 | 
			
		||||
; * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
; *
 | 
			
		||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
 | 
			
		||||
; * not use this file except in compliance with the License.
 | 
			
		||||
; * You may obtain a copy of the License at
 | 
			
		||||
; *
 | 
			
		||||
; * www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
; *
 | 
			
		||||
; * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
; * See the License for the specific language governing permissions and
 | 
			
		||||
; * limitations under the License.
 | 
			
		||||
; *
 | 
			
		||||
; * -----------------------------------------------------------------------------
 | 
			
		||||
; *
 | 
			
		||||
; * Title:       Cortex-M Fault Exception handlers ( Common for both ARMv7M and ARMV6M )
 | 
			
		||||
; *
 | 
			
		||||
; * -----------------------------------------------------------------------------
 | 
			
		||||
; */
 | 
			
		||||
 | 
			
		||||
                IF       :LNOT::DEF:__DOMAIN_NS
 | 
			
		||||
__DOMAIN_NS     EQU      1
 | 
			
		||||
                ENDIF
 | 
			
		||||
                    
 | 
			
		||||
FAULT_TYPE_HARD_FAULT           EQU      0x10
 | 
			
		||||
FAULT_TYPE_MEMMANAGE_FAULT      EQU      0x20
 | 
			
		||||
FAULT_TYPE_BUS_FAULT            EQU      0x30
 | 
			
		||||
FAULT_TYPE_USAGE_FAULT          EQU      0x40
 | 
			
		||||
 | 
			
		||||
                PRESERVE8
 | 
			
		||||
                THUMB
 | 
			
		||||
 | 
			
		||||
                AREA     |.text|, CODE, READONLY
 | 
			
		||||
 | 
			
		||||
HardFault_Handler\
 | 
			
		||||
                PROC
 | 
			
		||||
                EXPORT   HardFault_Handler
 | 
			
		||||
                LDR      R3,=FAULT_TYPE_HARD_FAULT                   
 | 
			
		||||
                B        Fault_Handler
 | 
			
		||||
                ENDP                
 | 
			
		||||
 | 
			
		||||
MemManage_Handler\
 | 
			
		||||
                PROC
 | 
			
		||||
                EXPORT   MemManage_Handler
 | 
			
		||||
                LDR      R3,=FAULT_TYPE_MEMMANAGE_FAULT      
 | 
			
		||||
                B        Fault_Handler
 | 
			
		||||
                ENDP                
 | 
			
		||||
                
 | 
			
		||||
BusFault_Handler\
 | 
			
		||||
                PROC
 | 
			
		||||
                EXPORT   BusFault_Handler
 | 
			
		||||
                LDR      R3,=FAULT_TYPE_BUS_FAULT                          
 | 
			
		||||
                B        Fault_Handler
 | 
			
		||||
                ENDP
 | 
			
		||||
 | 
			
		||||
UsageFault_Handler\
 | 
			
		||||
                PROC
 | 
			
		||||
                EXPORT   UsageFault_Handler
 | 
			
		||||
                LDR      R3,=FAULT_TYPE_USAGE_FAULT                          
 | 
			
		||||
                B        Fault_Handler 
 | 
			
		||||
                ENDP
 | 
			
		||||
                    
 | 
			
		||||
Fault_Handler   PROC
 | 
			
		||||
                EXPORT   Fault_Handler
 | 
			
		||||
                IF       __DOMAIN_NS = 1                    
 | 
			
		||||
                IMPORT   osRtxInfo
 | 
			
		||||
                IMPORT   mbed_fault_handler
 | 
			
		||||
                IMPORT   mbed_fault_context
 | 
			
		||||
                
 | 
			
		||||
                MRS      R0,MSP
 | 
			
		||||
                LDR      R1,=0x4                
 | 
			
		||||
                MOV      R2,LR
 | 
			
		||||
                TST      R2,R1                    ; Check EXC_RETURN for bit 2
 | 
			
		||||
                BEQ      Fault_Handler_Continue
 | 
			
		||||
                MRS      R0,PSP
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue
 | 
			
		||||
                MOV      R12,R3
 | 
			
		||||
                LDR      R1,=mbed_fault_context     
 | 
			
		||||
                LDR      R2,[R0]                  ; Capture R0
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#4]               ; Capture R1
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#8]               ; Capture R2
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#12]              ; Capture R3
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                STMIA    R1!,{R4-R7}              ; Capture R4..R7
 | 
			
		||||
                MOV      R7,R8                    ; Capture R8
 | 
			
		||||
                STR      R7,[R1]                  
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                MOV      R7,R9                    ; Capture R9
 | 
			
		||||
                STR      R7,[R1]                  
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                MOV      R7,R10                   ; Capture R10
 | 
			
		||||
                STR      R7,[R1]                  
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                MOV      R7,R11                   ; Capture R11
 | 
			
		||||
                STR      R7,[R1]                  
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#16]              ; Capture R12
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#8                    ; Add 8 here to capture LR next, we will capture SP later
 | 
			
		||||
                LDR      R2,[R0,#20]              ; Capture LR
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#24]              ; Capture PC
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R2,[R0,#28]              ; Capture xPSR
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                ; Adjust stack pointer to its original value and capture it
 | 
			
		||||
                MOV      R3,R0
 | 
			
		||||
                ADDS     R3,#0x20                 ; Add 0x20 to get the SP value prior to exception
 | 
			
		||||
                LDR      R6,=0x200
 | 
			
		||||
                TST      R2,R6                    ; Check for if STK was aligned by checking bit-9 in xPSR value
 | 
			
		||||
                BEQ      Fault_Handler_Continue1
 | 
			
		||||
                ADDS     R3,#0x4
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue1
 | 
			
		||||
                MOV      R5,LR
 | 
			
		||||
                LDR      R6,=0x10                 ; Check for bit-4 to see if FP context was saved
 | 
			
		||||
                TST      R5,R6
 | 
			
		||||
                BNE      Fault_Handler_Continue2
 | 
			
		||||
                ADDS     R3,#0x48                 ; 16 FP regs + FPCSR + 1 Reserved
 | 
			
		||||
                
 | 
			
		||||
Fault_Handler_Continue2                
 | 
			
		||||
                MOV      R4,R1
 | 
			
		||||
                SUBS     R4,#0x10                 ; Set the location of SP in ctx
 | 
			
		||||
                STR      R3,[R4]                  ; Capture the adjusted SP
 | 
			
		||||
                MRS      R2,PSP                   ; Get PSP           
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                MRS      R2,MSP                   ; Get MSP           
 | 
			
		||||
                STR      R2,[R1]
 | 
			
		||||
                ADDS     R1,#4
 | 
			
		||||
                LDR      R3,=mbed_fault_handler     ; Load address of mbedFaultHandler
 | 
			
		||||
                MOV      R0,R12
 | 
			
		||||
                LDR      R1,=mbed_fault_context
 | 
			
		||||
                LDR      R2,=osRtxInfo
 | 
			
		||||
                BLX      R3
 | 
			
		||||
                ENDIF    
 | 
			
		||||
                B        .                         ; Just in case we come back here                
 | 
			
		||||
                ENDP
 | 
			
		||||
                    
 | 
			
		||||
                END
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,190 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the License); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * Title:       Cortex-M Fault Exception handlers ( Common for both ARMv7M and ARMV6M )
 | 
			
		||||
 *
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .file    "except_cm0.S"
 | 
			
		||||
        .syntax  unified
 | 
			
		||||
        
 | 
			
		||||
        .ifndef  __DOMAIN_NS
 | 
			
		||||
        .equ     __DOMAIN_NS, 1
 | 
			
		||||
        .endif
 | 
			
		||||
            
 | 
			
		||||
        .equ     FAULT_TYPE_HARD_FAULT,         0x10
 | 
			
		||||
        .equ     FAULT_TYPE_MEMMANAGE_FAULT,    0x20
 | 
			
		||||
        .equ     FAULT_TYPE_BUS_FAULT,          0x30
 | 
			
		||||
        .equ     FAULT_TYPE_USAGE_FAULT,        0x40
 | 
			
		||||
        
 | 
			
		||||
        .thumb
 | 
			
		||||
        .section ".text"
 | 
			
		||||
        .align   2
 | 
			
		||||
 | 
			
		||||
//HardFault_Handler
 | 
			
		||||
        .thumb_func
 | 
			
		||||
        .type    HardFault_Handler, %function
 | 
			
		||||
        .global  HardFault_Handler
 | 
			
		||||
        .fnstart
 | 
			
		||||
        .cantunwind
 | 
			
		||||
        
 | 
			
		||||
HardFault_Handler:
 | 
			
		||||
        LDR      R3,=FAULT_TYPE_HARD_FAULT  
 | 
			
		||||
        B        Fault_Handler
 | 
			
		||||
 | 
			
		||||
        .fnend
 | 
			
		||||
        .size    HardFault_Handler, .-HardFault_Handler
 | 
			
		||||
        
 | 
			
		||||
//MemManage_Handler        
 | 
			
		||||
        .thumb_func
 | 
			
		||||
        .type    MemManage_Handler, %function
 | 
			
		||||
        .global  MemManage_Handler
 | 
			
		||||
        .fnstart
 | 
			
		||||
        .cantunwind
 | 
			
		||||
        
 | 
			
		||||
MemManage_Handler:
 | 
			
		||||
        LDR      R3,=FAULT_TYPE_MEMMANAGE_FAULT  
 | 
			
		||||
        B        Fault_Handler
 | 
			
		||||
 | 
			
		||||
        .fnend
 | 
			
		||||
        .size    MemManage_Handler, .-MemManage_Handler
 | 
			
		||||
 | 
			
		||||
//BusFault_Handler     
 | 
			
		||||
        .thumb_func
 | 
			
		||||
        .type    BusFault_Handler, %function
 | 
			
		||||
        .global  BusFault_Handler
 | 
			
		||||
        .fnstart
 | 
			
		||||
        .cantunwind
 | 
			
		||||
        
 | 
			
		||||
BusFault_Handler:
 | 
			
		||||
        LDR      R3,=FAULT_TYPE_BUS_FAULT  
 | 
			
		||||
        B        Fault_Handler
 | 
			
		||||
 | 
			
		||||
        .fnend
 | 
			
		||||
        .size    BusFault_Handler, .-BusFault_Handler
 | 
			
		||||
        
 | 
			
		||||
//UsageFault_Handler         
 | 
			
		||||
        .thumb_func
 | 
			
		||||
        .type    UsageFault_Handler, %function
 | 
			
		||||
        .global  UsageFault_Handler
 | 
			
		||||
        .fnstart
 | 
			
		||||
        .cantunwind
 | 
			
		||||
        
 | 
			
		||||
UsageFault_Handler:
 | 
			
		||||
        LDR      R3,=FAULT_TYPE_USAGE_FAULT  
 | 
			
		||||
        B        Fault_Handler
 | 
			
		||||
 | 
			
		||||
        .fnend
 | 
			
		||||
        .size    UsageFault_Handler, .-UsageFault_Handler
 | 
			
		||||
 | 
			
		||||
//Common Fault_Handler to capture the context
 | 
			
		||||
        .thumb_func
 | 
			
		||||
        .type    Fault_Handler, %function
 | 
			
		||||
        .global  Fault_Handler
 | 
			
		||||
        .fnstart
 | 
			
		||||
        .cantunwind
 | 
			
		||||
 | 
			
		||||
Fault_Handler:
 | 
			
		||||
        .if      __DOMAIN_NS == 1
 | 
			
		||||
        MRS      R0,MSP
 | 
			
		||||
        LDR      R1,=0x4                
 | 
			
		||||
        MOV      R2,LR
 | 
			
		||||
        TST      R2,R1                    // Check EXC_RETURN for bit 2
 | 
			
		||||
        BEQ      Fault_Handler_Continue
 | 
			
		||||
        MRS      R0,PSP
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue:
 | 
			
		||||
        MOV      R12,R3
 | 
			
		||||
        LDR      R1,=mbed_fault_context     
 | 
			
		||||
        LDR      R2,[R0]                  // Capture R0
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#4]               // Capture R1
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#8]               // Capture R2
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#12]              // Capture R3
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        STMIA    R1!,{R4-R7}              // Capture R4..R7
 | 
			
		||||
        MOV      R7,R8                    // Capture R8
 | 
			
		||||
        STR      R7,[R1]                  
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        MOV      R7,R9                    // Capture R9
 | 
			
		||||
        STR      R7,[R1]                  
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        MOV      R7,R10                   // Capture R10
 | 
			
		||||
        STR      R7,[R1]                  
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        MOV      R7,R11                   // Capture R11
 | 
			
		||||
        STR      R7,[R1]                  
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#16]              // Capture R12
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#8                    // Add 8 here to capture LR next, we will capture SP later
 | 
			
		||||
        LDR      R2,[R0,#20]              // Capture LR
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#24]              // Capture PC
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R2,[R0,#28]              // Capture xPSR
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        // Adjust stack pointer to its original value and capture it
 | 
			
		||||
        MOV      R3,R0
 | 
			
		||||
        ADDS     R3,#0x20                 // Add 0x20 to get the SP value prior to exception
 | 
			
		||||
        LDR      R6,=0x200
 | 
			
		||||
        TST      R2,R6                    // Check for if STK was aligned by checking bit-9 in xPSR value
 | 
			
		||||
        BEQ      Fault_Handler_Continue1
 | 
			
		||||
        ADDS     R3,#0x4
 | 
			
		||||
        
 | 
			
		||||
Fault_Handler_Continue1:
 | 
			
		||||
        MOV      R5,LR
 | 
			
		||||
        LDR      R6,=0x10                 // Check for bit-4 to see if FP context was saved
 | 
			
		||||
        TST      R5,R6
 | 
			
		||||
        BNE      Fault_Handler_Continue2
 | 
			
		||||
        ADDS     R3,#0x48                 // 16 FP regs + FPCSR + 1 Reserved
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue2:
 | 
			
		||||
        MOV      R4,R1
 | 
			
		||||
        SUBS     R4,#0x10                 // Set the location of SP in ctx
 | 
			
		||||
        STR      R3,[R4]                  // Capture the adjusted SP
 | 
			
		||||
        MRS      R2,PSP                   // Get PSP           
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        MRS      R2,MSP                   // Get MSP           
 | 
			
		||||
        STR      R2,[R1]
 | 
			
		||||
        ADDS     R1,#4
 | 
			
		||||
        LDR      R3,=mbed_fault_handler     // Load address of mbedFaultHandler
 | 
			
		||||
        MOV      R0,R12
 | 
			
		||||
        LDR      R1,=mbed_fault_context
 | 
			
		||||
        LDR      R2,=osRtxInfo
 | 
			
		||||
        BLX      R3
 | 
			
		||||
        .endif
 | 
			
		||||
        B        .                        // Just in case we come back here   
 | 
			
		||||
        
 | 
			
		||||
        .fnend
 | 
			
		||||
        .size    Fault_Handler, .-Fault_Handler
 | 
			
		||||
 | 
			
		||||
        .end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
;/*
 | 
			
		||||
; * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
 | 
			
		||||
; *
 | 
			
		||||
; * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
; *
 | 
			
		||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
 | 
			
		||||
; * not use this file except in compliance with the License.
 | 
			
		||||
; * You may obtain a copy of the License at
 | 
			
		||||
; *
 | 
			
		||||
; * www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
; *
 | 
			
		||||
; * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
; * See the License for the specific language governing permissions and
 | 
			
		||||
; * limitations under the License.
 | 
			
		||||
; *
 | 
			
		||||
; * -----------------------------------------------------------------------------
 | 
			
		||||
; *
 | 
			
		||||
; * Title:       Cortex-M Fault Exception handlers ( Common for both ARMv7M and ARMV6M ); 
 | 
			
		||||
; *
 | 
			
		||||
; * -----------------------------------------------------------------------------
 | 
			
		||||
; */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                NAME    except_cm0.s
 | 
			
		||||
                
 | 
			
		||||
#ifndef __DOMAIN_NS 
 | 
			
		||||
#define __DOMAIN_NS 1
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
FAULT_TYPE_HARD_FAULT           EQU      0x10
 | 
			
		||||
FAULT_TYPE_MEMMANAGE_FAULT      EQU      0x20
 | 
			
		||||
FAULT_TYPE_BUS_FAULT            EQU      0x30
 | 
			
		||||
FAULT_TYPE_USAGE_FAULT          EQU      0x40
 | 
			
		||||
 | 
			
		||||
                PRESERVE8
 | 
			
		||||
                SECTION .rodata:DATA:NOROOT(2)
 | 
			
		||||
                
 | 
			
		||||
                THUMB
 | 
			
		||||
                SECTION .text:CODE:NOROOT(2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HardFault_Handler
 | 
			
		||||
                EXPORT  HardFault_Handler
 | 
			
		||||
                LDR     R3,=FAULT_TYPE_HARD_FAULT   
 | 
			
		||||
                B       Fault_Handler
 | 
			
		||||
                
 | 
			
		||||
MemManage_Handler
 | 
			
		||||
                EXPORT  MemManage_Handler
 | 
			
		||||
                LDR     R3,=FAULT_TYPE_MEMMANAGE_FAULT   
 | 
			
		||||
                B       Fault_Handler
 | 
			
		||||
 | 
			
		||||
BusFault_Handler
 | 
			
		||||
                EXPORT  BusFault_Handler
 | 
			
		||||
                LDR     R3,=FAULT_TYPE_BUS_FAULT   
 | 
			
		||||
                B       Fault_Handler
 | 
			
		||||
                
 | 
			
		||||
UsageFault_Handler
 | 
			
		||||
                EXPORT  UsageFault_Handler
 | 
			
		||||
                LDR     R3,=FAULT_TYPE_USAGE_FAULT   
 | 
			
		||||
                B       Fault_Handler                
 | 
			
		||||
                
 | 
			
		||||
Fault_Handler
 | 
			
		||||
                EXPORT  Fault_Handler
 | 
			
		||||
#if (__DOMAIN_NS == 1)                    
 | 
			
		||||
                IMPORT  osRtxInfo
 | 
			
		||||
                IMPORT  mbed_fault_context    
 | 
			
		||||
                IMPORT  mbed_fault_handler    
 | 
			
		||||
                
 | 
			
		||||
                MRS     R0,MSP
 | 
			
		||||
                LDR     R1,=0x4                
 | 
			
		||||
                MOV     R2,LR
 | 
			
		||||
                TST     R2,R1                    ; Check EXC_RETURN for bit 2
 | 
			
		||||
                BEQ     Fault_Handler_Continue
 | 
			
		||||
                MRS     R0,PSP
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue
 | 
			
		||||
                MOV     R12,R3
 | 
			
		||||
                LDR     R1,=mbed_fault_context     
 | 
			
		||||
                LDR     R2,[R0]                  ; Capture R0
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#4]               ; Capture R1
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#8]               ; Capture R2
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#12]              ; Capture R3
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                STMIA   R1!,{R4-R7}              ; Capture R4..R7
 | 
			
		||||
                MOV     R7,R8                    ; Capture R8
 | 
			
		||||
                STR     R7,[R1]                  
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                MOV     R7,R9                    ; Capture R9
 | 
			
		||||
                STR     R7,[R1]                  
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                MOV     R7,R10                   ; Capture R10
 | 
			
		||||
                STR     R7,[R1]                  
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                MOV     R7,R11                   ; Capture R11
 | 
			
		||||
                STR     R7,[R1]                  
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#16]              ; Capture R12
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#8                    ; Add 8 here to capture LR next, we will capture SP later
 | 
			
		||||
                LDR     R2,[R0,#20]              ; Capture LR
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#24]              ; Capture PC
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R2,[R0,#28]              ; Capture xPSR
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                ; Adjust stack pointer to its original value and capture it
 | 
			
		||||
                MOV     R3,R0
 | 
			
		||||
                ADDS    R3,#0x20                 ; Add 0x20 to get the SP value prior to exception
 | 
			
		||||
                LDR     R6,=0x200
 | 
			
		||||
                TST     R2,R6                    ; Check for if STK was aligned by checking bit-9 in xPSR value
 | 
			
		||||
                BEQ     Fault_Handler_Continue1
 | 
			
		||||
                ADDS    R3,#0x4
 | 
			
		||||
                
 | 
			
		||||
Fault_Handler_Continue1
 | 
			
		||||
                MOV     R5,LR 
 | 
			
		||||
                LDR     R6,=0x10                 ; Check for bit-4 to see if FP context was saved
 | 
			
		||||
                TST     R5,R6
 | 
			
		||||
                BNE     Fault_Handler_Continue2
 | 
			
		||||
                ADDS    R3,#0x48                 ; 16 FP regs + FPCSR + 1 Reserved                
 | 
			
		||||
 | 
			
		||||
Fault_Handler_Continue2
 | 
			
		||||
                MOV     R4,R1
 | 
			
		||||
                SUBS    R4,#0x10                 ; Set the location of SP in ctx
 | 
			
		||||
                STR     R3,[R4]                  ; Capture the adjusted SP
 | 
			
		||||
                MRS     R2,PSP                   ; Get PSP           
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                MRS     R2,MSP                   ; Get MSP           
 | 
			
		||||
                STR     R2,[R1]
 | 
			
		||||
                ADDS    R1,#4
 | 
			
		||||
                LDR     R3,=mbed_fault_handler     ; Load address of mbedFaultHandler
 | 
			
		||||
                MOV     R0,R12
 | 
			
		||||
                LDR     R1,=mbed_fault_context
 | 
			
		||||
                LDR     R2,=osRtxInfo
 | 
			
		||||
                BLX     R3 
 | 
			
		||||
#endif                
 | 
			
		||||
                B       .                         ; Just in case we come back here    
 | 
			
		||||
 | 
			
		||||
                END
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,213 @@
 | 
			
		|||
/* mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2006-2018 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rtx_os.h"
 | 
			
		||||
#include "mbed_rtx.h"
 | 
			
		||||
#include "mbed_rtx_fault_handler.h"
 | 
			
		||||
#include "hal/serial_api.h"
 | 
			
		||||
 | 
			
		||||
//Global for populating the context in exception handler
 | 
			
		||||
mbed_fault_context_t mbed_fault_context;
 | 
			
		||||
 | 
			
		||||
//Structure to capture the context
 | 
			
		||||
void fault_print_init(void);
 | 
			
		||||
void fault_print_str(char *fmtstr, uint32_t *values);
 | 
			
		||||
void hex_to_str(uint32_t value, char *hex_star);
 | 
			
		||||
void print_context_info(void);
 | 
			
		||||
void print_threads_info(osRtxThread_t *);
 | 
			
		||||
void print_thread(osRtxThread_t *thread);
 | 
			
		||||
void print_register(char *regtag, uint32_t regval);
 | 
			
		||||
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
extern int stdio_uart_inited;
 | 
			
		||||
extern serial_t stdio_uart;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
 | 
			
		||||
{
 | 
			
		||||
    fault_print_init();
 | 
			
		||||
    fault_print_str("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
 | 
			
		||||
        
 | 
			
		||||
    switch( fault_type ) {
 | 
			
		||||
      case HARD_FAULT_EXCEPTION: fault_print_str("HardFault",NULL); break;
 | 
			
		||||
      case MEMMANAGE_FAULT_EXCEPTION: fault_print_str("MemManageFault",NULL); break;
 | 
			
		||||
      case BUS_FAULT_EXCEPTION: fault_print_str("BusFault",NULL); break;
 | 
			
		||||
      case USAGE_FAULT_EXCEPTION: fault_print_str("UsageFault",NULL); break;
 | 
			
		||||
      default: fault_print_str("Unknown Fault",NULL); break;
 | 
			
		||||
    }
 | 
			
		||||
    fault_print_str("\n\nContext:",NULL);
 | 
			
		||||
    print_context_info();
 | 
			
		||||
        
 | 
			
		||||
    fault_print_str("\n\nThread Info:\nCurrent:",NULL);
 | 
			
		||||
    print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr);
 | 
			
		||||
  
 | 
			
		||||
    fault_print_str("\nNext:",NULL);
 | 
			
		||||
    print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next);
 | 
			
		||||
    
 | 
			
		||||
    fault_print_str("\nWait Threads:",NULL);
 | 
			
		||||
    osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list;
 | 
			
		||||
    print_threads_info(threads);
 | 
			
		||||
    
 | 
			
		||||
    fault_print_str("\nDelay Threads:",NULL);
 | 
			
		||||
    threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list;
 | 
			
		||||
    print_threads_info(threads);
 | 
			
		||||
    
 | 
			
		||||
    fault_print_str("\nIdle Thread:",NULL);
 | 
			
		||||
    threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle;
 | 
			
		||||
    print_threads_info(threads);
 | 
			
		||||
    
 | 
			
		||||
    fault_print_str("\n\n-- MbedOS Fault Handler --\n\n",NULL);
 | 
			
		||||
        
 | 
			
		||||
    /* Just spin here, we have alrady crashed */
 | 
			
		||||
    for (;;) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_context_info()
 | 
			
		||||
{
 | 
			
		||||
    //Context Regs
 | 
			
		||||
    fault_print_str( "\nR0   : %" 
 | 
			
		||||
                    "\nR1   : %" 
 | 
			
		||||
                    "\nR2   : %" 
 | 
			
		||||
                    "\nR3   : %" 
 | 
			
		||||
                    "\nR4   : %" 
 | 
			
		||||
                    "\nR5   : %" 
 | 
			
		||||
                    "\nR6   : %" 
 | 
			
		||||
                    "\nR7   : %" 
 | 
			
		||||
                    "\nR8   : %" 
 | 
			
		||||
                    "\nR9   : %" 
 | 
			
		||||
                    "\nR10  : %" 
 | 
			
		||||
                    "\nR11  : %" 
 | 
			
		||||
                    "\nR12  : %" 
 | 
			
		||||
                    "\nSP   : %" 
 | 
			
		||||
                    "\nLR   : %" 
 | 
			
		||||
                    "\nPC   : %" 
 | 
			
		||||
                    "\nxPSR : %" 
 | 
			
		||||
                    "\nPSP  : %" 
 | 
			
		||||
                    "\nMSP  : %", (uint32_t *)&mbed_fault_context);
 | 
			
		||||
                       
 | 
			
		||||
    //Capture CPUID to get core/cpu info
 | 
			
		||||
    fault_print_str("\nCPUID: %",(uint32_t *)&SCB->CPUID);
 | 
			
		||||
    
 | 
			
		||||
#if !defined(TARGET_M0) && !defined(TARGET_M0P)
 | 
			
		||||
    //Capture fault information registers to infer the cause of exception
 | 
			
		||||
    uint32_t FSR[7] = {0};
 | 
			
		||||
    
 | 
			
		||||
    FSR[0] = SCB->HFSR;
 | 
			
		||||
    //Split/Capture CFSR into MMFSR, BFSR, UFSR
 | 
			
		||||
    FSR[1] = 0xFF & SCB->CFSR;//MMFSR
 | 
			
		||||
    FSR[2] = (0xFF00 & SCB->CFSR) >> 8;//BFSR
 | 
			
		||||
    FSR[3] = (0xFFFF0000 & SCB->CFSR) >> 16;//UFSR
 | 
			
		||||
    FSR[4] = SCB->DFSR;
 | 
			
		||||
    FSR[5] = SCB->AFSR;
 | 
			
		||||
    FSR[6] = SCB->SHCSR;
 | 
			
		||||
    fault_print_str("\nHFSR : %"
 | 
			
		||||
                    "\nMMFSR: %"
 | 
			
		||||
                    "\nBFSR : %"
 | 
			
		||||
                    "\nUFSR : %"
 | 
			
		||||
                    "\nDFSR : %"
 | 
			
		||||
                    "\nAFSR : %"
 | 
			
		||||
                    "\nSHCSR: %",FSR); 
 | 
			
		||||
    
 | 
			
		||||
    //Print MMFAR only if its valid as indicated by MMFSR
 | 
			
		||||
    if(FSR[1] & 0x80) {
 | 
			
		||||
        fault_print_str("\nMMFAR: %",(uint32_t *)&SCB->MMFAR); 
 | 
			
		||||
    }
 | 
			
		||||
    //Print BFAR only if its valid as indicated by BFSR
 | 
			
		||||
    if(FSR[2] & 0x80) {
 | 
			
		||||
        fault_print_str("\nBFAR : %",(uint32_t *)&SCB->BFAR); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Prints thread info from a list */
 | 
			
		||||
void print_threads_info(osRtxThread_t *threads)
 | 
			
		||||
{
 | 
			
		||||
    while(threads != NULL) {
 | 
			
		||||
        print_thread( threads );
 | 
			
		||||
        threads = threads->thread_next;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Prints info of a thread(using osRtxThread_t struct)*/
 | 
			
		||||
void print_thread(osRtxThread_t *thread)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t data[5];
 | 
			
		||||
 | 
			
		||||
    data[0]=thread->state;
 | 
			
		||||
    data[1]=thread->thread_addr;
 | 
			
		||||
    data[2]=thread->stack_size;
 | 
			
		||||
    data[3]=(uint32_t)thread->stack_mem;
 | 
			
		||||
    data[4]=thread->sp;
 | 
			
		||||
    fault_print_str("\nState: % EntryFn: % Stack Size: % Mem: % SP: %", data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initializes std uart for spitting the info out */
 | 
			
		||||
void fault_print_init()
 | 
			
		||||
{
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
    if (!stdio_uart_inited) {
 | 
			
		||||
        serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Limited print functionality which prints the string out to 
 | 
			
		||||
stdout/uart without using stdlib by directly calling serial-api 
 | 
			
		||||
and also uses less resources 
 | 
			
		||||
The fmtstr contains the format string for printing and for every %
 | 
			
		||||
found in that it fetches a uint32 value from values buffer
 | 
			
		||||
and prints it in hex format.
 | 
			
		||||
*/
 | 
			
		||||
void fault_print_str(char *fmtstr, uint32_t *values)
 | 
			
		||||
{
 | 
			
		||||
#if DEVICE_SERIAL
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    int idx = 0;
 | 
			
		||||
    int vidx = 0;
 | 
			
		||||
    char hex_str[9]={0};
 | 
			
		||||
        
 | 
			
		||||
    while(fmtstr[i] != '\0') {
 | 
			
		||||
        if(fmtstr[i] == '\n' || fmtstr[i] == '\r') {
 | 
			
		||||
            serial_putc(&stdio_uart, '\r');
 | 
			
		||||
        } else {
 | 
			
		||||
            if(fmtstr[i]=='%') {
 | 
			
		||||
                hex_to_str(values[vidx++],hex_str);
 | 
			
		||||
                for(idx=7; idx>=0; idx--) {
 | 
			
		||||
                    serial_putc(&stdio_uart, hex_str[idx]);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                serial_putc(&stdio_uart, fmtstr[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        i++;
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Converts a uint32 to hex char string */
 | 
			
		||||
void hex_to_str(uint32_t value, char *hex_str)
 | 
			
		||||
{
 | 
			
		||||
    char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    
 | 
			
		||||
    //Return without converting if hex_str is not provided
 | 
			
		||||
    if(hex_str == NULL) return;
 | 
			
		||||
        
 | 
			
		||||
    for(i=7; i>=0; i--) {
 | 
			
		||||
        hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/* mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2006-2018 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//Fault context struct
 | 
			
		||||
//WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
 | 
			
		||||
//Offset of these registers are used by fault handler in except.S
 | 
			
		||||
typedef struct {
 | 
			
		||||
  uint32_t R0;
 | 
			
		||||
  uint32_t R1;
 | 
			
		||||
  uint32_t R2;
 | 
			
		||||
  uint32_t R3;
 | 
			
		||||
  uint32_t R4;
 | 
			
		||||
  uint32_t R5;
 | 
			
		||||
  uint32_t R6;
 | 
			
		||||
  uint32_t R7;
 | 
			
		||||
  uint32_t R8;
 | 
			
		||||
  uint32_t R9;
 | 
			
		||||
  uint32_t R10;
 | 
			
		||||
  uint32_t R11;
 | 
			
		||||
  uint32_t R12;
 | 
			
		||||
  uint32_t SP;
 | 
			
		||||
  uint32_t LR;
 | 
			
		||||
  uint32_t PC;
 | 
			
		||||
  uint32_t xPSR;
 | 
			
		||||
  uint32_t PSP;
 | 
			
		||||
  uint32_t MSP;
 | 
			
		||||
} mbed_fault_context_t;
 | 
			
		||||
 | 
			
		||||
//Fault type definitions
 | 
			
		||||
//WARNING: DO NOT CHANGE THESE VALUES WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
 | 
			
		||||
#define HARD_FAULT_EXCEPTION       (0x10) //Keep some gap between values for any future insertion/expansion
 | 
			
		||||
#define MEMMANAGE_FAULT_EXCEPTION  (0x20)
 | 
			
		||||
#define BUS_FAULT_EXCEPTION        (0x30)
 | 
			
		||||
#define USAGE_FAULT_EXCEPTION      (0x40)
 | 
			
		||||
 | 
			
		||||
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
## Crash Log Parser Tool
 | 
			
		||||
This post-processing tool can be used to parse crash log generated by Mbed-OS when an exception happens. 
 | 
			
		||||
 | 
			
		||||
## Capturing crash log
 | 
			
		||||
When an exception happens Mbed-OS will print out the crash information to STDOUT.
 | 
			
		||||
The crash information contains register context at the time exception and current threads in the system.
 | 
			
		||||
The information printed out to STDOUT will be similar to below.
 | 
			
		||||
 | 
			
		||||
++ MbedOS Fault Handler ++
 | 
			
		||||
 | 
			
		||||
FaultType: HardFault
 | 
			
		||||
 | 
			
		||||
Context:
 | 
			
		||||
R0   : 0000AAA3
 | 
			
		||||
R1   : 20002070
 | 
			
		||||
R2   : 00009558
 | 
			
		||||
R3   : 00412A02
 | 
			
		||||
R4   : E000ED14
 | 
			
		||||
R5   : 00000000
 | 
			
		||||
R6   : 00000000
 | 
			
		||||
R7   : 00000000
 | 
			
		||||
R8   : 00000000
 | 
			
		||||
R9   : 00000000
 | 
			
		||||
R10  : 00000000
 | 
			
		||||
R11  : 00000000
 | 
			
		||||
R12  : 0000BCE5
 | 
			
		||||
SP   : 20002070
 | 
			
		||||
LR   : 00009E75
 | 
			
		||||
PC   : 00009512
 | 
			
		||||
xPSR : 01000000
 | 
			
		||||
PSP  : 20002008
 | 
			
		||||
MSP  : 2002FFD8
 | 
			
		||||
CPUID: 410FC241
 | 
			
		||||
HFSR : 40000000
 | 
			
		||||
MMFSR: 00000000
 | 
			
		||||
BFSR : 00000000
 | 
			
		||||
UFSR : 00000100
 | 
			
		||||
DFSR : 00000008
 | 
			
		||||
AFSR : 00000000
 | 
			
		||||
SHCSR: 00000000
 | 
			
		||||
 | 
			
		||||
Thread Info:
 | 
			
		||||
Current:
 | 
			
		||||
State: 00000002 EntryFn: 0000ADF5 Stack Size: 00001000 Mem: 20001070 SP: 20002030
 | 
			
		||||
Next:
 | 
			
		||||
State: 00000002 EntryFn: 0000ADF5 Stack Size: 00001000 Mem: 20001070 SP: 20002030
 | 
			
		||||
Wait Threads:
 | 
			
		||||
State: 00000083 EntryFn: 0000AA1D Stack Size: 00000300 Mem: 20000548 SP: 200007D8
 | 
			
		||||
Delay Threads:
 | 
			
		||||
Idle Thread:
 | 
			
		||||
State: 00000001 EntryFn: 00009F59 Stack Size: 00000200 Mem: 20000348 SP: 20000508
 | 
			
		||||
 | 
			
		||||
-- MbedOS Fault Handler --
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
To generate more information copy and save this crash information to a text file and run the crash_log_parser.py tool as below.
 | 
			
		||||
NOTE: Make sure you copy the section with text "MbedOS Fault Handler" as the this tool looks for that header.
 | 
			
		||||
 | 
			
		||||
## Running the Crash Log Parser
 | 
			
		||||
crash_log_parser.py -i <Path to Crash log> -e <Path to Elf/Axf file of the build> -m <Path to Map file of the build>
 | 
			
		||||
For example:
 | 
			
		||||
crashlogparse.py -i crash.log -e C:\MyProject\BUILD\k64f\arm\mbed-os-hf-handler.elf -m C:\MyProject\BUILD\k64f\arm\mbed-os-hf-handler.map
 | 
			
		||||
 | 
			
		||||
An example output from running crash_log_parser is shown below.
 | 
			
		||||
 | 
			
		||||
Parsed Crash Info:
 | 
			
		||||
        Crash location = zero_div_test() [0000693E]
 | 
			
		||||
        Caller location = $Super$$main [00009E99]
 | 
			
		||||
        Stack Pointer at the time of crash = [20001CC0]
 | 
			
		||||
        Target/Fault Info:
 | 
			
		||||
                Processor Arch: ARM-V7M or above
 | 
			
		||||
                Processor Variant: C24
 | 
			
		||||
                Forced exception, a fault with configurable priority has been escalated to HardFault
 | 
			
		||||
                Divide by zero error has occurred
 | 
			
		||||
 | 
			
		||||
Done parsing...
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,266 @@
 | 
			
		|||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
from os import path
 | 
			
		||||
import re, bisect
 | 
			
		||||
from subprocess import check_output
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
#arm-none-eabi-nm -nl <elf file>
 | 
			
		||||
NM_EXEC = "arm-none-eabi-nm"
 | 
			
		||||
OPT = "-nlC"
 | 
			
		||||
ptn = re.compile("([0-9a-f]*) ([Tt]) ([^\t\n]*)(?:\t(.*):([0-9]*))?")
 | 
			
		||||
fnt = None
 | 
			
		||||
fnt = ""
 | 
			
		||||
 | 
			
		||||
class ElfHelper(object):
 | 
			
		||||
    def __init__(self, p,m):
 | 
			
		||||
        if path.isfile(p):
 | 
			
		||||
            elf_path = p
 | 
			
		||||
        if path.isfile(m):
 | 
			
		||||
            map_path = m
 | 
			
		||||
        
 | 
			
		||||
        op = check_output([NM_EXEC, OPT, elf_path])
 | 
			
		||||
        map_file = open(map_path)
 | 
			
		||||
        self.maplines = map_file.readlines()
 | 
			
		||||
        self.matches = ptn.findall(op)
 | 
			
		||||
        self.addrs = [int(x[0],16) for x in self.matches]
 | 
			
		||||
        #print(self.maplines)
 | 
			
		||||
        
 | 
			
		||||
    def function_addrs(self):
 | 
			
		||||
        return self.addrs
 | 
			
		||||
    
 | 
			
		||||
    def function_name_for_addr(self, addr):
 | 
			
		||||
        i = bisect.bisect_right(self.addrs, addr)
 | 
			
		||||
        funcname = self.matches[i-1][2]
 | 
			
		||||
        return funcname
 | 
			
		||||
 | 
			
		||||
    def file_name_for_function_name(self, funcname):
 | 
			
		||||
        for eachline in self.maplines:
 | 
			
		||||
            #print("%s:%s"%(eachline,funcname))
 | 
			
		||||
            result = eachline.find(funcname)
 | 
			
		||||
            if(result != -1):
 | 
			
		||||
                break
 | 
			
		||||
        toks = eachline.split()   
 | 
			
		||||
        #print("%s:%s"%(str(funcname),str(toks)))
 | 
			
		||||
        if(len(toks) <= 0):
 | 
			
		||||
            print("WARN: Unable to find %s in map file"%(str(funcname)))
 | 
			
		||||
            #return funcname
 | 
			
		||||
            return ("%s [FUNCTION]"%(str(funcname)))
 | 
			
		||||
        else:    
 | 
			
		||||
            #return toks[-1].replace("./BUILD/","").replace("/","\\")
 | 
			
		||||
            return toks[-1]
 | 
			
		||||
            
 | 
			
		||||
def parseHFSR(hfsr):
 | 
			
		||||
    if(hfsr != 0):            
 | 
			
		||||
        if( int(hfsr,16) & 0x80000000 ):
 | 
			
		||||
            print("\t\tDebug Event Occured")
 | 
			
		||||
        if( int(hfsr,16) & 0x40000000 ):
 | 
			
		||||
            print("\t\tForced exception, a fault with configurable priority has been escalated to HardFault")    
 | 
			
		||||
        if( int(hfsr,16) & 0x2 ):
 | 
			
		||||
            print("\t\tVector table read fault has occurred")        
 | 
			
		||||
 | 
			
		||||
def parseMMFSR(mmfsr,mmfar):            
 | 
			
		||||
    if(mmfsr != 0):
 | 
			
		||||
        if( int(mmfsr,16) & 0x20 ):
 | 
			
		||||
            print("\t\tA MemManage fault occurred during FP lazy state preservation")
 | 
			
		||||
        if( int(mmfsr,16) & 0x10 ):
 | 
			
		||||
            print("\t\tA derived MemManage fault occurred on exception entry")            
 | 
			
		||||
        if( int(mmfsr,16) & 0x8 ):
 | 
			
		||||
            print("\t\tA derived MemManage fault occurred on exception return")                
 | 
			
		||||
        if( int(mmfsr,16) & 0x2 ):
 | 
			
		||||
            if( int(mmfsr,16) & 0x80 ):
 | 
			
		||||
                print("\t\tData access violation. Faulting address: %s"%(str(mmfar)))                    
 | 
			
		||||
            else:     
 | 
			
		||||
                print("\t\tData access violation. WARNING: Fault address in MMFAR is NOT valid")                    
 | 
			
		||||
        if( int(mmfsr,16) & 0x1 ):
 | 
			
		||||
            print("\t\tMPU or Execute Never (XN) default memory map access violation on an instruction fetch has occurred")                        
 | 
			
		||||
    
 | 
			
		||||
def parseBFSR(bfsr,bfar):
 | 
			
		||||
    if(bfsr != 0):
 | 
			
		||||
        if( int(bfsr,16) & 0x20 ):
 | 
			
		||||
            print("\t\tA bus fault occurred during FP lazy state preservation")
 | 
			
		||||
        if( int(bfsr,16) & 0x10 ):
 | 
			
		||||
            print("\t\tA derived bus fault has occurred on exception entry")  
 | 
			
		||||
        if( int(bfsr,16) & 0x8 ):
 | 
			
		||||
            print("\t\tA derived bus fault has occurred on exception return") 
 | 
			
		||||
        if( int(bfsr,16) & 0x4 ):
 | 
			
		||||
            print("\t\tImprecise data access error has occurred")               
 | 
			
		||||
        if( int(bfsr,16) & 0x2 ):
 | 
			
		||||
            if( int(bfsr,16) & 0x80 ):
 | 
			
		||||
                print("\t\tA precise data access error has occurred. Faulting address: %s"%(str(bfar)))                    
 | 
			
		||||
            else:     
 | 
			
		||||
                print("\t\tA precise data access error has occurred. WARNING: Fault address in BFAR is NOT valid")             
 | 
			
		||||
        if( int(bfsr,16) & 0x1 ):
 | 
			
		||||
            print("\t\tA bus fault on an instruction prefetch has occurred")                           
 | 
			
		||||
 | 
			
		||||
def parseUFSR(ufsr):            
 | 
			
		||||
    if(ufsr != 0):
 | 
			
		||||
        if( int(ufsr,16) & 0x200 ):
 | 
			
		||||
            print("\t\tDivide by zero error has occurred")
 | 
			
		||||
        if( int(ufsr,16) & 0x100 ):
 | 
			
		||||
            print("\t\tUnaligned access error has occurred")
 | 
			
		||||
        if( int(ufsr,16) & 0x8 ):
 | 
			
		||||
            print("\t\tA coprocessor access error has occurred. This shows that the coprocessor is disabled or not present")
 | 
			
		||||
        if( int(ufsr,16) & 0x4 ):
 | 
			
		||||
            print("\t\tAn integrity check error has occurred on EXC_RETURN")
 | 
			
		||||
        if( int(ufsr,16) & 0x2 ):
 | 
			
		||||
            print("\t\tInstruction executed with invalid EPSR.T or EPSR.IT field( This may be caused by Thumb bit not being set in branching instruction )")    
 | 
			
		||||
        if( int(ufsr,16) & 0x1 ):
 | 
			
		||||
            print("\t\tThe processor has attempted to execute an undefined instruction")        
 | 
			
		||||
    
 | 
			
		||||
def parseCPUID(cpuid):            
 | 
			
		||||
    if( ( ( int(cpuid,16) & 0xF0000 ) >> 16 ) == 0xC ):
 | 
			
		||||
        print("\t\tProcessor Arch: ARM-V6M")
 | 
			
		||||
    else:        
 | 
			
		||||
        print("\t\tProcessor Arch: ARM-V7M or above")
 | 
			
		||||
    
 | 
			
		||||
    print("\t\tProcessor Variant: %X"%(( ( int(cpuid,16) & 0xFFF0 ) >> 4 )))    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
def main(input):
 | 
			
		||||
    global fnt, pc_val, pc_name, lr_val, lr_name, sp_val, hfsr_val, mmfsr_val, ufsr_val, bfsr_val, cpuid_val, mmfar_val, bfar_val
 | 
			
		||||
    start_parsing = False
 | 
			
		||||
    mmfar_val = 0
 | 
			
		||||
    bfar_val = 0
 | 
			
		||||
    crash_file = open(input)
 | 
			
		||||
    lines = crash_file.readlines()
 | 
			
		||||
    
 | 
			
		||||
    cnt = 0
 | 
			
		||||
    for eachline in lines:
 | 
			
		||||
        idx = eachline.find("MbedOS Fault Handler")
 | 
			
		||||
        if(-1 != idx):
 | 
			
		||||
            break
 | 
			
		||||
        cnt=cnt+1    
 | 
			
		||||
 | 
			
		||||
    if(idx == -1):
 | 
			
		||||
        print("ERROR: Unable to find \"MbedOS Fault Handler\" header")
 | 
			
		||||
        return
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    print("\n\nParsed Crash Info:")    
 | 
			
		||||
    for i in range(cnt,len(lines)):
 | 
			
		||||
        eachline=lines[i]
 | 
			
		||||
        if(-1 != eachline.find("--- MbedOS Fault Handler ---")):
 | 
			
		||||
            break
 | 
			
		||||
        #print(eachline)
 | 
			
		||||
        
 | 
			
		||||
        if(eachline.startswith("PC")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, pc_val = l
 | 
			
		||||
            pc_name = fnt.function_name_for_addr(int(pc_val,16))
 | 
			
		||||
                        
 | 
			
		||||
        if(eachline.startswith("LR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, lr_val = l
 | 
			
		||||
            lr_name = fnt.function_name_for_addr(int(lr_val,16))
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("SP")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, sp_val = l
 | 
			
		||||
                        
 | 
			
		||||
        if(eachline.startswith("HFSR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, hfsr_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("MMFSR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, mmfsr_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("BFSR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, bfsr_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("UFSR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, ufsr_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("CPUID")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, cpuid_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("MMFAR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, mmfar_val = l
 | 
			
		||||
            
 | 
			
		||||
        if(eachline.startswith("BFAR")):
 | 
			
		||||
            l = re.findall(r"[\w']+", eachline)
 | 
			
		||||
            l = [x.strip() for x in l if x != '']
 | 
			
		||||
            tag, bfar_val = l    
 | 
			
		||||
        
 | 
			
		||||
    print("\tCrash location = %s [%s] (based on PC value)"%(pc_name.strip(),str(pc_val)))
 | 
			
		||||
    print("\tCaller location = %s [%s] (based on LR value)"%(lr_name.strip(),str(lr_val)))        
 | 
			
		||||
    print("\tStack Pointer at the time of crash = [%s]"%(str(sp_val)))
 | 
			
		||||
    
 | 
			
		||||
    print("\tTarget/Fault Info:")
 | 
			
		||||
    parseCPUID(cpuid_val)
 | 
			
		||||
    parseHFSR(hfsr_val)
 | 
			
		||||
    parseMMFSR(mmfsr_val,mmfar_val)
 | 
			
		||||
    parseBFSR(bfsr_val,bfar_val)
 | 
			
		||||
    parseUFSR(ufsr_val)
 | 
			
		||||
        
 | 
			
		||||
    print("\nDone parsing...")    
 | 
			
		||||
        
 | 
			
		||||
                            
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import argparse
 | 
			
		||||
    
 | 
			
		||||
    parser = argparse.ArgumentParser(
 | 
			
		||||
        description='Analyse mbed-os crash log')
 | 
			
		||||
 | 
			
		||||
    # specify arguments
 | 
			
		||||
    parser.add_argument('-i','--input', metavar='<path to input file with crash log output>', type=str,
 | 
			
		||||
                       help='path to input file')      
 | 
			
		||||
    parser.add_argument('-e','--elfpath', metavar='<module or elf file path>', type=str,
 | 
			
		||||
                       help='path to elf file')             
 | 
			
		||||
    parser.add_argument('-m','--mappath', metavar='<map file path>', type=str,
 | 
			
		||||
                       help='path to map file')                                    
 | 
			
		||||
 | 
			
		||||
    # get and validate arguments
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    
 | 
			
		||||
    p = args.elfpath
 | 
			
		||||
    m = args.mappath
 | 
			
		||||
    i = args.input
 | 
			
		||||
    if(p == None or m == None or i == None):
 | 
			
		||||
        print("Invalid arguments, exiting")
 | 
			
		||||
        parser.print_usage()
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
        
 | 
			
		||||
    if not path.exists(p):
 | 
			
		||||
        print("Elf path %s does not exist"%(str(p)))
 | 
			
		||||
        parser.print_usage()
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
        
 | 
			
		||||
    if not path.exists(m):
 | 
			
		||||
        print("Map path %s does not exist"%(str(m)))
 | 
			
		||||
        parser.print_usage()
 | 
			
		||||
        sys.exit(1)    
 | 
			
		||||
        
 | 
			
		||||
    if not path.exists(i):
 | 
			
		||||
        print("Input crash log path %s does not exist"%(str(i)))
 | 
			
		||||
        parser.print_usage()
 | 
			
		||||
        sys.exit(1) 
 | 
			
		||||
 | 
			
		||||
    print("Inputs:")        
 | 
			
		||||
    print("\tCrash Log: %s"%(i))        
 | 
			
		||||
    print("\tElf Path: %s"%(p))        
 | 
			
		||||
    print("\tMap Path: %s"%(m))        
 | 
			
		||||
    
 | 
			
		||||
    fnt = ElfHelper(p,m)
 | 
			
		||||
    
 | 
			
		||||
    # parse input and write to output
 | 
			
		||||
    main(i)
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue