1use anyhow::Result;
2use cfg_if::cfg_if;
3use cranelift_codegen::ir::function::FunctionParameters;
4use cranelift_codegen::ir::Function;
5use cranelift_codegen::isa::TargetIsa;
6use cranelift_codegen::{FinalizedMachReloc, MachTrap};
7use std::fmt::Write;
8
9fn print_relocs(func_params: &FunctionParameters, relocs: &[FinalizedMachReloc]) -> String {
10 let mut text = String::new();
11 for &FinalizedMachReloc {
12 kind,
13 offset,
14 ref target,
15 addend,
16 } in relocs
17 {
18 writeln!(
19 text,
20 "reloc_external: {} {} {} at {}",
21 kind,
22 target.display(Some(func_params)),
23 addend,
24 offset
25 )
26 .unwrap();
27 }
28 text
29}
30
31pub fn print_traps(traps: &[MachTrap]) -> String {
32 let mut text = String::new();
33 for &MachTrap { offset, code } in traps {
34 writeln!(text, "trap: {code} at {offset:#x}").unwrap();
35 }
36 text
37}
38
39cfg_if! {
40 if #[cfg(feature = "disas")] {
41 pub fn print_disassembly(func: &Function, isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> {
42 #[cfg(feature = "pulley")]
43 let is_pulley = match isa.triple().architecture {
44 target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => true,
45 _ => false,
46 };
47 println!("\nDisassembly of {} bytes <{}>:", mem.len(), func.name);
48
49 #[cfg(feature = "pulley")]
50 if is_pulley {
51 let mut disas = pulley_interpreter::disas::Disassembler::new(mem);
52 pulley_interpreter::decode::Decoder::decode_all(&mut disas)?;
53 println!("{}", disas.disas());
54 return Ok(());
55 }
56 let cs = isa.to_capstone().map_err(|e| anyhow::format_err!("{}", e))?;
57
58 let insns = cs.disasm_all(&mem, 0x0).unwrap();
59 for i in insns.iter() {
60 let mut line = String::new();
61
62 write!(&mut line, "{:4x}:\t", i.address()).unwrap();
63
64 let mut bytes_str = String::new();
65 let mut len = 0;
66 let mut first = true;
67 for b in i.bytes() {
68 if !first {
69 write!(&mut bytes_str, " ").unwrap();
70 }
71 write!(&mut bytes_str, "{b:02x}").unwrap();
72 len += 1;
73 first = false;
74 }
75 write!(&mut line, "{bytes_str:21}\t").unwrap();
76 if len > 8 {
77 write!(&mut line, "\n\t\t\t\t").unwrap();
78 }
79
80 if let Some(s) = i.mnemonic() {
81 write!(&mut line, "{s}\t").unwrap();
82 }
83
84 if let Some(s) = i.op_str() {
85 write!(&mut line, "{s}").unwrap();
86 }
87
88 println!("{line}");
89 }
90 Ok(())
91 }
92 } else {
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}