Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions rust/src/low_level_il/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ where
F: FunctionForm,
R: ExpressionResultType,
{
pub(crate) fn new(
function: &'func LowLevelILFunction<M, F>,
index: LowLevelExpressionIndex,
) -> Self {
pub fn new(function: &'func LowLevelILFunction<M, F>, index: LowLevelExpressionIndex) -> Self {
// TODO: Validate expression here?
Self {
function,
Expand Down
115 changes: 114 additions & 1 deletion rust/src/low_level_il/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ where
};
PossibleValueSet::from_owned_core_raw(raw_pvs)
}

/// Get the raw operand from the operand list.
///
/// This has no type information associated with it. It's up to the caller to know what the correct type of the
/// underlying u64 should be.
///
/// # Panic
/// `idx` must be less than 4. This is to protect against an out of bounds access.
///
/// # Safety
/// Even if `idx` is valid, it may index to an unitialized or unused value. Make sure you index into an operand that
/// you know should be initialized properly.
pub unsafe fn get_operand(&self, idx: usize) -> u64 {
assert!(idx < 4);
self.op.operands[idx]
}
}

impl<M, O> Operation<'_, M, NonSSA, O>
Expand Down Expand Up @@ -214,16 +230,98 @@ where
// LLIL_INTRINSIC, LLIL_INTRINSIC_SSA
pub struct Intrinsic;

#[derive(Debug, Clone, Copy)]
pub enum RegOrFlag {
Reg(CoreRegister),
Flag(CoreFlag),
}

impl From<CoreRegister> for RegOrFlag {
fn from(value: CoreRegister) -> Self {
Self::Reg(value)
}
}

impl From<CoreFlag> for RegOrFlag {
fn from(value: CoreFlag) -> Self {
Self::Flag(value)
}
}

impl<M, F> Operation<'_, M, F, Intrinsic>
where
M: FunctionMutability,
F: FunctionForm,
{
// Order of operands for this operation:
// 1. Number of outputs in the reg or flag list
// 2. Reg or flag list
// 3. Intrinsic id
// 4. Operand list

// TODO: Support register and expression lists
pub fn intrinsic(&self) -> Option<CoreIntrinsic> {
let raw_id = self.op.operands[2] as u32;
self.function.arch().intrinsic_from_id(IntrinsicId(raw_id))
}

/// Number of outputs the intrinsic has.
#[inline]
pub fn output_count(&self) -> usize {
self.op.operands[0] as usize
}

/// Get the output list.
pub fn outputs(&self) -> Vec<RegOrFlag> {
let mut outputs = Vec::new();
let mut output_size = self.op.operands[0] as usize;
if output_size == 0 {
return outputs;
}
let out_list = unsafe {
BNLowLevelILGetOperandList(
self.function.handle,
self.expr_idx.0,
0,
&mut output_size as *mut _,
)
};
let out_list = unsafe { std::slice::from_raw_parts_mut(out_list, output_size) };
for val in out_list.iter() {
if *val & (1 << 32) != 0 {
outputs.push(
self.function
.arch()
.flag_from_id(FlagId((*val & 0xffffffff) as u32))
.expect("Invalid core flag ID")
.into(),
);
} else {
outputs.push(
self.function
.arch()
.register_from_id(RegisterId((*val & 0xffffffff) as u32))
.expect("Invalid register ID")
.into(),
);
}
}
// Need to drop the list at the end. This will get leaked if there's a panic anywhere.
// TODO: Make a new type for this that implements drop so it can't be leaked.
unsafe { BNLowLevelILFreeOperandList(out_list.as_mut_ptr()) };
outputs
}

/// Get the input list for the intrinsic.
///
/// This will just be a CallParamSsa expression.
#[inline]
pub fn inputs(&self) -> LowLevelILExpression<'_, M, F, ValueExpr> {
LowLevelILExpression::new(
self.function,
LowLevelExpressionIndex(self.op.operands[3] as usize),
)
}
}

impl<M, F> Debug for Operation<'_, M, F, Intrinsic>
Expand Down Expand Up @@ -1013,13 +1111,28 @@ where
// LLIL_FLAG, LLIL_FLAG_SSA
pub struct Flag;

impl<M, F> Operation<'_, M, F, Flag>
where
M: FunctionMutability,
F: FunctionForm,
{
pub fn source_flag(&self) -> CoreFlag {
self.function
.arch()
.flag_from_id(FlagId(self.op.operands[0] as u32))
.expect("Bad flag ID")
}
}

impl<M, F> Debug for Operation<'_, M, F, Flag>
where
M: FunctionMutability,
F: FunctionForm,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Flag").finish()
f.debug_struct("Flag")
.field("source_flag", &self.source_flag())
.finish()
}
}

Expand Down