Skip to main content

AddressMapSection

Struct AddressMapSection 

Source
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_count is the total number of entries (pc/srcloc combos) in the section and block_count is the number of blocks, ceil(entry_count / ADDRMAP_BLOCK_SIZE).
  • In the block index, first_offset is the text_offset of the block’s first entry and block_pos is 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. Here pc_delta is this entry’s text_offset minus the previous entry’s (the first entry’s delta is relative to the block’s first_offset and is therefore 0). If pos_is_none is set this entry’s file position is FilePos::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

Source

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.

Source

pub fn append_to(self, obj: &mut Object<'_>)

Finishes encoding this section into the Object provided.

Trait Implementations§

Source§

impl Default for AddressMapSection

Source§

fn default() -> AddressMapSection

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.