mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-15 00:54:22 +00:00

Add support for tabulating static memory consumption data from ELF binaries. This relies on static symbols, defined in the linker files, that provide information about the memory ranges. Change-Id: Ie19cd2b80a7b591607640feeb84c63266963ea4d Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
127 lines
4.1 KiB
Python
Executable file
127 lines
4.1 KiB
Python
Executable file
#
|
|
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
|
|
from prettytable import PrettyTable
|
|
|
|
|
|
class TfaPrettyPrinter:
|
|
"""A class for printing the memory layout of ELF files.
|
|
|
|
This class provides interfaces for printing various memory layout views of
|
|
ELF files in a TF-A build. It can be used to understand how the memory is
|
|
structured and consumed.
|
|
"""
|
|
|
|
def __init__(self, columns: int = None, as_decimal: bool = False):
|
|
self.term_size = columns if columns and columns > 120 else 120
|
|
self._footprint = None
|
|
self._symbol_map = None
|
|
self.as_decimal = as_decimal
|
|
|
|
def format_args(self, *args, width=10, fmt=None):
|
|
if not fmt and type(args[0]) is int:
|
|
fmt = f">{width}x" if not self.as_decimal else f">{width}"
|
|
return [f"{arg:{fmt}}" if fmt else arg for arg in args]
|
|
|
|
@staticmethod
|
|
def map_elf_symbol(
|
|
leading: str,
|
|
section_name: str,
|
|
rel_pos: int,
|
|
columns: int,
|
|
width: int = None,
|
|
is_edge: bool = False,
|
|
):
|
|
empty_col = "{:{}{}}"
|
|
|
|
# Some symbols are longer than the column width, truncate them until
|
|
# we find a more elegant way to display them!
|
|
len_over = len(section_name) - width
|
|
if len_over > 0:
|
|
section_name = section_name[len_over:-len_over]
|
|
|
|
sec_row = f"+{section_name:-^{width-1}}+"
|
|
sep, fill = ("+", "-") if is_edge else ("|", "")
|
|
|
|
sec_row_l = empty_col.format(sep, fill + "<", width) * rel_pos
|
|
sec_row_r = empty_col.format(sep, fill + ">", width) * (
|
|
columns - rel_pos - 1
|
|
)
|
|
|
|
return leading + sec_row_l + sec_row + sec_row_r
|
|
|
|
def print_footprint(
|
|
self, app_mem_usage: dict, sort_key: str = None, fields: list = None
|
|
):
|
|
assert len(app_mem_usage), "Empty memory layout dictionary!"
|
|
if not fields:
|
|
fields = ["Component", "Start", "Limit", "Size", "Free", "Total"]
|
|
|
|
sort_key = fields[0] if not sort_key else sort_key
|
|
|
|
# Iterate through all the memory types, create a table for each
|
|
# type, rows represent a single module.
|
|
for mem in sorted(set(k for _, v in app_mem_usage.items() for k in v)):
|
|
table = PrettyTable(
|
|
sortby=sort_key,
|
|
title=f"Memory Usage (bytes) [{mem.upper()}]",
|
|
field_names=fields,
|
|
)
|
|
|
|
for mod, vals in app_mem_usage.items():
|
|
if mem in vals.keys():
|
|
val = vals[mem]
|
|
table.add_row(
|
|
[
|
|
mod.upper(),
|
|
*self.format_args(
|
|
*[val[k.lower()] for k in fields[1:]]
|
|
),
|
|
]
|
|
)
|
|
print(table, "\n")
|
|
|
|
def print_symbol_table(
|
|
self,
|
|
symbols: list,
|
|
modules: list,
|
|
start: int = 11,
|
|
):
|
|
assert len(symbols), "Empty symbol list!"
|
|
modules = sorted(modules)
|
|
col_width = int((self.term_size - start) / len(modules))
|
|
|
|
num_fmt = "0=#010x" if not self.as_decimal else ">10"
|
|
|
|
_symbol_map = [
|
|
" " * start
|
|
+ "".join(self.format_args(*modules, fmt=f"^{col_width}"))
|
|
]
|
|
last_addr = None
|
|
|
|
for i, (name, addr, mod) in enumerate(symbols):
|
|
# Do not print out an address twice if two symbols overlap,
|
|
# for example, at the end of one region and start of another.
|
|
leading = (
|
|
f"{addr:{num_fmt}}" + " " if addr != last_addr else " " * start
|
|
)
|
|
|
|
_symbol_map.append(
|
|
self.map_elf_symbol(
|
|
leading,
|
|
name,
|
|
modules.index(mod),
|
|
len(modules),
|
|
width=col_width,
|
|
is_edge=(not i or i == len(symbols) - 1),
|
|
)
|
|
)
|
|
|
|
last_addr = addr
|
|
|
|
self._symbol_map = ["Memory Layout:"]
|
|
self._symbol_map += list(reversed(_symbol_map))
|
|
print("\n".join(self._symbol_map))
|