2018-01-12 20:54:44 +00:00
#!/usr/bin/env python
2018-01-26 16:19:49 +00:00
"""
mbed SDK
Copyright ( c ) 2017 - 2019 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 .
LIBRARIES BUILD
"""
2018-01-12 20:54:44 +00:00
from __future__ import print_function
from os import path
2018-01-29 20:54:30 +00:00
import re
import bisect
2018-01-12 20:54:44 +00:00
from subprocess import check_output
import sys
#arm-none-eabi-nm -nl <elf file>
2018-01-29 20:54:30 +00:00
_NM_EXEC = " arm-none-eabi-nm "
_OPT = " -nlC "
_PTN = re . compile ( " ([0-9a-f]*) ([Tt]) ([^ \t \n ]*)(?: \t (.*):([0-9]*))? " )
2018-01-12 20:54:44 +00:00
class ElfHelper ( object ) :
2018-01-29 20:54:30 +00:00
def __init__ ( self , elf_file , map_file ) :
op = check_output ( [ _NM_EXEC , _OPT , elf_file . name ] )
2018-01-12 20:54:44 +00:00
self . maplines = map_file . readlines ( )
2018-01-29 20:54:30 +00:00
self . matches = _PTN . findall ( op )
2018-01-12 20:54:44 +00:00
self . addrs = [ int ( x [ 0 ] , 16 ) for x in self . matches ]
2018-01-26 16:19:49 +00:00
2018-01-12 20:54:44 +00:00
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
2018-01-29 20:54:30 +00:00
def print_HFSR_info ( hfsr ) :
2018-01-12 20:54:44 +00:00
if ( hfsr != 0 ) :
if ( int ( hfsr , 16 ) & 0x80000000 ) :
print ( " \t \t Debug Event Occured " )
if ( int ( hfsr , 16 ) & 0x40000000 ) :
print ( " \t \t Forced exception, a fault with configurable priority has been escalated to HardFault " )
if ( int ( hfsr , 16 ) & 0x2 ) :
print ( " \t \t Vector table read fault has occurred " )
2018-01-29 20:54:30 +00:00
def print_MMFSR_info ( mmfsr , mmfar ) :
2018-01-12 20:54:44 +00:00
if ( mmfsr != 0 ) :
if ( int ( mmfsr , 16 ) & 0x20 ) :
print ( " \t \t A MemManage fault occurred during FP lazy state preservation " )
if ( int ( mmfsr , 16 ) & 0x10 ) :
print ( " \t \t A derived MemManage fault occurred on exception entry " )
if ( int ( mmfsr , 16 ) & 0x8 ) :
print ( " \t \t A derived MemManage fault occurred on exception return " )
if ( int ( mmfsr , 16 ) & 0x2 ) :
if ( int ( mmfsr , 16 ) & 0x80 ) :
print ( " \t \t Data access violation. Faulting address: %s " % ( str ( mmfar ) ) )
else :
print ( " \t \t Data access violation. WARNING: Fault address in MMFAR is NOT valid " )
if ( int ( mmfsr , 16 ) & 0x1 ) :
print ( " \t \t MPU or Execute Never (XN) default memory map access violation on an instruction fetch has occurred " )
2018-01-29 20:54:30 +00:00
def print_BFSR_info ( bfsr , bfar ) :
2018-01-12 20:54:44 +00:00
if ( bfsr != 0 ) :
if ( int ( bfsr , 16 ) & 0x20 ) :
print ( " \t \t A bus fault occurred during FP lazy state preservation " )
if ( int ( bfsr , 16 ) & 0x10 ) :
print ( " \t \t A derived bus fault has occurred on exception entry " )
if ( int ( bfsr , 16 ) & 0x8 ) :
print ( " \t \t A derived bus fault has occurred on exception return " )
if ( int ( bfsr , 16 ) & 0x4 ) :
print ( " \t \t Imprecise data access error has occurred " )
if ( int ( bfsr , 16 ) & 0x2 ) :
if ( int ( bfsr , 16 ) & 0x80 ) :
print ( " \t \t A precise data access error has occurred. Faulting address: %s " % ( str ( bfar ) ) )
else :
print ( " \t \t A precise data access error has occurred. WARNING: Fault address in BFAR is NOT valid " )
if ( int ( bfsr , 16 ) & 0x1 ) :
print ( " \t \t A bus fault on an instruction prefetch has occurred " )
2018-01-29 20:54:30 +00:00
def print_UFSR_info ( ufsr ) :
2018-01-12 20:54:44 +00:00
if ( ufsr != 0 ) :
if ( int ( ufsr , 16 ) & 0x200 ) :
print ( " \t \t Divide by zero error has occurred " )
if ( int ( ufsr , 16 ) & 0x100 ) :
print ( " \t \t Unaligned access error has occurred " )
if ( int ( ufsr , 16 ) & 0x8 ) :
print ( " \t \t A coprocessor access error has occurred. This shows that the coprocessor is disabled or not present " )
if ( int ( ufsr , 16 ) & 0x4 ) :
print ( " \t \t An integrity check error has occurred on EXC_RETURN " )
if ( int ( ufsr , 16 ) & 0x2 ) :
print ( " \t \t Instruction 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 \t The processor has attempted to execute an undefined instruction " )
2018-01-29 20:54:30 +00:00
def print_CPUID_info ( cpuid ) :
2018-01-12 20:54:44 +00:00
if ( ( ( int ( cpuid , 16 ) & 0xF0000 ) >> 16 ) == 0xC ) :
print ( " \t \t Processor Arch: ARM-V6M " )
else :
print ( " \t \t Processor Arch: ARM-V7M or above " )
print ( " \t \t Processor Variant: %X " % ( ( ( int ( cpuid , 16 ) & 0xFFF0 ) >> 4 ) ) )
2018-01-29 20:54:30 +00:00
def parse_line_for_register ( line ) :
line = re . findall ( r " [ \ w ' ]+ " , line )
line = [ x . strip ( ) for x in line if x != ' ' ]
tag , register_val = line
return register_val
def main ( crash_log , elfhelper ) :
global pc_val , pc_name , lr_val , lr_name , sp_val , hfsr_val , mmfsr_val , ufsr_val , bfsr_val , cpuid_val , mmfar_val , bfar_val
2018-01-12 20:54:44 +00:00
mmfar_val = 0
bfar_val = 0
2018-01-29 20:54:30 +00:00
lines = crash_log . readlines ( )
2018-01-12 20:54:44 +00:00
cnt = 0
for eachline in lines :
2018-01-29 20:54:30 +00:00
if " ++ MbedOS Fault Handler ++ " in eachline :
2018-01-12 20:54:44 +00:00
break
2018-01-29 20:54:30 +00:00
else :
2018-01-12 20:54:44 +00:00
print ( " ERROR: Unable to find \" MbedOS Fault Handler \" header " )
return
2018-01-29 20:54:30 +00:00
for eachline in lines :
if ( " -- MbedOS Fault Handler -- " in eachline ) :
2018-01-12 20:54:44 +00:00
break
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " PC " ) ) :
pc_val = parse_line_for_register ( eachline )
pc_name = elfhelper . function_name_for_addr ( int ( pc_val , 16 ) )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " LR " ) ) :
lr_val = parse_line_for_register ( eachline )
lr_name = elfhelper . function_name_for_addr ( int ( lr_val , 16 ) )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " SP " ) ) :
sp_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " HFSR " ) ) :
hfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " MMFSR " ) ) :
mmfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " BFSR " ) ) :
bfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " UFSR " ) ) :
ufsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " CPUID " ) ) :
cpuid_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " MMFAR " ) ) :
mmfar_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elif ( eachline . startswith ( " BFAR " ) ) :
bfar_val = parse_line_for_register ( eachline )
print ( " \n \n Crash Info: " )
2018-01-12 20:54:44 +00:00
print ( " \t Crash location = %s [ %s ] (based on PC value) " % ( pc_name . strip ( ) , str ( pc_val ) ) )
print ( " \t Caller location = %s [ %s ] (based on LR value) " % ( lr_name . strip ( ) , str ( lr_val ) ) )
print ( " \t Stack Pointer at the time of crash = [ %s ] " % ( str ( sp_val ) ) )
2018-01-29 20:54:30 +00:00
print ( " \t Target and Fault Info: " )
print_CPUID_info ( cpuid_val )
print_HFSR_info ( hfsr_val )
print_MMFSR_info ( mmfsr_val , mmfar_val )
print_BFSR_info ( bfsr_val , bfar_val )
print_UFSR_info ( ufsr_val )
2018-01-12 20:54:44 +00:00
if __name__ == ' __main__ ' :
import argparse
2018-01-29 20:54:30 +00:00
parser = argparse . ArgumentParser ( description = ' Analyse mbed-os crash log. This tool requires arm-gcc binary utilities to be available in current path as it uses \' nm \' command ' )
2018-01-12 20:54:44 +00:00
# specify arguments
2018-01-29 20:54:30 +00:00
parser . add_argument ( ' -i ' , ' --input ' , metavar = ' <path to input file with crash log output> ' , type = argparse . FileType ( ' rb ' , 0 ) , required = True ,
2018-01-12 20:54:44 +00:00
help = ' path to input file ' )
2018-01-29 20:54:30 +00:00
parser . add_argument ( ' -e ' , ' --elfpath ' , metavar = ' <module or elf file path> ' , type = argparse . FileType ( ' rb ' , 0 ) , required = True ,
2018-01-12 20:54:44 +00:00
help = ' path to elf file ' )
2018-01-29 20:54:30 +00:00
parser . add_argument ( ' -m ' , ' --mappath ' , metavar = ' <map file path> ' , type = argparse . FileType ( ' rb ' , 0 ) , required = True ,
2018-01-12 20:54:44 +00:00
help = ' path to map file ' )
# get and validate arguments
args = parser . parse_args ( )
2018-01-29 20:54:30 +00:00
elf_file = args . elfpath
map_file = args . mappath
input_crash_log = args . input
2018-01-12 20:54:44 +00:00
print ( " Inputs: " )
2018-01-29 20:54:30 +00:00
print ( " \t Crash Log: %s " % ( input_crash_log . name ) )
print ( " \t Elf Path: %s " % ( elf_file . name ) )
print ( " \t Map Path: %s " % ( map_file . name ) )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
elfhelper = ElfHelper ( elf_file , map_file )
2018-01-12 20:54:44 +00:00
# parse input and write to output
2018-01-29 20:54:30 +00:00
main ( input_crash_log , elfhelper )
#close all files
elf_file . close ( )
map_file . close ( )
input_crash_log . close ( )
2018-01-12 20:54:44 +00:00