• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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