258 lines
8.6 KiB
Python
258 lines
8.6 KiB
Python
#!/usr/bin/env python
|
||
#coding:utf-8
|
||
|
||
#Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||
#The file is from Alios-Things, which is licensed under Apache License 2.0
|
||
#Modified:
|
||
# 2020-06-01 Zeng Zhijin support riscv
|
||
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
import argparse
|
||
import re
|
||
import logging
|
||
import operator
|
||
|
||
#--------------------------------------------------------------
|
||
# Global defines
|
||
#--------------------------------------------------------------
|
||
_TOOLCHAIN_NM_OPT_ = "-nlCS"
|
||
_TOOLCHAIN_SIZE_OPT_ = "-Axt"
|
||
_TOOLCHAIN_OBJDUMP_OPT_ = "-D"
|
||
_TOOLCHAIN_ADDR2LINE_OPT_ = "-pfiCe"
|
||
_TOOLCHAIN_READELF_OPT_ = "-h"
|
||
|
||
_TOOLCHAIN_PREFIX_ = ""
|
||
_TOOLCHAIN_GCC_ = ""
|
||
_TOOLCHAIN_NM_ = ""
|
||
_TOOLCHAIN_SIZE_ = ""
|
||
_TOOLCHAIN_OBJDUMP_ = ""
|
||
_TOOLCHAIN_ADDR2LINE_ = ""
|
||
_TOOLCHAIN_READELF_ = ""
|
||
|
||
_ARM_TOOLCHAIN_PREFIX_ = "arm-melis-eabi-"
|
||
_ARM_TOOLCHAIN_GCC_ = "arm-melis-eabi-gcc"
|
||
_ARM_TOOLCHAIN_NM_ = "arm-melis-eabi-nm"
|
||
_ARM_TOOLCHAIN_SIZE_ = "arm-melis-eabi-size"
|
||
_ARM_TOOLCHAIN_OBJDUMP_ = "arm-melis-eabi-objdump"
|
||
_ARM_TOOLCHAIN_ADDR2LINE_ = "arm-melis-eabi-addr2line"
|
||
_ARM_TOOLCHAIN_READELF_ = "arm-melis-eabi-readelf"
|
||
|
||
_RISCV_TOOLCHAIN_PREFIX_ = "riscv64-unknown-elf-"
|
||
_RISCV_TOOLCHAIN_GCC_ = "riscv64-unknown-elf-gcc"
|
||
_RISCV_TOOLCHAIN_NM_ = "riscv64-unknown-elf-nm"
|
||
_RISCV_TOOLCHAIN_SIZE_ = "riscv64-unknown-elf-size"
|
||
_RISCV_TOOLCHAIN_OBJDUMP_ = "riscv64-unknown-elf-objdump"
|
||
_RISCV_TOOLCHAIN_ADDR2LINE_ = "riscv64-unknown-elf-addr2line"
|
||
_RISCV_TOOLCHAIN_READELF_ = "riscv64-unknown-elf-readelf"
|
||
|
||
_HOST_READELF_ = "readelf"
|
||
_HOST_READELF_OPT_ = "-h"
|
||
|
||
_CRASH_LOG_ = "crash_log"
|
||
|
||
MATCH_ADDR = re.compile(r'0x[0-9a-f]{1,8}', re.IGNORECASE)
|
||
|
||
_ARCH_TYPE_ARM_ = "ARM"
|
||
_ARCH_TYPE_RISCV_ = "RISC-V"
|
||
_ARCH_TYPE_RISCV_ID_ = "0xf3"
|
||
|
||
g_arch = [_ARCH_TYPE_ARM_, _ARCH_TYPE_RISCV_, _ARCH_TYPE_RISCV_ID_]
|
||
|
||
def get_arch_from_elf(elf_file):
|
||
if not elf_file:
|
||
return ""
|
||
|
||
arch_info = subprocess.check_output(
|
||
[_HOST_READELF_, _HOST_READELF_OPT_, elf_file])
|
||
|
||
for line in arch_info.splitlines():
|
||
if 'Machine' in line:
|
||
temp = line.split()
|
||
for arch in g_arch:
|
||
if arch in temp:
|
||
return arch
|
||
for line in arch_info.splitlines():
|
||
if "系统架构" in line:
|
||
temp = line.split()
|
||
for arch in g_arch:
|
||
if arch in temp:
|
||
return arch
|
||
return ""
|
||
|
||
class Core_Dump(object):
|
||
def __init__(self, crash_log, elf_file, toolchain_path):
|
||
super(Core_Dump, self).__init__()
|
||
self.crash_log = crash_log
|
||
self.elf_file = elf_file.name
|
||
self.toolchain_path = toolchain_path
|
||
|
||
self.parse_addr_list = []
|
||
self.arch = _ARCH_TYPE_ARM_
|
||
|
||
self.check_env()
|
||
self.global_list = self.get_filelist('./', [])
|
||
|
||
def get_filelist(self, dir, Filelist):
|
||
newDir = dir
|
||
if os.path.isfile(dir):
|
||
if os.path.splitext(dir)[1] == '.elf':
|
||
Filelist.append(dir)
|
||
elif os.path.isdir(dir):
|
||
for s in os.listdir(dir):
|
||
newDir=os.path.join(dir,s)
|
||
self.get_filelist(newDir, Filelist)
|
||
return Filelist
|
||
|
||
def getTargetFileName(self, list, pc_addr, try_list):
|
||
for e in list:
|
||
arch_info = subprocess.check_output(
|
||
[_TOOLCHAIN_READELF_, _TOOLCHAIN_READELF_OPT_ , e])
|
||
|
||
for line in arch_info.splitlines():
|
||
if 'Entry' in line:
|
||
entry_line=line.split(":", 1)[1]
|
||
entry=entry_line.strip()
|
||
if cmp(entry.lower()[2:5], pc_addr.lower()[2:5]):
|
||
if cmp(entry.lower()[2:4], "40") or cmp(pc_addr.lower()[2:4], "40"):
|
||
continue
|
||
else:
|
||
try_list.append(e)
|
||
else:
|
||
try_list.append(e)
|
||
for line in arch_info.splitlines():
|
||
if "入口" in line:
|
||
entry_line=line.split(":", 1)[1]
|
||
entry=entry_line.strip()
|
||
if cmp(entry.lower()[2:5], pc_addr.lower()[2:5]):
|
||
if cmp(entry.lower()[2:4], "40") or cmp(pc_addr.lower()[2:4], "40"):
|
||
continue
|
||
else:
|
||
try_list.append(e)
|
||
else:
|
||
try_list.append(e)
|
||
list_len=len(list)
|
||
trylist_len=len(try_list)
|
||
if list_len == 1 and trylist_len == 0:
|
||
try_list.append(e)
|
||
return try_list
|
||
|
||
def find_pc_addr(self, pc_addr):
|
||
list = self.global_list
|
||
elf = self.getTargetFileName(list, pc_addr, [])
|
||
i=0
|
||
list_len=len(elf)
|
||
err_num=0
|
||
for e in elf:
|
||
try:
|
||
pc_trans = subprocess.check_output([_TOOLCHAIN_ADDR2LINE_, _TOOLCHAIN_ADDR2LINE_OPT_, e, pc_addr])
|
||
except Exception as err:
|
||
logging.exception(err)
|
||
else:
|
||
if not "?? ??:0" in pc_trans:
|
||
if i==0:
|
||
print pc_trans.strip()
|
||
elif i==list_len:
|
||
print(" or "+pc_trans.strip())
|
||
else:
|
||
print(" or "+pc_trans.strip())
|
||
else:
|
||
err_num+=1
|
||
i+=1
|
||
if (err_num == list_len) and (err_num != 0):
|
||
print "addr invalid"
|
||
print ""
|
||
|
||
def get_value_form_line(self, line, index):
|
||
val_list = re.findall(MATCH_ADDR, line)
|
||
if val_list:
|
||
if index > len(val_list):
|
||
return ""
|
||
return val_list[index]
|
||
else:
|
||
return ""
|
||
|
||
def parse_addr(self, line, index):
|
||
addr = self.get_value_form_line(line, index)
|
||
if addr:
|
||
self.parse_addr_list.append(addr)
|
||
self.find_pc_addr(addr)
|
||
|
||
def check_env(self):
|
||
global _TOOLCHAIN_GCC_
|
||
global _TOOLCHAIN_ADDR2LINE_
|
||
|
||
if sys.version_info.major > 2:
|
||
error = """
|
||
This parser tools do not support Python Version 3 and above.
|
||
Python {py_version} detected.
|
||
""".format(py_version=sys.version_info)
|
||
|
||
print error
|
||
sys.exit(1)
|
||
|
||
def show(self):
|
||
|
||
log_lines = iter(self.crash_log.read().splitlines())
|
||
|
||
for line in log_lines:
|
||
if "backtrace" in line:
|
||
self.parse_addr(line, 0)
|
||
else:
|
||
pass
|
||
|
||
def main():
|
||
|
||
global _TOOLCHAIN_PREFIX_
|
||
global _TOOLCHAIN_GCC_
|
||
global _TOOLCHAIN_NM_
|
||
global _TOOLCHAIN_SIZE_
|
||
global _TOOLCHAIN_OBJDUMP_
|
||
global _TOOLCHAIN_ADDR2LINE_
|
||
global _TOOLCHAIN_READELF_
|
||
|
||
parser = argparse.ArgumentParser(description='Melis crash log core dump')
|
||
|
||
# specify arguments
|
||
parser.add_argument(metavar='CRASH LOG', type=argparse.FileType('rb', 0),
|
||
dest='crash_log', help='path to backtrace log file')
|
||
|
||
parser.add_argument(metavar='ELF FILE', type=argparse.FileType('rb', 0),
|
||
dest='elf_file', help='elf file of application')
|
||
|
||
parser.add_argument('-p','--path', help="absolute path of toolchain", default='')
|
||
|
||
args = parser.parse_args()
|
||
|
||
arch = get_arch_from_elf(args.elf_file.name)
|
||
if (arch == _ARCH_TYPE_RISCV_) or (arch == _ARCH_TYPE_RISCV_ID_):
|
||
_TOOLCHAIN_PREFIX_ = _RISCV_TOOLCHAIN_PREFIX_
|
||
_TOOLCHAIN_GCC_ = _RISCV_TOOLCHAIN_GCC_
|
||
_TOOLCHAIN_NM_ = _RISCV_TOOLCHAIN_NM_
|
||
_TOOLCHAIN_SIZE_ = _RISCV_TOOLCHAIN_SIZE_
|
||
_TOOLCHAIN_OBJDUMP_ = _RISCV_TOOLCHAIN_OBJDUMP_
|
||
_TOOLCHAIN_ADDR2LINE_ = _RISCV_TOOLCHAIN_ADDR2LINE_
|
||
_TOOLCHAIN_READELF_ = _RISCV_TOOLCHAIN_READELF_
|
||
else:
|
||
_TOOLCHAIN_PREFIX_ = _ARM_TOOLCHAIN_PREFIX_
|
||
_TOOLCHAIN_GCC_ = _ARM_TOOLCHAIN_GCC_
|
||
_TOOLCHAIN_NM_ = _ARM_TOOLCHAIN_NM_
|
||
_TOOLCHAIN_SIZE_ = _ARM_TOOLCHAIN_SIZE_
|
||
_TOOLCHAIN_OBJDUMP_ = _ARM_TOOLCHAIN_OBJDUMP_
|
||
_TOOLCHAIN_ADDR2LINE_ = _ARM_TOOLCHAIN_ADDR2LINE_
|
||
_TOOLCHAIN_READELF_ = _ARM_TOOLCHAIN_READELF_
|
||
|
||
core_dump_ins = Core_Dump(args.crash_log, args.elf_file, args.path)
|
||
|
||
core_dump_ins.show()
|
||
|
||
if args.crash_log:
|
||
args.crash_log.close()
|
||
|
||
if args.elf_file:
|
||
args.elf_file.close()
|
||
|
||
if __name__ == "__main__":
|
||
main()
|