use std::fmt::{self, Write}; use yaxpeax_arch::{Decoder, LengthedInstruction}; use yaxpeax_arch::display::{ArchDisplayRules, DisplaySink}; use yaxpeax_power::Power; use yaxpeax_power::InstDecoder; use yaxpeax_power::DisplayRules; fn test_display_rule DisplayRules>>>( decoder: &InstDecoder, testcase: &'static TestCase, rules: &Rules ) { let mut reader = yaxpeax_arch::U8Reader::new(testcase.bytes); let instr = decoder.decode(&mut reader).expect("display rule tests only run on instructions that decode"); assert_eq!(instr.len().to_const(), testcase.bytes.len() as u64, "instruction length is incorrect"); let actual = instr.display_rules(rules).to_string(); if testcase.expected != actual { let mut hex = String::new(); for b in testcase.bytes { write!(hex, "{:02x}", b).unwrap(); } eprintln!("rule-based formatting test failed. \n \ instr: {}\n \ hex: {}", instr, hex); eprintln!(" [-] got: {}, wanted {}", testcase.expected, actual); panic!("issues in display rule formatting"); } } struct TestCase { bytes: &'static [u8], expected: &'static str, } #[test] fn test_absolute_addr() { let rules = yaxpeax_power::AbsoluteAddressFormatter::new(0x82113e04); let decoder = InstDecoder::default(); static CASES: &'static [TestCase] = &[ TestCase { bytes: &[0x48, 0x5c, 0x53, 0xcd], expected: "bl 0x826d91d0", } ]; for case in CASES.iter() { test_display_rule(&decoder, case, &rules); } } /// a simple DisplayRules impl to test that addresses directly at symbols are printed reasonably. /// if a symbol is not directly at an address, the address is printed instead. #[derive(Copy, Clone)] struct SimpleSymbolicator<'syms> { pc: u64, symbols: &'syms [(u64, &'static str)], } impl<'syms> SimpleSymbolicator<'syms> { pub fn new(pc: u64, symbols: &'syms [(u64, &'static str)]) -> Self { SimpleSymbolicator { pc, symbols, } } } impl<'syms, S: DisplaySink> ArchDisplayRules for SimpleSymbolicator<'syms> { fn instr_addr(&self) -> Option { Some(self.pc) } fn emit_address(&self, addr: u64, s: &mut S) -> Result { for (sym_addr, sym) in self.symbols { eprintln!("does symbol {} at {:04x} match {:04x}?", sym, sym_addr, addr); if *sym_addr == addr { s.write_str(sym)?; return Ok(true); } } Ok(false) } } impl<'syms, S: DisplaySink> DisplayRules for SimpleSymbolicator<'syms> {} #[test] fn test_symbolication() { let syms = &[ (0x0002_0000, "memcpy"), (0x0020_0000, "global"), (0x0021_0006, "global_riprel"), (0x0001_0002, "branch_target"), (0x0001_0005, "wide_target"), ]; let rules = SimpleSymbolicator::new(0x0001_0000, syms); let decoder = InstDecoder::default(); static CASES: &'static [TestCase] = &[ ]; for case in CASES.iter() { test_display_rule(&decoder, case, &rules); } }