1#!/usr/bin/env python3 2# encoding=utf-8 3# ============================================================================ 4# @brief Script file 5# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 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 19''' 20Read in an elf file and generate a 'du' output for it. 21''' 22from __future__ import print_function 23from collections import OrderedDict 24import subprocess 25import re 26import os 27import argparse 28 29if __name__ == '__main__': 30 parser = argparse.ArgumentParser( 31 description='Generate du output from an elf file') 32 parser.add_argument('root_dir', metavar="Root_dir", help="Code root_dir") 33 parser.add_argument('elf', metavar="ELF", help="ELF file to parse") 34 parser.add_argument('nm', metavar="nm", help="gcc nm path") 35 args = parser.parse_args() 36 37 # Get nm and elf filenames from command line args 38 root_dir = args.root_dir 39 nm = args.nm 40 elf = args.elf 41 42 # build command line and run nm 43 cmd = nm + ' -l -A -t x -f sysv -S ' + elf 44 p = subprocess.Popen( 45 cmd.split(), 46 stdin=subprocess.PIPE, 47 stdout=subprocess.PIPE) 48 stdout, stderr = p.communicate() 49 return_code = p.wait() 50 if (return_code != 0): 51 raise Exception(nm + " returned: " + str(return_code)) 52 53 # parse the output 54 line_count = 0 55 line_match = 0 56 symbol_type = OrderedDict() 57 58 # Convert stdout from bytes to a string 59 stdoutstr = stdout.decode("utf-8") 60 61 # Loop over each line in the string 62 for line in iter(stdoutstr.splitlines()): 63 line_count = line_count + 1 64 65 sl = line.split("|") 66 if (len(sl) == 7): 67 elfsym = re.match(r'^(.*):([^\s]*)', sl[0]) 68 if elfsym: 69 elf = elfsym.group(1) 70 symbol = elfsym.group(2) 71 72 if (len(sl[1].strip())): 73 location = int(sl[1], 16) 74 else: 75 location = 0 76 77 c = sl[2].strip() 78 t = sl[3].strip() 79 if (len(sl[4].strip())): 80 size = int(sl[4], 16) 81 else: 82 size = 0 83 u2 = sl[5] 84 segmentfileline = re.match(r'([^\t]*)\t(.*):([^\|]*)', sl[6]) 85 if segmentfileline: 86 try: 87 segment = segmentfileline.group(1) 88 src_file = segmentfileline.group(2) 89 src_file_line = int(segmentfileline.group(3)) 90 if segment not in symbol_type: 91 symbol_type[segment] = list() 92 symbol_type[segment].append((src_file, symbol, size)) 93 line_match = line_match + 1 94 except Exception as e: 95 print("warning:", e.with_traceback()) 96 97 98 # Find common filename prefix string from all input files 99 init_prefix = True 100 file_count = 0 101 # Loop through displaying each line and totals 102 segment_total = 0 103 # Loop over each segment 104 for segment in symbol_type: 105 filename_total = 0 106 curr_filename = '' 107 108 # Loop over each symbol in segment 109 for symbol in symbol_type[segment]: 110 filename = symbol[0] 111 sym = symbol[1] 112 size = symbol[2] 113 114 # strip prefix from start of filename 115 if (root_dir): 116 filename = filename.replace(root_dir, '', 1) 117 # convert \\ to / in filename 118 filename = filename.replace('\\', '/') 119 120 if filename != curr_filename: 121 curr_filename = filename 122 filename_total = 0 123 filename_total = filename_total + size 124 segment_total = segment_total + size 125 # print line for filename/function 126 out_str = os.path.normpath('%(sz)-8u./%(segment)s/%(file)s/%(sym)s' % 127 {'sz': size, 'segment': segment, 'file': filename, 128 'sym': sym}) 129 print(out_str) 130 131 # print total for filename (last one) 132 133 # print total for segment 134 segment_total = 0 135 136 print("done. Lines: %s, Matches: %s" % (str(line_count), str(line_match))) 137