1dd8c48b3SAlex Crichton use crate::FunctionAddressMap;
290ac295eSAlex Crichton use crate::debug::Compilation;
387c33c29SAlex Crichton use gimli::write;
487c33c29SAlex Crichton use std::collections::BTreeMap;
5dd8c48b3SAlex Crichton use wasmtime_environ::{DefinedFuncIndex, FilePos, PrimaryMap, StaticModuleIndex};
687c33c29SAlex Crichton 
787c33c29SAlex Crichton pub type GeneratedAddress = usize;
887c33c29SAlex Crichton pub type WasmAddress = u64;
987c33c29SAlex Crichton 
1087c33c29SAlex Crichton /// Contains mapping of the generated address to its original
1187c33c29SAlex Crichton /// source location.
1287c33c29SAlex Crichton #[derive(Debug)]
1387c33c29SAlex Crichton pub struct AddressMap {
1487c33c29SAlex Crichton     pub generated: GeneratedAddress,
1587c33c29SAlex Crichton     pub wasm: WasmAddress,
1687c33c29SAlex Crichton }
1787c33c29SAlex Crichton 
1887c33c29SAlex Crichton /// Information about generated function code: its body start,
1987c33c29SAlex Crichton /// length, and instructions addresses.
2087c33c29SAlex Crichton #[derive(Debug)]
2187c33c29SAlex Crichton pub struct FunctionMap {
22dd8c48b3SAlex Crichton     pub symbol: usize,
2387c33c29SAlex Crichton     pub offset: GeneratedAddress,
2487c33c29SAlex Crichton     pub len: GeneratedAddress,
2587c33c29SAlex Crichton     pub wasm_start: WasmAddress,
2687c33c29SAlex Crichton     pub wasm_end: WasmAddress,
2787c33c29SAlex Crichton     pub addresses: Box<[AddressMap]>,
2887c33c29SAlex Crichton }
2987c33c29SAlex Crichton 
3087c33c29SAlex Crichton /// Mapping of the source location to its generated code range.
3187c33c29SAlex Crichton #[derive(Debug)]
3287c33c29SAlex Crichton struct Position {
3387c33c29SAlex Crichton     wasm_pos: WasmAddress,
3487c33c29SAlex Crichton     gen_start: GeneratedAddress,
3587c33c29SAlex Crichton     gen_end: GeneratedAddress,
3687c33c29SAlex Crichton }
3787c33c29SAlex Crichton 
3887c33c29SAlex Crichton /// Mapping of continuous range of source location to its generated
3987c33c29SAlex Crichton /// code. The positions are always in ascending order for search.
4087c33c29SAlex Crichton #[derive(Debug)]
4187c33c29SAlex Crichton struct Range {
4287c33c29SAlex Crichton     wasm_start: WasmAddress,
4387c33c29SAlex Crichton     wasm_end: WasmAddress,
4487c33c29SAlex Crichton     gen_start: GeneratedAddress,
4587c33c29SAlex Crichton     gen_end: GeneratedAddress,
4687c33c29SAlex Crichton     positions: Box<[Position]>,
4787c33c29SAlex Crichton }
4887c33c29SAlex Crichton 
4987c33c29SAlex Crichton type RangeIndex = usize;
5087c33c29SAlex Crichton 
5187c33c29SAlex Crichton /// Helper function address lookup data. Contains ranges start positions
5287c33c29SAlex Crichton /// index and ranges data. The multiple ranges can include the same
5387c33c29SAlex Crichton /// original source position. The index (B-Tree) uses range start
5487c33c29SAlex Crichton /// position as a key. The index values reference the ranges array.
5587c33c29SAlex Crichton /// The item are ordered RangeIndex.
5687c33c29SAlex Crichton #[derive(Debug)]
5787c33c29SAlex Crichton struct FuncLookup {
5887c33c29SAlex Crichton     index: Vec<(WasmAddress, Box<[RangeIndex]>)>,
5987c33c29SAlex Crichton     ranges: Box<[Range]>,
6087c33c29SAlex Crichton }
6187c33c29SAlex Crichton 
6287c33c29SAlex Crichton /// Mapping of original functions to generated code locations/ranges.
6387c33c29SAlex Crichton #[derive(Debug)]
6487c33c29SAlex Crichton struct FuncTransform {
6587c33c29SAlex Crichton     start: WasmAddress,
6687c33c29SAlex Crichton     end: WasmAddress,
6787c33c29SAlex Crichton     index: DefinedFuncIndex,
6887c33c29SAlex Crichton     lookup: FuncLookup,
6987c33c29SAlex Crichton }
7087c33c29SAlex Crichton 
7187c33c29SAlex Crichton /// Module functions mapping to generated code.
7287c33c29SAlex Crichton #[derive(Debug)]
7387c33c29SAlex Crichton pub struct AddressTransform {
7487c33c29SAlex Crichton     map: PrimaryMap<DefinedFuncIndex, FunctionMap>,
7587c33c29SAlex Crichton     func: Vec<(WasmAddress, FuncTransform)>,
7687c33c29SAlex Crichton }
7787c33c29SAlex Crichton 
7887c33c29SAlex Crichton /// Returns a wasm bytecode offset in the code section from SourceLoc.
get_wasm_code_offset(loc: FilePos, code_section_offset: u64) -> WasmAddress7987c33c29SAlex Crichton fn get_wasm_code_offset(loc: FilePos, code_section_offset: u64) -> WasmAddress {
8087c33c29SAlex Crichton     // Code section size <= 4GB, allow wrapped SourceLoc to recover the overflow.
8187c33c29SAlex Crichton     loc.file_offset()
8287c33c29SAlex Crichton         .unwrap()
8387c33c29SAlex Crichton         .wrapping_sub(code_section_offset as u32) as WasmAddress
8487c33c29SAlex Crichton }
8587c33c29SAlex Crichton 
build_function_lookup( ft: &FunctionAddressMap, code_section_offset: u64, ) -> (WasmAddress, WasmAddress, FuncLookup)8687c33c29SAlex Crichton fn build_function_lookup(
8787c33c29SAlex Crichton     ft: &FunctionAddressMap,
8887c33c29SAlex Crichton     code_section_offset: u64,
8987c33c29SAlex Crichton ) -> (WasmAddress, WasmAddress, FuncLookup) {
901321c234SAlex Crichton     assert!(code_section_offset <= ft.start_srcloc.file_offset().unwrap().into());
9187c33c29SAlex Crichton     let fn_start = get_wasm_code_offset(ft.start_srcloc, code_section_offset);
9287c33c29SAlex Crichton     let fn_end = get_wasm_code_offset(ft.end_srcloc, code_section_offset);
931321c234SAlex Crichton     assert!(fn_start <= fn_end);
9487c33c29SAlex Crichton 
9587c33c29SAlex Crichton     // Build ranges of continuous source locations. The new ranges starts when
9687c33c29SAlex Crichton     // non-descending order is interrupted. Assuming the same origin location can
9787c33c29SAlex Crichton     // be present in multiple ranges.
9887c33c29SAlex Crichton     let mut range_wasm_start = fn_start;
9987c33c29SAlex Crichton     let mut range_gen_start = ft.body_offset;
10087c33c29SAlex Crichton     let mut last_wasm_pos = range_wasm_start;
10187c33c29SAlex Crichton     let mut ranges = Vec::new();
10287c33c29SAlex Crichton     let mut ranges_index = BTreeMap::new();
10387c33c29SAlex Crichton     let mut current_range = Vec::new();
10487c33c29SAlex Crichton     let mut last_gen_inst_empty = false;
10587c33c29SAlex Crichton     for (i, t) in ft.instructions.iter().enumerate() {
10687c33c29SAlex Crichton         if t.srcloc.file_offset().is_none() {
10787c33c29SAlex Crichton             continue;
10887c33c29SAlex Crichton         }
10987c33c29SAlex Crichton 
11087c33c29SAlex Crichton         let offset = get_wasm_code_offset(t.srcloc, code_section_offset);
1111321c234SAlex Crichton         assert!(fn_start <= offset);
1121321c234SAlex Crichton         assert!(offset <= fn_end);
11387c33c29SAlex Crichton 
11487c33c29SAlex Crichton         let inst_gen_start = t.code_offset as usize;
11587c33c29SAlex Crichton         let inst_gen_end = match ft.instructions.get(i + 1) {
11687c33c29SAlex Crichton             Some(i) => i.code_offset as usize,
11787c33c29SAlex Crichton             None => ft.body_len as usize,
11887c33c29SAlex Crichton         };
11987c33c29SAlex Crichton 
12087c33c29SAlex Crichton         if last_wasm_pos > offset {
12187c33c29SAlex Crichton             // Start new range.
12287c33c29SAlex Crichton             ranges_index.insert(range_wasm_start, ranges.len());
12387c33c29SAlex Crichton             ranges.push(Range {
12487c33c29SAlex Crichton                 wasm_start: range_wasm_start,
12587c33c29SAlex Crichton                 wasm_end: last_wasm_pos,
12687c33c29SAlex Crichton                 gen_start: range_gen_start,
12787c33c29SAlex Crichton                 gen_end: inst_gen_start,
12887c33c29SAlex Crichton                 positions: current_range.into_boxed_slice(),
12987c33c29SAlex Crichton             });
13087c33c29SAlex Crichton             range_wasm_start = offset;
13187c33c29SAlex Crichton             range_gen_start = inst_gen_start;
13287c33c29SAlex Crichton             current_range = Vec::new();
13387c33c29SAlex Crichton             last_gen_inst_empty = false;
13487c33c29SAlex Crichton         }
13587c33c29SAlex Crichton         if last_gen_inst_empty && current_range.last().unwrap().gen_start == inst_gen_start {
13687c33c29SAlex Crichton             // It is possible that previous inst_gen_start == inst_gen_end, so
13787c33c29SAlex Crichton             // make an attempt to merge all such positions with current one.
13887c33c29SAlex Crichton             if inst_gen_start < inst_gen_end {
13987c33c29SAlex Crichton                 let last = current_range.last_mut().unwrap();
14087c33c29SAlex Crichton                 last.gen_end = inst_gen_end;
14187c33c29SAlex Crichton                 last_gen_inst_empty = false;
14287c33c29SAlex Crichton             }
14387c33c29SAlex Crichton         } else {
14487c33c29SAlex Crichton             // Continue existing range: add new wasm->generated code position.
14587c33c29SAlex Crichton             current_range.push(Position {
14687c33c29SAlex Crichton                 wasm_pos: offset,
14787c33c29SAlex Crichton                 gen_start: inst_gen_start,
14887c33c29SAlex Crichton                 gen_end: inst_gen_end,
14987c33c29SAlex Crichton             });
15087c33c29SAlex Crichton             // Track if last position was empty (see if-branch above).
15187c33c29SAlex Crichton             last_gen_inst_empty = inst_gen_start == inst_gen_end;
15287c33c29SAlex Crichton         }
15387c33c29SAlex Crichton         last_wasm_pos = offset;
15487c33c29SAlex Crichton     }
15587c33c29SAlex Crichton     let last_gen_addr = ft.body_offset + ft.body_len as usize;
15687c33c29SAlex Crichton     ranges_index.insert(range_wasm_start, ranges.len());
15787c33c29SAlex Crichton     ranges.push(Range {
15887c33c29SAlex Crichton         wasm_start: range_wasm_start,
15987c33c29SAlex Crichton         wasm_end: fn_end,
16087c33c29SAlex Crichton         gen_start: range_gen_start,
16187c33c29SAlex Crichton         gen_end: last_gen_addr,
16287c33c29SAlex Crichton         positions: current_range.into_boxed_slice(),
16387c33c29SAlex Crichton     });
16487c33c29SAlex Crichton 
16587c33c29SAlex Crichton     // Making ranges lookup faster by building index: B-tree with every range
16687c33c29SAlex Crichton     // start position that maps into list of active ranges at this position.
16787c33c29SAlex Crichton     let ranges = ranges.into_boxed_slice();
16887c33c29SAlex Crichton     let mut active_ranges = Vec::new();
16987c33c29SAlex Crichton     let mut index = BTreeMap::new();
17087c33c29SAlex Crichton     let mut last_wasm_pos = None;
17187c33c29SAlex Crichton     for (wasm_start, range_index) in ranges_index {
17287c33c29SAlex Crichton         if Some(wasm_start) == last_wasm_pos {
17387c33c29SAlex Crichton             active_ranges.push(range_index);
17487c33c29SAlex Crichton             continue;
17587c33c29SAlex Crichton         }
17687c33c29SAlex Crichton         if let Some(position) = last_wasm_pos {
17787c33c29SAlex Crichton             let mut sorted_ranges = active_ranges.clone();
17887c33c29SAlex Crichton             sorted_ranges.sort();
17987c33c29SAlex Crichton             index.insert(position, sorted_ranges.into_boxed_slice());
18087c33c29SAlex Crichton         }
18187c33c29SAlex Crichton         active_ranges.retain(|r| ranges[*r].wasm_end.cmp(&wasm_start) != std::cmp::Ordering::Less);
18287c33c29SAlex Crichton         active_ranges.push(range_index);
18387c33c29SAlex Crichton         last_wasm_pos = Some(wasm_start);
18487c33c29SAlex Crichton     }
18587c33c29SAlex Crichton     active_ranges.sort();
18687c33c29SAlex Crichton     index.insert(last_wasm_pos.unwrap(), active_ranges.into_boxed_slice());
187703871a2SAlex Crichton     let index = Vec::from_iter(index);
18887c33c29SAlex Crichton     (fn_start, fn_end, FuncLookup { index, ranges })
18987c33c29SAlex Crichton }
19087c33c29SAlex Crichton 
build_function_addr_map( compilation: &Compilation<'_>, module: StaticModuleIndex, ) -> PrimaryMap<DefinedFuncIndex, FunctionMap>19187c33c29SAlex Crichton fn build_function_addr_map(
192dd8c48b3SAlex Crichton     compilation: &Compilation<'_>,
193dd8c48b3SAlex Crichton     module: StaticModuleIndex,
19487c33c29SAlex Crichton ) -> PrimaryMap<DefinedFuncIndex, FunctionMap> {
19587c33c29SAlex Crichton     let mut map = PrimaryMap::new();
196dd8c48b3SAlex Crichton     for idx in compilation.translations[module]
197dd8c48b3SAlex Crichton         .module
198dd8c48b3SAlex Crichton         .defined_func_indices()
199dd8c48b3SAlex Crichton     {
200dd8c48b3SAlex Crichton         let (symbol, metadata) = compilation.function(module, idx);
201dd8c48b3SAlex Crichton         let code_section_offset = compilation.translations[module]
202dd8c48b3SAlex Crichton             .debuginfo
203dd8c48b3SAlex Crichton             .wasm_file
204dd8c48b3SAlex Crichton             .code_section_offset;
2051cbca5a5SSaúl Cabrera         let ft = &metadata.address_map;
20687c33c29SAlex Crichton         let mut fn_map = Vec::new();
20787c33c29SAlex Crichton         for t in ft.instructions.iter() {
20887c33c29SAlex Crichton             if t.srcloc.file_offset().is_none() {
20987c33c29SAlex Crichton                 continue;
21087c33c29SAlex Crichton             }
21187c33c29SAlex Crichton             let offset = get_wasm_code_offset(t.srcloc, code_section_offset);
21287c33c29SAlex Crichton             fn_map.push(AddressMap {
21387c33c29SAlex Crichton                 generated: t.code_offset as usize,
21487c33c29SAlex Crichton                 wasm: offset,
21587c33c29SAlex Crichton             });
21687c33c29SAlex Crichton         }
21787c33c29SAlex Crichton 
2186fbddc19SAlex Crichton         if cfg!(debug_assertions) {
21987c33c29SAlex Crichton             // fn_map is sorted by the generated field -- see FunctionAddressMap::instructions.
22087c33c29SAlex Crichton             for i in 1..fn_map.len() {
2211321c234SAlex Crichton                 assert!(fn_map[i - 1].generated <= fn_map[i].generated);
22287c33c29SAlex Crichton             }
22387c33c29SAlex Crichton         }
22487c33c29SAlex Crichton 
22587c33c29SAlex Crichton         map.push(FunctionMap {
226dd8c48b3SAlex Crichton             symbol,
22787c33c29SAlex Crichton             offset: ft.body_offset,
22887c33c29SAlex Crichton             len: ft.body_len as usize,
22987c33c29SAlex Crichton             wasm_start: get_wasm_code_offset(ft.start_srcloc, code_section_offset),
23087c33c29SAlex Crichton             wasm_end: get_wasm_code_offset(ft.end_srcloc, code_section_offset),
23187c33c29SAlex Crichton             addresses: fn_map.into_boxed_slice(),
23287c33c29SAlex Crichton         });
23387c33c29SAlex Crichton     }
23487c33c29SAlex Crichton     map
23587c33c29SAlex Crichton }
23687c33c29SAlex Crichton 
23787c33c29SAlex Crichton // Utility iterator to find all ranges starts for specific Wasm address.
23887c33c29SAlex Crichton // The iterator returns generated addresses sorted by RangeIndex.
23987c33c29SAlex Crichton struct TransformRangeStartIter<'a> {
24087c33c29SAlex Crichton     addr: WasmAddress,
24187c33c29SAlex Crichton     indices: &'a [RangeIndex],
24287c33c29SAlex Crichton     ranges: &'a [Range],
24387c33c29SAlex Crichton }
24487c33c29SAlex Crichton 
24587c33c29SAlex Crichton impl<'a> TransformRangeStartIter<'a> {
new(func: &'a FuncTransform, addr: WasmAddress) -> Self24687c33c29SAlex Crichton     fn new(func: &'a FuncTransform, addr: WasmAddress) -> Self {
24787c33c29SAlex Crichton         let found = match func
24887c33c29SAlex Crichton             .lookup
24987c33c29SAlex Crichton             .index
25087c33c29SAlex Crichton             .binary_search_by(|entry| entry.0.cmp(&addr))
25187c33c29SAlex Crichton         {
25287c33c29SAlex Crichton             Ok(i) => Some(&func.lookup.index[i].1),
25387c33c29SAlex Crichton             Err(i) => {
25487c33c29SAlex Crichton                 if i > 0 {
25587c33c29SAlex Crichton                     Some(&func.lookup.index[i - 1].1)
25687c33c29SAlex Crichton                 } else {
25787c33c29SAlex Crichton                     None
25887c33c29SAlex Crichton                 }
25987c33c29SAlex Crichton             }
26087c33c29SAlex Crichton         };
26187c33c29SAlex Crichton         if let Some(range_indices) = found {
26287c33c29SAlex Crichton             TransformRangeStartIter {
26387c33c29SAlex Crichton                 addr,
26487c33c29SAlex Crichton                 indices: range_indices,
26587c33c29SAlex Crichton                 ranges: &func.lookup.ranges,
26687c33c29SAlex Crichton             }
26787c33c29SAlex Crichton         } else {
26887c33c29SAlex Crichton             unreachable!();
26987c33c29SAlex Crichton         }
27087c33c29SAlex Crichton     }
27187c33c29SAlex Crichton }
27287c33c29SAlex Crichton 
27387c33c29SAlex Crichton impl<'a> Iterator for TransformRangeStartIter<'a> {
27487c33c29SAlex Crichton     type Item = (GeneratedAddress, RangeIndex);
next(&mut self) -> Option<Self::Item>27587c33c29SAlex Crichton     fn next(&mut self) -> Option<Self::Item> {
27687c33c29SAlex Crichton         if let Some((first, tail)) = self.indices.split_first() {
27787c33c29SAlex Crichton             let range_index = *first;
27887c33c29SAlex Crichton             let range = &self.ranges[range_index];
27987c33c29SAlex Crichton             self.indices = tail;
28087c33c29SAlex Crichton             let address = match range
28187c33c29SAlex Crichton                 .positions
28287c33c29SAlex Crichton                 .binary_search_by(|a| a.wasm_pos.cmp(&self.addr))
28387c33c29SAlex Crichton             {
28487c33c29SAlex Crichton                 Ok(i) => range.positions[i].gen_start,
28587c33c29SAlex Crichton                 Err(i) => {
28687c33c29SAlex Crichton                     if i == 0 {
28787c33c29SAlex Crichton                         range.gen_start
28887c33c29SAlex Crichton                     } else {
28987c33c29SAlex Crichton                         range.positions[i - 1].gen_end
29087c33c29SAlex Crichton                     }
29187c33c29SAlex Crichton                 }
29287c33c29SAlex Crichton             };
29387c33c29SAlex Crichton             Some((address, range_index))
29487c33c29SAlex Crichton         } else {
29587c33c29SAlex Crichton             None
29687c33c29SAlex Crichton         }
29787c33c29SAlex Crichton     }
29887c33c29SAlex Crichton }
29987c33c29SAlex Crichton 
30087c33c29SAlex Crichton // Utility iterator to find all ranges ends for specific Wasm address.
30187c33c29SAlex Crichton // The iterator returns generated addresses sorted by RangeIndex.
30287c33c29SAlex Crichton struct TransformRangeEndIter<'a> {
30387c33c29SAlex Crichton     addr: WasmAddress,
30487c33c29SAlex Crichton     indices: &'a [RangeIndex],
30587c33c29SAlex Crichton     ranges: &'a [Range],
30687c33c29SAlex Crichton }
30787c33c29SAlex Crichton 
30887c33c29SAlex Crichton impl<'a> TransformRangeEndIter<'a> {
new(func: &'a FuncTransform, addr: WasmAddress) -> Self30987c33c29SAlex Crichton     fn new(func: &'a FuncTransform, addr: WasmAddress) -> Self {
31087c33c29SAlex Crichton         let found = match func
31187c33c29SAlex Crichton             .lookup
31287c33c29SAlex Crichton             .index
31387c33c29SAlex Crichton             .binary_search_by(|entry| entry.0.cmp(&addr))
31487c33c29SAlex Crichton         {
31587c33c29SAlex Crichton             Ok(i) => Some(&func.lookup.index[i].1),
31687c33c29SAlex Crichton             Err(i) => {
31787c33c29SAlex Crichton                 if i > 0 {
31887c33c29SAlex Crichton                     Some(&func.lookup.index[i - 1].1)
31987c33c29SAlex Crichton                 } else {
32087c33c29SAlex Crichton                     None
32187c33c29SAlex Crichton                 }
32287c33c29SAlex Crichton             }
32387c33c29SAlex Crichton         };
32487c33c29SAlex Crichton         if let Some(range_indices) = found {
32587c33c29SAlex Crichton             TransformRangeEndIter {
32687c33c29SAlex Crichton                 addr,
32787c33c29SAlex Crichton                 indices: range_indices,
32887c33c29SAlex Crichton                 ranges: &func.lookup.ranges,
32987c33c29SAlex Crichton             }
33087c33c29SAlex Crichton         } else {
33187c33c29SAlex Crichton             unreachable!();
33287c33c29SAlex Crichton         }
33387c33c29SAlex Crichton     }
33487c33c29SAlex Crichton }
33587c33c29SAlex Crichton 
33687c33c29SAlex Crichton impl<'a> Iterator for TransformRangeEndIter<'a> {
33787c33c29SAlex Crichton     type Item = (GeneratedAddress, RangeIndex);
next(&mut self) -> Option<Self::Item>33887c33c29SAlex Crichton     fn next(&mut self) -> Option<Self::Item> {
33987c33c29SAlex Crichton         while let Some((first, tail)) = self.indices.split_first() {
34087c33c29SAlex Crichton             let range_index = *first;
34187c33c29SAlex Crichton             let range = &self.ranges[range_index];
34287c33c29SAlex Crichton             self.indices = tail;
34387c33c29SAlex Crichton             if range.wasm_start >= self.addr {
34487c33c29SAlex Crichton                 continue;
34587c33c29SAlex Crichton             }
34687c33c29SAlex Crichton             let address = match range
34787c33c29SAlex Crichton                 .positions
34887c33c29SAlex Crichton                 .binary_search_by(|a| a.wasm_pos.cmp(&self.addr))
34987c33c29SAlex Crichton             {
35087c33c29SAlex Crichton                 Ok(i) => range.positions[i].gen_end,
35187c33c29SAlex Crichton                 Err(i) => {
35287c33c29SAlex Crichton                     if i == range.positions.len() {
35387c33c29SAlex Crichton                         range.gen_end
35487c33c29SAlex Crichton                     } else {
35587c33c29SAlex Crichton                         range.positions[i].gen_start
35687c33c29SAlex Crichton                     }
35787c33c29SAlex Crichton                 }
35887c33c29SAlex Crichton             };
35987c33c29SAlex Crichton             return Some((address, range_index));
36087c33c29SAlex Crichton         }
36187c33c29SAlex Crichton         None
36287c33c29SAlex Crichton     }
36387c33c29SAlex Crichton }
36487c33c29SAlex Crichton 
36587c33c29SAlex Crichton // Utility iterator to iterate by translated function ranges.
366dd8c48b3SAlex Crichton struct TransformRangeIter<'a> {
36787c33c29SAlex Crichton     func: &'a FuncTransform,
36887c33c29SAlex Crichton     start_it: TransformRangeStartIter<'a>,
36987c33c29SAlex Crichton     end_it: TransformRangeEndIter<'a>,
37087c33c29SAlex Crichton     last_start: Option<(GeneratedAddress, RangeIndex)>,
37187c33c29SAlex Crichton     last_end: Option<(GeneratedAddress, RangeIndex)>,
37287c33c29SAlex Crichton     last_item: Option<(GeneratedAddress, GeneratedAddress)>,
37387c33c29SAlex Crichton }
37487c33c29SAlex Crichton 
37587c33c29SAlex Crichton impl<'a> TransformRangeIter<'a> {
new(func: &'a FuncTransform, start: WasmAddress, end: WasmAddress) -> Self37687c33c29SAlex Crichton     fn new(func: &'a FuncTransform, start: WasmAddress, end: WasmAddress) -> Self {
37787c33c29SAlex Crichton         let mut start_it = TransformRangeStartIter::new(func, start);
37887c33c29SAlex Crichton         let last_start = start_it.next();
37987c33c29SAlex Crichton         let mut end_it = TransformRangeEndIter::new(func, end);
38087c33c29SAlex Crichton         let last_end = end_it.next();
38187c33c29SAlex Crichton         TransformRangeIter {
38287c33c29SAlex Crichton             func,
38387c33c29SAlex Crichton             start_it,
38487c33c29SAlex Crichton             end_it,
38587c33c29SAlex Crichton             last_start,
38687c33c29SAlex Crichton             last_end,
38787c33c29SAlex Crichton             last_item: None,
38887c33c29SAlex Crichton         }
38987c33c29SAlex Crichton     }
39087c33c29SAlex Crichton }
39187c33c29SAlex Crichton 
39287c33c29SAlex Crichton impl<'a> Iterator for TransformRangeIter<'a> {
39387c33c29SAlex Crichton     type Item = (GeneratedAddress, GeneratedAddress);
next(&mut self) -> Option<Self::Item>39487c33c29SAlex Crichton     fn next(&mut self) -> Option<Self::Item> {
39587c33c29SAlex Crichton         loop {
39687c33c29SAlex Crichton             // Merge TransformRangeStartIter and TransformRangeEndIter data using
3970e9121daSFrankReh             // FuncLookup index's field property to be sorted by RangeIndex.
39887c33c29SAlex Crichton             let (start, end, range_index): (
39987c33c29SAlex Crichton                 Option<GeneratedAddress>,
40087c33c29SAlex Crichton                 Option<GeneratedAddress>,
40187c33c29SAlex Crichton                 RangeIndex,
40287c33c29SAlex Crichton             ) = {
40387c33c29SAlex Crichton                 match (self.last_start.as_ref(), self.last_end.as_ref()) {
40487c33c29SAlex Crichton                     (Some((s, sri)), Some((e, eri))) => {
40587c33c29SAlex Crichton                         if sri == eri {
40687c33c29SAlex Crichton                             // Start and end RangeIndex matched.
40787c33c29SAlex Crichton                             (Some(*s), Some(*e), *sri)
40887c33c29SAlex Crichton                         } else if sri < eri {
40987c33c29SAlex Crichton                             (Some(*s), None, *sri)
41087c33c29SAlex Crichton                         } else {
41187c33c29SAlex Crichton                             (None, Some(*e), *eri)
41287c33c29SAlex Crichton                         }
41387c33c29SAlex Crichton                     }
41487c33c29SAlex Crichton                     (Some((s, sri)), None) => (Some(*s), None, *sri),
41587c33c29SAlex Crichton                     (None, Some((e, eri))) => (None, Some(*e), *eri),
41687c33c29SAlex Crichton                     (None, None) => {
41787c33c29SAlex Crichton                         // Reached ends for start and end iterators.
41887c33c29SAlex Crichton                         return None;
41987c33c29SAlex Crichton                     }
42087c33c29SAlex Crichton                 }
42187c33c29SAlex Crichton             };
42287c33c29SAlex Crichton             let range_start = match start {
42387c33c29SAlex Crichton                 Some(range_start) => {
42487c33c29SAlex Crichton                     // Consume start iterator.
42587c33c29SAlex Crichton                     self.last_start = self.start_it.next();
42687c33c29SAlex Crichton                     range_start
42787c33c29SAlex Crichton                 }
42887c33c29SAlex Crichton                 None => {
42987c33c29SAlex Crichton                     let range = &self.func.lookup.ranges[range_index];
43087c33c29SAlex Crichton                     range.gen_start
43187c33c29SAlex Crichton                 }
43287c33c29SAlex Crichton             };
43387c33c29SAlex Crichton             let range_end = match end {
43487c33c29SAlex Crichton                 Some(range_end) => {
43587c33c29SAlex Crichton                     // Consume end iterator.
43687c33c29SAlex Crichton                     self.last_end = self.end_it.next();
43787c33c29SAlex Crichton                     range_end
43887c33c29SAlex Crichton                 }
43987c33c29SAlex Crichton                 None => {
44087c33c29SAlex Crichton                     let range = &self.func.lookup.ranges[range_index];
44187c33c29SAlex Crichton                     range.gen_end
44287c33c29SAlex Crichton                 }
44387c33c29SAlex Crichton             };
44487c33c29SAlex Crichton 
44587c33c29SAlex Crichton             if cfg!(debug_assertions) {
44687c33c29SAlex Crichton                 match self.last_item.replace((range_start, range_end)) {
44787c33c29SAlex Crichton                     Some((_, last_end)) => debug_assert!(last_end <= range_start),
44887c33c29SAlex Crichton                     None => (),
44987c33c29SAlex Crichton                 }
45087c33c29SAlex Crichton             }
45187c33c29SAlex Crichton 
45287c33c29SAlex Crichton             if range_start < range_end {
45387c33c29SAlex Crichton                 return Some((range_start, range_end));
45487c33c29SAlex Crichton             }
45587c33c29SAlex Crichton             // Throw away empty ranges.
45687c33c29SAlex Crichton             debug_assert!(range_start == range_end);
45787c33c29SAlex Crichton         }
45887c33c29SAlex Crichton     }
45987c33c29SAlex Crichton }
46087c33c29SAlex Crichton 
46187c33c29SAlex Crichton impl AddressTransform {
new(compilation: &Compilation<'_>, module: StaticModuleIndex) -> Self462dd8c48b3SAlex Crichton     pub fn new(compilation: &Compilation<'_>, module: StaticModuleIndex) -> Self {
46387c33c29SAlex Crichton         let mut func = BTreeMap::new();
464dd8c48b3SAlex Crichton         let code_section_offset = compilation.translations[module]
465dd8c48b3SAlex Crichton             .debuginfo
466dd8c48b3SAlex Crichton             .wasm_file
467dd8c48b3SAlex Crichton             .code_section_offset;
468dd8c48b3SAlex Crichton 
469dd8c48b3SAlex Crichton         for idx in compilation.translations[module]
470dd8c48b3SAlex Crichton             .module
471dd8c48b3SAlex Crichton             .defined_func_indices()
472dd8c48b3SAlex Crichton         {
473dd8c48b3SAlex Crichton             let (_, metadata) = compilation.function(module, idx);
4741cbca5a5SSaúl Cabrera             let (fn_start, fn_end, lookup) =
4751cbca5a5SSaúl Cabrera                 build_function_lookup(&metadata.address_map, code_section_offset);
47687c33c29SAlex Crichton 
47787c33c29SAlex Crichton             func.insert(
47887c33c29SAlex Crichton                 fn_start,
47987c33c29SAlex Crichton                 FuncTransform {
48087c33c29SAlex Crichton                     start: fn_start,
48187c33c29SAlex Crichton                     end: fn_end,
482dd8c48b3SAlex Crichton                     index: idx,
48387c33c29SAlex Crichton                     lookup,
48487c33c29SAlex Crichton                 },
48587c33c29SAlex Crichton             );
48687c33c29SAlex Crichton         }
48787c33c29SAlex Crichton 
488dd8c48b3SAlex Crichton         let map = build_function_addr_map(compilation, module);
489703871a2SAlex Crichton         let func = Vec::from_iter(func);
49087c33c29SAlex Crichton         AddressTransform { map, func }
49187c33c29SAlex Crichton     }
49287c33c29SAlex Crichton 
493dd8c48b3SAlex Crichton     #[cfg(test)]
mock( module_map: &wasmtime_environ::PrimaryMap< wasmtime_environ::DefinedFuncIndex, &crate::CompiledFunctionMetadata, >, wasm_file: wasmtime_environ::WasmFileInfo, ) -> Self494dd8c48b3SAlex Crichton     pub fn mock(
495dd8c48b3SAlex Crichton         module_map: &wasmtime_environ::PrimaryMap<
496dd8c48b3SAlex Crichton             wasmtime_environ::DefinedFuncIndex,
497dd8c48b3SAlex Crichton             &crate::CompiledFunctionMetadata,
498dd8c48b3SAlex Crichton         >,
499dd8c48b3SAlex Crichton         wasm_file: wasmtime_environ::WasmFileInfo,
500dd8c48b3SAlex Crichton     ) -> Self {
501*cfc05638SNick Fitzgerald         use cranelift_entity::EntityRef;
502*cfc05638SNick Fitzgerald 
503dd8c48b3SAlex Crichton         let mut translations = wasmtime_environ::PrimaryMap::new();
504*cfc05638SNick Fitzgerald         let mut translation = wasmtime_environ::ModuleTranslation::new(StaticModuleIndex::new(0));
505dd8c48b3SAlex Crichton         translation.debuginfo.wasm_file = wasm_file;
506dd8c48b3SAlex Crichton         translation
507dd8c48b3SAlex Crichton             .module
508dd8c48b3SAlex Crichton             .push_function(wasmtime_environ::ModuleInternedTypeIndex::from_u32(0));
509dd8c48b3SAlex Crichton         translations.push(translation);
510dd8c48b3SAlex Crichton 
511dd8c48b3SAlex Crichton         let mut dummy_obj = object::write::Object::new(
512dd8c48b3SAlex Crichton             object::BinaryFormat::Elf,
513dd8c48b3SAlex Crichton             object::Architecture::Wasm32,
514dd8c48b3SAlex Crichton             object::Endianness::Little,
515dd8c48b3SAlex Crichton         );
516dd8c48b3SAlex Crichton         let dummy_symbol = dummy_obj.add_file_symbol(Vec::new());
517dd8c48b3SAlex Crichton         let func_lookup = move |_, f| (dummy_symbol, module_map[f]);
518dd8c48b3SAlex Crichton         let tunables = wasmtime_environ::Tunables::default_host();
519dd8c48b3SAlex Crichton         let compile = Compilation::new(
520dd8c48b3SAlex Crichton             &*cranelift_codegen::isa::lookup(target_lexicon::Triple::host())
521dd8c48b3SAlex Crichton                 .unwrap()
522dd8c48b3SAlex Crichton                 .finish(cranelift_codegen::settings::Flags::new(
523dd8c48b3SAlex Crichton                     cranelift_codegen::settings::builder(),
524dd8c48b3SAlex Crichton                 ))
525dd8c48b3SAlex Crichton                 .unwrap(),
526dd8c48b3SAlex Crichton             &translations,
527dd8c48b3SAlex Crichton             &func_lookup,
528dd8c48b3SAlex Crichton             None,
529dd8c48b3SAlex Crichton             &tunables,
530dd8c48b3SAlex Crichton         );
531dd8c48b3SAlex Crichton         Self::new(&compile, StaticModuleIndex::from_u32(0))
532dd8c48b3SAlex Crichton     }
533dd8c48b3SAlex Crichton 
find_func(&self, addr: u64) -> Option<&FuncTransform>53487c33c29SAlex Crichton     fn find_func(&self, addr: u64) -> Option<&FuncTransform> {
53587c33c29SAlex Crichton         // TODO check if we need to include end address
53687c33c29SAlex Crichton         let func = match self.func.binary_search_by(|entry| entry.0.cmp(&addr)) {
53787c33c29SAlex Crichton             Ok(i) => &self.func[i].1,
53887c33c29SAlex Crichton             Err(i) => {
53987c33c29SAlex Crichton                 if i > 0 {
54087c33c29SAlex Crichton                     &self.func[i - 1].1
54187c33c29SAlex Crichton                 } else {
54287c33c29SAlex Crichton                     return None;
54387c33c29SAlex Crichton                 }
54487c33c29SAlex Crichton             }
54587c33c29SAlex Crichton         };
54687c33c29SAlex Crichton         if addr >= func.start {
54787c33c29SAlex Crichton             return Some(func);
54887c33c29SAlex Crichton         }
54987c33c29SAlex Crichton         None
55087c33c29SAlex Crichton     }
55187c33c29SAlex Crichton 
find_func_index(&self, addr: u64) -> Option<DefinedFuncIndex>55287c33c29SAlex Crichton     pub fn find_func_index(&self, addr: u64) -> Option<DefinedFuncIndex> {
55387c33c29SAlex Crichton         self.find_func(addr).map(|f| f.index)
55487c33c29SAlex Crichton     }
55587c33c29SAlex Crichton 
translate_raw(&self, addr: u64) -> Option<(usize, GeneratedAddress)>556dd8c48b3SAlex Crichton     fn translate_raw(&self, addr: u64) -> Option<(usize, GeneratedAddress)> {
5579b0e1b9dSPhilip Craig         const TOMBSTONE: u64 = u32::MAX as u64;
5589b0e1b9dSPhilip Craig         if addr == 0 || addr == TOMBSTONE {
5599b0e1b9dSPhilip Craig             // Addresses for unlinked code may be left as 0 or replaced
5609b0e1b9dSPhilip Craig             // with -1, depending on the linker used.
56187c33c29SAlex Crichton             return None;
56287c33c29SAlex Crichton         }
56387c33c29SAlex Crichton         if let Some(func) = self.find_func(addr) {
564dd8c48b3SAlex Crichton             let map = &self.map[func.index];
56587c33c29SAlex Crichton             if addr == func.end {
56687c33c29SAlex Crichton                 // Clamp last address to the end to extend translation to the end
56787c33c29SAlex Crichton                 // of the function.
568dd8c48b3SAlex Crichton                 return Some((map.symbol, map.len));
56987c33c29SAlex Crichton             }
57087c33c29SAlex Crichton             let first_result = TransformRangeStartIter::new(func, addr).next();
571dd8c48b3SAlex Crichton             first_result.map(|(address, _)| (map.symbol, address))
57287c33c29SAlex Crichton         } else {
57387c33c29SAlex Crichton             // Address was not found: function was not compiled?
57487c33c29SAlex Crichton             None
57587c33c29SAlex Crichton         }
57687c33c29SAlex Crichton     }
57787c33c29SAlex Crichton 
can_translate_address(&self, addr: u64) -> bool57887c33c29SAlex Crichton     pub fn can_translate_address(&self, addr: u64) -> bool {
57987c33c29SAlex Crichton         self.translate(addr).is_some()
58087c33c29SAlex Crichton     }
58187c33c29SAlex Crichton 
translate(&self, addr: u64) -> Option<write::Address>58287c33c29SAlex Crichton     pub fn translate(&self, addr: u64) -> Option<write::Address> {
58387c33c29SAlex Crichton         self.translate_raw(addr)
584dd8c48b3SAlex Crichton             .map(|(symbol, address)| write::Address::Symbol {
585dd8c48b3SAlex Crichton                 symbol,
58687c33c29SAlex Crichton                 addend: address as i64,
58787c33c29SAlex Crichton             })
58887c33c29SAlex Crichton     }
58987c33c29SAlex Crichton 
translate_ranges_raw<'a>( &'a self, start: u64, end: u64, ) -> Option<(usize, impl Iterator<Item = (usize, usize)> + 'a)>59087c33c29SAlex Crichton     pub fn translate_ranges_raw<'a>(
59187c33c29SAlex Crichton         &'a self,
59287c33c29SAlex Crichton         start: u64,
59387c33c29SAlex Crichton         end: u64,
594dd8c48b3SAlex Crichton     ) -> Option<(usize, impl Iterator<Item = (usize, usize)> + 'a)> {
59587c33c29SAlex Crichton         if start == 0 {
59687c33c29SAlex Crichton             // It's normally 0 for debug info without the linked code.
59787c33c29SAlex Crichton             return None;
59887c33c29SAlex Crichton         }
59987c33c29SAlex Crichton         if let Some(func) = self.find_func(start) {
60087c33c29SAlex Crichton             let result = TransformRangeIter::new(func, start, end);
601dd8c48b3SAlex Crichton             let symbol = self.map[func.index].symbol;
602dd8c48b3SAlex Crichton             return Some((symbol, result));
60387c33c29SAlex Crichton         }
60487c33c29SAlex Crichton         // Address was not found: function was not compiled?
60587c33c29SAlex Crichton         None
60687c33c29SAlex Crichton     }
60787c33c29SAlex Crichton 
translate_ranges<'a>( &'a self, start: u64, end: u64, ) -> impl Iterator<Item = (write::Address, u64)> + 'a60887c33c29SAlex Crichton     pub fn translate_ranges<'a>(
60987c33c29SAlex Crichton         &'a self,
61087c33c29SAlex Crichton         start: u64,
61187c33c29SAlex Crichton         end: u64,
61287c33c29SAlex Crichton     ) -> impl Iterator<Item = (write::Address, u64)> + 'a {
61387c33c29SAlex Crichton         enum TranslateRangesResult<'a> {
61487c33c29SAlex Crichton             Empty,
61587c33c29SAlex Crichton             Raw {
61687c33c29SAlex Crichton                 symbol: usize,
61787c33c29SAlex Crichton                 it: Box<dyn Iterator<Item = (usize, usize)> + 'a>,
61887c33c29SAlex Crichton             },
61987c33c29SAlex Crichton         }
62087c33c29SAlex Crichton         impl<'a> Iterator for TranslateRangesResult<'a> {
62187c33c29SAlex Crichton             type Item = (write::Address, u64);
62287c33c29SAlex Crichton             fn next(&mut self) -> Option<Self::Item> {
62387c33c29SAlex Crichton                 match self {
62487c33c29SAlex Crichton                     TranslateRangesResult::Empty => None,
62587c33c29SAlex Crichton                     TranslateRangesResult::Raw { symbol, it } => match it.next() {
62687c33c29SAlex Crichton                         Some((start, end)) => {
62787c33c29SAlex Crichton                             debug_assert!(start < end);
62887c33c29SAlex Crichton                             Some((
62987c33c29SAlex Crichton                                 write::Address::Symbol {
63087c33c29SAlex Crichton                                     symbol: *symbol,
63187c33c29SAlex Crichton                                     addend: start as i64,
63287c33c29SAlex Crichton                                 },
63387c33c29SAlex Crichton                                 (end - start) as u64,
63487c33c29SAlex Crichton                             ))
63587c33c29SAlex Crichton                         }
63687c33c29SAlex Crichton                         None => None,
63787c33c29SAlex Crichton                     },
63887c33c29SAlex Crichton                 }
63987c33c29SAlex Crichton             }
64087c33c29SAlex Crichton         }
64187c33c29SAlex Crichton 
64287c33c29SAlex Crichton         match self.translate_ranges_raw(start, end) {
643dd8c48b3SAlex Crichton             Some((symbol, ranges)) => TranslateRangesResult::Raw {
644dd8c48b3SAlex Crichton                 symbol,
64587c33c29SAlex Crichton                 it: Box::new(ranges),
64687c33c29SAlex Crichton             },
64787c33c29SAlex Crichton             None => TranslateRangesResult::Empty,
64887c33c29SAlex Crichton         }
64987c33c29SAlex Crichton     }
65087c33c29SAlex Crichton 
map(&self) -> &PrimaryMap<DefinedFuncIndex, FunctionMap>65187c33c29SAlex Crichton     pub fn map(&self) -> &PrimaryMap<DefinedFuncIndex, FunctionMap> {
65287c33c29SAlex Crichton         &self.map
65387c33c29SAlex Crichton     }
65487c33c29SAlex Crichton 
func_range(&self, index: DefinedFuncIndex) -> (GeneratedAddress, GeneratedAddress)65587c33c29SAlex Crichton     pub fn func_range(&self, index: DefinedFuncIndex) -> (GeneratedAddress, GeneratedAddress) {
65687c33c29SAlex Crichton         let map = &self.map[index];
65787c33c29SAlex Crichton         (map.offset, map.offset + map.len)
65887c33c29SAlex Crichton     }
65987c33c29SAlex Crichton 
func_source_range(&self, index: DefinedFuncIndex) -> (WasmAddress, WasmAddress)66087c33c29SAlex Crichton     pub fn func_source_range(&self, index: DefinedFuncIndex) -> (WasmAddress, WasmAddress) {
66187c33c29SAlex Crichton         let map = &self.map[index];
66287c33c29SAlex Crichton         (map.wasm_start, map.wasm_end)
66387c33c29SAlex Crichton     }
66487c33c29SAlex Crichton }
66587c33c29SAlex Crichton 
66687c33c29SAlex Crichton #[cfg(test)]
66787c33c29SAlex Crichton mod tests {
66890ac295eSAlex Crichton     use super::{AddressTransform, build_function_lookup, get_wasm_code_offset};
669b545cc50STrevor Elliott     use crate::{CompiledFunctionMetadata, FunctionAddressMap};
67087c33c29SAlex Crichton     use cranelift_entity::PrimaryMap;
67187c33c29SAlex Crichton     use gimli::write::Address;
67287c33c29SAlex Crichton     use std::mem;
673fc911766SAlex Crichton     use wasmtime_environ::{FilePos, InstructionAddressMap, WasmFileInfo};
67487c33c29SAlex Crichton 
67587c33c29SAlex Crichton     #[test]
test_get_wasm_code_offset()67687c33c29SAlex Crichton     fn test_get_wasm_code_offset() {
67787c33c29SAlex Crichton         let offset = get_wasm_code_offset(FilePos::new(3), 1);
67887c33c29SAlex Crichton         assert_eq!(2, offset);
67987c33c29SAlex Crichton         let offset = get_wasm_code_offset(FilePos::new(16), 0xF000_0000);
68087c33c29SAlex Crichton         assert_eq!(0x1000_0010, offset);
68187c33c29SAlex Crichton         let offset = get_wasm_code_offset(FilePos::new(1), 0x20_8000_0000);
68287c33c29SAlex Crichton         assert_eq!(0x8000_0001, offset);
68387c33c29SAlex Crichton     }
68487c33c29SAlex Crichton 
create_simple_func(wasm_offset: u32) -> FunctionAddressMap68587c33c29SAlex Crichton     fn create_simple_func(wasm_offset: u32) -> FunctionAddressMap {
68687c33c29SAlex Crichton         FunctionAddressMap {
68787c33c29SAlex Crichton             instructions: vec![
68887c33c29SAlex Crichton                 InstructionAddressMap {
68987c33c29SAlex Crichton                     srcloc: FilePos::new(wasm_offset + 2),
69087c33c29SAlex Crichton                     code_offset: 5,
69187c33c29SAlex Crichton                 },
69287c33c29SAlex Crichton                 InstructionAddressMap {
69387c33c29SAlex Crichton                     srcloc: FilePos::default(),
69487c33c29SAlex Crichton                     code_offset: 8,
69587c33c29SAlex Crichton                 },
69687c33c29SAlex Crichton                 InstructionAddressMap {
69787c33c29SAlex Crichton                     srcloc: FilePos::new(wasm_offset + 7),
69887c33c29SAlex Crichton                     code_offset: 15,
69987c33c29SAlex Crichton                 },
70087c33c29SAlex Crichton                 InstructionAddressMap {
70187c33c29SAlex Crichton                     srcloc: FilePos::default(),
70287c33c29SAlex Crichton                     code_offset: 23,
70387c33c29SAlex Crichton                 },
70487c33c29SAlex Crichton             ]
70587c33c29SAlex Crichton             .into(),
70687c33c29SAlex Crichton             start_srcloc: FilePos::new(wasm_offset),
70787c33c29SAlex Crichton             end_srcloc: FilePos::new(wasm_offset + 10),
70887c33c29SAlex Crichton             body_offset: 0,
70987c33c29SAlex Crichton             body_len: 30,
71087c33c29SAlex Crichton         }
71187c33c29SAlex Crichton     }
71287c33c29SAlex Crichton 
71387c33c29SAlex Crichton     #[test]
test_build_function_lookup_simple()71487c33c29SAlex Crichton     fn test_build_function_lookup_simple() {
71587c33c29SAlex Crichton         let input = create_simple_func(11);
71687c33c29SAlex Crichton         let (start, end, lookup) = build_function_lookup(&input, 1);
71787c33c29SAlex Crichton         assert_eq!(10, start);
71887c33c29SAlex Crichton         assert_eq!(20, end);
71987c33c29SAlex Crichton 
72087c33c29SAlex Crichton         assert_eq!(1, lookup.index.len());
72187c33c29SAlex Crichton         let index_entry = lookup.index.into_iter().next().unwrap();
72287c33c29SAlex Crichton         assert_eq!((10u64, vec![0].into_boxed_slice()), index_entry);
72387c33c29SAlex Crichton         assert_eq!(1, lookup.ranges.len());
72487c33c29SAlex Crichton         let range = &lookup.ranges[0];
72587c33c29SAlex Crichton         assert_eq!(10, range.wasm_start);
72687c33c29SAlex Crichton         assert_eq!(20, range.wasm_end);
72787c33c29SAlex Crichton         assert_eq!(0, range.gen_start);
72887c33c29SAlex Crichton         assert_eq!(30, range.gen_end);
72987c33c29SAlex Crichton         let positions = &range.positions;
73087c33c29SAlex Crichton         assert_eq!(2, positions.len());
73187c33c29SAlex Crichton         assert_eq!(12, positions[0].wasm_pos);
73287c33c29SAlex Crichton         assert_eq!(5, positions[0].gen_start);
73387c33c29SAlex Crichton         assert_eq!(8, positions[0].gen_end);
73487c33c29SAlex Crichton         assert_eq!(17, positions[1].wasm_pos);
73587c33c29SAlex Crichton         assert_eq!(15, positions[1].gen_start);
73687c33c29SAlex Crichton         assert_eq!(23, positions[1].gen_end);
73787c33c29SAlex Crichton     }
73887c33c29SAlex Crichton 
73987c33c29SAlex Crichton     #[test]
test_build_function_lookup_two_ranges()74087c33c29SAlex Crichton     fn test_build_function_lookup_two_ranges() {
74187c33c29SAlex Crichton         let mut input = create_simple_func(11);
74287c33c29SAlex Crichton         // append instruction with same srcloc as input.instructions[0]
74387c33c29SAlex Crichton         let mut list = Vec::from(mem::take(&mut input.instructions));
74487c33c29SAlex Crichton         list.push(InstructionAddressMap {
74587c33c29SAlex Crichton             srcloc: FilePos::new(11 + 2),
74687c33c29SAlex Crichton             code_offset: 23,
74787c33c29SAlex Crichton         });
74887c33c29SAlex Crichton         list.push(InstructionAddressMap {
74987c33c29SAlex Crichton             srcloc: FilePos::default(),
75087c33c29SAlex Crichton             code_offset: 26,
75187c33c29SAlex Crichton         });
75287c33c29SAlex Crichton         input.instructions = list.into();
75387c33c29SAlex Crichton         let (start, end, lookup) = build_function_lookup(&input, 1);
75487c33c29SAlex Crichton         assert_eq!(10, start);
75587c33c29SAlex Crichton         assert_eq!(20, end);
75687c33c29SAlex Crichton 
75787c33c29SAlex Crichton         assert_eq!(2, lookup.index.len());
758703871a2SAlex Crichton         let index_entries = Vec::from_iter(lookup.index);
75987c33c29SAlex Crichton         assert_eq!((10u64, vec![0].into_boxed_slice()), index_entries[0]);
76087c33c29SAlex Crichton         assert_eq!((12u64, vec![0, 1].into_boxed_slice()), index_entries[1]);
76187c33c29SAlex Crichton         assert_eq!(2, lookup.ranges.len());
76287c33c29SAlex Crichton 
76387c33c29SAlex Crichton         let range = &lookup.ranges[0];
76487c33c29SAlex Crichton         assert_eq!(10, range.wasm_start);
76587c33c29SAlex Crichton         assert_eq!(17, range.wasm_end);
76687c33c29SAlex Crichton         assert_eq!(0, range.gen_start);
76787c33c29SAlex Crichton         assert_eq!(23, range.gen_end);
76887c33c29SAlex Crichton         let positions = &range.positions;
76987c33c29SAlex Crichton         assert_eq!(2, positions.len());
77087c33c29SAlex Crichton         assert_eq!(12, positions[0].wasm_pos);
77187c33c29SAlex Crichton         assert_eq!(5, positions[0].gen_start);
77287c33c29SAlex Crichton         assert_eq!(8, positions[0].gen_end);
77387c33c29SAlex Crichton         assert_eq!(17, positions[1].wasm_pos);
77487c33c29SAlex Crichton         assert_eq!(15, positions[1].gen_start);
77587c33c29SAlex Crichton         assert_eq!(23, positions[1].gen_end);
77687c33c29SAlex Crichton 
77787c33c29SAlex Crichton         let range = &lookup.ranges[1];
77887c33c29SAlex Crichton         assert_eq!(12, range.wasm_start);
77987c33c29SAlex Crichton         assert_eq!(20, range.wasm_end);
78087c33c29SAlex Crichton         assert_eq!(23, range.gen_start);
78187c33c29SAlex Crichton         assert_eq!(30, range.gen_end);
78287c33c29SAlex Crichton         let positions = &range.positions;
78387c33c29SAlex Crichton         assert_eq!(1, positions.len());
78487c33c29SAlex Crichton         assert_eq!(12, positions[0].wasm_pos);
78587c33c29SAlex Crichton         assert_eq!(23, positions[0].gen_start);
78687c33c29SAlex Crichton         assert_eq!(26, positions[0].gen_end);
78787c33c29SAlex Crichton     }
78887c33c29SAlex Crichton 
78987c33c29SAlex Crichton     #[test]
test_addr_translate()79087c33c29SAlex Crichton     fn test_addr_translate() {
79148f4621fSAlex Crichton         // Ignore this test if cranelift doesn't support the native platform.
79248f4621fSAlex Crichton         if cranelift_native::builder().is_err() {
79348f4621fSAlex Crichton             return;
79448f4621fSAlex Crichton         }
7951cbca5a5SSaúl Cabrera         let func = CompiledFunctionMetadata {
796cd53bed8SAlex Crichton             address_map: create_simple_func(11),
797cd53bed8SAlex Crichton             ..Default::default()
798cd53bed8SAlex Crichton         };
799cd53bed8SAlex Crichton         let input = PrimaryMap::from_iter([&func]);
800dd8c48b3SAlex Crichton         let at = AddressTransform::mock(
80187c33c29SAlex Crichton             &input,
802dd8c48b3SAlex Crichton             WasmFileInfo {
80387c33c29SAlex Crichton                 path: None,
80487c33c29SAlex Crichton                 code_section_offset: 1,
80587c33c29SAlex Crichton                 imported_func_count: 0,
80687c33c29SAlex Crichton                 funcs: Vec::new(),
80787c33c29SAlex Crichton             },
80887c33c29SAlex Crichton         );
80987c33c29SAlex Crichton 
81087c33c29SAlex Crichton         let addr = at.translate(10);
81187c33c29SAlex Crichton         assert_eq!(
81287c33c29SAlex Crichton             Some(Address::Symbol {
81387c33c29SAlex Crichton                 symbol: 0,
81487c33c29SAlex Crichton                 addend: 0,
81587c33c29SAlex Crichton             }),
81687c33c29SAlex Crichton             addr
81787c33c29SAlex Crichton         );
81887c33c29SAlex Crichton 
81987c33c29SAlex Crichton         let addr = at.translate(20);
82087c33c29SAlex Crichton         assert_eq!(
82187c33c29SAlex Crichton             Some(Address::Symbol {
82287c33c29SAlex Crichton                 symbol: 0,
82387c33c29SAlex Crichton                 addend: 30,
82487c33c29SAlex Crichton             }),
82587c33c29SAlex Crichton             addr
82687c33c29SAlex Crichton         );
82787c33c29SAlex Crichton 
82887c33c29SAlex Crichton         let addr = at.translate(0);
82987c33c29SAlex Crichton         assert_eq!(None, addr);
83087c33c29SAlex Crichton 
83187c33c29SAlex Crichton         let addr = at.translate(12);
83287c33c29SAlex Crichton         assert_eq!(
83387c33c29SAlex Crichton             Some(Address::Symbol {
83487c33c29SAlex Crichton                 symbol: 0,
83587c33c29SAlex Crichton                 addend: 5,
83687c33c29SAlex Crichton             }),
83787c33c29SAlex Crichton             addr
83887c33c29SAlex Crichton         );
83987c33c29SAlex Crichton 
84087c33c29SAlex Crichton         let addr = at.translate(18);
84187c33c29SAlex Crichton         assert_eq!(
84287c33c29SAlex Crichton             Some(Address::Symbol {
84387c33c29SAlex Crichton                 symbol: 0,
84487c33c29SAlex Crichton                 addend: 23,
84587c33c29SAlex Crichton             }),
84687c33c29SAlex Crichton             addr
84787c33c29SAlex Crichton         );
84887c33c29SAlex Crichton     }
84987c33c29SAlex Crichton }
850