mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-07 21:33:54 +00:00
refactor: improve readability of symbol table
Make the symbol table produced by the memory mapping script more readable. Add a generic interface for interacting with ELF binaries. This interface enables us to get symbols that provide some insights into TF-A's memory usage. Change-Id: I6646f817a1d38d6184b837b78039b7465a533c5c Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
This commit is contained in:
parent
dcf430656c
commit
af5b49e992
14 changed files with 535 additions and 146 deletions
|
@ -94,7 +94,6 @@ module.exports = {
|
|||
|
||||
return contents.replace(/^(version\s=\s")((\d).?)*$/m, _ver)
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
15
Makefile
15
Makefile
|
@ -1074,11 +1074,6 @@ ROMLIBPATH ?= lib/romlib
|
|||
# Variable for use with Python
|
||||
PYTHON ?= python3
|
||||
|
||||
# Variables for use with PRINT_MEMORY_MAP
|
||||
PRINT_MEMORY_MAP_PATH ?= tools/memory
|
||||
PRINT_MEMORY_MAP ?= ${PRINT_MEMORY_MAP_PATH}/print_memory_map.py
|
||||
INVERTED_MEMMAP ?= 0
|
||||
|
||||
# Variables for use with documentation build using Sphinx tool
|
||||
DOCS_PATH ?= docs
|
||||
|
||||
|
@ -1139,7 +1134,6 @@ $(eval $(call assert_booleans,\
|
|||
GICV2_G0_FOR_EL3 \
|
||||
HANDLE_EA_EL3_FIRST_NS \
|
||||
HW_ASSISTED_COHERENCY \
|
||||
INVERTED_MEMMAP \
|
||||
MEASURED_BOOT \
|
||||
DRTM_SUPPORT \
|
||||
NS_TIMER_SWITCH \
|
||||
|
@ -1653,9 +1647,14 @@ endif
|
|||
romlib.bin: libraries FORCE
|
||||
${Q}${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES='${INCLUDES}' DEFINES='${DEFINES}' --no-print-directory -C ${ROMLIBPATH} all
|
||||
|
||||
# Call print_memory_map tool
|
||||
memmap: all
|
||||
${Q}${PYTHON} ${PRINT_MEMORY_MAP} ${BUILD_PLAT} ${INVERTED_MEMMAP}
|
||||
ifdef UNIX_MK
|
||||
${Q}PYTHONPATH=${CURDIR}/tools/memory \
|
||||
${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
|
||||
else
|
||||
${Q}set PYTHONPATH=${CURDIR}/tools/memory && \
|
||||
${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
|
||||
endif
|
||||
|
||||
doc:
|
||||
@echo " BUILD DOCUMENTATION"
|
||||
|
|
|
@ -17,6 +17,7 @@ Trusted Firmware-A Documentation
|
|||
security_advisories/index
|
||||
design_documents/index
|
||||
threat_model/index
|
||||
tools/index
|
||||
change-log
|
||||
glossary
|
||||
license
|
||||
|
|
12
docs/tools/index.rst
Normal file
12
docs/tools/index.rst
Normal file
|
@ -0,0 +1,12 @@
|
|||
Tools
|
||||
=====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Contents
|
||||
|
||||
memory-layout-tool
|
||||
|
||||
--------------
|
||||
|
||||
*Copyright (c) 2023, Arm Limited. All rights reserved.*
|
120
docs/tools/memory-layout-tool.rst
Normal file
120
docs/tools/memory-layout-tool.rst
Normal file
|
@ -0,0 +1,120 @@
|
|||
TF-A Memory Layout Tool
|
||||
=======================
|
||||
|
||||
TF-A's memory layout tool is a Python script for analyzing the virtual
|
||||
memory layout of TF-A builds.
|
||||
|
||||
Prerequisites
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
#. Python (3.8 or later)
|
||||
#. `Poetry`_ Python package manager
|
||||
|
||||
Getting Started
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
#. Install Poetry
|
||||
|
||||
.. code:: shell
|
||||
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
#. Install the required packages
|
||||
|
||||
.. code:: shell
|
||||
|
||||
poetry install --with memory
|
||||
|
||||
#. Verify that the tool runs in the installed virtual environment
|
||||
|
||||
.. code:: shell
|
||||
|
||||
poetry run memory --help
|
||||
|
||||
Symbol Virtual Map
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The tool can be used to generate a visualisation of the symbol table. By
|
||||
default, it prints the symbols representing the start and end address of the
|
||||
main memory regions in an ELF file (i.e. text, bss, rodata) but can be modified
|
||||
to print any set of symbols.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ poetry run memory -s
|
||||
build-path: build/fvp/release
|
||||
Virtual Address Map:
|
||||
+------------__BL1_RAM_END__------------+---------------------------------------+
|
||||
+---------__COHERENT_RAM_END__----------+ |
|
||||
+--------__COHERENT_RAM_START__---------+ |
|
||||
0x0403b000 +----------__XLAT_TABLE_END__-----------+ |
|
||||
0x04036000 +---------__XLAT_TABLE_START__----------+ |
|
||||
+--------__BASE_XLAT_TABLE_END__--------+ |
|
||||
0x04035600 +--------------__BSS_END__--------------+ |
|
||||
+-------__BASE_XLAT_TABLE_START__-------+ |
|
||||
+-----__PMF_PERCPU_TIMESTAMP_END__------+ |
|
||||
+---------__PMF_TIMESTAMP_END__---------+ |
|
||||
0x04035400 +--------__PMF_TIMESTAMP_START__--------+ |
|
||||
+-------------__BSS_START__-------------+ |
|
||||
0x04034a00 +------------__STACKS_END__-------------+ |
|
||||
0x04034500 +-----------__STACKS_START__------------+ |
|
||||
0x040344c5 +-----------__DATA_RAM_END__------------+ |
|
||||
+-----------__BL1_RAM_START__-----------+ |
|
||||
0x04034000 +----------__DATA_RAM_START__-----------+ |
|
||||
| +---------__COHERENT_RAM_END__----------+
|
||||
| +--------__COHERENT_RAM_START__---------+
|
||||
0x0402e000 | +----------__XLAT_TABLE_END__-----------+
|
||||
0x04029000 | +---------__XLAT_TABLE_START__----------+
|
||||
| +--------__BASE_XLAT_TABLE_END__--------+
|
||||
0x04028800 | +--------------__BSS_END__--------------+
|
||||
| +-------__BASE_XLAT_TABLE_START__-------+
|
||||
| +-----__PMF_PERCPU_TIMESTAMP_END__------+
|
||||
| +---------__PMF_TIMESTAMP_END__---------+
|
||||
0x04028580 | +--------__PMF_TIMESTAMP_START__--------+
|
||||
0x04028000 | +-------------__BSS_START__-------------+
|
||||
0x04027e40 | +------------__STACKS_END__-------------+
|
||||
0x04027840 | +-----------__STACKS_START__------------+
|
||||
0x04027000 | +------------__RODATA_END__-------------+
|
||||
| +------------__CPU_OPS_END__------------+
|
||||
| +-----------__CPU_OPS_START__-----------+
|
||||
| +--------__FCONF_POPULATOR_END__--------+
|
||||
| +--------------__GOT_END__--------------+
|
||||
| +-------------__GOT_START__-------------+
|
||||
| +---------__PMF_SVC_DESCS_END__---------+
|
||||
0x04026c10 | +--------__PMF_SVC_DESCS_START__--------+
|
||||
0x04026bf8 | +-------__FCONF_POPULATOR_START__-------+
|
||||
| +-----------__RODATA_START__------------+
|
||||
0x04026000 | +-------------__TEXT_END__--------------+
|
||||
0x04021000 | +------------__TEXT_START__-------------+
|
||||
0x000062b5 +------------__BL1_ROM_END__------------+ |
|
||||
0x00005df0 +----------__DATA_ROM_START__-----------+ |
|
||||
+------------__CPU_OPS_END__------------+ |
|
||||
+--------------__GOT_END__--------------+ |
|
||||
+-------------__GOT_START__-------------+ |
|
||||
0x00005de8 +------------__RODATA_END__-------------+ |
|
||||
+-----------__CPU_OPS_START__-----------+ |
|
||||
+--------__FCONF_POPULATOR_END__--------+ |
|
||||
+---------__PMF_SVC_DESCS_END__---------+ |
|
||||
0x00005c98 +--------__PMF_SVC_DESCS_START__--------+ |
|
||||
0x00005c80 +-------__FCONF_POPULATOR_START__-------+ |
|
||||
+-----------__RODATA_START__------------+ |
|
||||
0x00005000 +-------------__TEXT_END__--------------+ |
|
||||
0x00000000 +------------__TEXT_START__-------------+---------------------------------------+
|
||||
|
||||
Addresses are displayed in hexadecimal by default but can be printed in decimal
|
||||
instead with the ``-d`` option.
|
||||
|
||||
Because of the length of many of the symbols, the tool defaults to a text width
|
||||
of 120 chars. This can be increased if needed with the ``-w`` option.
|
||||
|
||||
For more detailed help instructions, run:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
poetry run memory --help
|
||||
|
||||
--------------
|
||||
|
||||
*Copyright (c) 2023, Arm Limited. All rights reserved.*
|
||||
|
||||
.. _Poetry: https://python-poetry.org/docs/
|
144
poetry.lock
generated
144
poetry.lock
generated
|
@ -12,6 +12,25 @@ files = [
|
|||
{file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anytree"
|
||||
version = "2.8.0"
|
||||
description = "Powerful and Lightweight Python Tree Data Structure.."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "anytree-2.8.0-py2.py3-none-any.whl", hash = "sha256:14c55ac77492b11532395049a03b773d14c7e30b22aa012e337b1e983de31521"},
|
||||
{file = "anytree-2.8.0.tar.gz", hash = "sha256:3f0f93f355a91bc3e6245319bf4c1d50e3416cc7a35cc1133c1ff38306bbccab"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.9.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["check-manifest"]
|
||||
test = ["coverage"]
|
||||
|
||||
[[package]]
|
||||
name = "babel"
|
||||
version = "2.12.1"
|
||||
|
@ -213,14 +232,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.0.0"
|
||||
version = "6.6.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"},
|
||||
{file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"},
|
||||
{file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
|
||||
{file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -395,38 +414,38 @@ testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov",
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.0"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
|
||||
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pip"
|
||||
version = "23.0.1"
|
||||
version = "23.1.2"
|
||||
description = "The PyPA recommended tool for installing Python packages."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pip-23.0.1-py3-none-any.whl", hash = "sha256:236bcb61156d76c4b8a05821b988c7b8c35bf0da28a4b614e8d6ab5212c25c6f"},
|
||||
{file = "pip-23.0.1.tar.gz", hash = "sha256:cd015ea1bfb0fcef59d8a286c1f8bebcb983f6317719d415dc5351efb7cd7024"},
|
||||
{file = "pip-23.1.2-py3-none-any.whl", hash = "sha256:3ef6ac33239e4027d9a5598a381b9d30880a1477e50039db2eac6e8a8f6d1b18"},
|
||||
{file = "pip-23.1.2.tar.gz", hash = "sha256:0e7c86f486935893c708287b30bd050a36ac827ec7fe5e43fe7cb198dd835fba"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pip-tools"
|
||||
version = "6.12.3"
|
||||
version = "6.13.0"
|
||||
description = "pip-tools keeps your pinned dependencies fresh."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pip-tools-6.12.3.tar.gz", hash = "sha256:480d44fae6e09fad3f9bd3d0a7e8423088715d10477e8ef0663440db25e3114f"},
|
||||
{file = "pip_tools-6.12.3-py3-none-any.whl", hash = "sha256:8510420f46572b2e26c357541390593d9365eb6edd2d1e7505267910ecaec080"},
|
||||
{file = "pip-tools-6.13.0.tar.gz", hash = "sha256:61d46bd2eb8016ed4a924e196e6e5b0a268cd3babd79e593048720db23522bb1"},
|
||||
{file = "pip_tools-6.13.0-py3-none-any.whl", hash = "sha256:50943f151d87e752abddec8158622c34ad7f292e193836e90e30d87da60b19d9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -440,16 +459,46 @@ wheel = "*"
|
|||
coverage = ["pytest-cov"]
|
||||
testing = ["flit-core (>=2,<4)", "poetry-core (>=1.0.0)", "pytest (>=7.2.0)", "pytest-rerunfailures", "pytest-xdist"]
|
||||
|
||||
[[package]]
|
||||
name = "prettytable"
|
||||
version = "3.7.0"
|
||||
description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "prettytable-3.7.0-py3-none-any.whl", hash = "sha256:f4aaf2ed6e6062a82fd2e6e5289bbbe705ec2788fe401a3a1f62a1cea55526d2"},
|
||||
{file = "prettytable-3.7.0.tar.gz", hash = "sha256:ef8334ee40b7ec721651fc4d37ecc7bb2ef55fde5098d994438f0dfdaa385c0c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"]
|
||||
|
||||
[[package]]
|
||||
name = "pyelftools"
|
||||
version = "0.29"
|
||||
description = "Library for analyzing ELF files and DWARF debugging information"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pyelftools-0.29-py2.py3-none-any.whl", hash = "sha256:519f38cf412f073b2d7393aa4682b0190fa901f7c3fa0bff2b82d537690c7fc1"},
|
||||
{file = "pyelftools-0.29.tar.gz", hash = "sha256:ec761596aafa16e282a31de188737e5485552469ac63b60cfcccf22263fd24ff"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.14.0"
|
||||
version = "2.15.1"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
|
||||
{file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
|
||||
{file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
|
||||
{file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -472,14 +521,14 @@ tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
|||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2022.7.1"
|
||||
version = "2023.3"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
|
||||
{file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
|
||||
{file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"},
|
||||
{file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -534,21 +583,21 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.28.2"
|
||||
version = "2.30.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7, <4"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
|
||||
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
|
||||
{file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"},
|
||||
{file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
urllib3 = ">=1.21.1,<3"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
|
@ -556,14 +605,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "67.6.0"
|
||||
version = "67.7.2"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"},
|
||||
{file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"},
|
||||
{file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"},
|
||||
{file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -571,6 +620,18 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g
|
|||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snowballstemmer"
|
||||
version = "2.2.0"
|
||||
|
@ -792,20 +853,33 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.15"
|
||||
version = "2.0.2"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
|
||||
{file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
|
||||
{file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"},
|
||||
{file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.6"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
|
||||
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wheel"
|
||||
|
@ -841,4 +915,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "07432d506e3dc69114203b554d82c1489372ce0087d4a430d0380e437afa5714"
|
||||
content-hash = "9c25ef33612d10c7caafa551a3cf6a12753167c6400f49cc261fddd18c7eaf6e"
|
||||
|
|
|
@ -5,6 +5,12 @@ description = "Trusted Firmware-A (TF-A) Python dependencies."
|
|||
authors = ["Arm Ltd."]
|
||||
license = "BSD-3-Clause"
|
||||
readme = "readme.rst"
|
||||
packages = [
|
||||
{ include = "memory", from = "tools/memory"}
|
||||
]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
memory = "memory.memmap:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
|
@ -18,3 +24,9 @@ pip-tools = "^6.4.0"
|
|||
|
||||
[tool.poetry.group.ci.dependencies]
|
||||
click = "^8.1.3"
|
||||
|
||||
[tool.poetry.group.memory.dependencies]
|
||||
pyelftools = "^0.29"
|
||||
anytree = "^2.8.0"
|
||||
click = "^8.1.3"
|
||||
prettytable = "^3.5.0"
|
||||
|
|
7
tools/memory/__init__.py
Normal file
7
tools/memory/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
7
tools/memory/memory/__init__.py
Normal file
7
tools/memory/memory/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
56
tools/memory/memory/buildparser.py
Executable file
56
tools/memory/memory/buildparser.py
Executable file
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from memory.elfparser import TfaElfParser
|
||||
|
||||
|
||||
class TfaBuildParser:
|
||||
"""A class for performing analysis on the memory layout of a TF-A build."""
|
||||
|
||||
def __init__(self, path: Path):
|
||||
self._modules = dict()
|
||||
self._path = path
|
||||
self._parse_modules()
|
||||
|
||||
def __getitem__(self, module: str):
|
||||
"""Returns an TfaElfParser instance indexed by module."""
|
||||
return self._modules[module]
|
||||
|
||||
def _parse_modules(self):
|
||||
"""Parse ELF files in the build path."""
|
||||
for elf_file in self._path.glob("**/*.elf"):
|
||||
module_name = elf_file.name.split("/")[-1].split(".")[0]
|
||||
with open(elf_file, "rb") as file:
|
||||
self._modules[module_name] = TfaElfParser(file)
|
||||
|
||||
if not len(self._modules):
|
||||
raise FileNotFoundError(
|
||||
f"failed to find ELF files in path {self._path}!"
|
||||
)
|
||||
|
||||
@property
|
||||
def symbols(self) -> list:
|
||||
return [
|
||||
(*sym, k) for k, v in self._modules.items() for sym in v.symbols
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def filter_symbols(symbols: list, regex: str = None) -> list:
|
||||
"""Returns a map of symbols to modules."""
|
||||
regex = r".*" if not regex else regex
|
||||
return sorted(
|
||||
filter(lambda s: re.match(regex, s[0]), symbols),
|
||||
key=lambda s: (-s[1], s[0]),
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def module_names(self):
|
||||
"""Returns sorted list of module names."""
|
||||
return sorted(self._modules.keys())
|
33
tools/memory/memory/elfparser.py
Normal file
33
tools/memory/memory/elfparser.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
from typing import BinaryIO
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
|
||||
class TfaElfParser:
|
||||
"""A class representing an ELF file built for TF-A.
|
||||
|
||||
Provides a basic interface for reading the symbol table and other
|
||||
attributes of an ELF file. The constructor accepts a file-like object with
|
||||
the contents an ELF file.
|
||||
"""
|
||||
|
||||
def __init__(self, elf_file: BinaryIO):
|
||||
self._segments = {}
|
||||
self._memory_layout = {}
|
||||
|
||||
elf = ELFFile(elf_file)
|
||||
|
||||
self._symbols = {
|
||||
sym.name: sym.entry["st_value"]
|
||||
for sym in elf.get_section_by_name(".symtab").iter_symbols()
|
||||
}
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
return self._symbols.items()
|
78
tools/memory/memory/memmap.py
Executable file
78
tools/memory/memory/memmap.py
Executable file
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from memory.buildparser import TfaBuildParser
|
||||
from memory.printer import TfaPrettyPrinter
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"-r",
|
||||
"--root",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Root containing build output.",
|
||||
)
|
||||
@click.option(
|
||||
"-p",
|
||||
"--platform",
|
||||
show_default=True,
|
||||
default="fvp",
|
||||
help="The platform targeted for analysis.",
|
||||
)
|
||||
@click.option(
|
||||
"-b",
|
||||
"--build-type",
|
||||
default="release",
|
||||
help="The target build type.",
|
||||
type=click.Choice(["debug", "release"], case_sensitive=False),
|
||||
)
|
||||
@click.option(
|
||||
"-s",
|
||||
"--symbols",
|
||||
is_flag=True,
|
||||
show_default=True,
|
||||
default=True,
|
||||
help="Generate a map of important TF symbols.",
|
||||
)
|
||||
@click.option("-w", "--width", type=int, envvar="COLUMNS")
|
||||
@click.option(
|
||||
"-d",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Display numbers in decimal base.",
|
||||
)
|
||||
def main(
|
||||
root: Path,
|
||||
platform: str,
|
||||
build_type: str,
|
||||
symbols: bool,
|
||||
width: int,
|
||||
d: bool,
|
||||
):
|
||||
build_path = root if root else Path("build/", platform, build_type)
|
||||
click.echo(f"build-path: {build_path.resolve()}")
|
||||
|
||||
parser = TfaBuildParser(build_path)
|
||||
printer = TfaPrettyPrinter(columns=width, as_decimal=d)
|
||||
|
||||
if symbols:
|
||||
expr = (
|
||||
r"(.*)(TEXT|BSS|RODATA|STACKS|_OPS|PMF|XLAT|GOT|FCONF"
|
||||
r"|R.M)(.*)(START|END)__$"
|
||||
)
|
||||
printer.print_symbol_table(
|
||||
parser.filter_symbols(parser.symbols, expr), parser.module_names
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
93
tools/memory/memory/printer.py
Executable file
93
tools/memory/memory/printer.py
Executable file
|
@ -0,0 +1,93 @@
|
|||
#
|
||||
# Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
|
||||
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._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_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))
|
|
@ -1,102 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import operator
|
||||
|
||||
# List of folder/map to parse
|
||||
bl_images = ['bl1', 'bl2', 'bl31']
|
||||
|
||||
# List of symbols to search for
|
||||
blx_symbols = ['__BL1_RAM_START__', '__BL1_RAM_END__',
|
||||
'__BL2_END__',
|
||||
'__BL31_END__',
|
||||
'__RO_START__', '__RO_END_UNALIGNED__', '__RO_END__',
|
||||
'__TEXT_START__', '__TEXT_END__',
|
||||
'__TEXT_RESIDENT_START__', '__TEXT_RESIDENT_END__',
|
||||
'__RODATA_START__', '__RODATA_END__',
|
||||
'__DATA_START__', '__DATA_END__',
|
||||
'__STACKS_START__', '__STACKS_END__',
|
||||
'__BSS_START__', '__BSS_END__',
|
||||
'__COHERENT_RAM_START__', '__COHERENT_RAM_END__',
|
||||
'__CPU_OPS_START__', '__CPU_OPS_END__',
|
||||
'__FCONF_POPULATOR_START__', '__FCONF_POPULATOR_END__',
|
||||
'__GOT_START__', '__GOT_END__',
|
||||
'__PARSER_LIB_DESCS_START__', '__PARSER_LIB_DESCS_END__',
|
||||
'__PMF_TIMESTAMP_START__', '__PMF_TIMESTAMP_END__',
|
||||
'__PMF_SVC_DESCS_START__', '__PMF_SVC_DESCS_END__',
|
||||
'__RELA_START__', '__RELA_END__',
|
||||
'__RT_SVC_DESCS_START__', '__RT_SVC_DESCS_END__',
|
||||
'__BASE_XLAT_TABLE_START__', '__BASE_XLAT_TABLE_END__',
|
||||
'__XLAT_TABLE_START__', '__XLAT_TABLE_END__',
|
||||
]
|
||||
|
||||
# Regex to extract address from map file
|
||||
address_pattern = re.compile(r"\b0x\w*")
|
||||
|
||||
# List of found element: [address, symbol, file]
|
||||
address_list = []
|
||||
|
||||
# Get the directory from command line or use a default one
|
||||
inverted_print = True
|
||||
if len(sys.argv) >= 2:
|
||||
build_dir = sys.argv[1]
|
||||
if len(sys.argv) >= 3:
|
||||
inverted_print = sys.argv[2] == '0'
|
||||
else:
|
||||
build_dir = 'build/fvp/debug'
|
||||
|
||||
max_len = max(len(word) for word in blx_symbols) + 2
|
||||
if (max_len % 2) != 0:
|
||||
max_len += 1
|
||||
|
||||
# Extract all the required symbols from the map files
|
||||
for image in bl_images:
|
||||
file_path = os.path.join(build_dir, image, '{}.map'.format(image))
|
||||
if os.path.isfile(file_path):
|
||||
with open (file_path, 'rt') as mapfile:
|
||||
for line in mapfile:
|
||||
for symbol in blx_symbols:
|
||||
skip_symbol = 0
|
||||
# Regex to find symbol definition
|
||||
line_pattern = re.compile(r"\b0x\w*\s*" + symbol + "\s= .")
|
||||
match = line_pattern.search(line)
|
||||
if match:
|
||||
# Extract address from line
|
||||
match = address_pattern.search(line)
|
||||
if match:
|
||||
if '_END__' in symbol:
|
||||
sym_start = symbol.replace('_END__', '_START__')
|
||||
if [match.group(0), sym_start, image] in address_list:
|
||||
address_list.remove([match.group(0), sym_start, image])
|
||||
skip_symbol = 1
|
||||
if skip_symbol == 0:
|
||||
address_list.append([match.group(0), symbol, image])
|
||||
|
||||
# Sort by address
|
||||
address_list.sort(key=operator.itemgetter(0))
|
||||
|
||||
# Invert list for lower address at bottom
|
||||
if inverted_print:
|
||||
address_list = reversed(address_list)
|
||||
|
||||
# Generate memory view
|
||||
print(('{:-^%d}' % (max_len * 3 + 20 + 7)).format('Memory Map from: ' + build_dir))
|
||||
for address in address_list:
|
||||
if "bl1" in address[2]:
|
||||
print(address[0], ('+{:-^%d}+ |{:^%d}| |{:^%d}|' % (max_len, max_len, max_len)).format(address[1], '', ''))
|
||||
elif "bl2" in address[2]:
|
||||
print(address[0], ('|{:^%d}| +{:-^%d}+ |{:^%d}|' % (max_len, max_len, max_len)).format('', address[1], ''))
|
||||
elif "bl31" in address[2]:
|
||||
print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
|
||||
else:
|
||||
print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
|
||||
|
||||
print(('{:^20}{:_^%d} {:_^%d} {:_^%d}' % (max_len, max_len, max_len)).format('', '', '', ''))
|
||||
print(('{:^20}{:^%d} {:^%d} {:^%d}' % (max_len, max_len, max_len)).format('address', 'bl1', 'bl2', 'bl31'))
|
Loading…
Add table
Reference in a new issue