yaxpeax_core/arch/x86_64/
mod.rs

1use yaxpeax_arch::Arch;
2use yaxpeax_arch::Decoder;
3use arch::DecodeFrom;
4use analyses::control_flow;
5use analyses::static_single_assignment::SSA;
6use analyses::xrefs;
7use memory::MemoryRepr;
8use self::analyses::data_flow::DefaultCallingConvention;
9
10use petgraph::graphmap::GraphMap;
11
12use std::collections::HashMap;
13use std::collections::HashSet;
14use yaxpeax_x86::x86_64;
15use std::rc::Rc;
16use std::cell::RefCell;
17use std::cell::Ref;
18use num_traits::Zero;
19
20use arch::{BaseUpdate, CommentQuery, FunctionLayout, FunctionImpl, FunctionQuery, Symbol, SymbolQuery, Library};
21use data::ValueLocations;
22use data::modifier::InstructionModifiers;
23use timing::Timings;
24
25use ContextRead;
26use ContextWrite;
27
28pub mod analyses;
29pub mod cpu;
30#[cfg(target_os = "linux")]
31pub mod debug;
32pub mod display;
33pub mod semantic;
34
35impl<M: MemoryRepr<Self> + ?Sized> DecodeFrom<M> for x86_64 {
36    fn decode_with_decoder_into<'mem>(
37        decoder: &Self::Decoder,
38        cursor: &crate::memory::repr::ReadCursor<'mem, Self, M>,
39        instr: &mut Self::Instruction
40    ) -> Result<(), Self::DecodeError> {
41        let mut reader = cursor.to_reader();
42        decoder.decode_into(instr, &mut reader)
43    }
44}
45
46// TODO: DataMemo needs to be updated to serialize symbolic expression graphs
47// #[derive(Serialize, Deserialize)]
48#[allow(non_camel_case_types)]
49pub struct x86_64Data {
50//    #[serde(skip)]
51    pub timings: Timings<<x86_64 as Arch>::Address>,
52    pub preferred_addr: <x86_64 as Arch>::Address,
53    pub contexts: MergedContextTable,
54    pub cfg: control_flow::ControlFlowGraph<<x86_64 as Arch>::Address>,
55    pub ssa: HashMap<<x86_64 as Arch>::Address, (
56        control_flow::ControlFlowGraph<<x86_64 as Arch>::Address>,
57        SSA<x86_64>
58    )>,
59}
60
61pub struct DisplayCtx<'a> {
62    functions: Ref<'a, HashMap<<x86_64 as Arch>::Address, FunctionImpl<<x86_64 as ValueLocations>::Location>>>,
63    comments: &'a HashMap<<x86_64 as Arch>::Address, String>,
64    symbols: &'a HashMap<<x86_64 as Arch>::Address, Symbol>,
65}
66
67impl FunctionQuery<<x86_64 as Arch>::Address> for x86_64Data {
68    type Function = FunctionImpl<<x86_64 as ValueLocations>::Location>;
69    // TODO: !!!
70    fn function_at(&self, _addr: <x86_64 as Arch>::Address) -> Option<&Self::Function> {
71        unimplemented!("FunctionQuery::function_at for x86_64Data");
72    }
73    fn all_functions(&self) -> Vec<&Self::Function> {
74        unimplemented!("FunctionQuery::all_functions for x86_64Data");
75    }
76}
77
78impl CommentQuery<<x86_64 as Arch>::Address> for MergedContextTable {
79    fn comment_for(&self, addr: <x86_64 as Arch>::Address) -> Option<&str> {
80        self.comments.get(&addr).map(String::as_ref)
81    }
82}
83
84impl FunctionQuery<<x86_64 as Arch>::Address> for MergedContextTable {
85    type Function = FunctionImpl<<x86_64 as ValueLocations>::Location>;
86    // TODO: !!!
87    fn function_at(&self, _addr: <x86_64 as Arch>::Address) -> Option<&Self::Function> {
88        unimplemented!("FunctionQuery::function_at for MergedContextTable");
89    }
90    fn all_functions(&self) -> Vec<&Self::Function> {
91        unimplemented!("FunctionQuery::all_functions for MergedContextTable");
92    }
93}
94
95impl SymbolQuery<<x86_64 as Arch>::Address> for x86_64Data {
96    fn symbol_for(&self, addr: <x86_64 as Arch>::Address) -> Option<&Symbol> {
97        self.contexts.symbols.get(&addr)
98    }
99    fn symbol_addr(&self, sym: &Symbol) -> Option<<x86_64 as Arch>::Address> {
100        for (k, v) in self.contexts.symbols.iter() {
101            if v == sym {
102                return Some(*k);
103            }
104        }
105
106        None
107    }
108}
109
110impl<'a> FunctionQuery<<x86_64 as Arch>::Address> for DisplayCtx<'a> {
111    type Function = FunctionImpl<<x86_64 as ValueLocations>::Location>;
112    fn function_at(&self, addr: <x86_64 as Arch>::Address) -> Option<&Self::Function> {
113        self.functions.function_at(addr)
114    }
115    fn all_functions(&self) -> Vec<&Self::Function> {
116        self.functions.all_functions()
117    }
118}
119
120impl<'a> CommentQuery<<x86_64 as Arch>::Address> for DisplayCtx<'a> {
121    fn comment_for(&self, addr: <x86_64 as Arch>::Address) -> Option<&str> {
122        self.comments.get(&addr).map(String::as_ref)
123    }
124}
125
126impl<'a> SymbolQuery<<x86_64 as Arch>::Address> for DisplayCtx<'a> {
127    fn symbol_for(&self, addr: <x86_64 as Arch>::Address) -> Option<&Symbol> {
128        self.symbols.get(&addr)
129    }
130    fn symbol_addr(&self, sym: &Symbol) -> Option<<x86_64 as Arch>::Address> {
131        for (k, v) in self.symbols.iter() {
132            if v == sym {
133                return Some(*k);
134            }
135        }
136
137        None
138    }
139}
140
141impl Default for x86_64Data {
142    fn default() -> Self {
143        x86_64Data {
144            timings: Timings::new(),
145            preferred_addr: <x86_64 as Arch>::Address::zero(),
146            contexts: MergedContextTable::create_empty(),
147            cfg: control_flow::ControlFlowGraph::new(),
148            ssa: HashMap::new(),
149        }
150    }
151}
152
153#[derive(Serialize, Deserialize)]
154pub struct MergedContextTable {
155    pub user_contexts: HashMap<<x86_64 as Arch>::Address, Rc<()>>,
156    pub computed_contexts: HashMap<<x86_64 as Arch>::Address, Rc<()>>,
157    pub comments: HashMap<<x86_64 as Arch>::Address, String>,
158    #[serde(skip)]
159    pub call_graph: GraphMap<<x86_64 as Arch>::Address, (), petgraph::Directed>,
160    #[serde(skip)]
161    pub xrefs: xrefs::XRefCollection<<x86_64 as Arch>::Address>,
162    pub symbols: HashMap<<x86_64 as Arch>::Address, Symbol>,
163    #[serde(skip)]
164    pub reverse_symbols: HashMap<Symbol, <x86_64 as Arch>::Address>,
165    pub functions: Rc<RefCell<HashMap<<x86_64 as Arch>::Address, FunctionImpl<<x86_64 as ValueLocations>::Location>>>>,
166    pub function_data: HashMap<<x86_64 as Arch>::Address, RefCell<InstructionModifiers<x86_64>>>,
167    pub function_hints: Vec<<x86_64 as Arch>::Address>,
168    functions_hinted: HashSet<<x86_64 as Arch>::Address>,
169    pub default_abi: Option<DefaultCallingConvention>,
170}
171
172#[derive(Debug)]
173pub struct MergedContext {
174    pub computed: Option<Rc<()>>,
175    pub user: Option<Rc<()>>
176}
177
178impl Default for MergedContextTable {
179    fn default() -> Self {
180        MergedContextTable::create_empty()
181    }
182}
183
184impl MergedContextTable {
185    pub fn fn_count(&self) -> usize {
186        self.functions.borrow().len()
187    }
188    pub fn create_empty() -> MergedContextTable {
189        MergedContextTable {
190            user_contexts: HashMap::new(),
191            computed_contexts: HashMap::new(),
192            comments: HashMap::new(),
193            call_graph: GraphMap::new(),
194            xrefs: xrefs::XRefCollection::new(),
195            functions: Rc::new(RefCell::new(HashMap::new())),
196            function_hints: Vec::new(),
197            functions_hinted: HashSet::new(),
198            symbols: HashMap::new(),
199            reverse_symbols: HashMap::new(),
200            function_data: HashMap::new(),
201            default_abi: Some(DefaultCallingConvention::Microsoft), //None,
202        }
203    }
204
205    pub fn display_ctx(&self) -> DisplayCtx {
206        DisplayCtx {
207            functions: self.functions.borrow(),
208            symbols: &self.symbols,
209            comments: &self.comments,
210        }
211    }
212}
213
214/*
215pub enum Value {
216    U8(u8),
217    U16(u16),
218    U32(u32),
219    U64(u64),
220    U128(u64, u64),
221    U256(u64, u64, u64, u64),
222    U512(u64, u64, u64, u64, u64, u64, u64, u64)
223}
224
225trait PartialInstructionContext {
226    pub fn reg_value(reg: RegSpec) -> Option<Value>;
227    pub fn mem_value(addr: u64, width: u8) -> Option<Value>;
228}
229*/
230
231pub type Update = BaseUpdate<x86Update>;
232
233#[derive(Debug)]
234#[allow(non_camel_case_types)]
235pub enum x86Update {
236    AddXRef(xrefs::RefType, xrefs::RefAction, <x86_64 as Arch>::Address),
237    RemoveXRef(xrefs::RefType, xrefs::RefAction, <x86_64 as Arch>::Address),
238    FunctionHint
239}
240
241impl ContextRead<x86_64, MergedContext> for MergedContextTable {
242    fn at(&self, address: &<x86_64 as Arch>::Address) -> MergedContext {
243        MergedContext {
244            user: self.user_contexts.get(address).map(|v| Rc::clone(v)),
245            computed: self.computed_contexts.get(address).map(|v| Rc::clone(v))
246        }
247    }
248}
249
250impl ContextWrite<x86_64, Update> for MergedContextTable {
251    fn put(&mut self, address: <x86_64 as Arch>::Address, update: Update) {
252        // println!("Applying update: {} -> {:?}", address.stringy(), update);
253        match update {
254            BaseUpdate::Specialized(x86Update::FunctionHint) => {
255                if !self.functions.borrow().contains_key(&address) && !self.functions_hinted.contains(&address) {
256//                    println!("Function hint: {}", address.stringy());
257                    self.functions_hinted.insert(address);
258                    self.function_hints.push(address)
259                }
260            },
261            BaseUpdate::Specialized(x86Update::AddXRef(tpe, action, dest)) => {
262                // TODO: xrefs from non-code sources
263                self.xrefs.insert_from_code(tpe, action, address, dest);
264            },
265            BaseUpdate::Specialized(x86Update::RemoveXRef(tpe, action, dest)) => {
266                self.xrefs.delete_from_code(tpe, action, address, dest);
267            }
268            BaseUpdate::DefineSymbol(sym) => {
269                //println!("address of {:?} recorded at {}", sym, address.stringy());
270                if !self.symbols.contains_key(&address) {
271                    match Symbol::to_function(&sym) {
272                        Some(f) => {
273                            if let Some(abi) = self.default_abi {
274                                self.functions.borrow_mut().insert(address, f.implement_for(FunctionLayout::for_abi(abi)));
275                            } else {
276                                // TODO: indicate that the function should have been defined, but
277                                // was not because we don't know an ABI to map it to?
278                                self.functions.borrow_mut().insert(address, f.unimplemented());
279                            }
280                        }
281                        None => { }
282                    }
283                    self.symbols.insert(address, sym.clone());
284                    self.reverse_symbols.insert(sym, address);
285                }
286            }
287            BaseUpdate::DefineFunction(f) => {
288                if !self.functions.borrow().contains_key(&address) {
289                    self.symbols.insert(address, Symbol(Library::This, f.name.clone()));
290                    self.reverse_symbols.insert(Symbol(Library::This, f.name.clone()), address);
291                    if let Some(abi) = self.default_abi {
292                        self.functions.borrow_mut().insert(address, f.implement_for(FunctionLayout::for_abi(abi)));
293                    } else {
294                        // TODO: indicate that the function should have been defined, but was not
295                        // because we don't know an ABI to map it to?
296                        self.functions.borrow_mut().insert(address, f.unimplemented());
297                    }
298                }
299            }
300            BaseUpdate::AddCodeComment(comment) => {
301                self.comments.insert(address, comment);
302            }
303            _ => { /* todo: the rest */ }
304        }
305    }
306}