Build basic blocks for a function by disassembling its code and splitting at control flow boundaries.
(
func_body: &[u8],
func_offset: usize,
address_map: &[(usize, Option<u32>)],
clif_lines: &[(Option<u32>, String)],
wat_map: &BTreeMap<u32, String>,
target: &target_lexicon::Tr
| 612 | /// Build basic blocks for a function by disassembling its code and splitting |
| 613 | /// at control flow boundaries. |
| 614 | fn build_basic_blocks( |
| 615 | func_body: &[u8], |
| 616 | func_offset: usize, |
| 617 | address_map: &[(usize, Option<u32>)], |
| 618 | clif_lines: &[(Option<u32>, String)], |
| 619 | wat_map: &BTreeMap<u32, String>, |
| 620 | target: &target_lexicon::Triple, |
| 621 | ) -> Result<Vec<BasicBlock>> { |
| 622 | let cs = build_capstone(target)?; |
| 623 | let insts = |
| 624 | crate::disas::disas_with_capstone(&cs, func_body, u64::try_from(func_offset).unwrap())?; |
| 625 | |
| 626 | // Build a map from code offset -> wasm offset for instructions in this function. |
| 627 | let mut offset_to_wasm: BTreeMap<usize, Option<u32>> = BTreeMap::new(); |
| 628 | for &(code_offset, wasm_offset) in address_map { |
| 629 | if code_offset >= func_offset && code_offset < func_offset + func_body.len() { |
| 630 | offset_to_wasm.insert(code_offset, wasm_offset); |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | // Build a map from wasm offset -> CLIF text. |
| 635 | let mut wasm_to_clif: BTreeMap<u32, Vec<&str>> = BTreeMap::new(); |
| 636 | for (wasm_off, clif_text) in clif_lines { |
| 637 | if let Some(off) = wasm_off { |
| 638 | wasm_to_clif.entry(*off).or_default().push(clif_text); |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | // Build annotated instructions and split into basic blocks. |
| 643 | let mut blocks = Vec::new(); |
| 644 | let mut current_block = Vec::new(); |
| 645 | |
| 646 | for inst in &insts { |
| 647 | let addr = usize::try_from(inst.address).unwrap(); |
| 648 | let offset_in_func = addr - func_offset; |
| 649 | |
| 650 | // Find wasm offset for this instruction. |
| 651 | let wasm_offset = find_wasm_offset_for_address(&offset_to_wasm, addr); |
| 652 | |
| 653 | // Find CLIF text for this wasm offset. |
| 654 | let clif = wasm_offset |
| 655 | .and_then(|wo| wasm_to_clif.get(&wo)) |
| 656 | .map(|lines| lines.join("; ")); |
| 657 | |
| 658 | // Find Wasm text for this wasm offset from the WAT map. |
| 659 | let wasm = wasm_offset.and_then(|wo| wat_map.get(&wo).cloned()); |
| 660 | |
| 661 | current_block.push(BlockInstruction { |
| 662 | offset_in_func, |
| 663 | assembly: inst.disassembly.clone(), |
| 664 | clif, |
| 665 | wasm_offset, |
| 666 | wasm, |
| 667 | }); |
| 668 | |
| 669 | if inst.is_jump || inst.is_return { |
| 670 | blocks.push(BasicBlock { |
| 671 | instructions: std::mem::take(&mut current_block), |