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