mcu_hi3321_watch/build/script/utils/elftodu.py
2025-06-06 15:13:55 +08:00

122 lines
4.0 KiB
Python

#!/usr/bin/env python3
# encoding=utf-8
# ============================================================================
# @brief Script file
# Copyright CompanyNameMagicTag 2022-2022. All rights reserved.
# ============================================================================
'''
Read in an elf file and generate a 'du' output for it.
'''
from __future__ import print_function
from collections import OrderedDict
import subprocess
import re
import os
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Generate du output from an elf file')
parser.add_argument('root_dir', metavar="Root_dir", help="Code root_dir")
parser.add_argument('elf', metavar="ELF", help="ELF file to parse")
parser.add_argument('nm', metavar="nm", help="gcc nm path")
args = parser.parse_args()
# Get nm and elf filenames from command line args
root_dir = args.root_dir
nm = args.nm
elf = args.elf
# build command line and run nm
cmd = nm + ' -l -A -t x -f sysv -S ' + elf
p = subprocess.Popen(
cmd.split(),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
return_code = p.wait()
if (return_code != 0):
raise Exception(nm + " returned: " + str(return_code))
# parse the output
line_count = 0
line_match = 0
symbol_type = OrderedDict()
# Convert stdout from bytes to a string
stdoutstr = stdout.decode("utf-8")
# Loop over each line in the string
for line in iter(stdoutstr.splitlines()):
line_count = line_count + 1
sl = line.split("|")
if (len(sl) == 7):
elfsym = re.match(r'^(.*):([^\s]*)', sl[0])
if elfsym:
elf = elfsym.group(1)
symbol = elfsym.group(2)
if (len(sl[1].strip())):
location = int(sl[1], 16)
else:
location = 0
c = sl[2].strip()
t = sl[3].strip()
if (len(sl[4].strip())):
size = int(sl[4], 16)
else:
size = 0
u2 = sl[5]
segmentfileline = re.match(r'([^\t]*)\t(.*):([^\|]*)', sl[6])
if segmentfileline:
segment = segmentfileline.group(1)
src_file = segmentfileline.group(2)
src_file_line = int(segmentfileline.group(3))
if segment not in symbol_type:
symbol_type[segment] = list()
symbol_type[segment].append((src_file, symbol, size))
line_match = line_match + 1
# Find common filename prefix string from all input files
init_prefix = True
file_count = 0
# Loop through displaying each line and totals
segment_total = 0
# Loop over each segment
for segment in symbol_type:
filename_total = 0
curr_filename = ''
# Loop over each symbol in segment
for symbol in symbol_type[segment]:
filename = symbol[0]
sym = symbol[1]
size = symbol[2]
# strip prefix from start of filename
if (root_dir):
filename = filename.replace(root_dir, '', 1)
# convert \\ to / in filename
filename = filename.replace('\\', '/')
if filename != curr_filename:
curr_filename = filename
filename_total = 0
filename_total = filename_total + size
segment_total = segment_total + size
# print line for filename/function
out_str = os.path.normpath('%(sz)-8u./%(segment)s/%(file)s/%(sym)s' %
{'sz': size, 'segment': segment, 'file': filename,
'sym': sym})
print(out_str)
# print total for filename (last one)
# print total for segment
segment_total = 0
print("done. Lines: %s, Matches: %s" % (str(line_count), str(line_match)))