hex_patch/app/
instruction.rs

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
use std::{collections::HashMap, fmt::Display};

use capstone::Insn;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Instruction {
    pub(super) mnemonic: String,
    pub(super) operands: String,
    pub(super) virtual_address: u64,
    pub(super) bytes: Vec<u8>,
}

impl Instruction {
    pub fn new(instruction: &Insn, symbols: Option<&HashMap<u64, String>>) -> Self {
        let mnemonic = instruction.mnemonic().expect("Failed to get mnemonic");
        let operands = instruction.op_str().expect("Failed to get operands");
        let operands = operands.split(", ").collect::<Vec<_>>();
        let mut operands_string = String::new();
        for (i, operand) in operands.iter().enumerate() {
            let mut found_symbol = false;
            if let Some(symbols) = &symbols {
                if let Some(operand) = operand.strip_prefix("0x") {
                    if let Ok(operand_address) = u64::from_str_radix(operand, 16) {
                        if let Some(symbol) = symbols.get(&operand_address) {
                            found_symbol = true;
                            operands_string.push_str(symbol);
                        }
                    }
                }
                if let Some(operand) = operand.strip_prefix("#0x") {
                    if let Ok(operand_address) = u64::from_str_radix(operand, 16) {
                        if let Some(symbol) = symbols.get(&operand_address) {
                            found_symbol = true;
                            operands_string.push_str(symbol);
                        }
                    }
                }
            }
            if !found_symbol {
                operands_string.push_str(operand);
            }
            if i < operands.len() - 1 {
                operands_string.push_str(", ");
            }
        }
        let virtual_address = instruction.address();
        let bytes = instruction.bytes().to_vec();
        Instruction {
            mnemonic: mnemonic.to_string(),
            operands: operands_string,
            virtual_address,
            bytes,
        }
    }

    pub fn mnemonic(&self) -> &str {
        &self.mnemonic
    }

    pub fn operands(&self) -> &str {
        &self.operands
    }

    pub fn ip(&self) -> u64 {
        self.virtual_address
    }

    pub fn len(&self) -> usize {
        self.bytes.len()
    }

    pub fn is_empty(&self) -> bool {
        self.bytes.is_empty()
    }
}

impl Display for Instruction {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{} {}", self.mnemonic, self.operands)
    }
}