diff --git a/tools/debug_tools/crash_log_parser/README.md b/tools/debug_tools/crash_log_parser/README.md index e412a44..779958c 100644 --- a/tools/debug_tools/crash_log_parser/README.md +++ b/tools/debug_tools/crash_log_parser/README.md @@ -4,7 +4,9 @@ ## 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. +The information printed out to STDOUT will be similar to below. Registers captured depends on specific +Cortex-M core you are using. For example, if your target is using Cortex-M0, some registers like +MMFSR, BFSR, UFSR may not be available and will not appear in the crash log. ++ MbedOS Fault Handler ++ @@ -57,9 +59,9 @@ 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 -e -m +crash_log_parser.py 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 +crashlogparse.py crash.log C:\MyProject\BUILD\k64f\arm\mbed-os-hf-handler.elf C:\MyProject\BUILD\k64f\arm\mbed-os-hf-handler.map An example output from running crash_log_parser is shown below. diff --git a/tools/debug_tools/crash_log_parser/crash_log_parser.py b/tools/debug_tools/crash_log_parser/crash_log_parser.py index 5ab221b..96bf0ad 100644 --- a/tools/debug_tools/crash_log_parser/crash_log_parser.py +++ b/tools/debug_tools/crash_log_parser/crash_log_parser.py @@ -31,12 +31,12 @@ _PTN = re.compile("([0-9a-f]*) ([Tt]) ([^\t\n]*)(?:\t(.*):([0-9]*))?") class ElfHelper(object): - def __init__(self, elf_file,map_file): + def __init__(self, elf_file, map_file): op = check_output([_NM_EXEC, _OPT, elf_file.name]) self.maplines = map_file.readlines() self.matches = _PTN.findall(op) - self.addrs = [int(x[0],16) for x in self.matches] + self.addrs = [int(x[0], 16) for x in self.matches] def function_addrs(self): return self.addrs @@ -47,85 +47,76 @@ return funcname def print_HFSR_info(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") + 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 print_MMFSR_info(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 print_MMFSR_info(mmfsr, mmfar): + 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 print_BFSR_info(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 print_BFSR_info(bfsr, bfar): + 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 print_UFSR_info(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") + 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 print_CPUID_info(cpuid): - if( ( ( int(cpuid,16) & 0xF0000 ) >> 16 ) == 0xC ): + if (int(cpuid, 16) & 0xF0000) == 0xC0000: 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 ))) + print("\t\tProcessor Variant: %X" % ((int(cpuid,16) & 0xFFF0 ) >> 4)) 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 + _, register_val = line.split(":") + return register_val.strip() -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 +def main(crash_log, elfhelper): mmfar_val = 0 bfar_val = 0 + lines = iter(crash_log.readlines()) - lines = crash_log.readlines() - - cnt = 0 for eachline in lines: if "++ MbedOS Fault Handler ++" in eachline: break @@ -134,51 +125,51 @@ return for eachline in lines: - if("-- MbedOS Fault Handler --" in eachline): + if "-- MbedOS Fault Handler --" in eachline: break - elif(eachline.startswith("PC")): + elif eachline.startswith("PC"): pc_val = parse_line_for_register(eachline) - pc_name = elfhelper.function_name_for_addr(int(pc_val,16)) + pc_name = elfhelper.function_name_for_addr(int(pc_val, 16)) - elif(eachline.startswith("LR")): + elif eachline.startswith("LR"): lr_val = parse_line_for_register(eachline) - lr_name = elfhelper.function_name_for_addr(int(lr_val,16)) + lr_name = elfhelper.function_name_for_addr(int(lr_val, 16)) - elif(eachline.startswith("SP")): + elif eachline.startswith("SP"): sp_val = parse_line_for_register(eachline) - elif(eachline.startswith("HFSR")): + elif eachline.startswith("HFSR"): hfsr_val = parse_line_for_register(eachline) - elif(eachline.startswith("MMFSR")): + elif eachline.startswith("MMFSR"): mmfsr_val = parse_line_for_register(eachline) - elif(eachline.startswith("BFSR")): + elif eachline.startswith("BFSR"): bfsr_val = parse_line_for_register(eachline) - elif(eachline.startswith("UFSR")): + elif eachline.startswith("UFSR"): ufsr_val = parse_line_for_register(eachline) - elif(eachline.startswith("CPUID")): + elif eachline.startswith("CPUID"): cpuid_val = parse_line_for_register(eachline) - elif(eachline.startswith("MMFAR")): + elif eachline.startswith("MMFAR"): mmfar_val = parse_line_for_register(eachline) - elif(eachline.startswith("BFAR")): + elif eachline.startswith("BFAR"): bfar_val = parse_line_for_register(eachline) - print("\n\nCrash Info:") - 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("\nCrash Info:") + print("\tCrash location = %s [0x%s] (based on PC value)" % (pc_name.strip(), str(pc_val))) + print("\tCaller location = %s [0x%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 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_MMFSR_info(mmfsr_val, mmfar_val) + print_BFSR_info(bfsr_val, bfar_val) print_UFSR_info(ufsr_val) @@ -187,35 +178,23 @@ 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') # specify arguments - parser.add_argument('-i','--input', metavar='', type=argparse.FileType('rb', 0), required=True, - help='path to input file') - parser.add_argument('-e','--elfpath', metavar='', type=argparse.FileType('rb', 0), required=True, - help='path to elf file') - parser.add_argument('-m','--mappath', metavar='', type=argparse.FileType('rb', 0), required=True, - help='path to map file') + 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), + dest='elffile',help='path to elf file') + parser.add_argument(metavar='MAP FILE', type=argparse.FileType('rb', 0), + dest='mapfile',help='path to map file') # get and validate arguments args = parser.parse_args() - elf_file = args.elfpath - map_file = args.mappath - input_crash_log = args.input - - print("Inputs:") - print("\tCrash Log: %s"%(input_crash_log.name)) - print("\tElf Path: %s"%(elf_file.name)) - print("\tMap Path: %s"%(map_file.name)) - - elfhelper = ElfHelper(elf_file,map_file) + elfhelper = ElfHelper(args.elffile, args.mapfile) # parse input and write to output - main(input_crash_log,elfhelper) + main(args.crashlog, elfhelper) #close all files - elf_file.close() - map_file.close() - input_crash_log.close() - - - + args.elffile.close() + args.mapfile.close() + args.crashlog.close()