Skip to content

Commit ca10267

Browse files
committed
Some more changes
1 parent 93279f3 commit ca10267

File tree

3 files changed

+86
-56
lines changed

3 files changed

+86
-56
lines changed

rust/src/architecture.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ impl FlagGroup for CoreFlagGroup {
12911291
}
12921292
}
12931293

1294-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1294+
#[derive(Copy, Clone, Eq, PartialEq)]
12951295
pub struct CoreIntrinsic {
12961296
pub arch: CoreArchitecture,
12971297
pub id: IntrinsicId,
@@ -1377,6 +1377,18 @@ impl Intrinsic for CoreIntrinsic {
13771377
}
13781378
}
13791379

1380+
impl Debug for CoreIntrinsic {
1381+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1382+
f.debug_struct("CoreIntrinsic")
1383+
.field("id", &self.id)
1384+
.field("name", &self.name())
1385+
.field("class", &self.class())
1386+
.field("inputs", &self.inputs())
1387+
.field("outputs", &self.outputs())
1388+
.finish()
1389+
}
1390+
}
1391+
13801392
// TODO: WTF?!?!?!?
13811393
pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize);
13821394

rust/src/low_level_il/operation.rs

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -230,19 +230,19 @@ where
230230
// LLIL_INTRINSIC, LLIL_INTRINSIC_SSA
231231
pub struct Intrinsic;
232232

