pub struct AddressMapSection { /* private fields */ }Expand description
Builder for the address map section of a wasmtime compilation image.
This builder is used to conveniently build the ELF_WASMTIME_ADDRMAP
section by compilers, and provides utilities to directly insert the results
into an Object.
§Section format
The section encodes a sequence of (text_offset, file_pos) entries, sorted
by text_offset, where text_offset is the location of an instruction
relative to the start of the text section and file_pos is the offset
within the original wasm file of the instruction it was compiled from, or
the FilePos::none() sentinel for generated code with no wasm-level
source. Unlike the trap section each entry here describes a range of pcs:
an entry covers addresses from its own text_offset up to the next
entry’s. This format is optimized to enable cheap (O(log n)) lookup given
an offset to find a source location while also being relatively compact as
this is included in all modules by default and is, uncompressed, the
largest of Wasmtime’s metadata sections. To satisfy this the section is
encoded as two major pieces: an index and a sequence of blocks.
The index is used to perform a binary search given a particular
text_offset to find a particular block. The index stores text offsets as
well as byte offsets in the “block bodies” section. Once a block is found
each block contains up to ADDRMAP_BLOCK_SIZE entries encoded next to each
other. Blocks take up a variable width of bytes to encode. More information
on decoding each block is below, but the general layout of the section looks
like:
┌───────────────────────────────────┐
│ entry_count: u32 │
│ block_count: u32 │
├───────────────────────────────────┤
│ block index │
│ ┌───────────────────────────────┐ │
│ │ first_offset: u32 │ │ one pair per block, sorted by
│ │ block_pos: u32 │ │ `first_offset`; `block_pos` is
│ ├───────────────────────────────┤ │ relative to the start of the
│ │ ... │ │ block bodies area below
│ └───────────────────────────────┘ │
├───────────────────────────────────┤
│ block bodies │
│ ┌───────────────────────────────┐ │
│ │ entry: uleb token │ │ one entry per instruction
│ │ [file_pos: uleb] │ │ mapping in the block,
│ ├───────────────────────────────┤ │ `ADDRMAP_BLOCK_SIZE` max
│ │ ... │ │
│ └───────────────────────────────┘ │
│ ┌───────────────────────────────┐ │
│ │ ... │ │
│ └───────────────────────────────┘ │
└───────────────────────────────────┘entry_countis the total number of entries (pc/srcloc combos) in the section andblock_countis the number of blocks,ceil(entry_count / ADDRMAP_BLOCK_SIZE).- In the block index,
first_offsetis thetext_offsetof the block’s first entry andblock_posis the position of the block’s body, relative to the start of the bodies area (i.e. the end of the index). - Each entry is a uleb-encoded token
(pc_delta << 1) | pos_is_none. Herepc_deltais this entry’stext_offsetminus the previous entry’s (the first entry’s delta is relative to the block’sfirst_offsetand is therefore 0). Ifpos_is_noneis set this entry’s file position isFilePos::none()and nothing else follows the token. Otherwise the token is followed by the entry’s file position: the first non-none position in a block is uleb-encoded absolutely and subsequent positions are sleb-encoded deltas from the previous non-none position. Delta chains restart at each block so blocks can be decoded independently.
Lookup (lookup_file_pos) binary searches the fixed-width block index for
the last block whose first_offset is <= the pc in question, then
linearly decodes at most ADDRMAP_BLOCK_SIZE entries of that block’s body
looking for the last entry whose text_offset is <= the pc.
This encoding leans on a few properties of address map metadata: consecutive instructions are close together (pc deltas almost always fit in a single-byte leb), consecutive source locations are close together and mostly increasing (position deltas almost always fit in a single-byte sleb), and entries with no source location are common (a quarter of all entries) and cost only the token’s flag bit. This is all in service of shrinking the previous 8 bytes per entry (u32 offset, u32 file position) to roughly 2 bytes per entry in practice.
Note that at this time this section has an alignment of 1. Additionally due to the 32-bit offsets in the block index this doesn’t support images
= 4GB.
Implementations§
Source§impl AddressMapSection
impl AddressMapSection
Sourcepub fn push(&mut self, func: Range<u64>, instrs: &[InstructionAddressMap])
pub fn push(&mut self, func: Range<u64>, instrs: &[InstructionAddressMap])
Pushes a new set of instruction mapping information for a function added in the executable.
The func argument here is the range of the function, relative to the
start of the text section in the executable. The instrs provided are
the descriptors for instructions in the function and their various
mappings back to original source positions.
This is required to be called for func values that are strictly
increasing in addresses (e.g. as the object is built). Additionally the
instrs map must be sorted based on code offset in the native text
section.