1use cxx::CxxString;
2use cxx::CxxVector;
3use cxx::UniquePtr;
4use std::os::raw::c_char;
5
6use num_derive::FromPrimitive;
7
8#[derive(Debug, FromPrimitive)]
9pub enum SpaceType {
10 Constant = 0,
11 Processor = 1,
12 SpaceBase = 2,
13 Internal = 3,
14 Fspec = 4,
15 Iop = 5,
16 Join = 6,
17}
18
19impl SpaceType {
20 pub fn from_u32(val: u32) -> Option<Self> {
21 num::FromPrimitive::from_u32(val)
22 }
23}
24
25#[derive(Debug, FromPrimitive)]
26pub enum Opcode {
27 Copy = 1,
28 Load = 2,
30 Store = 3,
32 Branch = 4,
34 CBranch = 5,
36 BranchInd = 6,
38 Call = 7,
40 CallInd = 8,
42 CallOther = 9,
44 Return = 10,
46 IntEqual = 11,
49 IntNotEqual = 12,
51 IntSLess = 13,
53 IntSLessEqual = 14,
55 IntLess = 15,
57 IntLessEqual = 16,
60 IntZExt = 17,
62 IntSExt = 18,
64 IntAdd = 19,
66 IntSub = 20,
68 IntCarry = 21,
70 IntSCarry = 22,
72 IntSBorrow = 23,
74 Int2Comp = 24,
76 IntNegate = 25,
78 IntXor = 26,
80 IntAnd = 27,
82 IntOr = 28,
84 IntLeft = 29,
86 IntRight = 30,
88 IntSRight = 31,
90 IntMult = 32,
92 IntDiv = 33,
94 IntSDiv = 34,
96 IntRem = 35,
98 IntSRem = 36,
100 BoolNegate = 37,
102 BoolXor = 38,
104 BoolAnd = 39,
106 BoolOr = 40,
108 FloatEqual = 41,
111 FloatNotEqual = 42,
113 FloatLess = 43,
115 FloatLessEqual = 44,
117 FloatNan = 46,
120 FloatAdd = 47,
122 FloatDiv = 48,
124 FloatMult = 49,
126 FloatSub = 50,
128 FloatNeg = 51,
130 FloatAbs = 52,
132 FloatSqrt = 53,
134 FloatInt2Float = 54,
136 FloatFloat2Float = 55,
138 FloatTrunc = 56,
140 FloatCeil = 57,
142 FloatFloor = 58,
144 FloatRound = 59,
146 MultiEqual = 60,
152 Indirect = 61,
154 Piece = 62,
156 SubPiece = 63,
158 Cast = 64,
160 PtrAdd = 65,
162 PtrSub = 66,
164 SegmentOp = 67,
166 CPoolRef = 68,
168 New = 69,
170 Insert = 70,
172 Extract = 71,
174 PopCount = 72,
176 Max = 73,
178}
179
180impl Opcode {
181 pub fn from_u32(val: u32) -> Option<Self> {
182 num::FromPrimitive::from_u32(val)
183 }
184}
185
186pub trait AssemblyEmit {
192 fn dump(&mut self, addr: &ffi::Address, mnem: &str, body: &str);
193}
194
195pub struct RustAssemblyEmit<'a> {
196 internal: &'a mut dyn AssemblyEmit,
197}
198
199impl<'a> RustAssemblyEmit<'a> {
200 pub fn from_internal(internal: &'a mut dyn AssemblyEmit) -> Self {
201 Self { internal }
202 }
203
204 pub fn dump(&mut self, address: &ffi::Address, mnem: &CxxString, body: &CxxString) {
205 let mnem = mnem.to_str().unwrap();
206 let body = body.to_str().unwrap();
207
208 self.internal.dump(address, mnem, body);
209 }
210}
211
212pub trait PCodeEmit {
213 fn dump(
219 &mut self,
220 address: &ffi::Address,
221 opcode: Opcode,
222 outvar: Option<&ffi::VarnodeData>,
223 vars: &[ffi::VarnodeData],
224 );
225}
226
227pub struct RustPCodeEmit<'a> {
228 pub internal: &'a mut dyn PCodeEmit,
229}
230
231pub trait LoadImage {
232 fn load_fill(&mut self, ptr: &mut [u8], addr: &ffi::Address);
233 fn adjust_vma(&mut self, _adjust: isize) {}
234}
235
236pub struct RustLoadImage<'a> {
237 internal: &'a mut dyn LoadImage,
238}
239
240impl<'a> RustLoadImage<'a> {
241 pub fn from_internal(internal: &'a mut dyn LoadImage) -> Self {
242 Self { internal }
243 }
244
245 unsafe fn load_fill(&mut self, ptr: *mut u8, size: u32, addr: &ffi::Address) {
246 let slice = std::slice::from_raw_parts_mut(ptr, size as usize);
247 self.internal.load_fill(slice, addr);
248 }
249
250 fn adjust_vma(&mut self, adjust: isize) {
251 self.internal.adjust_vma(adjust)
252 }
253}
254
255impl<'a> RustPCodeEmit<'a> {
256 pub fn from_internal(internal: &'a mut dyn PCodeEmit) -> Self {
257 Self { internal }
258 }
259
260 unsafe fn dump(
261 &mut self,
262 address: &ffi::Address,
263 opcode: u32,
264 outvar: *const ffi::VarnodeData,
265 vars: *const ffi::VarnodeData,
266 size: i32,
267 ) {
268 let outvar = if outvar.is_null() {
269 None
270 } else {
271 Some(&*outvar)
272 };
273 let vars = std::slice::from_raw_parts(vars, size as usize);
274 let opcode = num::FromPrimitive::from_u32(opcode).unwrap();
275 self.internal.dump(address, opcode, outvar, vars);
276 }
277}
278
279#[cxx::bridge]
280pub mod ffi {
281 extern "Rust" {
282 type RustAssemblyEmit<'a>;
283 fn dump(self: &mut RustAssemblyEmit, address: &Address, mnem: &CxxString, body: &CxxString);
284
285 type RustPCodeEmit<'a>;
286 unsafe fn dump(
287 self: &mut RustPCodeEmit,
288 address: &Address,
289 opcode: u32,
290 outvar: *const VarnodeData,
291 vars: *const VarnodeData,
292 size: i32,
293 );
294
295 type RustLoadImage<'a>;
296 unsafe fn load_fill(self: &mut RustLoadImage, ptr: *mut u8, size: u32, addr: &Address);
297 fn adjust_vma(self: &mut RustLoadImage, adjust: isize);
299 }
300
301 unsafe extern "C++" {
302 include!("bridge.hh");
303
304 type Address;
305 fn isInvalid(self: &Address) -> bool;
306 fn getAddrSize(self: &Address) -> i32;
307 fn isBigEndian(self: &Address) -> bool;
308 fn getSpace(self: &Address) -> *mut AddrSpace;
309 fn getOffset(self: &Address) -> u64;
310 fn toPhysical(self: Pin<&mut Address>);
311 fn getShortcut(self: &Address) -> c_char;
312 fn containedBy(self: &Address, sz: i32, op2: &Address, sz2: i32) -> bool;
313 fn justifiedContain(
314 self: &Address,
315 sz: i32,
316 op2: &Address,
317 sz2: i32,
318 forceleft: bool,
319 ) -> i32;
320 fn overlap(self: &Address, skip: i32, op: &Address, size: i32) -> i32;
321 fn isContiguous(self: &Address, sz: i32, loaddr: &Address, losz: i32) -> bool;
322 fn isConstant(self: &Address) -> bool;
323 fn renormalize(self: Pin<&mut Address>, size: i32);
324 fn isJoin(self: &Address) -> bool;
325
326 type VarnodeData;
327 fn getVarnodeDataAddress(data: &VarnodeData) -> UniquePtr<Address>;
328 fn getVarnodeSize(data: &VarnodeData) -> u32;
329
330 type spacetype;
331 type AddrSpace;
332 fn getName(self: &AddrSpace) -> &CxxString;
333 fn getDelay(self: &AddrSpace) -> i32;
335 fn getDeadcodeDelay(self: &AddrSpace) -> i32;
336 fn getIndex(self: &AddrSpace) -> i32;
337 fn getWordSize(self: &AddrSpace) -> u32;
338 fn getAddrSize(self: &AddrSpace) -> u32;
339 fn getHighest(self: &AddrSpace) -> u64;
340 fn getPointerLowerBound(self: &AddrSpace) -> u64;
341 fn getPointerUpperBound(self: &AddrSpace) -> u64;
342 fn getMinimumPtrSize(self: &AddrSpace) -> i32;
343 fn wrapOffset(self: &AddrSpace, off: u64) -> u64;
344 fn getShortcut(self: &AddrSpace) -> c_char;
345 fn isHeritaged(self: &AddrSpace) -> bool;
346 fn doesDeadcode(self: &AddrSpace) -> bool;
347 fn hasPhysical(self: &AddrSpace) -> bool;
348 fn isBigEndian(self: &AddrSpace) -> bool;
349 fn isReverseJustified(self: &AddrSpace) -> bool;
350 fn isOverlay(self: &AddrSpace) -> bool;
351 fn isOverlayBase(self: &AddrSpace) -> bool;
352 fn isOtherSpace(self: &AddrSpace) -> bool;
353 fn isTruncated(self: &AddrSpace) -> bool;
354 fn hasNearPointers(self: &AddrSpace) -> bool;
355 fn numSpacebase(self: &AddrSpace) -> i32;
356 fn getSpacebase(self: &AddrSpace, i: i32) -> &VarnodeData;
357 fn getSpacebaseFull(self: &AddrSpace, i: i32) -> &VarnodeData;
358 fn stackGrowsNegative(self: &AddrSpace) -> bool;
359 fn getContain(self: &AddrSpace) -> *mut AddrSpace;
360
361 type OpCode;
362
363 type DocumentStorage;
364
365 type ContextInternal;
366 type ContextDatabase;
367
368 fn setVariableDefault(self: Pin<&mut ContextDatabase>, nm: &CxxString, val: u32);
369 fn getDefaultValue(self: &ContextDatabase, nm: &CxxString) -> u32;
370 fn setVariable(self: Pin<&mut ContextDatabase>, nm: &CxxString, addr: &Address, val: u32);
371 fn getVariable(self: &ContextDatabase, nm: &CxxString, addr: &Address) -> u32;
372
373 fn newAddress() -> UniquePtr<Address>;
374 fn newContext() -> UniquePtr<ContextDatabase>;
375 fn newDocumentStorage(s: &CxxString) -> UniquePtr<DocumentStorage>;
376
377 fn getAddrSpaceType(addr: &AddrSpace) -> u32;
378
379 type Decompiler;
380 unsafe fn translate(self: &Decompiler, emit: *mut RustPCodeEmit, addr: u64) -> i32;
381 unsafe fn disassemble(self: &Decompiler, emit: *mut RustAssemblyEmit, addr: u64) -> i32;
382 unsafe fn getContext(self: Pin<&mut Decompiler>) -> *mut ContextDatabase;
383 unsafe fn newDecompiler(
384 loadImage: *mut RustLoadImage,
385 spec: UniquePtr<DocumentStorage>,
386 ) -> UniquePtr<Decompiler>;
387
388 }
389}
390
391#[cfg(test)]
392mod tests {
393 use super::ffi;
394 #[test]
395 fn test_new() {
396 let _a = ffi::newAddress();
397 let _a = ffi::newContext();
398 }
399}