1use anyhow::Result;
2use cranelift_codegen::ir::Function;
3use cranelift_codegen::ir::function::FunctionParameters;
4use cranelift_codegen::isa::TargetIsa;
5use cranelift_codegen::{FinalizedMachReloc, MachTrap};
6use std::fmt::Write;
7
8fn print_relocs(func_params: &FunctionParameters, relocs: &[FinalizedMachReloc]) -> String {
9 let mut text = String::new();
10 for &FinalizedMachReloc {
11 kind,
12 offset,
13 ref target,
14 addend,
15 } in relocs
16 {
17 writeln!(
18 text,
19 "reloc_external: {} {} {} at {}",
20 kind,
21 target.display(Some(func_params)),
22 addend,
23 offset
24 )
25 .unwrap();
26 }
27 text
28}
29
30pub fn print_traps(traps: &[MachTrap]) -> String {
31 let mut text = String::new();
32 for &MachTrap { offset, code } in traps {
33 writeln!(text, "trap: {code} at {offset:#x}").unwrap();
34 }
35 text
36}
37
38cfg_select! {
39 feature = "disas" => {
40 pub fn print_disassembly(func: &Function, isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> {
41 #[cfg(feature = "pulley")]
42 let is_pulley = match isa.triple().architecture {
43 target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => true,
44 _ => false,
45 };
46 println!("\nDisassembly of {} bytes <{}>:", mem.len(), func.name);
47
48 #[cfg(feature = "pulley")]
49 if is_pulley {
50 let mut disas = pulley_interpreter::disas::Disassembler::new(mem);
51 pulley_interpreter::decode::Decoder::decode_all(&mut disas)?;
52 println!("{}", disas.disas());
53 return Ok(());
54 }
55 let cs = isa.to_capstone().map_err(|e| anyhow::format_err!("{e}"))?;
56
57 let insns = cs.disasm_all(&mem, 0x0).unwrap();
58 for i in insns.iter() {
59 let mut line = String::new();
60
61 write!(&mut line, "{:4x}:\t", i.address()).unwrap();
62
63 let mut bytes_str = String::new();
64 let mut len = 0;
65 let mut first = true;
66 for b in i.bytes() {
67 if !first {
68 write!(&mut bytes_str, " ").unwrap();
69 }
70 write!(&mut bytes_str, "{b:02x}").unwrap();
71 len += 1;
72 first = false;
73 }
74 write!(&mut line, "{bytes_str:21}\t").unwrap();
75 if len > 8 {
76 write!(&mut line, "\n\t\t\t\t").unwrap();
77 }
78
79 if let Some(s) = i.mnemonic() {
80 write!(&mut line, "{s}\t").unwrap();
81 }
82
83 if let Some(s) = i.op_str() {
84 write!(&mut line, "{s}").unwrap();
85 }
86
87 println!("{line}");
88 }
89 Ok(())
90 }
91 }
92 _ => {
93 pub fn print_disassembly(_: &Function, _: &dyn TargetIsa, _: &[u8]) -> Result<()> {
94 println!("\nNo disassembly available.");
95 Ok(())
96 }
97 }
98}
99
100pub fn print_all(
101 isa: &dyn TargetIsa,
102 func: &Function,
103 mem: &[u8],
104 code_size: u32,
105 print: bool,
106 relocs: &[FinalizedMachReloc],
107 traps: &[MachTrap],
108) -> Result<()> {
109 print_bytes(&mem);
110 print_disassembly(func, isa, &mem[0..code_size as usize])?;
111 if print {
112 println!(
113 "\n{}\n{}",
114 print_relocs(&func.params, relocs),
115 print_traps(traps),
116 );
117 }
118 Ok(())
119}
120
121pub fn print_bytes(mem: &[u8]) {
122 print!(".byte ");
123 let mut first = true;
124 for byte in mem.iter() {
125 if first {
126 first = false;
127 } else {
128 print!(", ");
129 }
130 print!("{byte}");
131 }
132 println!();
133}