1 use crate::TrapInformation;
2 use crate::obj::ELF_WASMTIME_TRAPS;
3 use crate::prelude::*;
4 use object::write::{Object, StandardSegment};
5 use object::{LittleEndian, SectionKind, U32};
6 use std::ops::Range;
7 
8 /// A helper structure to build the custom-encoded section of a wasmtime
9 /// compilation image which encodes trap information.
10 ///
11 /// This structure is incrementally fed the results of compiling individual
12 /// functions and handles all the encoding internally, allowing usage of
13 /// `lookup_trap_code` below with the resulting section.
14 #[derive(Default)]
15 pub struct TrapEncodingBuilder {
16     offsets: Vec<U32<LittleEndian>>,
17     traps: Vec<u8>,
18     last_offset: u32,
19 }
20 
21 impl TrapEncodingBuilder {
22     /// Appends trap information about a function into this section.
23     ///
24     /// This function is called to describe traps for the `func` range
25     /// specified. The `func` offsets are specified relative to the text section
26     /// itself, and the `traps` offsets are specified relative to the start of
27     /// `func`.
28     ///
29     /// This is required to be called in-order for increasing ranges of `func`
30     /// to ensure the final array is properly sorted. Additionally `traps` must
31     /// be sorted.
push(&mut self, func: Range<u64>, traps: &[TrapInformation])32     pub fn push(&mut self, func: Range<u64>, traps: &[TrapInformation]) {
33         // NB: for now this only supports <=4GB text sections in object files.
34         // Alternative schemes will need to be created for >32-bit offsets to
35         // avoid making this section overly large.
36         let func_start = u32::try_from(func.start).unwrap();
37         let func_end = u32::try_from(func.end).unwrap();
38 
39         // Sanity-check to ensure that functions are pushed in-order, otherwise
40         // the `offsets` array won't be sorted which is our goal.
41         assert!(func_start >= self.last_offset);
42 
43         self.offsets.reserve(traps.len());
44         self.traps.reserve(traps.len());
45         for info in traps {
46             let pos = func_start + info.code_offset;
47             assert!(pos >= self.last_offset);
48             self.offsets.push(U32::new(LittleEndian, pos));
49             self.traps.push(info.trap_code as u8);
50             self.last_offset = pos;
51         }
52 
53         self.last_offset = func_end;
54     }
55 
56     /// Encodes this section into the object provided.
append_to(self, obj: &mut Object)57     pub fn append_to(self, obj: &mut Object) {
58         let section = obj.add_section(
59             obj.segment_name(StandardSegment::Data).to_vec(),
60             ELF_WASMTIME_TRAPS.as_bytes().to_vec(),
61             SectionKind::ReadOnlyData,
62         );
63 
64         // NB: this matches the encoding expected by `lookup` below.
65         let amt = u32::try_from(self.traps.len()).unwrap();
66         obj.append_section_data(section, &amt.to_le_bytes(), 1);
67         obj.append_section_data(section, object::bytes_of_slice(&self.offsets), 1);
68         obj.append_section_data(section, &self.traps, 1);
69     }
70 }
71