objdiff_core/obj/
mod.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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
pub mod read;
pub mod split_meta;

use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};

use filetime::FileTime;
use flagset::{flags, FlagSet};
use object::RelocationFlags;
use split_meta::SplitMeta;

use crate::{arch::ObjArch, util::ReallySigned};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ObjSectionKind {
    Code,
    Data,
    Bss,
}
flags! {
    pub enum ObjSymbolFlags: u8 {
        Global,
        Local,
        Weak,
        Common,
        Hidden,
        /// Has extra data associated with the symbol
        /// (e.g. exception table entry)
        HasExtra,
    }
}
#[derive(Debug, Copy, Clone, Default)]
pub struct ObjSymbolFlagSet(pub FlagSet<ObjSymbolFlags>);

#[derive(Debug, Clone)]
pub struct ObjSection {
    pub name: String,
    pub kind: ObjSectionKind,
    pub address: u64,
    pub size: u64,
    pub data: Vec<u8>,
    pub orig_index: usize,
    pub symbols: Vec<ObjSymbol>,
    pub relocations: Vec<ObjReloc>,
    pub virtual_address: Option<u64>,
    /// Line number info (.line or .debug_line section)
    pub line_info: BTreeMap<u64, u32>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ObjInsArgValue {
    Signed(i64),
    Unsigned(u64),
    Opaque(Cow<'static, str>),
}

impl ObjInsArgValue {
    pub fn loose_eq(&self, other: &ObjInsArgValue) -> bool {
        match (self, other) {
            (ObjInsArgValue::Signed(a), ObjInsArgValue::Signed(b)) => a == b,
            (ObjInsArgValue::Unsigned(a), ObjInsArgValue::Unsigned(b)) => a == b,
            (ObjInsArgValue::Signed(a), ObjInsArgValue::Unsigned(b))
            | (ObjInsArgValue::Unsigned(b), ObjInsArgValue::Signed(a)) => *a as u64 == *b,
            (ObjInsArgValue::Opaque(a), ObjInsArgValue::Opaque(b)) => a == b,
            _ => false,
        }
    }
}

impl fmt::Display for ObjInsArgValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ObjInsArgValue::Signed(v) => write!(f, "{:#x}", ReallySigned(*v)),
            ObjInsArgValue::Unsigned(v) => write!(f, "{:#x}", v),
            ObjInsArgValue::Opaque(v) => write!(f, "{}", v),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ObjInsArg {
    PlainText(Cow<'static, str>),
    Arg(ObjInsArgValue),
    Reloc,
    BranchDest(u64),
}

impl ObjInsArg {
    pub fn loose_eq(&self, other: &ObjInsArg) -> bool {
        match (self, other) {
            (ObjInsArg::Arg(a), ObjInsArg::Arg(b)) => a.loose_eq(b),
            (ObjInsArg::Reloc, ObjInsArg::Reloc) => true,
            (ObjInsArg::BranchDest(a), ObjInsArg::BranchDest(b)) => a == b,
            _ => false,
        }
    }
}

#[derive(Debug, Clone)]
pub struct ObjIns {
    pub address: u64,
    pub size: u8,
    pub op: u16,
    pub mnemonic: String,
    pub args: Vec<ObjInsArg>,
    pub reloc: Option<ObjReloc>,
    pub branch_dest: Option<u64>,
    /// Line number
    pub line: Option<u32>,
    /// Formatted instruction
    pub formatted: String,
    /// Original (unsimplified) instruction
    pub orig: Option<String>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
pub enum ObjSymbolKind {
    #[default]
    Unknown,
    Function,
    Object,
    Section,
}

#[derive(Debug, Clone)]
pub struct ObjSymbol {
    pub name: String,
    pub demangled_name: Option<String>,
    pub address: u64,
    pub section_address: u64,
    pub size: u64,
    pub size_known: bool,
    pub kind: ObjSymbolKind,
    pub flags: ObjSymbolFlagSet,
    pub orig_section_index: Option<usize>,
    /// Original virtual address (from .note.split section)
    pub virtual_address: Option<u64>,
    /// Original index in object symbol table
    pub original_index: Option<usize>,
    pub bytes: Vec<u8>,
}

pub struct ObjInfo {
    pub arch: Box<dyn ObjArch>,
    pub path: Option<PathBuf>,
    pub timestamp: Option<FileTime>,
    pub sections: Vec<ObjSection>,
    /// Common BSS symbols
    pub common: Vec<ObjSymbol>,
    /// Split object metadata (.note.split section)
    pub split_meta: Option<SplitMeta>,
}

#[derive(Debug, Clone)]
pub struct ObjReloc {
    pub flags: RelocationFlags,
    pub address: u64,
    pub target: ObjSymbol,
    pub addend: i64,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SymbolRef {
    pub section_idx: usize,
    pub symbol_idx: usize,
}

impl ObjInfo {
    pub fn section_symbol(&self, symbol_ref: SymbolRef) -> (Option<&ObjSection>, &ObjSymbol) {
        if symbol_ref.section_idx == self.sections.len() {
            let symbol = &self.common[symbol_ref.symbol_idx];
            return (None, symbol);
        }
        let section = &self.sections[symbol_ref.section_idx];
        let symbol = &section.symbols[symbol_ref.symbol_idx];
        (Some(section), symbol)
    }
}