1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# 5# Copyright (c) 2020-2022 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import re 20import sys 21import argparse 22import os 23import datetime 24 25g_version = 2.5 26g_excel_support = False 27g_row_num = 0 28 29try: 30 from openpyxl import Workbook 31except: 32 print("excel output is not support, need install openpyxl") 33else: 34 g_excel_support = True 35 36def is_number(num): 37 try: 38 int(num, 16) 39 return True 40 except ValueError: 41 pass 42 return False 43 44static_map = {} 45def storage_static_data(offset, section, sizeHex, symbol, lib, obj): 46 global g_row_num 47 if (0 == g_row_num): 48 static_map[g_row_num] = {'offsets' : "offsets", 'section' : "section",\ 49 'sizeH' : "size(Hex)", 'sizeD' : "size(Dec)",\ 50 'symbol' : "symbol", 'lib' : "lib", 'obj' : "object"} 51 g_row_num = g_row_num + 1 52 53 size = int(sizeHex, 16) 54 static_map[g_row_num] = {'offsets': offset, 'section' : section,\ 55 'sizeH' : sizeHex, 'sizeD' : size,\ 56 'symbol' : symbol, 'lib' : lib, 'obj' : obj} 57 g_row_num = g_row_num + 1 58 59def store_static_excel(): 60 wb = Workbook() 61 ws = wb.active 62 for base_address, values in static_map.items(): 63 c = ws.cell(row=base_address + 1, column=1) 64 c.value = values.get('offsets') 65 c = ws.cell(row=base_address + 1, column=2) 66 c.value = values.get('section') 67 c = ws.cell(row=base_address + 1, column=3) 68 c.value = values.get('sizeH') 69 c = ws.cell(row=base_address + 1, column=4) 70 c.value = values.get('sizeD') 71 c = ws.cell(row=base_address + 1, column=5) 72 c.value = values.get('symbol') 73 c = ws.cell(row=base_address + 1, column=6) 74 c.value = values.get('lib') 75 c = ws.cell(row=base_address + 1, column=7) 76 c.value = values.get('obj') 77 wb.save('static_symbol-%s.xlsx' % datetime.datetime.now().strftime('%Y-%m-%d %H_%M_%S')) 78 return 79 80def format_store_static(): 81 global g_excel_support 82 target_list = [] 83 84 for base_address, values in static_map.items(): 85 target_list.append('{:<10s}'.format(values.get('offsets'))) 86 target_list.append('{:<30s}'.format(values.get('section'))) 87 target_list.append('{:<10}'.format(values.get('sizeH'))) 88 target_list.append('{:<10}'.format(values.get('sizeD'))) 89 target_list.append('{:<55s}{:<55s}{:<55s}'.format(values.get('symbol'), values.get('lib'), values.get('obj'))) 90 target_list.append("\r") 91 92 with open("./static_symbol_out.txt", "w+") as out_fd: 93 out_fd.write("".join(target_list)) 94 if g_excel_support == True: 95 store_static_excel() 96 return 97 98dync_map = {} 99#dync map multiple LR, first dync_map node will record LR size 100def storage_dync_head(size): 101 global g_row_num 102 dync_map[0] = {'addr' : "Memnode", 'symbol' : "size", 'lib' : size} 103 g_row_num = 1 104 105#when the analysis of one line LR is finished, need record "\r\n" and the new line info 106def storage_dync_node(node_addr, size): 107 global g_row_num 108 dync_map[g_row_num] = {'addr' : "\r\n", 'symbol' : node_addr, 'lib' : size} 109 g_row_num = g_row_num + 1 110 111def storage_dync_data(addr, symbol, lib): 112 global g_row_num 113 dync_map[g_row_num] = {'addr' : addr, 'symbol' : symbol, 'lib' : lib} 114 g_row_num = g_row_num + 1 115 116def store_dync_excel(): 117 wb = Workbook() 118 ws = wb.active 119 row = 1 120 column = 0 121 for base_address, values in dync_map.items(): 122 if (0 == base_address): 123 c = ws.cell(row, 1) 124 c.value = values.get('addr') 125 c = ws.cell(row, 2) 126 c.value = values.get('symbol') 127 for i in range(values.get('lib')): 128 column = i * 3 + 2 129 addr_name = "LR%s_addr" % (str(i)) 130 c = ws.cell(row, column + 1) 131 c.value = addr_name 132 symbol_name = "LR%s_symbol" % (str(i)) 133 c = ws.cell(row, column + 2) 134 c.value = symbol_name 135 object_name = "LR%s_object" % (str(i)) 136 c = ws.cell(row, column + 3) 137 c.value = object_name 138 else: 139 if("\r\n" == values.get('addr')): 140 row = row + 1 141 column = 1 142 c = ws.cell(row, column) 143 c.value = values.get('symbol') 144 column = column + 1 145 c = ws.cell(row, column) 146 c.value = values.get('lib') 147 else: 148 c = ws.cell(row, column + 1) 149 c.value = values.get('addr') 150 c = ws.cell(row, column + 2) 151 c.value = values.get('symbol') 152 c = ws.cell(row, column + 3) 153 c.value = values.get('lib') 154 column = column + 3 155 wb.save('dync_mem-%s.xlsx' % datetime.datetime.now().strftime('%Y-%m-%d %H_%M_%S')) 156 return 157 158def format_store_dync(): 159 global g_excel_support 160 target_list = [] 161 162 for base_address, values in dync_map.items(): 163 if (0 == base_address): 164 target_list.append('{:<15s}{:<15s}'.format("node", "size")) 165 for i in range(values.get('lib')): 166 addr_name = "LR%s_addr" % (str(i)) 167 symbol_name = "LR%s_symbol" % (str(i)) 168 object_name = "LR%s_object" % (str(i)) 169 target_list.append('{:<15s}{:<55s}{:<55s}'.format(addr_name, symbol_name, object_name)) 170 171 else: 172 if ("\r\n" == values.get('addr')): 173 target_list.append("\r") 174 target_list.append('{:<15s}{:<15}'.format(values.get('symbol'), values.get('lib'))) 175 else: 176 target_list.append('{:<15s}'.format(values.get('addr'))) 177 target_list.append('{:<55s}'.format(values.get('symbol'))) 178 target_list.append('{:<55s}'.format(values.get('lib'))) 179 180 with open("./dynamic_memory_out.txt", "w+") as out_fd: 181 out_fd.write("".join(target_list)) 182 if g_excel_support == True: 183 store_dync_excel() 184 return 185 186address_map = {} 187def get_func_by_name(function_name): 188 for base_address, values in address_map.items(): 189 if values.get('func_name') == function_name: 190 return values.get('lib_name'), values.get('obj_name') 191 return "none", "none" 192 193def get_func_by_address(address): 194 if 0 == address: 195 return "none", "none" 196 197 for base_address, values in address_map.items(): 198 if (base_address <= address) and (base_address + values.get('size') > address): 199 return values.get('func_name'), values.get('obj_name') 200 return "none", "none" 201 202def line_start_check(line): 203 if line.startswith(' .text.'): 204 function_name = line.split(".text.")[1] 205 elif line.startswith(' .rodata.'): 206 function_name = line.split(".rodata.")[1] 207 elif line.startswith(' .bss.'): 208 function_name = line.split(".bss.")[1] 209 elif line.startswith(' .sram.text.'): 210 function_name = line.split(".sram.text.")[1] 211 elif line.startswith(' .data.'): 212 function_name = line.split(".data.")[1] 213 else: 214 return None 215 return function_name 216 217def parse_map(file_path): 218 parse_begin = False 219 function_name = "" 220 address = None 221 size = None 222 obj_name = "" 223 lib_name = "" 224 pl = re.compile(r'[(](.*?)[)]', re.S) 225 with open(file_path, "r") as f: 226 for line in f.readlines(): 227 if not parse_begin: 228 function_name = line_start_check(line) 229 if function_name != None: 230 if len(function_name.split()) > 1: 231 strs = function_name.split() 232 function_name = strs[0] 233 function_name = function_name.strip() 234 address = int(strs[1], 16) 235 size = int(strs[2], 16) 236 obj_name = re.findall(pl, strs[3]) 237 if len(obj_name) > 0: 238 obj_name = obj_name[0] 239 else: 240 obj_name = strs[3] 241 char_temp = strs[3].split('(') 242 if len(char_temp) > 1: 243 lib_name = char_temp[0].split('/')[-1] 244 else: 245 lib_name = "none" 246 address_map[address] = {'size' : size, 'lib_name' : lib_name, \ 247 'obj_name' : obj_name, 'func_name' : function_name} 248 else: 249 parse_begin = True 250 else: 251 continue 252 else: 253 parse_begin = False 254 if len(line.strip().split()) != 3: 255 continue 256 strs = line.strip().split() 257 address = int(strs[0], 16) 258 size = int(strs[1], 16) 259 obj_name = re.findall(pl, strs[2]) 260 if len(obj_name) > 0: 261 obj_name = obj_name[0] 262 else: 263 obj_name = strs[2] 264 function_name = function_name.strip() 265 char_temp = strs[2].split('(') 266 if len(char_temp) > 1: 267 lib_name = char_temp[0].split('/')[-1] 268 else: 269 lib_name = "none" 270 address_map[address] = {'size' : size, 'lib_name' : lib_name, \ 271 'obj_name' : obj_name, 'func_name' : function_name} 272 273def parse_dump(dump_path): 274 with open(dump_path, "r") as symbol_fd: 275 symline = symbol_fd.readlines() 276 277 for index, line in enumerate(symline): 278 offset = line[:8] 279 280 #According to the regular expression of objdump , section start at 17 char 281 symbol_list = line[17:].split() 282 if len(symbol_list) < 3: 283 continue 284 285 sec = symbol_list[0] 286 size = symbol_list[1] 287 if (False == is_number(size)) or 0 == int(size, 16): 288 continue 289 290 lib, obj = get_func_by_name(symbol_list[-1]) 291 storage_static_data(offset, sec, size, symbol_list[-1], lib, obj) 292 293def parse_log(log_path): 294 with open(log_path, "r") as log_fd: 295 logline = log_fd.readlines() 296 get_valid_log = False 297 for index, line in enumerate(logline): 298 char_list = line.split() 299 if len(char_list) < 3: 300 continue 301 if ("node" == char_list[0]) & ("LR[0]" == char_list[2]): 302 storage_dync_head(len(char_list) - 2) 303 get_valid_log = True 304 continue 305 306 if True == get_valid_log: 307 mem_addr = char_list[0].split(':') 308 if True == is_number(mem_addr[0]): 309 for i in range(len(char_list)): 310 if i == 0: 311 size = int(char_list[1], 16) 312 storage_dync_node(mem_addr[0], size) 313 if i > 1: 314 symbol, lib = get_func_by_address(int(char_list[i], 16)) 315 storage_dync_data(char_list[i], symbol, lib) 316 else: 317 get_valid_log = False 318 continue 319 320def main(): 321 print("memory parses tool ver.%2f\r\n" % g_version) 322 parser = argparse.ArgumentParser() 323 parser.add_argument('--m', help='map path.') 324 parser.add_argument('--l', help='dynamic mem log path.') 325 parser.add_argument('--d', help='objdump path.') 326 args = parser.parse_args() 327 328 print("map path: %s\r\n" % args.m) 329 if args.m == None : 330 print("arg error, input -h get the help list\r\n") 331 return 332 333 parse_map(args.m) 334 335 print("dump path: %s" % args.d) 336 if args.d != None : 337 parse_dump(args.d) 338 format_store_static() 339 else: 340 print("dump path unspecified, will not be static parser") 341 print("you can enter the objdump -t command under the linux shell to obtain dump information\r\n") 342 343 print("log path: %s" % args.l) 344 if args.l != None : 345 parse_log(args.l) 346 format_store_dync() 347 else: 348 print("log path unspecified, will not be dynamic parser\r\n") 349 350 return 351 352if __name__ == '__main__': 353 sys.exit(main())