Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers crash_log_parser.py Source File

crash_log_parser.py

00001 #!/usr/bin/env python
00002 """
00003 mbed SDK
00004 Copyright (c) 2017-2019 ARM Limited
00005 
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009 
00010     http://www.apache.org/licenses/LICENSE-2.0
00011 
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 
00018 LIBRARIES BUILD
00019 """
00020 
00021 from __future__ import print_function
00022 from os import path
00023 import re
00024 import bisect
00025 from subprocess import check_output
00026 import sys
00027 
00028 #arm-none-eabi-nm -nl <elf file>
00029 _NM_EXEC = "arm-none-eabi-nm"
00030 _OPT = "-nlC"
00031 _PTN = re.compile("([0-9a-f]*) ([Tt]) ([^\t\n]*)(?:\t(.*):([0-9]*))?")
00032 
00033 class ElfHelper(object):
00034     def __init__(self, elf_file, map_file):
00035     
00036         op = check_output([_NM_EXEC, _OPT, elf_file.name])
00037         self.maplines = map_file.readlines()
00038         self.matches = _PTN.findall(op)
00039         self.addrs = [int(x[0], 16) for x in self.matches]
00040                 
00041     def function_addrs(self):
00042         return self.addrs
00043     
00044     def function_name_for_addr(self, addr):
00045         i = bisect.bisect_right(self.addrs, addr)
00046         funcname = self.matches[i-1][2]
00047         return funcname
00048 
00049 def print_HFSR_info(hfsr):
00050     if int(hfsr, 16) & 0x80000000:
00051         print("\t\tDebug Event Occurred")
00052     if int(hfsr, 16) & 0x40000000:
00053         print("\t\tForced exception, a fault with configurable priority has been escalated to HardFault")    
00054     if int(hfsr, 16) & 0x2:
00055         print("\t\tVector table read fault has occurred")        
00056 
00057 def print_MMFSR_info(mmfsr, mmfar):            
00058     if int(mmfsr, 16) & 0x20:
00059         print("\t\tA MemManage fault occurred during FP lazy state preservation")
00060     if int(mmfsr, 16) & 0x10:
00061         print("\t\tA derived MemManage fault occurred on exception entry")            
00062     if int(mmfsr, 16) & 0x8:
00063         print("\t\tA derived MemManage fault occurred on exception return")                
00064     if int(mmfsr, 16) & 0x2:
00065         if int(mmfsr, 16) & 0x80:
00066             print("\t\tData access violation. Faulting address: %s"%(str(mmfar)))                    
00067         else:     
00068             print("\t\tData access violation. WARNING: Fault address in MMFAR is NOT valid")                    
00069     if int(mmfsr, 16) & 0x1:
00070         print("\t\tMPU or Execute Never (XN) default memory map access violation on an instruction fetch has occurred")                        
00071     
00072 def print_BFSR_info(bfsr, bfar):
00073     if int(bfsr, 16) & 0x20:
00074         print("\t\tA bus fault occurred during FP lazy state preservation")
00075     if int(bfsr, 16) & 0x10:
00076         print("\t\tA derived bus fault has occurred on exception entry")  
00077     if int(bfsr, 16) & 0x8:
00078         print("\t\tA derived bus fault has occurred on exception return") 
00079     if int(bfsr, 16) & 0x4:
00080         print("\t\tImprecise data access error has occurred")               
00081     if int(bfsr, 16) & 0x2:
00082         if int(bfsr,16) & 0x80:
00083             print("\t\tA precise data access error has occurred. Faulting address: %s"%(str(bfar)))                    
00084         else:     
00085             print("\t\tA precise data access error has occurred. WARNING: Fault address in BFAR is NOT valid")             
00086     if int(bfsr, 16) & 0x1:
00087         print("\t\tA bus fault on an instruction prefetch has occurred")                           
00088 
00089 def print_UFSR_info(ufsr):            
00090     if int(ufsr, 16) & 0x200:
00091         print("\t\tDivide by zero error has occurred")
00092     if int(ufsr, 16) & 0x100:
00093         print("\t\tUnaligned access error has occurred")
00094     if int(ufsr, 16) & 0x8:
00095         print("\t\tA coprocessor access error has occurred. This shows that the coprocessor is disabled or not present")
00096     if int(ufsr, 16) & 0x4:
00097         print("\t\tAn integrity check error has occurred on EXC_RETURN")
00098     if int(ufsr, 16) & 0x2:
00099         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 )")    
00100     if int(ufsr, 16) & 0x1:
00101         print("\t\tThe processor has attempted to execute an undefined instruction")        
00102     
00103 def print_CPUID_info(cpuid):            
00104     if (int(cpuid, 16) & 0xF0000) == 0xC0000:
00105         print("\t\tProcessor Arch: ARM-V6M")
00106     else:        
00107         print("\t\tProcessor Arch: ARM-V7M or above")
00108     
00109     print("\t\tProcessor Variant: %X" % ((int(cpuid,16) & 0xFFF0 ) >> 4))    
00110 
00111 def parse_line_for_register(line):
00112     _, register_val = line.split(":")
00113     return register_val.strip()    
00114 
00115 def main(crash_log, elfhelper):
00116     mmfar_val = 0
00117     bfar_val = 0
00118     lines = iter(crash_log.readlines())
00119     
00120     for eachline in lines:
00121         if "++ MbedOS Fault Handler ++" in eachline:
00122             break
00123     else:
00124         print("ERROR: Unable to find \"MbedOS Fault Handler\" header")
00125         return
00126     
00127     for eachline in lines:
00128         if "-- MbedOS Fault Handler --" in eachline:
00129             break
00130         
00131         elif eachline.startswith("PC"):
00132             pc_val = parse_line_for_register(eachline)
00133             if elfhelper:
00134                 pc_name = elfhelper.function_name_for_addr(int(pc_val, 16))
00135             else:
00136                 pc_name = "<unknown-symbol>"
00137                         
00138         elif eachline.startswith("LR"):
00139             lr_val = parse_line_for_register(eachline)
00140             if elfhelper:
00141                 lr_name = elfhelper.function_name_for_addr(int(lr_val, 16))
00142             else:
00143                 lr_name = "<unknown-symbol>"
00144             
00145         elif eachline.startswith("SP"):
00146             sp_val = parse_line_for_register(eachline)
00147                         
00148         elif eachline.startswith("HFSR"):
00149             hfsr_val = parse_line_for_register(eachline)
00150             
00151         elif eachline.startswith("MMFSR"):
00152             mmfsr_val = parse_line_for_register(eachline)
00153             
00154         elif eachline.startswith("BFSR"):
00155             bfsr_val = parse_line_for_register(eachline)
00156             
00157         elif eachline.startswith("UFSR"):
00158             ufsr_val = parse_line_for_register(eachline)
00159             
00160         elif eachline.startswith("CPUID"):
00161             cpuid_val = parse_line_for_register(eachline)
00162             
00163         elif eachline.startswith("MMFAR"):
00164             mmfar_val = parse_line_for_register(eachline)
00165             
00166         elif eachline.startswith("BFAR"):
00167             bfar_val = parse_line_for_register(eachline)    
00168     
00169     print("\nCrash Info:")        
00170     print("\tCrash location = %s [0x%s] (based on PC value)" % (pc_name.strip(), str(pc_val)))
00171     print("\tCaller location = %s [0x%s] (based on LR value)" % (lr_name.strip(), str(lr_val)))        
00172     print("\tStack Pointer at the time of crash = [%s]" % (str(sp_val)))
00173     
00174     print("\tTarget and Fault Info:")
00175     print_CPUID_info(cpuid_val)
00176     print_HFSR_info(hfsr_val)
00177     print_MMFSR_info(mmfsr_val, mmfar_val)
00178     print_BFSR_info(bfsr_val, bfar_val)
00179     print_UFSR_info(ufsr_val)
00180         
00181                             
00182 if __name__ == '__main__':
00183     import argparse
00184     
00185     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')
00186     # specify arguments
00187     parser.add_argument(metavar='CRASH LOG', type=argparse.FileType('rb', 0),
00188                         dest='crashlog',help='path to crash log file')      
00189     parser.add_argument(metavar='ELF FILE', type=argparse.FileType('rb', 0),
00190                         nargs='?',const=None,dest='elffile',help='path to elf file')             
00191     parser.add_argument(metavar='MAP FILE', type=argparse.FileType('rb', 0),
00192                         nargs='?',const=None,dest='mapfile',help='path to map file')                                    
00193 
00194     # get and validate arguments
00195     args = parser.parse_args()
00196 
00197     # if both the ELF and MAP files are present, the addresses can be converted to symbol names
00198     if args.elffile and args.mapfile:
00199         elfhelper = ElfHelper(args.elffile, args.mapfile)
00200     else:
00201         print("ELF or MAP file missing, logging raw values.")
00202         elfhelper = None
00203     
00204     # parse input and write to output
00205     main(args.crashlog, elfhelper)
00206     
00207     #close all files
00208     if args.elffile:
00209         args.elffile.close()
00210     if args.mapfile:
00211         args.mapfile.close()
00212     args.crashlog.close()
00213