233-
#[derive(Debug, Clone, Copy)]
234-
pub enum RegOrFlag {
233+
#[derive(Debug, Clone, Copy, PartialEq)]
234+
pub enum IntrinsicOutput {
235235
Reg(CoreRegister),
236236
Flag(CoreFlag),
237237
}
238238

239-
impl From<CoreRegister> for RegOrFlag {
239+
impl From<CoreRegister> for IntrinsicOutput {
240240
fn from(value: CoreRegister) -> Self {
241241
Self::Reg(value)
242242
}
243243
}
244244

245-
impl From<CoreFlag> for RegOrFlag {
245+
impl From<CoreFlag> for IntrinsicOutput {
246246
fn from(value: CoreFlag) -> Self {
247247
Self::Flag(value)
248248
}
@@ -253,63 +253,34 @@ where
253253
M: FunctionMutability,
254254
F: FunctionForm,
255255
{
256-
// Order of operands for this operation:
257-
// 1. Number of outputs in the reg or flag list
258-
// 2. Reg or flag list
259-
// 3. Intrinsic id
260-
// 4. Operand list
261-
262-
// TODO: Support register and expression lists
263256
pub fn intrinsic(&self) -> Option<CoreIntrinsic> {
264257
let raw_id = self.op.operands[2] as u32;
265258
self.function.arch().intrinsic_from_id(IntrinsicId(raw_id))
266259
}
267260

268-
/// Number of outputs the intrinsic has.
269-
#[inline]
270-
pub fn output_count(&self) -> usize {
271-
self.op.operands[0] as usize
272-
}
273-
274261
/// Get the output list.
275-
pub fn outputs(&self) -> Vec<RegOrFlag> {
276-
let mut outputs = Vec::new();
277-
let mut output_size = self.op.operands[0] as usize;
278-
if output_size == 0 {
279-
return outputs;
280-
}
281-
let out_list = unsafe {
282-
BNLowLevelILGetOperandList(
283-
self.function.handle,
284-
self.expr_idx.0,
285-
0,
286-
&mut output_size as *mut _,
287-
)
288-
};
289-
let out_list = unsafe { std::slice::from_raw_parts_mut(out_list, output_size) };
290-
for val in out_list.iter() {
291-
if *val & (1 << 32) != 0 {
292-
outputs.push(
293-
self.function
294-
.arch()
295-
.flag_from_id(FlagId((*val & 0xffffffff) as u32))
296-
.expect("Invalid core flag ID")
297-
.into(),
298-
);
262+
pub fn outputs(&self) -> Vec<IntrinsicOutput> {
263+
// Convert the operand to either a register or flag id.
264+
let operand_to_output = |o: u64| {
265+
if o & (1 << 32) != 0 {
266+
self.function
267+
.arch()
268+
.flag_from_id(FlagId((o & 0xffffffff) as u32))
269+
.expect("Invalid core flag ID")
270+
.into()
299271
} else {
300-
outputs.push(
301-
self.function
302-
.arch()
303-
.register_from_id(RegisterId((*val & 0xffffffff) as u32))
304-
.expect("Invalid register ID")
305-
.into(),
306-
);
272+
self.function
273+
.arch()
274+
.register_from_id(RegisterId((o & 0xffffffff) as u32))
275+
.expect("Invalid register ID")
276+
.into()
307277
}
308-
}
309-
// Need to drop the list at the end. This will get leaked if there's a panic anywhere.
310-
// TODO: Make a new type for this that implements drop so it can't be leaked.
311-
unsafe { BNLowLevelILFreeOperandList(out_list.as_mut_ptr()) };
312-
outputs
278+
};
279+
280+
self.get_operand_list(0)
281+
.into_iter()
282+
.map(operand_to_output)
283+
.collect::<Vec<_>>()
313284
}
314285

315286
/// Get the input list for the intrinsic.
@@ -330,9 +301,15 @@ where
330301
F: FunctionForm,
331302
{
332303
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
304+
use crate::architecture::Intrinsic;
333305
f.debug_struct("Intrinsic")
334306
.field("address", &self.address())
335-
.field("size", &self.intrinsic())
307+
.field(
308+
"intrinsic",
309+
&self.intrinsic().expect("Valid intrinsic").name(),
310+
)
311+
.field("outputs", &self.outputs())
312+
.field("inputs", &self.inputs())
336313
.finish()
337314
}
338315
}

rust/tests/low_level_il.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use binaryninja::architecture::Register;
1+
use binaryninja::architecture::{ArchitectureExt, Intrinsic, Register};
22
use binaryninja::binary_view::BinaryViewExt;
33
use binaryninja::headless::Session;
44
use binaryninja::low_level_il::expression::{
@@ -7,6 +7,7 @@ use binaryninja::low_level_il::expression::{
77
use binaryninja::low_level_il::instruction::{
88
InstructionHandler, LowLevelILInstructionKind, LowLevelInstructionIndex,
99
};
10+
use binaryninja::low_level_il::operation::IntrinsicOutput;
1011
use binaryninja::low_level_il::{LowLevelILRegisterKind, LowLevelILSSARegisterKind, VisitorAction};
1112
use std::path::PathBuf;
1213

@@ -308,3 +309,43 @@ fn test_llil_ssa() {
308309
_ => panic!("Expected CallSsa"),
309310
}
310311
}
312+
313+
#[test]
314+
fn test_llil_intrinsic() {
315+
let _session = Session::new().expect("Failed to initialize session");
316+
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
317+
let view = binaryninja::load(out_dir.join("atof.obj")).expect("Failed to create view");
318+
let image_base = view.original_image_base();
319+
let platform = view.default_platform().unwrap();
320+
let arch = platform.arch();
321+
322+
// Sample function: __crt_strtox::bit_scan_reverse
323+
let sample_function = view
324+
.function_at(&platform, image_base + 0x00037310)
325+
.unwrap();
326+
let llil_function = sample_function.low_level_il().unwrap();
327+
328+
// 5 @ 0004731d (LLIL_INTRINSIC eax, eflags = __bsr_gprv_memv((LLIL_LOAD.d [(LLIL_ADD.d (LLIL_REG.d ebp) + (LLIL_CONST.d 8)) {arg1}].d)))
329+
let instr_5 = llil_function
330+
.instruction_from_index(LowLevelInstructionIndex(5))
331+
.expect("Valid instruction");
332+
assert_eq!(instr_5.address(), image_base + 0x0003731d);
333+
println!("{:?}", instr_5);
334+
println!("{:#?}", instr_5.kind());
335+
match instr_5.kind() {
336+
LowLevelILInstructionKind::Intrinsic(op) => {
337+
assert_eq!(op.intrinsic().unwrap().name(), "__bsr_gprv_memv");
338+
assert_eq!(op.outputs().len(), 2);
339+
let reg_out_0 = arch.register_by_name("eax").unwrap();
340+
let reg_out_1 = arch.register_by_name("eflags").unwrap();
341+
assert_eq!(
342+
op.outputs(),
343+
vec![
344+
IntrinsicOutput::Reg(reg_out_0),
345+
IntrinsicOutput::Reg(reg_out_1),
346+
]
347+
);
348+
}
349+
_ => panic!("Expected Intrinsic"),
350+
}
351+
}

0 commit comments

Comments
 (0)