1#!/usr/bin/env python3 2# coding=utf-8 3# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from os import listdir 17from os.path import isdir, exists 18import re 19import subprocess 20import sys 21 22 23ELF_SYMBOL_RULE = r'^[0-9a-zA-Z]{8}' 24 25 26class CommonUtils: 27 symbol_key_arr = [] 28 symbol_data = {} 29 30 @staticmethod 31 def get_prefix(path): 32 data = { 33 'prefix': '', 34 'environment': '' 35 } 36 if not exists(path) or not isdir(path): 37 print(f'compiler path not find or not a directory: {path}') 38 raise FileExistsError() 39 cp_files = listdir(path) 40 41 objdump_win_sign = '-objdump.exe' 42 objdump_linux_sign = '-objdump' 43 has_compiler = False 44 45 for file_name in cp_files: 46 if file_name.endswith(objdump_win_sign): 47 data['prefix'] = file_name[0: file_name.rindex(objdump_win_sign)] 48 data['environment'] = 'windows' 49 has_compiler = True 50 break 51 elif file_name.endswith(objdump_linux_sign): 52 data['prefix'] = file_name[0: file_name.rindex(objdump_linux_sign)] 53 data['environment'] = 'linux' 54 has_compiler = True 55 break 56 if not has_compiler: 57 print(f'Incorrect compiler path: {path}') 58 raise Exception() 59 60 return data 61 62 @staticmethod 63 def check_elf_file(file_path): 64 with open(file_path, 'rb') as f: 65 elf_ident = f.read(16) 66 elf_str = '' 67 for i in elf_ident: 68 elf_str += hex(i)[2:] 69 return elf_str.find('7f454c46') >= 0 70 71 @staticmethod 72 def get_obj_dump_info(obj_dump_path, arg, elf_file_path, is_return_arr=True, is_convert=True): 73 result = [] 74 if not exists(obj_dump_path): 75 return result 76 cmd = [obj_dump_path, arg, elf_file_path] 77 data = CommonUtils.exec_cmd(cmd, is_convert) 78 if data: 79 if is_return_arr: 80 result = data.strip().split('\n') 81 else: 82 result.append(data) 83 return result 84 85 @staticmethod 86 def exec_cmd(cmd, is_convert=True): 87 try: 88 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 89 out, _ = p.communicate(timeout=120) 90 if is_convert: 91 out = out.decode() 92 return out 93 except subprocess.TimeoutExpired as e: 94 print('cmd timeouot') 95 raise SystemError() from e 96 except SystemError as e: 97 print('cmd error') 98 raise SystemError() from e 99 100 @staticmethod 101 def get_symbol_data(obj_dump_path='', elf_file_path=''): 102 if not obj_dump_path or not exists(obj_dump_path): 103 raise FileExistsError(f'objdump path not find: {obj_dump_path}') 104 if not elf_file_path or not exists(elf_file_path): 105 raise FileExistsError(f'elf path not find: {elf_file_path}') 106 CommonUtils.symbol_data = {} 107 CommonUtils.symbol_key_arr = [] 108 res = CommonUtils.get_obj_dump_info(obj_dump_path, '-t', elf_file_path) 109 for item in res: 110 line = re.sub(r'\s+', ' ', item) 111 if re.search(ELF_SYMBOL_RULE, line): 112 data_arr = line.split(' ') 113 section_name = data_arr[3] 114 symbol_name = data_arr[-1] 115 type_name = data_arr[2] 116 if section_name != symbol_name and type_name == 'F': 117 CommonUtils.symbol_data[data_arr[0]] = symbol_name 118 for keys in CommonUtils.symbol_data.keys(): 119 hex_str = '0x' + keys 120 CommonUtils.symbol_key_arr.append(int(hex_str, 16)) 121 122 if len(CommonUtils.symbol_key_arr) == 0: 123 return 124 CommonUtils.symbol_key_arr.sort(reverse=True) 125 126 @staticmethod 127 def get_function_name(num): 128 index = 0 129 d_value = sys.maxsize 130 if num.find('0x') < 0: 131 num = '0x' + num 132 for i, symbol_key_val in enumerate(CommonUtils.symbol_key_arr): 133 new_value = int(num, 16) - symbol_key_val 134 if d_value >= new_value >= 0: 135 if new_value == d_value and symbol_key_val < CommonUtils.symbol_key_arr[index]: 136 continue 137 index = i 138 d_value = new_value 139 break 140 if CommonUtils.symbol_key_arr[index]: 141 addr = hex(CommonUtils.symbol_key_arr[index]) 142 return { 143 'funcname': CommonUtils.symbol_data['%08x' % int(addr, 16)], 144 'funcaddr': '0x%08x' % int(addr, 16) 145 } 146 return { 147 'funcname': '', 148 'funcaddr': '' 149 } 150 151 @staticmethod 152 def read_uint16_le(data, offset=0): 153 return int.from_bytes(data[offset:offset + 2][::-1], byteorder='big') 154 155 @staticmethod 156 def read_uint32_le(data, offset=0): 157 return int.from_bytes(data[offset:offset + 4][::-1], byteorder='big') 158