Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 1 | # |
| 2 | # Copyright (c) 2023, Arm Limited. All rights reserved. |
| 3 | # |
| 4 | # SPDX-License-Identifier: BSD-3-Clause |
| 5 | # |
| 6 | |
| 7 | import re |
| 8 | from pathlib import Path |
| 9 | |
| 10 | from memory.elfparser import TfaElfParser |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 11 | from memory.mapparser import TfaMapParser |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 12 | |
| 13 | |
| 14 | class TfaBuildParser: |
| 15 | """A class for performing analysis on the memory layout of a TF-A build.""" |
| 16 | |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 17 | def __init__(self, path: Path, map_backend=False): |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 18 | self._modules = dict() |
| 19 | self._path = path |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 20 | self.map_backend = map_backend |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 21 | self._parse_modules() |
| 22 | |
| 23 | def __getitem__(self, module: str): |
| 24 | """Returns an TfaElfParser instance indexed by module.""" |
| 25 | return self._modules[module] |
| 26 | |
| 27 | def _parse_modules(self): |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 28 | """Parse the build files using the selected backend.""" |
| 29 | backend = TfaElfParser |
| 30 | files = list(self._path.glob("**/*.elf")) |
| 31 | io_perms = "rb" |
| 32 | |
| 33 | if self.map_backend or len(files) == 0: |
| 34 | backend = TfaMapParser |
| 35 | files = self._path.glob("**/*.map") |
| 36 | io_perms = "r" |
| 37 | |
| 38 | for file in files: |
| 39 | module_name = file.name.split("/")[-1].split(".")[0] |
| 40 | with open(file, io_perms) as f: |
| 41 | self._modules[module_name] = backend(f) |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 42 | |
| 43 | if not len(self._modules): |
| 44 | raise FileNotFoundError( |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 45 | f"failed to find files to analyse in path {self._path}!" |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 46 | ) |
| 47 | |
| 48 | @property |
| 49 | def symbols(self) -> list: |
| 50 | return [ |
| 51 | (*sym, k) for k, v in self._modules.items() for sym in v.symbols |
| 52 | ] |
| 53 | |
| 54 | @staticmethod |
| 55 | def filter_symbols(symbols: list, regex: str = None) -> list: |
| 56 | """Returns a map of symbols to modules.""" |
| 57 | regex = r".*" if not regex else regex |
| 58 | return sorted( |
| 59 | filter(lambda s: re.match(regex, s[0]), symbols), |
| 60 | key=lambda s: (-s[1], s[0]), |
| 61 | reverse=True, |
| 62 | ) |
| 63 | |
Harrison Mutai | d9d5eb1 | 2023-02-23 11:30:17 +0000 | [diff] [blame] | 64 | def get_mem_usage_dict(self) -> dict: |
| 65 | """Returns map of memory usage per memory type for each module.""" |
| 66 | mem_map = {} |
| 67 | for k, v in self._modules.items(): |
Harrison Mutai | d0e3053 | 2023-06-07 11:28:16 +0100 | [diff] [blame] | 68 | mod_mem_map = v.get_memory_layout() |
Harrison Mutai | d9d5eb1 | 2023-02-23 11:30:17 +0000 | [diff] [blame] | 69 | if len(mod_mem_map): |
| 70 | mem_map[k] = mod_mem_map |
| 71 | return mem_map |
| 72 | |
Harrison Mutai | cc60aba | 2023-02-23 11:30:55 +0000 | [diff] [blame] | 73 | def get_mem_tree_as_dict(self) -> dict: |
| 74 | """Returns _tree of modules, segments and segments and their total |
| 75 | memory usage.""" |
| 76 | return { |
| 77 | k: { |
| 78 | "name": k, |
| 79 | **v.get_mod_mem_usage_dict(), |
| 80 | **{"children": v.get_seg_map_as_dict()}, |
| 81 | } |
| 82 | for k, v in self._modules.items() |
| 83 | } |
| 84 | |
Harrison Mutai | af5b49e | 2023-02-23 10:33:58 +0000 | [diff] [blame] | 85 | @property |
| 86 | def module_names(self): |
| 87 | """Returns sorted list of module names.""" |
| 88 | return sorted(self._modules.keys()) |