Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/compile/address_map.rs
1693 views
1
//! Data structures to provide transformation of the source
2
3
use crate::InstructionAddressMap;
4
use crate::obj::ELF_WASMTIME_ADDRMAP;
5
use crate::prelude::*;
6
use object::write::{Object, StandardSegment};
7
use object::{LittleEndian, SectionKind, U32Bytes};
8
use 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)]
16
pub struct AddressMapSection {
17
offsets: Vec<U32Bytes<LittleEndian>>,
18
positions: Vec<U32Bytes<LittleEndian>>,
19
last_offset: u32,
20
}
21
22
impl 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
let mut last_srcloc = None;
45
for map in instrs {
46
// Sanity-check to ensure that functions are pushed in-order, otherwise
47
// the `offsets` array won't be sorted which is our goal.
48
let pos = func_start + map.code_offset;
49
assert!(pos >= self.last_offset);
50
self.last_offset = pos;
51
52
// Drop duplicate instruction mappings that match what was
53
// previously pushed into the array since the representation used
54
// here will naturally cover `pos` with the previous entry.
55
let srcloc = map.srcloc.file_offset().unwrap_or(u32::MAX);
56
if Some(srcloc) == last_srcloc {
57
continue;
58
}
59
last_srcloc = Some(srcloc);
60
61
self.offsets.push(U32Bytes::new(LittleEndian, pos));
62
self.positions.push(U32Bytes::new(LittleEndian, srcloc));
63
}
64
self.last_offset = func_end;
65
}
66
67
/// Finishes encoding this section into the `Object` provided.
68
pub fn append_to(self, obj: &mut Object) {
69
let section = obj.add_section(
70
obj.segment_name(StandardSegment::Data).to_vec(),
71
ELF_WASMTIME_ADDRMAP.as_bytes().to_vec(),
72
SectionKind::ReadOnlyData,
73
);
74
75
// NB: this matches the encoding expected by `lookup` below.
76
let amt = u32::try_from(self.offsets.len()).unwrap();
77
obj.append_section_data(section, &amt.to_le_bytes(), 1);
78
obj.append_section_data(section, object::bytes_of_slice(&self.offsets), 1);
79
obj.append_section_data(section, object::bytes_of_slice(&self.positions), 1);
80
}
81
}
82
83