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