blob: 3d0876304de4da2f2df13532f609908d59b8e99c [file] [log] [blame]
yu.dongc33b3072024-08-21 23:14:49 -07001#!/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
58import struct
59import subprocess
60
61
62class 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)