Fix code style issues and update documentation

pull/5847/head
Senthil Ramakrishnan 2018-01-29 17:45:20 -06:00
parent 8967b52bfb
commit 3340a020ed
2 changed files with 91 additions and 110 deletions

View File

@ -4,7 +4,9 @@ This post-processing tool can be used to parse crash log generated by Mbed-OS wh
## Capturing crash log ## Capturing crash log
When an exception happens Mbed-OS will print out the crash information to STDOUT. 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 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 ++ ++ MbedOS Fault Handler ++
@ -57,9 +59,9 @@ To generate more information copy and save this crash information to a text file
NOTE: Make sure you copy the section with text "MbedOS Fault Handler" as the this tool looks for that header. 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 ## 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> crash_log_parser.py <Path to Crash log> <Path to Elf/Axf file of the build> <Path to Map file of the build>
For example: 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. An example output from running crash_log_parser is shown below.

View File

@ -31,12 +31,12 @@ _OPT = "-nlC"
_PTN = re.compile("([0-9a-f]*) ([Tt]) ([^\t\n]*)(?:\t(.*):([0-9]*))?") _PTN = re.compile("([0-9a-f]*) ([Tt]) ([^\t\n]*)(?:\t(.*):([0-9]*))?")
class ElfHelper(object): 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]) op = check_output([_NM_EXEC, _OPT, elf_file.name])
self.maplines = map_file.readlines() self.maplines = map_file.readlines()
self.matches = _PTN.findall(op) 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): def function_addrs(self):
return self.addrs return self.addrs
@ -47,85 +47,76 @@ class ElfHelper(object):
return funcname return funcname
def print_HFSR_info(hfsr): def print_HFSR_info(hfsr):
if(hfsr != 0): if int(hfsr, 16) & 0x80000000:
if( int(hfsr,16) & 0x80000000 ): print("\t\tDebug Event Occured")
print("\t\tDebug Event Occured") if int(hfsr, 16) & 0x40000000:
if( int(hfsr,16) & 0x40000000 ): print("\t\tForced exception, a fault with configurable priority has been escalated to HardFault")
print("\t\tForced exception, a fault with configurable priority has been escalated to HardFault") if int(hfsr, 16) & 0x2:
if( int(hfsr,16) & 0x2 ): print("\t\tVector table read fault has occurred")
print("\t\tVector table read fault has occurred")
def print_MMFSR_info(mmfsr,mmfar): def print_MMFSR_info(mmfsr, mmfar):
if(mmfsr != 0): if int(mmfsr, 16) & 0x20:
if( int(mmfsr,16) & 0x20 ): print("\t\tA MemManage fault occurred during FP lazy state preservation")
print("\t\tA MemManage fault occurred during FP lazy state preservation") if int(mmfsr, 16) & 0x10:
if( int(mmfsr,16) & 0x10 ): print("\t\tA derived MemManage fault occurred on exception entry")
print("\t\tA derived MemManage fault occurred on exception entry") if int(mmfsr, 16) & 0x8:
if( int(mmfsr,16) & 0x8 ): print("\t\tA derived MemManage fault occurred on exception return")
print("\t\tA derived MemManage fault occurred on exception return") if int(mmfsr, 16) & 0x2:
if( int(mmfsr,16) & 0x2 ): if int(mmfsr, 16) & 0x80:
if( int(mmfsr,16) & 0x80 ): print("\t\tData access violation. Faulting address: %s"%(str(mmfar)))
print("\t\tData access violation. Faulting address: %s"%(str(mmfar))) else:
else: print("\t\tData access violation. WARNING: Fault address in MMFAR is NOT valid")
print("\t\tData access violation. WARNING: Fault address in MMFAR is NOT valid") if int(mmfsr, 16) & 0x1:
if( int(mmfsr,16) & 0x1 ): print("\t\tMPU or Execute Never (XN) default memory map access violation on an instruction fetch has occurred")
print("\t\tMPU or Execute Never (XN) default memory map access violation on an instruction fetch has occurred")
def print_BFSR_info(bfsr,bfar): def print_BFSR_info(bfsr, bfar):
if(bfsr != 0): if int(bfsr, 16) & 0x20:
if( int(bfsr,16) & 0x20 ): print("\t\tA bus fault occurred during FP lazy state preservation")
print("\t\tA bus fault occurred during FP lazy state preservation") if int(bfsr, 16) & 0x10:
if( int(bfsr,16) & 0x10 ): print("\t\tA derived bus fault has occurred on exception entry")
print("\t\tA derived bus fault has occurred on exception entry") if int(bfsr, 16) & 0x8:
if( int(bfsr,16) & 0x8 ): print("\t\tA derived bus fault has occurred on exception return")
print("\t\tA derived bus fault has occurred on exception return") if int(bfsr, 16) & 0x4:
if( int(bfsr,16) & 0x4 ): print("\t\tImprecise data access error has occurred")
print("\t\tImprecise data access error has occurred") if int(bfsr, 16) & 0x2:
if( int(bfsr,16) & 0x2 ): if int(bfsr,16) & 0x80:
if( int(bfsr,16) & 0x80 ): print("\t\tA precise data access error has occurred. Faulting address: %s"%(str(bfar)))
print("\t\tA precise data access error has occurred. Faulting address: %s"%(str(bfar))) else:
else: print("\t\tA precise data access error has occurred. WARNING: Fault address in BFAR is NOT valid")
print("\t\tA precise data access error has occurred. WARNING: Fault address in BFAR is NOT valid") if int(bfsr, 16) & 0x1:
if( int(bfsr,16) & 0x1 ): print("\t\tA bus fault on an instruction prefetch has occurred")
print("\t\tA bus fault on an instruction prefetch has occurred")
def print_UFSR_info(ufsr): def print_UFSR_info(ufsr):
if(ufsr != 0): if int(ufsr, 16) & 0x200:
if( int(ufsr,16) & 0x200 ): print("\t\tDivide by zero error has occurred")
print("\t\tDivide by zero error has occurred") if int(ufsr, 16) & 0x100:
if( int(ufsr,16) & 0x100 ): print("\t\tUnaligned access error has occurred")
print("\t\tUnaligned access error has occurred") if int(ufsr, 16) & 0x8:
if( int(ufsr,16) & 0x8 ): print("\t\tA coprocessor access error has occurred. This shows that the coprocessor is disabled or not present")
print("\t\tA coprocessor access error has occurred. This shows that the coprocessor is disabled or not present") if int(ufsr, 16) & 0x4:
if( int(ufsr,16) & 0x4 ): print("\t\tAn integrity check error has occurred on EXC_RETURN")
print("\t\tAn integrity check error has occurred on EXC_RETURN") if int(ufsr, 16) & 0x2:
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 )")
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:
if( int(ufsr,16) & 0x1 ): print("\t\tThe processor has attempted to execute an undefined instruction")
print("\t\tThe processor has attempted to execute an undefined instruction")
def print_CPUID_info(cpuid): def print_CPUID_info(cpuid):
if( ( ( int(cpuid,16) & 0xF0000 ) >> 16 ) == 0xC ): if (int(cpuid, 16) & 0xF0000) == 0xC0000:
print("\t\tProcessor Arch: ARM-V6M") print("\t\tProcessor Arch: ARM-V6M")
else: else:
print("\t\tProcessor Arch: ARM-V7M or above") 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): def parse_line_for_register(line):
line = re.findall(r"[\w']+", line) _, register_val = line.split(":")
line = [x.strip() for x in line if x != ''] return register_val.strip()
tag, register_val = line
return register_val
def main(crash_log,elfhelper): 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
mmfar_val = 0 mmfar_val = 0
bfar_val = 0 bfar_val = 0
lines = iter(crash_log.readlines())
lines = crash_log.readlines()
cnt = 0
for eachline in lines: for eachline in lines:
if "++ MbedOS Fault Handler ++" in eachline: if "++ MbedOS Fault Handler ++" in eachline:
break break
@ -134,51 +125,51 @@ def main(crash_log,elfhelper):
return return
for eachline in lines: for eachline in lines:
if("-- MbedOS Fault Handler --" in eachline): if "-- MbedOS Fault Handler --" in eachline:
break break
elif(eachline.startswith("PC")): elif eachline.startswith("PC"):
pc_val = parse_line_for_register(eachline) 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_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) sp_val = parse_line_for_register(eachline)
elif(eachline.startswith("HFSR")): elif eachline.startswith("HFSR"):
hfsr_val = parse_line_for_register(eachline) hfsr_val = parse_line_for_register(eachline)
elif(eachline.startswith("MMFSR")): elif eachline.startswith("MMFSR"):
mmfsr_val = parse_line_for_register(eachline) mmfsr_val = parse_line_for_register(eachline)
elif(eachline.startswith("BFSR")): elif eachline.startswith("BFSR"):
bfsr_val = parse_line_for_register(eachline) bfsr_val = parse_line_for_register(eachline)
elif(eachline.startswith("UFSR")): elif eachline.startswith("UFSR"):
ufsr_val = parse_line_for_register(eachline) ufsr_val = parse_line_for_register(eachline)
elif(eachline.startswith("CPUID")): elif eachline.startswith("CPUID"):
cpuid_val = parse_line_for_register(eachline) cpuid_val = parse_line_for_register(eachline)
elif(eachline.startswith("MMFAR")): elif eachline.startswith("MMFAR"):
mmfar_val = parse_line_for_register(eachline) mmfar_val = parse_line_for_register(eachline)
elif(eachline.startswith("BFAR")): elif eachline.startswith("BFAR"):
bfar_val = parse_line_for_register(eachline) bfar_val = parse_line_for_register(eachline)
print("\n\nCrash Info:") print("\nCrash Info:")
print("\tCrash location = %s [%s] (based on PC value)"%(pc_name.strip(),str(pc_val))) print("\tCrash location = %s [0x%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("\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("\tStack Pointer at the time of crash = [%s]" % (str(sp_val)))
print("\tTarget and Fault Info:") print("\tTarget and Fault Info:")
print_CPUID_info(cpuid_val) print_CPUID_info(cpuid_val)
print_HFSR_info(hfsr_val) print_HFSR_info(hfsr_val)
print_MMFSR_info(mmfsr_val,mmfar_val) print_MMFSR_info(mmfsr_val, mmfar_val)
print_BFSR_info(bfsr_val,bfar_val) print_BFSR_info(bfsr_val, bfar_val)
print_UFSR_info(ufsr_val) print_UFSR_info(ufsr_val)
@ -187,35 +178,23 @@ if __name__ == '__main__':
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') 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 # specify arguments
parser.add_argument('-i','--input', metavar='<path to input file with crash log output>', type=argparse.FileType('rb', 0), required=True, parser.add_argument(metavar='CRASH LOG', type=argparse.FileType('rb', 0),
help='path to input file') dest='crashlog',help='path to crash log file')
parser.add_argument('-e','--elfpath', metavar='<module or elf file path>', type=argparse.FileType('rb', 0), required=True, parser.add_argument(metavar='ELF FILE', type=argparse.FileType('rb', 0),
help='path to elf file') dest='elffile',help='path to elf file')
parser.add_argument('-m','--mappath', metavar='<map file path>', type=argparse.FileType('rb', 0), required=True, parser.add_argument(metavar='MAP FILE', type=argparse.FileType('rb', 0),
help='path to map file') dest='mapfile',help='path to map file')
# get and validate arguments # get and validate arguments
args = parser.parse_args() args = parser.parse_args()
elf_file = args.elfpath elfhelper = ElfHelper(args.elffile, args.mapfile)
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)
# parse input and write to output # parse input and write to output
main(input_crash_log,elfhelper) main(args.crashlog, elfhelper)
#close all files #close all files
elf_file.close() args.elffile.close()
map_file.close() args.mapfile.close()
input_crash_log.close() args.crashlog.close()