use anyhow::Result; use cfg_if::cfg_if; use cranelift_codegen::ir::Function; use cranelift_codegen::ir::function::FunctionParameters; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{FinalizedMachReloc, MachTrap}; use std::fmt::Write; fn print_relocs(func_params: &FunctionParameters, relocs: &[FinalizedMachReloc]) -> String { let mut text = String::new(); for &FinalizedMachReloc { kind, offset, ref target, addend, } in relocs { writeln!( text, "reloc_external: {} {} {} at {}", kind, target.display(Some(func_params)), addend, offset ) .unwrap(); } text } pub fn print_traps(traps: &[MachTrap]) -> String { let mut text = String::new(); for &MachTrap { offset, code } in traps { writeln!(text, "trap: {code} at {offset:#x}").unwrap(); } text } cfg_if! { if #[cfg(feature = "disas")] { pub fn print_disassembly(func: &Function, isa: &dyn TargetIsa, mem: &[u8]) -> Result<()> { #[cfg(feature = "pulley")] let is_pulley = match isa.triple().architecture { target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64 => true, _ => false, }; println!("\nDisassembly of {} bytes <{}>:", mem.len(), func.name); #[cfg(feature = "pulley")] if is_pulley { let mut disas = pulley_interpreter::disas::Disassembler::new(mem); pulley_interpreter::decode::Decoder::decode_all(&mut disas)?; println!("{}", disas.disas()); return Ok(()); } let cs = isa.to_capstone().map_err(|e| anyhow::format_err!("{e}"))?; let insns = cs.disasm_all(&mem, 0x0).unwrap(); for i in insns.iter() { let mut line = String::new(); write!(&mut line, "{:4x}:\t", i.address()).unwrap(); let mut bytes_str = String::new(); let mut len = 0; let mut first = true; for b in i.bytes() { if !first { write!(&mut bytes_str, " ").unwrap(); } write!(&mut bytes_str, "{b:02x}").unwrap(); len += 1; first = false; } write!(&mut line, "{bytes_str:21}\t").unwrap(); if len > 8 { write!(&mut line, "\n\t\t\t\t").unwrap(); } if let Some(s) = i.mnemonic() { write!(&mut line, "{s}\t").unwrap(); } if let Some(s) = i.op_str() { write!(&mut line, "{s}").unwrap(); } println!("{line}"); } Ok(()) } } else { pub fn print_disassembly(_: &Function, _: &dyn TargetIsa, _: &[u8]) -> Result<()> { println!("\nNo disassembly available."); Ok(()) } } } pub fn print_all( isa: &dyn TargetIsa, func: &Function, mem: &[u8], code_size: u32, print: bool, relocs: &[FinalizedMachReloc], traps: &[MachTrap], ) -> Result<()> { print_bytes(&mem); print_disassembly(func, isa, &mem[0..code_size as usize])?; if print { println!( "\n{}\n{}", print_relocs(&func.params, relocs), print_traps(traps), ); } Ok(()) } pub fn print_bytes(mem: &[u8]) { print!(".byte "); let mut first = true; for byte in mem.iter() { if first { first = false; } else { print!(", "); } print!("{byte}"); } println!(); }