1use crate::{CompiledFunctions, FunctionAddressMap};
2use gimli::write;
3use std::collections::BTreeMap;
4use std::iter::FromIterator;
5use wasmtime_environ::{DefinedFuncIndex, EntityRef, FilePos, PrimaryMap, WasmFileInfo};
6
7pub type GeneratedAddress = usize;
8pub type WasmAddress = u64;
9
10#[derive(Debug)]
13pub struct AddressMap {
14 pub generated: GeneratedAddress,
15 pub wasm: WasmAddress,
16}
17
18#[derive(Debug)]
21pub struct FunctionMap {
22 pub offset: GeneratedAddress,
23 pub len: GeneratedAddress,
24 pub wasm_start: WasmAddress,
25 pub wasm_end: WasmAddress,
26 pub addresses: Box<[AddressMap]>,
27}
28
29#[derive(Debug)]
31struct Position {
32 wasm_pos: WasmAddress,
33 gen_start: GeneratedAddress,
34 gen_end: GeneratedAddress,
35}
36
37#[derive(Debug)]
40struct Range {
41 wasm_start: WasmAddress,
42 wasm_end: WasmAddress,
43 gen_start: GeneratedAddress,
44 gen_end: GeneratedAddress,
45 positions: Box<[Position]>,
46}
47
48type RangeIndex = usize;
49
50#[derive(Debug)]
56struct FuncLookup {
57 index: Vec<(WasmAddress, Box<[RangeIndex]>)>,
58 ranges: Box<[Range]>,
59}
60
61#[derive(Debug)]
63struct FuncTransform {
64 start: WasmAddress,
65 end: WasmAddress,
66 index: DefinedFuncIndex,
67 lookup: FuncLookup,
68}
69
70#[derive(Debug)]
72pub struct AddressTransform {
73 map: PrimaryMap<DefinedFuncIndex, FunctionMap>,
74 func: Vec<(WasmAddress, FuncTransform)>,
75}
76
77fn get_wasm_code_offset(loc: FilePos, code_section_offset: u64) -> WasmAddress {
79 loc.file_offset()
81 .unwrap()
82 .wrapping_sub(code_section_offset as u32) as WasmAddress
83}
84
85fn build_function_lookup(
86 ft: &FunctionAddressMap,
87 code_section_offset: u64,
88) -> (WasmAddress, WasmAddress, FuncLookup) {
89 assert!(code_section_offset <= ft.start_srcloc.file_offset().unwrap().into());
90 let fn_start = get_wasm_code_offset(ft.start_srcloc, code_section_offset);
91 let fn_end = get_wasm_code_offset(ft.end_srcloc, code_section_offset);
92 assert!(fn_start <= fn_end);
93
94 let mut range_wasm_start = fn_start;
98 let mut range_gen_start = ft.body_offset;
99 let mut last_wasm_pos = range_wasm_start;
100 let mut ranges = Vec::new();
101 let mut ranges_index = BTreeMap::new();
102 let mut current_range = Vec::new();
103 let mut last_gen_inst_empty = false;
104 for (i, t) in ft.instructions.iter().enumerate() {
105 if t.srcloc.file_offset().is_none() {
106 continue;
107 }
108
109 let offset = get_wasm_code_offset(t.srcloc, code_section_offset);
110 assert!(fn_start <= offset);
111 assert!(offset <= fn_end);
112
113 let inst_gen_start = t.code_offset as usize;
114 let inst_gen_end = match ft.instructions.get(i + 1) {
115 Some(i) => i.code_offset as usize,
116 None => ft.body_len as usize,
117 };
118
119 if last_wasm_pos > offset {
120 ranges_index.insert(range_wasm_start, ranges.len());
122 ranges.push(Range {
123 wasm_start: range_wasm_start,
124 wasm_end: last_wasm_pos,
125 gen_start: range_gen_start,
126 gen_end: inst_gen_start,
127 positions: current_range.into_boxed_slice(),
128 });
129 range_wasm_start = offset;
130 range_gen_start = inst_gen_start;
131 current_range = Vec::new();
132 last_gen_inst_empty = false;
133 }
134 if last_gen_inst_empty && current_range.last().unwrap().gen_start == inst_gen_start {
135 if inst_gen_start < inst_gen_end {
138 let last = current_range.last_mut().unwrap();
139 last.gen_end = inst_gen_end;
140 last_gen_inst_empty = false;
141 }
142 } else {
143 current_range.push(Position {
145 wasm_pos: offset,
146 gen_start: inst_gen_start,
147 gen_end: inst_gen_end,
148 });
149 last_gen_inst_empty = inst_gen_start == inst_gen_end;
151 }
152 last_wasm_pos = offset;
153 }
154 let last_gen_addr = ft.body_offset + ft.body_len as usize;
155 ranges_index.insert(range_wasm_start, ranges.len());
156 ranges.push(Range {
157 wasm_start: range_wasm_start,
158 wasm_end: fn_end,
159 gen_start: range_gen_start,
160 gen_end: last_gen_addr,
161 positions: current_range.into_boxed_slice(),
162 });
163
164 let ranges = ranges.into_boxed_slice();
167 let mut active_ranges = Vec::new();
168 let mut index = BTreeMap::new();
169 let mut last_wasm_pos = None;
170 for (wasm_start, range_index) in ranges_index {
171 if Some(wasm_start) == last_wasm_pos {
172 active_ranges.push(range_index);
173 continue;
174 }
175 if let Some(position) = last_wasm_pos {
176 let mut sorted_ranges = active_ranges.clone();
177 sorted_ranges.sort();
178 index.insert(position, sorted_ranges.into_boxed_slice());
179 }
180 active_ranges.retain(|r| ranges[*r].wasm_end.cmp(&wasm_start) != std::cmp::Ordering::Less);
181 active_ranges.push(range_index);
182 last_wasm_pos = Some(wasm_start);
183 }
184 active_ranges.sort();
185 index.insert(last_wasm_pos.unwrap(), active_ranges.into_boxed_slice());
186 let index = Vec::from_iter(index.into_iter());
187 (fn_start, fn_end, FuncLookup { index, ranges })
188}
189
190fn build_function_addr_map(
191 funcs: &CompiledFunctions,
192 code_section_offset: u64,
193) -> PrimaryMap<DefinedFuncIndex, FunctionMap> {
194 let mut map = PrimaryMap::new();
195 for (_, f) in funcs {
196 let ft = &f.address_map;
197 let mut fn_map = Vec::new();
198 for t in ft.instructions.iter() {
199 if t.srcloc.file_offset().is_none() {
200 continue;
201 }
202 let offset = get_wasm_code_offset(t.srcloc, code_section_offset);
203 fn_map.push(AddressMap {
204 generated: t.code_offset as usize,
205 wasm: offset,
206 });
207 }
208
209 if cfg!(debug_assertions) {
210 for i in 1..fn_map.len() {
212 assert!(fn_map[i - 1].generated <= fn_map[i].generated);
213 }
214 }
215
216 map.push(FunctionMap {
217 offset: ft.body_offset,
218 len: ft.body_len as usize,
219 wasm_start: get_wasm_code_offset(ft.start_srcloc, code_section_offset),
220 wasm_end: get_wasm_code_offset(ft.end_srcloc, code_section_offset),
221 addresses: fn_map.into_boxed_slice(),
222 });
223 }
224 map
225}
226
227struct TransformRangeStartIter<'a> {
230 addr: WasmAddress,
231 indices: &'a [RangeIndex],
232 ranges: &'a [Range],
233}
234
235impl<'a> TransformRangeStartIter<'a> {
236 fn new(func: &'a FuncTransform, addr: WasmAddress) -> Self {
237 let found = match func
238 .lookup
239 .index
240 .binary_search_by(|entry| entry.0.cmp(&addr))
241 {
242 Ok(i) => Some(&func.lookup.index[i].1),
243 Err(i) => {
244 if i > 0 {
245 Some(&func.lookup.index[i - 1].1)
246 } else {
247 None
248 }
249 }
250 };
251 if let Some(range_indices) = found {
252 TransformRangeStartIter {
253 addr,
254 indices: range_indices,
255 ranges: &func.lookup.ranges,
256 }
257 } else {
258 unreachable!();
259 }
260 }
261}
262
263impl<'a> Iterator for TransformRangeStartIter<'a> {
264 type Item = (GeneratedAddress, RangeIndex);
265 fn next(&mut self) -> Option<Self::Item> {
266 if let Some((first, tail)) = self.indices.split_first() {
267 let range_index = *first;
268 let range = &self.ranges[range_index];
269 self.indices = tail;
270 let address = match range
271 .positions
272 .binary_search_by(|a| a.wasm_pos.cmp(&self.addr))
273 {
274 Ok(i) => range.positions[i].gen_start,
275 Err(i) => {
276 if i == 0 {
277 range.gen_start
278 } else {
279 range.positions[i - 1].gen_end
280 }
281 }
282 };
283 Some((address, range_index))
284 } else {
285 None
286 }
287 }
288}
289
290struct TransformRangeEndIter<'a> {
293 addr: WasmAddress,
294 indices: &'a [RangeIndex],
295 ranges: &'a [Range],
296}
297
298impl<'a> TransformRangeEndIter<'a> {
299 fn new(func: &'a FuncTransform, addr: WasmAddress) -> Self {
300 let found = match func
301 .lookup
302 .index
303 .binary_search_by(|entry| entry.0.cmp(&addr))
304 {
305 Ok(i) => Some(&func.lookup.index[i].1),
306 Err(i) => {
307 if i > 0 {
308 Some(&func.lookup.index[i - 1].1)
309 } else {
310 None
311 }
312 }
313 };
314 if let Some(range_indices) = found {
315 TransformRangeEndIter {
316 addr,
317 indices: range_indices,
318 ranges: &func.lookup.ranges,
319 }
320 } else {
321 unreachable!();
322 }
323 }
324}
325
326impl<'a> Iterator for TransformRangeEndIter<'a> {
327 type Item = (GeneratedAddress, RangeIndex);
328 fn next(&mut self) -> Option<Self::Item> {
329 while let Some((first, tail)) = self.indices.split_first() {
330 let range_index = *first;
331 let range = &self.ranges[range_index];
332 self.indices = tail;
333 if range.wasm_start >= self.addr {
334 continue;
335 }
336 let address = match range
337 .positions
338 .binary_search_by(|a| a.wasm_pos.cmp(&self.addr))
339 {
340 Ok(i) => range.positions[i].gen_end,
341 Err(i) => {
342 if i == range.positions.len() {
343 range.gen_end
344 } else {
345 range.positions[i].gen_start
346 }
347 }
348 };
349 return Some((address, range_index));
350 }
351 None
352 }
353}
354
355pub struct TransformRangeIter<'a> {
357 func: &'a FuncTransform,
358 start_it: TransformRangeStartIter<'a>,
359 end_it: TransformRangeEndIter<'a>,
360 last_start: Option<(GeneratedAddress, RangeIndex)>,
361 last_end: Option<(GeneratedAddress, RangeIndex)>,
362 last_item: Option<(GeneratedAddress, GeneratedAddress)>,
363}
364
365impl<'a> TransformRangeIter<'a> {
366 fn new(func: &'a FuncTransform, start: WasmAddress, end: WasmAddress) -> Self {
367 let mut start_it = TransformRangeStartIter::new(func, start);
368 let last_start = start_it.next();
369 let mut end_it = TransformRangeEndIter::new(func, end);
370 let last_end = end_it.next();
371 TransformRangeIter {
372 func,
373 start_it,
374 end_it,
375 last_start,
376 last_end,
377 last_item: None,
378 }
379 }
380}
381
382impl<'a> Iterator for TransformRangeIter<'a> {
383 type Item = (GeneratedAddress, GeneratedAddress);
384 fn next(&mut self) -> Option<Self::Item> {
385 loop {
386 let (start, end, range_index): (
389 Option<GeneratedAddress>,
390 Option<GeneratedAddress>,
391 RangeIndex,
392 ) = {
393 match (self.last_start.as_ref(), self.last_end.as_ref()) {
394 (Some((s, sri)), Some((e, eri))) => {
395 if sri == eri {
396 (Some(*s), Some(*e), *sri)
398 } else if sri < eri {
399 (Some(*s), None, *sri)
400 } else {
401 (None, Some(*e), *eri)
402 }
403 }
404 (Some((s, sri)), None) => (Some(*s), None, *sri),
405 (None, Some((e, eri))) => (None, Some(*e), *eri),
406 (None, None) => {
407 return None;
409 }
410 }
411 };
412 let range_start = match start {
413 Some(range_start) => {
414 self.last_start = self.start_it.next();
416 range_start
417 }
418 None => {
419 let range = &self.func.lookup.ranges[range_index];
420 range.gen_start
421 }
422 };
423 let range_end = match end {
424 Some(range_end) => {
425 self.last_end = self.end_it.next();
427 range_end
428 }
429 None => {
430 let range = &self.func.lookup.ranges[range_index];
431 range.gen_end
432 }
433 };
434
435 if cfg!(debug_assertions) {
436 match self.last_item.replace((range_start, range_end)) {
437 Some((_, last_end)) => debug_assert!(last_end <= range_start),
438 None => (),
439 }
440 }
441
442 if range_start < range_end {
443 return Some((range_start, range_end));
444 }
445 debug_assert!(range_start == range_end);
447 }
448 }
449}
450
451impl AddressTransform {
452 pub fn new(funcs: &CompiledFunctions, wasm_file: &WasmFileInfo) -> Self {
453 let code_section_offset = wasm_file.code_section_offset;
454
455 let mut func = BTreeMap::new();
456 for (i, f) in funcs {
457 let ft = &f.address_map;
458 let (fn_start, fn_end, lookup) = build_function_lookup(ft, code_section_offset);
459
460 func.insert(
461 fn_start,
462 FuncTransform {
463 start: fn_start,
464 end: fn_end,
465 index: i,
466 lookup,
467 },
468 );
469 }
470
471 let map = build_function_addr_map(funcs, code_section_offset);
472 let func = Vec::from_iter(func.into_iter());
473 AddressTransform { map, func }
474 }
475
476 fn find_func(&self, addr: u64) -> Option<&FuncTransform> {
477 let func = match self.func.binary_search_by(|entry| entry.0.cmp(&addr)) {
479 Ok(i) => &self.func[i].1,
480 Err(i) => {
481 if i > 0 {
482 &self.func[i - 1].1
483 } else {
484 return None;
485 }
486 }
487 };
488 if addr >= func.start {
489 return Some(func);
490 }
491 None
492 }
493
494 pub fn find_func_index(&self, addr: u64) -> Option<DefinedFuncIndex> {
495 self.find_func(addr).map(|f| f.index)
496 }
497
498 pub fn translate_raw(&self, addr: u64) -> Option<(DefinedFuncIndex, GeneratedAddress)> {
499 if addr == 0 {
500 return None;
502 }
503 if let Some(func) = self.find_func(addr) {
504 if addr == func.end {
505 let map = &self.map[func.index];
508 return Some((func.index, map.len));
509 }
510 let first_result = TransformRangeStartIter::new(func, addr).next();
511 first_result.map(|(address, _)| (func.index, address))
512 } else {
513 None
515 }
516 }
517
518 pub fn can_translate_address(&self, addr: u64) -> bool {
519 self.translate(addr).is_some()
520 }
521
522 pub fn translate(&self, addr: u64) -> Option<write::Address> {
523 self.translate_raw(addr)
524 .map(|(func_index, address)| write::Address::Symbol {
525 symbol: func_index.index(),
526 addend: address as i64,
527 })
528 }
529
530 pub fn translate_ranges_raw<'a>(
531 &'a self,
532 start: u64,
533 end: u64,
534 ) -> Option<(DefinedFuncIndex, impl Iterator<Item = (usize, usize)> + 'a)> {
535 if start == 0 {
536 return None;
538 }
539 if let Some(func) = self.find_func(start) {
540 let result = TransformRangeIter::new(func, start, end);
541 return Some((func.index, result));
542 }
543 None
545 }
546
547 pub fn translate_ranges<'a>(
548 &'a self,
549 start: u64,
550 end: u64,
551 ) -> impl Iterator<Item = (write::Address, u64)> + 'a {
552 enum TranslateRangesResult<'a> {
553 Empty,
554 Raw {
555 symbol: usize,
556 it: Box<dyn Iterator<Item = (usize, usize)> + 'a>,
557 },
558 }
559 impl<'a> Iterator for TranslateRangesResult<'a> {
560 type Item = (write::Address, u64);
561 fn next(&mut self) -> Option<Self::Item> {
562 match self {
563 TranslateRangesResult::Empty => None,
564 TranslateRangesResult::Raw { symbol, it } => match it.next() {
565 Some((start, end)) => {
566 debug_assert!(start < end);
567 Some((
568 write::Address::Symbol {
569 symbol: *symbol,
570 addend: start as i64,
571 },
572 (end - start) as u64,
573 ))
574 }
575 None => None,
576 },
577 }
578 }
579 }
580
581 match self.translate_ranges_raw(start, end) {
582 Some((func_index, ranges)) => TranslateRangesResult::Raw {
583 symbol: func_index.index(),
584 it: Box::new(ranges),
585 },
586 None => TranslateRangesResult::Empty,
587 }
588 }
589
590 pub fn map(&self) -> &PrimaryMap<DefinedFuncIndex, FunctionMap> {
591 &self.map
592 }
593
594 pub fn func_range(&self, index: DefinedFuncIndex) -> (GeneratedAddress, GeneratedAddress) {
595 let map = &self.map[index];
596 (map.offset, map.offset + map.len)
597 }
598
599 pub fn func_source_range(&self, index: DefinedFuncIndex) -> (WasmAddress, WasmAddress) {
600 let map = &self.map[index];
601 (map.wasm_start, map.wasm_end)
602 }
603}
604
605#[cfg(test)]
606mod tests {
607 use super::{build_function_lookup, get_wasm_code_offset, AddressTransform};
608 use crate::{CompiledFunction, FunctionAddressMap};
609 use cranelift_entity::PrimaryMap;
610 use gimli::write::Address;
611 use std::iter::FromIterator;
612 use std::mem;
613 use wasmtime_environ::{FilePos, InstructionAddressMap, WasmFileInfo};
614
615 #[test]
616 fn test_get_wasm_code_offset() {
617 let offset = get_wasm_code_offset(FilePos::new(3), 1);
618 assert_eq!(2, offset);
619 let offset = get_wasm_code_offset(FilePos::new(16), 0xF000_0000);
620 assert_eq!(0x1000_0010, offset);
621 let offset = get_wasm_code_offset(FilePos::new(1), 0x20_8000_0000);
622 assert_eq!(0x8000_0001, offset);
623 }
624
625 fn create_simple_func(wasm_offset: u32) -> FunctionAddressMap {
626 FunctionAddressMap {
627 instructions: vec![
628 InstructionAddressMap {
629 srcloc: FilePos::new(wasm_offset + 2),
630 code_offset: 5,
631 },
632 InstructionAddressMap {
633 srcloc: FilePos::default(),
634 code_offset: 8,
635 },
636 InstructionAddressMap {
637 srcloc: FilePos::new(wasm_offset + 7),
638 code_offset: 15,
639 },
640 InstructionAddressMap {
641 srcloc: FilePos::default(),
642 code_offset: 23,
643 },
644 ]
645 .into(),
646 start_srcloc: FilePos::new(wasm_offset),
647 end_srcloc: FilePos::new(wasm_offset + 10),
648 body_offset: 0,
649 body_len: 30,
650 }
651 }
652
653 #[test]
654 fn test_build_function_lookup_simple() {
655 let input = create_simple_func(11);
656 let (start, end, lookup) = build_function_lookup(&input, 1);
657 assert_eq!(10, start);
658 assert_eq!(20, end);
659
660 assert_eq!(1, lookup.index.len());
661 let index_entry = lookup.index.into_iter().next().unwrap();
662 assert_eq!((10u64, vec![0].into_boxed_slice()), index_entry);
663 assert_eq!(1, lookup.ranges.len());
664 let range = &lookup.ranges[0];
665 assert_eq!(10, range.wasm_start);
666 assert_eq!(20, range.wasm_end);
667 assert_eq!(0, range.gen_start);
668 assert_eq!(30, range.gen_end);
669 let positions = &range.positions;
670 assert_eq!(2, positions.len());
671 assert_eq!(12, positions[0].wasm_pos);
672 assert_eq!(5, positions[0].gen_start);
673 assert_eq!(8, positions[0].gen_end);
674 assert_eq!(17, positions[1].wasm_pos);
675 assert_eq!(15, positions[1].gen_start);
676 assert_eq!(23, positions[1].gen_end);
677 }
678
679 #[test]
680 fn test_build_function_lookup_two_ranges() {
681 let mut input = create_simple_func(11);
682 let mut list = Vec::from(mem::take(&mut input.instructions));
684 list.push(InstructionAddressMap {
685 srcloc: FilePos::new(11 + 2),
686 code_offset: 23,
687 });
688 list.push(InstructionAddressMap {
689 srcloc: FilePos::default(),
690 code_offset: 26,
691 });
692 input.instructions = list.into();
693 let (start, end, lookup) = build_function_lookup(&input, 1);
694 assert_eq!(10, start);
695 assert_eq!(20, end);
696
697 assert_eq!(2, lookup.index.len());
698 let index_entries = Vec::from_iter(lookup.index.into_iter());
699 assert_eq!((10u64, vec![0].into_boxed_slice()), index_entries[0]);
700 assert_eq!((12u64, vec![0, 1].into_boxed_slice()), index_entries[1]);
701 assert_eq!(2, lookup.ranges.len());
702
703 let range = &lookup.ranges[0];
704 assert_eq!(10, range.wasm_start);
705 assert_eq!(17, range.wasm_end);
706 assert_eq!(0, range.gen_start);
707 assert_eq!(23, range.gen_end);
708 let positions = &range.positions;
709 assert_eq!(2, positions.len());
710 assert_eq!(12, positions[0].wasm_pos);
711 assert_eq!(5, positions[0].gen_start);
712 assert_eq!(8, positions[0].gen_end);
713 assert_eq!(17, positions[1].wasm_pos);
714 assert_eq!(15, positions[1].gen_start);
715 assert_eq!(23, positions[1].gen_end);
716
717 let range = &lookup.ranges[1];
718 assert_eq!(12, range.wasm_start);
719 assert_eq!(20, range.wasm_end);
720 assert_eq!(23, range.gen_start);
721 assert_eq!(30, range.gen_end);
722 let positions = &range.positions;
723 assert_eq!(1, positions.len());
724 assert_eq!(12, positions[0].wasm_pos);
725 assert_eq!(23, positions[0].gen_start);
726 assert_eq!(26, positions[0].gen_end);
727 }
728
729 #[test]
730 fn test_addr_translate() {
731 let func = CompiledFunction {
732 address_map: create_simple_func(11),
733 ..Default::default()
734 };
735 let input = PrimaryMap::from_iter([&func]);
736 let at = AddressTransform::new(
737 &input,
738 &WasmFileInfo {
739 path: None,
740 code_section_offset: 1,
741 imported_func_count: 0,
742 funcs: Vec::new(),
743 },
744 );
745
746 let addr = at.translate(10);
747 assert_eq!(
748 Some(Address::Symbol {
749 symbol: 0,
750 addend: 0,
751 }),
752 addr
753 );
754
755 let addr = at.translate(20);
756 assert_eq!(
757 Some(Address::Symbol {
758 symbol: 0,
759 addend: 30,
760 }),
761 addr
762 );
763
764 let addr = at.translate(0);
765 assert_eq!(None, addr);
766
767 let addr = at.translate(12);
768 assert_eq!(
769 Some(Address::Symbol {
770 symbol: 0,
771 addend: 5,
772 }),
773 addr
774 );
775
776 let addr = at.translate(18);
777 assert_eq!(
778 Some(Address::Symbol {
779 symbol: 0,
780 addend: 23,
781 }),
782 addr
783 );
784 }
785}