Path: blob/main/crates/environ/src/compile/address_map.rs
1693 views
//! Data structures to provide transformation of the source12use crate::InstructionAddressMap;3use crate::obj::ELF_WASMTIME_ADDRMAP;4use crate::prelude::*;5use object::write::{Object, StandardSegment};6use object::{LittleEndian, SectionKind, U32Bytes};7use std::ops::Range;89/// Builder for the address map section of a wasmtime compilation image.10///11/// This builder is used to conveniently built the `ELF_WASMTIME_ADDRMAP`12/// section by compilers, and provides utilities to directly insert the results13/// into an `Object`.14#[derive(Default)]15pub struct AddressMapSection {16offsets: Vec<U32Bytes<LittleEndian>>,17positions: Vec<U32Bytes<LittleEndian>>,18last_offset: u32,19}2021impl AddressMapSection {22/// Pushes a new set of instruction mapping information for a function added23/// in the executable.24///25/// The `func` argument here is the range of the function, relative to the26/// start of the text section in the executable. The `instrs` provided are27/// the descriptors for instructions in the function and their various28/// mappings back to original source positions.29///30/// This is required to be called for `func` values that are strictly31/// increasing in addresses (e.g. as the object is built). Additionally the32/// `instrs` map must be sorted based on code offset in the native text33/// section.34pub fn push(&mut self, func: Range<u64>, instrs: &[InstructionAddressMap]) {35// NB: for now this only supports <=4GB text sections in object files.36// Alternative schemes will need to be created for >32-bit offsets to37// avoid making this section overly large.38let func_start = u32::try_from(func.start).unwrap();39let func_end = u32::try_from(func.end).unwrap();4041self.offsets.reserve(instrs.len());42self.positions.reserve(instrs.len());43let mut last_srcloc = None;44for map in instrs {45// Sanity-check to ensure that functions are pushed in-order, otherwise46// the `offsets` array won't be sorted which is our goal.47let pos = func_start + map.code_offset;48assert!(pos >= self.last_offset);49self.last_offset = pos;5051// Drop duplicate instruction mappings that match what was52// previously pushed into the array since the representation used53// here will naturally cover `pos` with the previous entry.54let srcloc = map.srcloc.file_offset().unwrap_or(u32::MAX);55if Some(srcloc) == last_srcloc {56continue;57}58last_srcloc = Some(srcloc);5960self.offsets.push(U32Bytes::new(LittleEndian, pos));61self.positions.push(U32Bytes::new(LittleEndian, srcloc));62}63self.last_offset = func_end;64}6566/// Finishes encoding this section into the `Object` provided.67pub fn append_to(self, obj: &mut Object) {68let section = obj.add_section(69obj.segment_name(StandardSegment::Data).to_vec(),70ELF_WASMTIME_ADDRMAP.as_bytes().to_vec(),71SectionKind::ReadOnlyData,72);7374// NB: this matches the encoding expected by `lookup` below.75let amt = u32::try_from(self.offsets.len()).unwrap();76obj.append_section_data(section, &amt.to_le_bytes(), 1);77obj.append_section_data(section, object::bytes_of_slice(&self.offsets), 1);78obj.append_section_data(section, object::bytes_of_slice(&self.positions), 1);79}80}818283