aboutsummaryrefslogtreecommitdiff
path: root/test/display.rs
blob: 23d82606a206f3c681ff7578f765c6cb5a56642b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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<Rules: for<'f, 'g> DisplayRules<yaxpeax_arch::display::FmtSink<'f, fmt::Formatter<'g>>>>(
    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<Power, S> for SimpleSymbolicator<'syms> {
    fn instr_addr(&self) -> Option<u64> {
        Some(self.pc)
    }

    fn emit_address(&self, addr: u64, s: &mut S) -> Result<bool, fmt::Error> {
        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<S> 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);
    }
}