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 23:45:20 +00:00
def __init__ ( self , elf_file , map_file ) :
2020-02-12 14:56:35 +00:00
op = check_output ( [ _NM_EXEC , _OPT , elf_file . name ] ) . decode ( ' utf-8 ' )
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-29 23:45:20 +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-29 23:45:20 +00:00
if int ( hfsr , 16 ) & 0x80000000 :
2018-01-16 21:08:14 +00:00
print ( " \t \t Debug Event Occurred " )
2018-01-29 23:45:20 +00:00
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 " )
def print_MMFSR_info ( mmfsr , mmfar ) :
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-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
def print_BFSR_info ( bfsr , bfar ) :
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-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
def print_UFSR_info ( ufsr ) :
2018-01-29 23:45:20 +00:00
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-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
def print_CPUID_info ( cpuid ) :
2018-01-29 23:45:20 +00:00
if ( int ( cpuid , 16 ) & 0xF0000 ) == 0xC0000 :
2018-01-12 20:54:44 +00:00
print ( " \t \t Processor Arch: ARM-V6M " )
else :
print ( " \t \t Processor Arch: ARM-V7M or above " )
2018-01-29 23:45:20 +00:00
print ( " \t \t Processor Variant: %X " % ( ( int ( cpuid , 16 ) & 0xFFF0 ) >> 4 ) )
2018-01-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
def parse_line_for_register ( line ) :
2018-01-29 23:45:20 +00:00
_ , register_val = line . split ( " : " )
return register_val . strip ( )
2018-01-29 20:54:30 +00:00
2018-01-29 23:45:20 +00:00
def main ( crash_log , elfhelper ) :
2018-01-12 20:54:44 +00:00
mmfar_val = 0
bfar_val = 0
2020-02-12 14:56:35 +00:00
lines = iter ( crash_log . read ( ) . decode ( ' utf-8 ' ) . splitlines ( ) )
2018-01-12 20:54:44 +00:00
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 :
2018-01-29 23:45:20 +00:00
if " -- MbedOS Fault Handler -- " in eachline :
2018-01-12 20:54:44 +00:00
break
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " PC " ) :
2018-01-29 20:54:30 +00:00
pc_val = parse_line_for_register ( eachline )
2018-06-08 09:39:25 +00:00
if elfhelper :
pc_name = elfhelper . function_name_for_addr ( int ( pc_val , 16 ) )
else :
pc_name = " <unknown-symbol> "
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " LR " ) :
2018-01-29 20:54:30 +00:00
lr_val = parse_line_for_register ( eachline )
2018-06-08 09:39:25 +00:00
if elfhelper :
lr_name = elfhelper . function_name_for_addr ( int ( lr_val , 16 ) )
else :
lr_name = " <unknown-symbol> "
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " SP " ) :
2018-01-29 20:54:30 +00:00
sp_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " HFSR " ) :
2018-01-29 20:54:30 +00:00
hfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " MMFSR " ) :
2018-01-29 20:54:30 +00:00
mmfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " BFSR " ) :
2018-01-29 20:54:30 +00:00
bfsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " UFSR " ) :
2018-01-29 20:54:30 +00:00
ufsr_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " CPUID " ) :
2018-01-29 20:54:30 +00:00
cpuid_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " MMFAR " ) :
2018-01-29 20:54:30 +00:00
mmfar_val = parse_line_for_register ( eachline )
2018-01-12 20:54:44 +00:00
2018-01-29 23:45:20 +00:00
elif eachline . startswith ( " BFAR " ) :
2018-01-29 20:54:30 +00:00
bfar_val = parse_line_for_register ( eachline )
2018-01-29 23:45:20 +00:00
print ( " \n Crash Info: " )
print ( " \t Crash location = %s [0x %s ] (based on PC value) " % ( pc_name . strip ( ) , str ( pc_val ) ) )
print ( " \t Caller location = %s [0x %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-12 20:54:44 +00:00
2018-01-29 20:54:30 +00:00
print ( " \t Target and Fault Info: " )
print_CPUID_info ( cpuid_val )
print_HFSR_info ( hfsr_val )
2018-01-29 23:45:20 +00:00
print_MMFSR_info ( mmfsr_val , mmfar_val )
print_BFSR_info ( bfsr_val , bfar_val )
2018-01-29 20:54:30 +00:00
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 23:45:20 +00:00
parser . add_argument ( metavar = ' CRASH LOG ' , type = argparse . FileType ( ' rb ' , 0 ) ,
dest = ' crashlog ' , help = ' path to crash log file ' )
parser . add_argument ( metavar = ' ELF FILE ' , type = argparse . FileType ( ' rb ' , 0 ) ,
2018-06-08 09:39:25 +00:00
nargs = ' ? ' , const = None , dest = ' elffile ' , help = ' path to elf file ' )
2018-01-29 23:45:20 +00:00
parser . add_argument ( metavar = ' MAP FILE ' , type = argparse . FileType ( ' rb ' , 0 ) ,
2018-06-08 09:39:25 +00:00
nargs = ' ? ' , const = None , dest = ' mapfile ' , help = ' path to map file ' )
2018-01-12 20:54:44 +00:00
# get and validate arguments
args = parser . parse_args ( )
2018-06-08 09:39:25 +00:00
# if both the ELF and MAP files are present, the addresses can be converted to symbol names
if args . elffile and args . mapfile :
elfhelper = ElfHelper ( args . elffile , args . mapfile )
else :
print ( " ELF or MAP file missing, logging raw values. " )
elfhelper = None
2018-01-12 20:54:44 +00:00
# parse input and write to output
2018-01-29 23:45:20 +00:00
main ( args . crashlog , elfhelper )
2018-01-29 20:54:30 +00:00
#close all files
2018-06-08 09:39:25 +00:00
if args . elffile :
args . elffile . close ( )
if args . mapfile :
args . mapfile . close ( )
2018-01-29 23:45:20 +00:00
args . crashlog . close ( )
2018-01-12 20:54:44 +00:00