wasmtime_environ/compile/address_map.rs
1//! Data structures to provide transformation of the source
2
3use crate::obj::ELF_WASMTIME_ADDRMAP;
4use crate::prelude::*;
5use crate::InstructionAddressMap;
6use object::write::{Object, StandardSegment};
7use object::{LittleEndian, SectionKind, U32Bytes};
8use std::ops::Range;
9
10/// Builder for the address map section of a wasmtime compilation image.
11///
12/// This builder is used to conveniently built the `ELF_WASMTIME_ADDRMAP`
13/// section by compilers, and provides utilities to directly insert the results
14/// into an `Object`.
15#[derive(Default)]
16pub struct AddressMapSection {
17 offsets: Vec<U32Bytes<LittleEndian>>,
18 positions: Vec<U32Bytes<LittleEndian>>,
19 last_offset: u32,
20}
21
22impl AddressMapSection {
23 /// Pushes a new set of instruction mapping information for a function added
24 /// in the executable.
25 ///
26 /// The `func` argument here is the range of the function, relative to the
27 /// start of the text section in the executable. The `instrs` provided are
28 /// the descriptors for instructions in the function and their various
29 /// mappings back to original source positions.
30 ///
31 /// This is required to be called for `func` values that are strictly
32 /// increasing in addresses (e.g. as the object is built). Additionally the
33 /// `instrs` map must be sorted based on code offset in the native text
34 /// section.
35 pub fn push(&mut self, func: Range<u64>, instrs: &[InstructionAddressMap]) {
36 // NB: for now this only supports <=4GB text sections in object files.
37 // Alternative schemes will need to be created for >32-bit offsets to
38 // avoid making this section overly large.
39 let func_start = u32::try_from(func.start).unwrap();
40 let func_end = u32::try_from(func.end).unwrap();
41
42 self.offsets.reserve(instrs.len());
43 self.positions.reserve(instrs.len());
44 for map in instrs {
45 // Sanity-check to ensure that functions are pushed in-order, otherwise
46 // the `offsets` array won't be sorted which is our goal.
47 let pos = func_start + map.code_offset;
48 assert!(pos >= self.last_offset);
49 self.offsets.push(U32Bytes::new(LittleEndian, pos));
50 self.positions.push(U32Bytes::new(
51 LittleEndian,
52 map.srcloc.file_offset().unwrap_or(u32::MAX),
53 ));
54 self.last_offset = pos;
55 }
56 self.last_offset = func_end;
57 }
58
59 /// Finishes encoding this section into the `Object` provided.
60 pub fn append_to(self, obj: &mut Object) {
61 let section = obj.add_section(
62 obj.segment_name(StandardSegment::Data).to_vec(),
63 ELF_WASMTIME_ADDRMAP.as_bytes().to_vec(),
64 SectionKind::ReadOnlyData,
65 );
66
67 // NB: this matches the encoding expected by `lookup` below.
68 let amt = u32::try_from(self.offsets.len()).unwrap();
69 obj.append_section_data(section, &amt.to_le_bytes(), 1);
70 obj.append_section_data(section, object::bytes_of_slice(&self.offsets), 1);
71 obj.append_section_data(section, object::bytes_of_slice(&self.positions), 1);
72 }
73}