1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-06 02:06:08 +00:00

feat(tools): add a script for printing Rust stacks' sizes

[no changelog]
This commit is contained in:
Roman Zeyde 2025-03-03 12:00:16 +02:00 committed by Roman Zeyde
parent e7680edac5
commit 11517f46fd
4 changed files with 72 additions and 1 deletions

View File

@ -84,6 +84,7 @@ jobs:
- run: nix-shell --run "poetry run make -C core build_prodtest"
if: matrix.coins == 'universal' && matrix.type != 'debuglink'
- run: nix-shell --run "poetry run make -C core build_firmware"
- run: nix-shell --run "poetry run ./tools/print-rust-stack-sizes.py | sort -k1 -n | tail -n 50"
- run: nix-shell --run "poetry run make -C core sizecheck"
if: matrix.coins == 'universal' && matrix.type != 'debuglink'
- run: nix-shell --run "poetry run ./tools/check-bitcoin-only core/build/firmware/firmware.bin"

13
poetry.lock generated
View File

@ -1163,6 +1163,17 @@ files = [
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
]
[[package]]
name = "pyelftools"
version = "0.32"
description = "Library for analyzing ELF files and DWARF debugging information"
optional = false
python-versions = "*"
files = [
{file = "pyelftools-0.32-py3-none-any.whl", hash = "sha256:013df952a006db5e138b1edf6d8a68ecc50630adbd0d83a2d41e7f846163d738"},
{file = "pyelftools-0.32.tar.gz", hash = "sha256:6de90ee7b8263e740c8715a925382d4099b354f29ac48ea40d840cf7aa14ace5"},
]
[[package]]
name = "pyflakes"
version = "3.2.0"
@ -1905,4 +1916,4 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-it
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
content-hash = "dc9c84386e9b6cf621114845c095bba59d9a5cc169b1622208de2b270d71cbb8"
content-hash = "1257cb4cd905c3a00c46535ffa5767cf7bc5af0ac33b80f0adbd5776a8c49d31"

View File

@ -76,6 +76,7 @@ toiftool = {path = "./python/tools/toiftool", develop = true, python = ">=3.8"}
trezor-pylint-plugin = {path = "./tools/trezor-pylint-plugin", develop = true}
trezor-core-tools = {path = "./core/tools", develop = true}
flake8-annotations = "^3.1.1"
pyelftools = "^0.32"
[tool.poetry.dev-dependencies]
scan-build = "*"

58
tools/print-rust-stack-sizes.py Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
import subprocess
from pathlib import Path
import click
from elftools.construct import Struct, ULInt32, GreedyRange
from elftools.common.construct_utils import ULEB128
from elftools.elf.elffile import ELFFile
SYMBOL_TYPES = ("t", "w") # text, weak
ROOT = Path(__file__).parent.parent.resolve()
FIRMWARE_ELF = ROOT / "core" / "build" / "firmware" / "firmware.elf"
elf = ELFFile(FIRMWARE_ELF.open("rb"))
def load_address_map():
"""Load address map from firmware ELF file using `nm`."""
out = subprocess.check_output(
args=["arm-none-eabi-nm", "--radix=d", "--demangle", FIRMWARE_ELF]
)
symbols = (line.decode().split(maxsplit=2) for line in out.splitlines())
return {
int(addr): name for addr, type, name in symbols if type.lower() in SYMBOL_TYPES
}
def load_stack_sizes():
"""Load Rust stack sizes from firmware ELF section generated by `-Z emit-stack-sizes`."""
stack_sizes = elf.get_section_by_name(".stack_sizes")
Entries = GreedyRange(
Struct(
"Entry",
ULInt32("symbol_addr"),
ULEB128("stack_size"),
)
)
return Entries.parse(stack_sizes.data())
@click.command()
def main():
"""Print Rust functions' stack size.
See https://blog.japaric.io/stack-analysis/ for more details.
"""
address_map = load_address_map()
for entry in load_stack_sizes():
symbol_name = address_map[entry.symbol_addr]
print(f"{entry.stack_size}\t{symbol_name}")
if __name__ == "__main__":
main()