# elf_inventory

The measured memory inventory of a linked image, read with the toolchain's own tools: every section with its address and size, the load segments, and how many rows could not be parsed.

Every name on this page is imported from `helia_profiler`.

**API tier:** `experimental`

Generated from the `src/helia_profiler` tree `f38e378c801d34438affb680257217e0b58d2cd1`.

[Machine-readable model](https://ambiqai.github.io/helia-profiler/reference/api/helia_profiler/elf_inventory.json)

`dataclass`

One section of the linked image, address included.

``index`` is the ELF section-header index — the section's IDENTITY.
Section NAMES are not unique: armlink emits one section per execution
region per content class all named after the region (a real NSX AP510
scatter link yields two ``MCU_TCM`` sections, PROGBITS + NOBITS), and
NSX's own gcc scripts declare ``.text`` twice. Never key a collection
of these on ``name`` alone — bytes vanish (#176).

``linker_reserved`` marks the NOBITS+allocated regions the linker
manufactures rather than the program needing them (today: fill-to-end
heaps, armlink's ``ARM_LIB_HEAP`` — the #24/#131 rule, same predicate
as the ``BinarySections.reserved`` split). ``.stack``/``ARM_LIB_STACK``
are deliberately NOT reserved: the stack is live memory the firmware
needs — but note it usually sits OUTSIDE the per-family app window
(``LinkedRegionWindow.app_window``), which is how the free-space math
stays consistent.

**API tier:** `experimental`

`dataclass`

One PT_LOAD program header: where bytes load (physical) vs run
(virtual) — the fact that makes initialized data's MRAM load image
accountable (#133 D3).

Toolchain shape caveat (#176, measured on real links against the NSX
AP510 scripts): GNU ld emits one PT_LOAD per load
region (``.data`` gets vaddr in DTCM, paddr in MRAM — per-section
recovery works). armlink emits a SINGLE PT_LOAD whose vaddr==paddr is
the image base and whose ``memory_size`` SUMS discontiguous execution
regions — ``paddr + memory_size`` is a phantom span, and mapping
sections into segments by vaddr containment understates armlink MRAM
~400x. Region-level load-image accounting that works on BOTH families:
sum ``file_size`` grouped by ``classify_address(physical_address)``,
never walk sections into segments. Per-symbol load-image attribution
on armlink is NOT recoverable from these primitives.

**API tier:** `experimental`

`dataclass`

The measured memory inventory of one linked binary.

``unparsed_rows`` counts SECTION rows/blocks that LOOKED like
inventory entries but failed to parse. When nonzero the section
inventory is PARTIAL — occupancy computed from it is understated, and
a consumer must treat the measured view as unavailable rather
than publish a silently-low number (#131's discipline, structural
instead of a debug log). Segment parse failures are NOT counted:
segments refine the inventory and their absence degrades
independently (empty tuple), on both tool paths.

**API tier:** `experimental`

The measured section/segment inventory of *binary_path*, or None.

Dispatches like :func:`binary_sections`: readelf for the size-probed
toolchains, ``fromelf --text -v`` for armclang. Degrades to ``None`` on
any tool or parse failure — the measured memory view simply does not
exist for that run, exactly like an absent ``reserved`` split.

**API tier:** `experimental`

---

Machine-readable: [`elf_inventory.json`](https://ambiqai.github.io/helia-profiler/reference/api/helia_profiler/elf_inventory.json) · [`elf_inventory.md`](https://ambiqai.github.io/helia-profiler/reference/api/helia_profiler/elf_inventory.md), complete and lossless.
