yu.dong | c33b307 | 2024-08-21 23:14:49 -0700 | [diff] [blame^] | 1 | #!/usr/bin/python |
| 2 | # **************************************************************************** |
| 3 | # Copyright Statement: |
| 4 | # -------------------- |
| 5 | # This software is protected by Copyright and the information contained |
| 6 | # herein is confidential. The software may not be copied and the information |
| 7 | # contained herein may not be used or disclosed except with the written |
| 8 | # permission of MediaTek Inc. (C) 2018 |
| 9 | # |
| 10 | # BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| 11 | # THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| 12 | # RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON |
| 13 | # AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
| 14 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
| 15 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
| 16 | # NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
| 17 | # SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
| 18 | # SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH |
| 19 | # THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO |
| 20 | # NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S |
| 21 | # SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. |
| 22 | # |
| 23 | # BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE |
| 24 | # LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
| 25 | # AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
| 26 | # OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO |
| 27 | # MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| 28 | # |
| 29 | # THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE |
| 30 | # WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF |
| 31 | # LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND |
| 32 | # RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER |
| 33 | # THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). |
| 34 | # |
| 35 | # **************************************************************************** |
| 36 | # |
| 37 | # **************************************************************************** |
| 38 | # |
| 39 | # Filename: |
| 40 | # --------- |
| 41 | # mer_utility.py |
| 42 | # |
| 43 | # Project: |
| 44 | # -------- |
| 45 | # MERTOS |
| 46 | # |
| 47 | # Description: |
| 48 | # ------------ |
| 49 | # Provide utilities used by MERTOS code generating. |
| 50 | # |
| 51 | # |
| 52 | # Author: |
| 53 | # ------- |
| 54 | # Ke-Ting Chen (mtk03141) |
| 55 | # |
| 56 | # **************************************************************************** |
| 57 | |
| 58 | import struct |
| 59 | import subprocess |
| 60 | |
| 61 | |
| 62 | class ElfDataExtractor(object): |
| 63 | def __init__(self, readelf_exec, elf_path): |
| 64 | self.elf_path = elf_path |
| 65 | |
| 66 | # Get symbol table |
| 67 | # Example lines: |
| 68 | # Num: Value Size Type Bind Vis Ndx Name |
| 69 | # 20: 00000b1c 5216 OBJECT GLOBAL DEFAULT 9 sys_comp_config_tbl |
| 70 | self.symbols = {} |
| 71 | symbol_text_lines = subprocess.check_output([readelf_exec, '--symbols', |
| 72 | '--wide', elf_path]).splitlines() |
| 73 | for line in symbol_text_lines: |
| 74 | if line and line.lstrip()[0].isdigit(): |
| 75 | contents = line.split() |
| 76 | if len(contents) == 7: |
| 77 | contents.append(contents[0][:-1]) |
| 78 | #print contents[0][:-1] |
| 79 | self.symbols[contents[7]] = { |
| 80 | 'name': contents[7], |
| 81 | 'type': contents[3], |
| 82 | 'section_number': (int(contents[6]) if contents[6].isdigit() else contents[6]), |
| 83 | 'address': int(contents[1], 16), |
| 84 | 'size': int(contents[2]), |
| 85 | 'number': int(contents[0][:-1])} |
| 86 | |
| 87 | # Assumes there is no hole in the number |
| 88 | self.symbol_list = sorted(self.symbols.viewvalues(), key=lambda x: x['number']) |
| 89 | |
| 90 | # Get section info |
| 91 | # Example lines: |
| 92 | # [Nr] Name Type Addr Off Size ES Flg Lk Inf Al |
| 93 | # [ 9] .rodata PROGBITS 00000000 000aa0 00231c 00 A 0 0 4 |
| 94 | self.sections = {} |
| 95 | section_text_lines = subprocess.check_output([readelf_exec, '--sections', |
| 96 | '--wide', elf_path]).splitlines() |
| 97 | for line in section_text_lines: |
| 98 | line = line.translate(None, '[]').lstrip() |
| 99 | if line and line[0].isdigit(): |
| 100 | contents = line.split() |
| 101 | if contents[0] == '0': |
| 102 | self.sections['NULL'] = {'name': 'NULL', 'number': 0, |
| 103 | 'address': 0, 'offset': 0, 'size': 0} |
| 104 | else: |
| 105 | self.sections[contents[1]] = { |
| 106 | 'name': contents[1], 'number': int(contents[0]), |
| 107 | 'address': int(contents[3], 16), 'offset': int(contents[4], 16), |
| 108 | 'size': int(contents[5], 16)} |
| 109 | |
| 110 | # Assumes there is no hole in the section number |
| 111 | self.section_list = sorted(self.sections.viewvalues(), key=lambda x: x['number']) |
| 112 | |
| 113 | # Get relocation tables |
| 114 | self.relocations = {} |
| 115 | with open(elf_path, 'rb') as elf_file: |
| 116 | for name, section in self.sections.viewitems(): |
| 117 | if name.startswith('.rel.') or name.startswith('.rela.'): |
| 118 | elf_file.seek(section['offset']) |
| 119 | raw_data = elf_file.read(section['size']) |
| 120 | if name.startswith('.rel.'): |
| 121 | #print 'processing ' + name |
| 122 | relocation = self.unpack_data_struct_array( |
| 123 | raw_data, '=IxHx', ['offset', 'symbol_number']) |
| 124 | for reloc_info in relocation: |
| 125 | reloc_info['addend'] = 0 |
| 126 | name = name[len('.rel'):] |
| 127 | else: |
| 128 | relocation = self.unpack_data_struct_array( |
| 129 | raw_data, '=IBHxI', ['offset', 'type', 'symbol_number', 'addend']) |
| 130 | #print 'processing ' + name |
| 131 | name = name[len('.rela'):] |
| 132 | relocation.sort(key=lambda x: x['offset']) |
| 133 | self.relocations[name] = relocation |
| 134 | |
| 135 | # Read in the elf and perform relocation to simplify query |
| 136 | elf_data = list(open(elf_path, 'rb').read()) |
| 137 | for section_name, relocation in self.relocations.viewitems(): |
| 138 | section_offset = self.sections[section_name]['offset'] |
| 139 | for reloc_info in relocation: |
| 140 | elf_address = reloc_info['offset'] + section_offset |
| 141 | symbol = self.symbol_list[reloc_info['symbol_number']] |
| 142 | #print symbol['name'], reloc_info['symbol_number'], symbol['type'] |
| 143 | if symbol['type'] == 'SECTION': |
| 144 | section = self.section_list[symbol['section_number']] |
| 145 | original_value = struct.unpack_from( |
| 146 | 'I', ''.join(elf_data[elf_address:elf_address + 4]))[0] |
| 147 | fill_data = original_value + section['offset'] + reloc_info['addend'] |
| 148 | #print 'SECTION', symbol['name'], elf_data[elf_address:elf_address+4], hex(fill_data), hex(original_value) |
| 149 | else: |
| 150 | fill_data = reloc_info['symbol_number'] | 0x80000000 |
| 151 | #print 'OTHER', symbol['name'], elf_data[elf_address:elf_address+4], hex(fill_data) |
| 152 | elf_data[elf_address:elf_address + 4] = struct.pack('I', fill_data) |
| 153 | elf_data = ''.join(elf_data) |
| 154 | |
| 155 | # Get symbol data from elf |
| 156 | for symbol in self.symbols.viewvalues(): |
| 157 | if symbol['size'] != 0: |
| 158 | # Get the content address in elf |
| 159 | section = self.section_list[symbol['section_number']] |
| 160 | address_offset = symbol['address'] - section['address'] |
| 161 | elf_address = address_offset + section['offset'] |
| 162 | # Get content from elf file |
| 163 | symbol['data'] = elf_data[elf_address:elf_address + symbol['size']] |
| 164 | |
| 165 | def get_symbol_data(self, symbol_name): |
| 166 | return self.symbols[symbol_name]['data'] |
| 167 | |
| 168 | def get_symbol_section_name(self, symbol_name): |
| 169 | return self.section_list[ |
| 170 | self.symbols[symbol_name]['section_number']]['name'] |
| 171 | |
| 172 | def get_symbol_name(self, target_address): |
| 173 | if target_address | 0x80000000: |
| 174 | symbol_number = target_address & 0x7FFFFFFF |
| 175 | return self.symbol_list[symbol_number]['name'] |
| 176 | else: |
| 177 | for symbol in self.symbol_list: |
| 178 | if symbol['offset'] == target_address: |
| 179 | return symbol['name'] |
| 180 | else: |
| 181 | return 'SYMBOL_NOT_FOUND' |
| 182 | |
| 183 | def get_string_data(self, target_address): |
| 184 | elf_address = target_address |
| 185 | |
| 186 | with open(self.elf_path, 'rb') as elf_file: |
| 187 | elf_file.seek(elf_address) |
| 188 | contents = '' |
| 189 | find_begin_index = 0 |
| 190 | while 1: |
| 191 | contents += elf_file.read(32) |
| 192 | string_end_index = contents.find('\x00', find_begin_index) |
| 193 | if string_end_index == -1: |
| 194 | find_begin_index = len(contents) |
| 195 | else: |
| 196 | contents = contents[:string_end_index+1] |
| 197 | break |
| 198 | return contents |
| 199 | |
| 200 | def unpack_symbol_data(self, format_string, symbol_name): |
| 201 | return struct.unpack_from(format_string, self.get_symbol_data(symbol_name)) |
| 202 | |
| 203 | def unpack_data_struct_array(self, raw_data, struct_format_string, field_names): |
| 204 | struct_size = struct.calcsize(struct_format_string) |
| 205 | array_length = len(raw_data) / struct_size |
| 206 | array = [] |
| 207 | #print len(raw_data), struct_size, struct_format_string, field_names |
| 208 | |
| 209 | for index in xrange(array_length): |
| 210 | data = struct.unpack_from(struct_format_string, raw_data, struct_size * index) |
| 211 | entry = dict(zip(field_names, data)) |
| 212 | array.append(entry) |
| 213 | |
| 214 | return array |
| 215 | |
| 216 | def unpack_symbol_data_struct_array(self, symbol_name, struct_format_string, field_names): |
| 217 | raw_data = self.get_symbol_data(symbol_name) |
| 218 | return self.unpack_data_struct_array(raw_data, struct_format_string, field_names) |