blob: eaccd1997d20965682eda3a614017c7150be2e63 [file] [log] [blame]
#
# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import re
from pathlib import Path
from typing import (
Any,
Dict,
List,
Union,
)
from memory.elfparser import TfaElfParser
from memory.image import Region
from memory.mapparser import TfaMapParser
class TfaBuildParser:
"""A class for performing analysis on the memory layout of a TF-A build."""
def __init__(self, path: Path, map_backend: bool = False) -> None:
self._modules: Dict[str, Union[TfaElfParser, TfaMapParser]] = {}
self._path: Path = path
self.map_backend: bool = map_backend
self._parse_modules()
def __getitem__(self, module: str) -> Union[TfaElfParser, TfaMapParser]:
"""Returns an TfaElfParser instance indexed by module."""
return self._modules[module]
def _parse_modules(self) -> None:
"""Parse the build files using the selected backend."""
backend = TfaElfParser
files = list(self._path.glob("**/*.elf"))
io_perms = "rb"
if self.map_backend or len(files) == 0:
backend = TfaMapParser
files = self._path.glob("**/*.map")
io_perms = "r"
for file in files:
module_name = file.name.split("/")[-1].split(".")[0]
with open(file, io_perms) as f:
self._modules[module_name] = backend(f)
if not len(self._modules):
raise FileNotFoundError(
f"failed to find files to analyse in path {self._path}!"
)
@property
def symbols(self) -> Dict[str, Dict[str, int]]:
return {k: v.symbols for k, v in self._modules.items()}
@staticmethod
def filter_symbols(
images: Dict[str, Dict[str, int]], regex: str
) -> Dict[str, Dict[str, int]]:
"""Returns a map of symbols to modules."""
return {
image: {
symbol: symbol_value
for symbol, symbol_value in symbols.items()
if re.match(regex, symbol)
}
for image, symbols in images.items()
}
def get_mem_usage_dict(self) -> Dict[str, Dict[str, Region]]:
"""Returns map of memory usage per memory type for each module."""
return {k: v.footprint for k, v in self._modules.items()}
def get_mem_tree_as_dict(self) -> Dict[str, Dict[str, Any]]:
"""Returns _tree of modules, segments and segments and their total
memory usage."""
return {
k: {
"name": k,
**v.get_mod_mem_usage_dict(),
**{"children": v.get_seg_map_as_dict()},
}
for k, v in self._modules.items()
}
@property
def module_names(self) -> List[str]:
"""Returns sorted list of module names."""
return sorted(self._modules.keys())