summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-12-23 13:12:02 -0700
committerRusty Wagner <rusty.wagner@gmail.com>2026-05-22 16:30:56 -0400
commit8d621c51b2797fda7b1dc22243dde611cfc04f68 (patch)
treeba5e6a90e644d21d13e75dabcbd0cc747444443a /rust
parent08e34ac325743085911f96b62c81d9a1f2127806 (diff)
Refactor calling conventions to support correct representation of structures
Diffstat (limited to 'rust')
-rw-r--r--rust/src/binary_view.rs35
-rw-r--r--rust/src/calling_convention.rs120
-rw-r--r--rust/src/confidence.rs17
-rw-r--r--rust/src/disassembly.rs5
-rw-r--r--rust/src/ffi.rs13
-rw-r--r--rust/src/function.rs121
-rw-r--r--rust/src/high_level_il/instruction.rs10
-rw-r--r--rust/src/high_level_il/lift.rs14
-rw-r--r--rust/src/medium_level_il/instruction.rs55
-rw-r--r--rust/src/medium_level_il/lift.rs38
-rw-r--r--rust/src/medium_level_il/operation.rs51
-rw-r--r--rust/src/types.rs396
-rw-r--r--rust/src/variable.rs51
13 files changed, 801 insertions, 125 deletions
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs
index 8d49e55e..c455635a 100644
--- a/rust/src/binary_view.rs
+++ b/rust/src/binary_view.rs
@@ -51,8 +51,9 @@ use crate::string::*;
use crate::symbol::{Symbol, SymbolType};
use crate::tags::{Tag, TagReference, TagType};
use crate::types::{
- NamedTypeReference, QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type,
- TypeArchive, TypeArchiveId, TypeContainer, TypeLibrary,
+ FunctionParameter, NamedTypeReference, QualifiedName, QualifiedNameAndType,
+ QualifiedNameTypeAndId, ReturnValue, Type, TypeArchive, TypeArchiveId, TypeContainer,
+ TypeLibrary,
};
use crate::variable::DataVariable;
use crate::workflow::Workflow;
@@ -2964,6 +2965,36 @@ impl BinaryView {
let path_str = unsafe { BnString::into_string(result) };
Some(PathBuf::from(path_str))
}
+
+ pub fn deref_return_value_named_type_references(
+ &self,
+ return_value: &ReturnValue,
+ ) -> ReturnValue {
+ ReturnValue {
+ ty: Conf::new(
+ return_value.ty.contents.deref_named_type_reference(self),
+ return_value.ty.confidence,
+ ),
+ location: return_value.location.clone(),
+ }
+ }
+
+ pub fn deref_parameter_named_type_references(
+ &self,
+ params: &[FunctionParameter],
+ ) -> Vec<FunctionParameter> {
+ params
+ .iter()
+ .map(|param| FunctionParameter {
+ ty: Conf::new(
+ param.ty.contents.deref_named_type_reference(self),
+ param.ty.confidence,
+ ),
+ name: param.name.clone(),
+ location: param.location.clone(),
+ })
+ .collect()
+ }
}
impl BinaryViewBase for BinaryView {
diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs
index a2c4fd94..f91e9803 100644
--- a/rust/src/calling_convention.rs
+++ b/rust/src/calling_convention.rs
@@ -15,6 +15,7 @@
//! Contains and provides information about different systems' calling conventions to analysis.
use std::borrow::Borrow;
+use std::collections::BTreeMap;
use std::ffi::c_void;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
@@ -25,10 +26,11 @@ use binaryninjacore_sys::*;
use crate::architecture::{
Architecture, ArchitectureExt, CoreArchitecture, CoreRegister, Register, RegisterId,
};
-use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
+use crate::binary_view::BinaryView;
+use crate::ffi::slice_from_raw_parts;
+use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
use crate::string::*;
-use crate::types::FunctionParameter;
-use crate::variable::Variable;
+use crate::types::{FunctionParameter, ReturnValue, ValueLocation};
// TODO
// force valid registers once Arch has _from_id methods
// CallingConvention impl
@@ -465,6 +467,23 @@ where
getParameterVariableForIncomingVariable: Some(cb_incoming_param_for_var::<C>),
areArgumentRegistersUsedForVarArgs: Some(cb_are_argument_registers_used_for_var_args::<C>),
+
+ isReturnTypeRegisterCompatible: None,
+ getIndirectReturnValueLocation: None,
+ getReturnedIndirectReturnValuePointer: None,
+ isArgumentTypeRegisterCompatible: None,
+ isNonRegisterArgumentIndirect: None,
+ areStackArgumentsNaturallyAligned: None,
+
+ getCallLayout: None,
+ freeCallLayout: None,
+ getReturnValueLocation: None,
+ freeValueLocation: None,
+ getParameterLocations: None,
+ freeParameterLocations: None,
+ getStackAdjustmentForLocations: None,
+ getRegisterStackAdjustments: None,
+ freeRegisterStackAdjustments: None,
};
unsafe {
@@ -514,46 +533,63 @@ impl CoreCallingConvention {
unsafe { BnString::into_string(BNGetCallingConventionName(self.handle)) }
}
- pub fn variables_for_parameters(
+ pub fn call_layout(
&self,
+ view: &BinaryView,
+ return_value: impl Into<ReturnValue>,
params: &[FunctionParameter],
permitted_registers: Option<&[CoreRegister]>,
- ) -> Vec<Variable> {
- let mut count: usize = 0;
+ ) -> CallLayout {
+ let raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let raw_params: Vec<BNFunctionParameter> = params
.iter()
.cloned()
.map(FunctionParameter::into_raw)
.collect();
- let raw_vars_ptr: *mut BNVariable = if let Some(permitted_args) = permitted_registers {
+ let raw_layout: BNCallLayout = if let Some(permitted_args) = permitted_registers {
let permitted_regs = permitted_args.iter().map(|r| r.id().0).collect::<Vec<_>>();
unsafe {
- BNGetVariablesForParameters(
+ BNGetCallLayout(
self.handle,
+ view.handle,
+ &raw_return_value,
raw_params.as_ptr(),
raw_params.len(),
permitted_regs.as_ptr(),
permitted_regs.len(),
- &mut count,
)
}
} else {
unsafe {
- BNGetVariablesForParametersDefaultPermittedArgs(
+ BNGetCallLayoutDefaultPermittedArgs(
self.handle,
+ view.handle,
+ &raw_return_value,
raw_params.as_ptr(),
raw_params.len(),
- &mut count,
)
}
};
- for raw_param in raw_params {
- FunctionParameter::free_raw(raw_param);
- }
+ ReturnValue::free_rust_raw(raw_return_value);
+ CallLayout::from_owned_core_raw(raw_layout)
+ }
- unsafe { Array::<Variable>::new(raw_vars_ptr, count, ()) }.to_vec()
+ pub fn return_value_location(
+ &self,
+ view: &BinaryView,
+ return_value: impl Into<ReturnValue>,
+ ) -> ValueLocation {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ let mut raw_location =
+ unsafe { BNGetReturnValueLocation(self.handle, view.handle, &mut raw_return_value) };
+ ReturnValue::free_rust_raw(raw_return_value);
+ let result = ValueLocation::from_raw(&raw_location);
+ unsafe {
+ BNFreeValueLocation(&mut raw_location);
+ }
+ result
}
}
@@ -1020,3 +1056,57 @@ impl<A: Architecture> CallingConvention for ConventionBuilder<A> {
unsafe impl<A: Architecture> Send for ConventionBuilder<A> {}
unsafe impl<A: Architecture> Sync for ConventionBuilder<A> {}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct CallLayout {
+ pub parameters: Vec<ValueLocation>,
+ pub return_value: Option<ValueLocation>,
+ pub stack_adjustment: i64,
+ pub register_stack_adjustments: BTreeMap<RegisterId, i32>,
+}
+
+impl CallLayout {
+ pub(crate) fn from_raw(value: &BNCallLayout) -> Self {
+ let raw_params = unsafe { slice_from_raw_parts(value.parameters, value.parameterCount) };
+ let parameters = raw_params.iter().map(ValueLocation::from_raw).collect();
+ let return_value = if value.returnValueValid {
+ Some(ValueLocation::from_raw(&value.returnValue))
+ } else {
+ None
+ };
+ let raw_regs = unsafe {
+ slice_from_raw_parts(
+ value.registerStackAdjustmentRegisters,
+ value.registerStackAdjustmentCount,
+ )
+ };
+ let raw_amounts = unsafe {
+ slice_from_raw_parts(
+ value.registerStackAdjustmentAmounts,
+ value.registerStackAdjustmentCount,
+ )
+ };
+ let mut register_stack_adjustments = BTreeMap::new();
+ for i in 0..value.registerStackAdjustmentCount {
+ register_stack_adjustments.insert(RegisterId(raw_regs[i]), raw_amounts[i]);
+ }
+ Self {
+ parameters,
+ return_value,
+ stack_adjustment: value.stackAdjustment,
+ register_stack_adjustments,
+ }
+ }
+
+ /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
+ pub(crate) fn from_owned_core_raw(mut value: BNCallLayout) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_core_raw(&mut value);
+ owned
+ }
+
+ /// Free a CORE ALLOCATED value. Do not use this with [Self::into_rust_raw] values.
+ pub(crate) fn free_core_raw(value: &mut BNCallLayout) {
+ unsafe { BNFreeCallLayout(value) }
+ }
+}
diff --git a/rust/src/confidence.rs b/rust/src/confidence.rs
index f8745180..31ce7582 100644
--- a/rust/src/confidence.rs
+++ b/rust/src/confidence.rs
@@ -3,11 +3,11 @@
use crate::architecture::{Architecture, CoreArchitecture};
use crate::calling_convention::CoreCallingConvention;
use crate::rc::{Ref, RefCountable};
-use crate::types::Type;
+use crate::types::{Type, ValueLocation};
use binaryninjacore_sys::{
BNBoolWithConfidence, BNCallingConventionWithConfidence, BNGetCallingConventionArchitecture,
BNInlineDuringAnalysis, BNInlineDuringAnalysisWithConfidence, BNOffsetWithConfidence,
- BNTypeWithConfidence,
+ BNTypeWithConfidence, BNValueLocation, BNValueLocationWithConfidence,
};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
@@ -225,6 +225,19 @@ impl Conf<Ref<Type>> {
}
}
+impl Conf<ValueLocation> {
+ pub(crate) fn into_rust_raw(value: Self) -> BNValueLocationWithConfidence {
+ BNValueLocationWithConfidence {
+ location: ValueLocation::into_rust_raw(&value.contents),
+ confidence: value.confidence,
+ }
+ }
+
+ pub(crate) fn free_rust_raw(value: BNValueLocationWithConfidence) {
+ ValueLocation::free_rust_raw(value.location);
+ }
+}
+
impl Conf<Ref<CoreCallingConvention>> {
pub(crate) fn from_raw(value: &BNCallingConventionWithConfidence) -> Self {
let arch = unsafe {
diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs
index cb9bf6a1..718c7737 100644
--- a/rust/src/disassembly.rs
+++ b/rust/src/disassembly.rs
@@ -506,6 +506,7 @@ pub enum InstructionTextTokenKind {
// TODO: Explain what this is
hash: Option<u64>,
},
+ ValueLocation,
CodeSymbol {
// Target address of the symbol
value: u64,
@@ -700,6 +701,7 @@ impl InstructionTextTokenKind {
hash => Some(hash),
},
},
+ BNInstructionTextTokenType::ValueLocationToken => Self::ValueLocation,
BNInstructionTextTokenType::CodeSymbolToken => Self::CodeSymbol {
value: value.value,
size: value.size,
@@ -914,6 +916,9 @@ impl From<InstructionTextTokenKind> for BNInstructionTextTokenType {
BNInstructionTextTokenType::BaseStructureSeparatorToken
}
InstructionTextTokenKind::Brace { .. } => BNInstructionTextTokenType::BraceToken,
+ InstructionTextTokenKind::ValueLocation => {
+ BNInstructionTextTokenType::ValueLocationToken
+ }
InstructionTextTokenKind::CodeSymbol { .. } => {
BNInstructionTextTokenType::CodeSymbolToken
}
diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs
index 45d142bf..aaa4851e 100644
--- a/rust/src/ffi.rs
+++ b/rust/src/ffi.rs
@@ -31,6 +31,19 @@ pub(crate) fn time_from_bn(timestamp: u64) -> SystemTime {
UNIX_EPOCH + m
}
+pub(crate) unsafe fn slice_from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+ if len == 0 {
+ // C can and will pass null pointers for data in the case of zero length arrays.
+ // According to the documentation of std::slice::from_raw_parts, data must be
+ // non-null and properly aligned. To avoid creating unsound slices, return an
+ // empty slice directly on any zero-length array, avoiding the unsound call
+ // to std::slice::from_raw_parts.
+ &[]
+ } else {
+ unsafe { std::slice::from_raw_parts(data, len) }
+ }
+}
+
#[macro_export]
macro_rules! ffi_span {
($name:expr, $bv:expr) => {{
diff --git a/rust/src/function.rs b/rust/src/function.rs
index 320382de..6a62946f 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -21,6 +21,7 @@ use crate::{
calling_convention::CoreCallingConvention,
component::Component,
disassembly::{DisassemblySettings, DisassemblyTextLine},
+ ffi::slice_from_raw_parts,
flowgraph::FlowGraph,
medium_level_il::FunctionGraphType,
platform::Platform,
@@ -28,7 +29,7 @@ use crate::{
string::*,
symbol::{Binding, Symbol},
tags::{Tag, TagReference, TagType},
- types::{IntegerDisplayType, QualifiedName, Type},
+ types::{IntegerDisplayType, QualifiedName, ReturnValue, Type, ValueLocation},
};
use crate::{data_buffer::DataBuffer, disassembly::InstructionTextToken, rc::*};
pub use binaryninjacore_sys::BNAnalysisSkipReason as AnalysisSkipReason;
@@ -657,6 +658,11 @@ impl Function {
Conf::<Ref<Type>>::from_owned_raw(raw_return_type)
}
+ pub fn return_value(&self) -> ReturnValue {
+ let raw_return_value = unsafe { BNGetFunctionReturnValue(self.handle) };
+ ReturnValue::from_owned_core_raw(raw_return_value)
+ }
+
pub fn set_auto_return_type<'a, C>(&self, return_type: C)
where
C: Into<Conf<&'a Type>>,
@@ -665,6 +671,22 @@ impl Function {
unsafe { BNSetAutoFunctionReturnType(self.handle, &mut raw_return_type) }
}
+ pub fn set_auto_is_return_value_default_location(&self, is_default: bool) {
+ unsafe { BNSetAutoIsFunctionReturnValueDefaultLocation(self.handle, is_default) }
+ }
+
+ pub fn set_auto_return_value_location(&self, location: impl Into<Conf<ValueLocation>>) {
+ let mut raw_location = Conf::<ValueLocation>::into_rust_raw(location.into());
+ unsafe { BNSetAutoFunctionReturnValueLocation(self.handle, &mut raw_location) };
+ Conf::<ValueLocation>::free_rust_raw(raw_location);
+ }
+
+ pub fn set_auto_return_value(&self, return_value: impl Into<ReturnValue>) {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ unsafe { BNSetAutoFunctionReturnValue(self.handle, &mut raw_return_value) }
+ ReturnValue::free_rust_raw(raw_return_value);
+ }
+
pub fn set_user_return_type<'a, C>(&self, return_type: C)
where
C: Into<Conf<&'a Type>>,
@@ -673,6 +695,22 @@ impl Function {
unsafe { BNSetUserFunctionReturnType(self.handle, &mut raw_return_type) }
}
+ pub fn set_user_is_return_value_default_location(&self, is_default: bool) {
+ unsafe { BNSetUserIsFunctionReturnValueDefaultLocation(self.handle, is_default) }
+ }
+
+ pub fn set_user_return_value_location(&self, location: impl Into<Conf<ValueLocation>>) {
+ let mut raw_location = Conf::<ValueLocation>::into_rust_raw(location.into());
+ unsafe { BNSetUserFunctionReturnValueLocation(self.handle, &mut raw_location) };
+ Conf::<ValueLocation>::free_rust_raw(raw_location);
+ }
+
+ pub fn set_user_return_value(&self, return_value: impl Into<ReturnValue>) {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ unsafe { BNSetUserFunctionReturnValue(self.handle, &mut raw_return_value) }
+ ReturnValue::free_rust_raw(raw_return_value);
+ }
+
pub fn function_type(&self) -> Ref<Type> {
unsafe { Type::ref_from_raw(BNGetFunctionType(self.handle)) }
}
@@ -1017,38 +1055,65 @@ impl Function {
}
}
- pub fn set_user_parameter_variables<I>(&self, values: I, confidence: u8)
+ pub fn parameter_locations(&self) -> Conf<Vec<ValueLocation>> {
+ unsafe {
+ let mut raw_locations = BNGetFunctionParameterLocations(self.handle);
+ let raw_location_list =
+ slice_from_raw_parts(raw_locations.locations, raw_locations.count);
+ let locations: Vec<ValueLocation> = raw_location_list
+ .iter()
+ .map(ValueLocation::from_raw)
+ .collect();
+ let confidence = raw_locations.confidence;
+ BNFreeParameterLocations(&mut raw_locations);
+ Conf::new(locations, confidence)
+ }
+ }
+
+ pub fn set_user_parameter_locations<I>(&self, values: I, confidence: u8)
where
- I: IntoIterator<Item = Variable>,
+ I: IntoIterator<Item = ValueLocation>,
{
- let vars: Vec<BNVariable> = values.into_iter().map(Into::into).collect();
+ let locations: Vec<BNValueLocation> = values
+ .into_iter()
+ .map(|location| ValueLocation::into_rust_raw(&location.into()))
+ .collect();
unsafe {
- BNSetUserFunctionParameterVariables(
+ BNSetUserFunctionParameterLocations(
self.handle,
- &mut BNParameterVariablesWithConfidence {
- vars: vars.as_ptr() as *mut _,
- count: vars.len(),
+ &mut BNValueLocationListWithConfidence {
+ locations: locations.as_ptr() as *mut _,
+ count: locations.len(),
confidence,
},
)
}
+ locations
+ .into_iter()
+ .for_each(|location| ValueLocation::free_rust_raw(location.into()));
}
- pub fn set_auto_parameter_variables<I>(&self, values: I, confidence: u8)
+ pub fn set_auto_parameter_locations<I>(&self, values: I, confidence: u8)
where
- I: IntoIterator<Item = Variable>,
+ I: IntoIterator<Item = ValueLocation>,
{
- let vars: Vec<BNVariable> = values.into_iter().map(Into::into).collect();
+ let locations: Vec<BNValueLocation> = values
+ .into_iter()
+ .map(|location| ValueLocation::into_rust_raw(&location.into()))
+ .collect();
unsafe {
- BNSetAutoFunctionParameterVariables(
+ BNSetAutoFunctionParameterLocations(
self.handle,
- &mut BNParameterVariablesWithConfidence {
- vars: vars.as_ptr() as *mut _,
- count: vars.len(),
+ &mut BNValueLocationListWithConfidence {
+ locations: locations.as_ptr() as *mut _,
+ count: locations.len(),
confidence,
},
)
}
+ locations
+ .into_iter()
+ .for_each(|location| ValueLocation::free_rust_raw(location.into()));
}
pub fn parameter_at(
@@ -2536,32 +2601,6 @@ impl Function {
Conf::new(regs, result.confidence)
}
- pub fn set_user_return_registers<I>(&self, values: I, confidence: u8)
- where
- I: IntoIterator<Item = CoreRegister>,
- {
- let mut regs: Box<[u32]> = values.into_iter().map(|reg| reg.id().0).collect();
- let mut regs = BNRegisterSetWithConfidence {
- regs: regs.as_mut_ptr(),
- count: regs.len(),
- confidence,
- };
- unsafe { BNSetUserFunctionReturnRegisters(self.handle, &mut regs) }
- }
-
- pub fn set_auto_return_registers<I>(&self, values: I, confidence: u8)
- where
- I: IntoIterator<Item = CoreRegister>,
- {
- let mut regs: Box<[u32]> = values.into_iter().map(|reg| reg.id().0).collect();
- let mut regs = BNRegisterSetWithConfidence {
- regs: regs.as_mut_ptr(),
- count: regs.len(),
- confidence,
- };
- unsafe { BNSetAutoFunctionReturnRegisters(self.handle, &mut regs) }
- }
-
/// Flow graph of unresolved stack adjustments
pub fn unresolved_stack_adjustment_graph(&self) -> Option<Ref<FlowGraph>> {
let graph = unsafe { BNGetUnresolvedStackAdjustmentGraph(self.handle) };
diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs
index 80be2a16..98839cae 100644
--- a/rust/src/high_level_il/instruction.rs
+++ b/rust/src/high_level_il/instruction.rs
@@ -400,6 +400,12 @@ impl HighLevelILInstruction {
HLIL_ADDRESS_OF => Op::AddressOf(UnaryOp {
src: HighLevelExpressionIndex::from(op.operands[0]),
}),
+ HLIL_PASS_BY_REF => Op::PassByRef(UnaryOp {
+ src: HighLevelExpressionIndex::from(op.operands[0]),
+ }),
+ HLIL_RETURN_BY_REF => Op::ReturnByRef(UnaryOp {
+ src: HighLevelExpressionIndex::from(op.operands[0]),
+ }),
HLIL_NEG => Op::Neg(UnaryOp {
src: HighLevelExpressionIndex::from(op.operands[0]),
}),
@@ -784,6 +790,8 @@ impl HighLevelILInstruction {
Deref(op) => Lifted::Deref(self.lift_unary_op(op)),
AddressOf(op) => Lifted::AddressOf(self.lift_unary_op(op)),
+ PassByRef(op) => Lifted::PassByRef(self.lift_unary_op(op)),
+ ReturnByRef(op) => Lifted::ReturnByRef(self.lift_unary_op(op)),
Neg(op) => Lifted::Neg(self.lift_unary_op(op)),
Not(op) => Lifted::Not(self.lift_unary_op(op)),
Sx(op) => Lifted::Sx(self.lift_unary_op(op)),
@@ -1161,6 +1169,8 @@ pub enum HighLevelILInstructionKind {
ConstData(ConstData),
Deref(UnaryOp),
AddressOf(UnaryOp),
+ PassByRef(UnaryOp),
+ ReturnByRef(UnaryOp),
Neg(UnaryOp),
Not(UnaryOp),
Sx(UnaryOp),
diff --git a/rust/src/high_level_il/lift.rs b/rust/src/high_level_il/lift.rs
index ab04f44b..e2ce3686 100644
--- a/rust/src/high_level_il/lift.rs
+++ b/rust/src/high_level_il/lift.rs
@@ -112,6 +112,8 @@ pub enum HighLevelILLiftedInstructionKind {
ConstData(LiftedConstData),
Deref(LiftedUnaryOp),
AddressOf(LiftedUnaryOp),
+ PassByRef(LiftedUnaryOp),
+ ReturnByRef(LiftedUnaryOp),
Neg(LiftedUnaryOp),
Not(LiftedUnaryOp),
Sx(LiftedUnaryOp),
@@ -240,6 +242,8 @@ impl HighLevelILLiftedInstruction {
ConstData(_) => "ConstData",
Deref(_) => "Deref",
AddressOf(_) => "AddressOf",
+ PassByRef(_) => "PassByRef",
+ ReturnByRef(_) => "ReturnByRef",
Neg(_) => "Neg",
Not(_) => "Not",
Sx(_) => "Sx",
@@ -360,10 +364,12 @@ impl HighLevelILLiftedInstruction {
"constant_data",
Operand::ConstantData(op.constant_data.clone()),
)],
- Deref(op) | AddressOf(op) | Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op)
- | BoolToInt(op) | UnimplMem(op) | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op)
- | IntToFloat(op) | FloatConv(op) | RoundToInt(op) | Floor(op) | Ceil(op)
- | Ftrunc(op) => vec![("src", Operand::Expr(*op.src.clone()))],
+ Deref(op) | AddressOf(op) | PassByRef(op) | ReturnByRef(op) | Neg(op) | Not(op)
+ | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op) | Fsqrt(op)
+ | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op)
+ | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) => {
+ vec![("src", Operand::Expr(*op.src.clone()))]
+ }
DerefFieldSsa(op) => vec![
("src", Operand::Expr(*op.src.clone())),
("src_memory", Operand::Int(op.src_memory)),
diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs
index a223f21e..41f2bbe4 100644
--- a/rust/src/medium_level_il/instruction.rs
+++ b/rust/src/medium_level_il/instruction.rs
@@ -654,9 +654,22 @@ impl MediumLevelILInstruction {
MLIL_VAR_OUTPUT => Op::VarOutput(VarOutput {
dest: get_var(op.operands[0]),
}),
+ MLIL_VAR_OUTPUT_FIELD => Op::VarOutputField(VarOutputField {
+ dest: get_var(op.operands[0]),
+ offset: op.operands[1],
+ }),
+ MLIL_STORE_OUTPUT => Op::StoreOutput(StoreOutput {
+ dest: MediumLevelExpressionIndex::from(op.operands[0]),
+ }),
MLIL_ADDRESS_OF => Op::AddressOf(Var {
src: get_var(op.operands[0]),
}),
+ MLIL_PASS_BY_REF => Op::PassByRef(UnaryOp {
+ src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
+ }),
+ MLIL_RETURN_BY_REF => Op::ReturnByRef(UnaryOp {
+ src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
+ }),
MLIL_VAR_FIELD => Op::VarField(Field {
src: get_var(op.operands[0]),
offset: op.operands[1],
@@ -682,9 +695,27 @@ impl MediumLevelILInstruction {
MLIL_VAR_OUTPUT_SSA => Op::VarOutputSsa(VarOutputSsa {
dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
}),
+ MLIL_VAR_OUTPUT_SSA_FIELD => Op::VarOutputSsaField(VarOutputSsaField {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ offset: op.operands[3],
+ }),
+ MLIL_VAR_OUTPUT_ALIASED => Op::VarOutputAliased(VarOutputAliased {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ }),
+ MLIL_VAR_OUTPUT_ALIASED_FIELD => Op::VarOutputAliasedField(VarOutputAliasedField {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ offset: op.operands[3],
+ }),
MLIL_TRAP => Op::Trap(Trap {
vector: op.operands[0],
}),
+ MLIL_BLOCK_TO_EXPAND => Op::BlockToExpand(BlockToExpand {
+ num_operands: op.operands[0] as usize,
+ first_operand: op.operands[1] as usize,
+ }),
};
Self {
@@ -1121,7 +1152,13 @@ impl MediumLevelILInstruction {
}),
Var(op) => Lifted::Var(op),
VarOutput(op) => Lifted::VarOutput(op),
+ VarOutputField(op) => Lifted::VarOutputField(op),
+ StoreOutput(op) => Lifted::StoreOutput(LiftedStoreOutput {
+ dest: self.lift_operand(op.dest),
+ }),
AddressOf(op) => Lifted::AddressOf(op),
+ PassByRef(op) => Lifted::PassByRef(self.lift_unary_op(op)),
+ ReturnByRef(op) => Lifted::ReturnByRef(self.lift_unary_op(op)),
VarField(op) => Lifted::VarField(op),
AddressOfField(op) => Lifted::AddressOfField(op),
VarSsa(op) => Lifted::VarSsa(op),
@@ -1129,7 +1166,17 @@ impl MediumLevelILInstruction {
VarSsaField(op) => Lifted::VarSsaField(op),
VarAliasedField(op) => Lifted::VarAliasedField(op),
VarOutputSsa(op) => Lifted::VarOutputSsa(op),
+ VarOutputSsaField(op) => Lifted::VarOutputSsaField(op),
+ VarOutputAliased(op) => Lifted::VarOutputAliased(op),
+ VarOutputAliasedField(op) => Lifted::VarOutputAliasedField(op),
Trap(op) => Lifted::Trap(op),
+ BlockToExpand(_op) => Lifted::BlockToExpand(LiftedBlockToExpand {
+ exprs: self
+ .get_expr_list(0)
+ .iter()
+ .map(|expr| expr.lift())
+ .collect(),
+ }),
};
MediumLevelILLiftedInstruction {
@@ -1823,6 +1870,8 @@ pub enum MediumLevelILInstructionKind {
SeparateParamList(SeparateParamList),
SharedParamSlot(SharedParamSlot),
VarOutput(VarOutput),
+ VarOutputField(VarOutputField),
+ StoreOutput(StoreOutput),
Neg(UnaryOp),
Not(UnaryOp),
Sx(UnaryOp),
@@ -1847,6 +1896,8 @@ pub enum MediumLevelILInstructionKind {
Ret(Ret),
Var(Var),
AddressOf(Var),
+ PassByRef(UnaryOp),
+ ReturnByRef(UnaryOp),
VarField(Field),
AddressOfField(Field),
VarSsa(VarSsa),
@@ -1854,7 +1905,11 @@ pub enum MediumLevelILInstructionKind {
VarSsaField(VarSsaField),
VarAliasedField(VarSsaField),
VarOutputSsa(VarOutputSsa),
+ VarOutputSsaField(VarOutputSsaField),
+ VarOutputAliased(VarOutputAliased),
+ VarOutputAliasedField(VarOutputAliasedField),
Trap(Trap),
+ BlockToExpand(BlockToExpand),
// A placeholder for instructions that the Rust bindings do not yet support.
// Distinct from `Unimpl` as that is a valid instruction.
NotYetImplemented,
diff --git a/rust/src/medium_level_il/lift.rs b/rust/src/medium_level_il/lift.rs
index 58ea8a13..aee8139f 100644
--- a/rust/src/medium_level_il/lift.rs
+++ b/rust/src/medium_level_il/lift.rs
@@ -176,7 +176,11 @@ pub enum MediumLevelILLiftedInstructionKind {
Ret(LiftedRet),
Var(Var),
VarOutput(VarOutput),
+ VarOutputField(VarOutputField),
+ StoreOutput(LiftedStoreOutput),
AddressOf(Var),
+ PassByRef(LiftedUnaryOp),
+ ReturnByRef(LiftedUnaryOp),
VarField(Field),
AddressOfField(Field),
VarSsa(VarSsa),
@@ -184,7 +188,11 @@ pub enum MediumLevelILLiftedInstructionKind {
VarSsaField(VarSsaField),
VarAliasedField(VarSsaField),
VarOutputSsa(VarOutputSsa),
+ VarOutputSsaField(VarOutputSsaField),
+ VarOutputAliased(VarOutputAliased),
+ VarOutputAliasedField(VarOutputAliasedField),
Trap(Trap),
+ BlockToExpand(LiftedBlockToExpand),
// A placeholder for instructions that the Rust bindings do not yet support.
// Distinct from `Unimpl` as that is a valid instruction.
NotYetImplemented,
@@ -301,6 +309,8 @@ impl MediumLevelILLiftedInstruction {
SeparateParamList(_) => "SeparateParamList",
SharedParamSlot(_) => "SharedParamSlot",
VarOutput(_) => "VarOutput",
+ VarOutputField(_) => "VarOutputField",
+ StoreOutput(_) => "StoreOutput",
Neg(_) => "Neg",
Not(_) => "Not",
Sx(_) => "Sx",
@@ -325,6 +335,8 @@ impl MediumLevelILLiftedInstruction {
Ret(_) => "Ret",
Var(_) => "Var",
AddressOf(_) => "AddressOf",
+ PassByRef(_) => "PassByRef",
+ ReturnByRef(_) => "ReturnByRef",
VarField(_) => "VarField",
AddressOfField(_) => "AddressOfField",
VarSsa(_) => "VarSsa",
@@ -332,7 +344,11 @@ impl MediumLevelILLiftedInstruction {
VarSsaField(_) => "VarSsaField",
VarAliasedField(_) => "VarAliasedField",
VarOutputSsa(_) => "VarOutputSsa",
+ VarOutputSsaField(_) => "VarOutputSsaField",
+ VarOutputAliased(_) => "VarOutputAliased",
+ VarOutputAliasedField(_) => "VarOutputAliasedField",
Trap(_) => "Trap",
+ BlockToExpand(_) => "BlockToExpand",
}
}
@@ -549,6 +565,13 @@ impl MediumLevelILLiftedInstruction {
SharedParamSlot(op) => vec![("params", Operand::ExprList(op.params.clone()))],
Var(op) | AddressOf(op) => vec![("src", Operand::Var(op.src))],
VarOutput(op) => vec![("dest", Operand::Var(op.dest))],
+ VarOutputField(op) => vec![
+ ("dest", Operand::Var(op.dest)),
+ ("offset", Operand::Int(op.offset)),
+ ],
+ StoreOutput(op) => vec![("dest", Operand::Expr(*op.dest.clone()))],
+ PassByRef(op) => vec![("src", Operand::Expr(*op.src.clone()))],
+ ReturnByRef(op) => vec![("src", Operand::Expr(*op.src.clone()))],
VarField(op) | AddressOfField(op) => vec![
("src", Operand::Var(op.src)),
("offset", Operand::Int(op.offset)),
@@ -559,7 +582,22 @@ impl MediumLevelILLiftedInstruction {
("offset", Operand::Int(op.offset)),
],
VarOutputSsa(op) => vec![("dest", Operand::VarSsa(op.dest))],
+ VarOutputSsaField(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ("offset", Operand::Int(op.offset)),
+ ],
+ VarOutputAliased(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ],
+ VarOutputAliasedField(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ("offset", Operand::Int(op.offset)),
+ ],
Trap(op) => vec![("vector", Operand::Int(op.vector))],
+ BlockToExpand(op) => vec![("exprs", Operand::ExprList(op.exprs.clone()))],
}
}
}
diff --git a/rust/src/medium_level_il/operation.rs b/rust/src/medium_level_il/operation.rs
index a9a791b0..1886b3d0 100644
--- a/rust/src/medium_level_il/operation.rs
+++ b/rust/src/medium_level_il/operation.rs
@@ -641,6 +641,23 @@ pub struct VarOutput {
pub dest: Variable,
}
+// VAR_OUTPUT_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputField {
+ pub dest: Variable,
+ pub offset: u64,
+}
+
+// STORE_OUTPUT
+#[derive(Debug, Copy, Clone)]
+pub struct StoreOutput {
+ pub dest: MediumLevelExpressionIndex,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStoreOutput {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+}
+
// VAR_FIELD, ADDRESS_OF_FIELD
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Field {
@@ -667,8 +684,42 @@ pub struct VarOutputSsa {
pub dest: SSAVariable,
}
+// VAR_OUTPUT_SSA_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputSsaField {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub offset: u64,
+}
+
+// VAR_OUTPUT_ALIASED
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputAliased {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+}
+
+// VAR_OUTPUT_ALIASED_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputAliasedField {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub offset: u64,
+}
+
// TRAP
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Trap {
pub vector: u64,
}
+
+// BLOCK_TO_EXPAND
+#[derive(Debug, Copy, Clone)]
+pub struct BlockToExpand {
+ pub first_operand: usize,
+ pub num_operands: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBlockToExpand {
+ pub exprs: Vec<MediumLevelILLiftedInstruction>,
+}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index e6c16f6b..a7ec517e 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -35,7 +35,7 @@ pub mod structure;
use binaryninjacore_sys::*;
use crate::{
- architecture::Architecture,
+ architecture::{Architecture, Register, RegisterId},
binary_view::BinaryView,
calling_convention::CoreCallingConvention,
rc::*,
@@ -449,12 +449,12 @@ impl TypeBuilder {
// TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
/// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
/// use [`Type::function`] where possible.
- pub fn function<'a, T: Into<Conf<&'a Type>>>(
- return_type: T,
+ pub fn function<'a, T: Into<ReturnValue>>(
+ return_value: T,
parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Self {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -473,15 +473,9 @@ impl TypeBuilder {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::from_raw(BNCreateFunctionTypeBuilder(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -491,7 +485,6 @@ impl TypeBuilder {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
@@ -509,16 +502,16 @@ impl TypeBuilder {
/// use [`Type::function_with_opts`] where possible.
pub fn function_with_opts<
'a,
- T: Into<Conf<&'a Type>>,
+ T: Into<ReturnValue>,
C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
- return_type: T,
+ return_value: T,
parameters: &[FunctionParameter],
variable_arguments: bool,
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Self {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -537,15 +530,9 @@ impl TypeBuilder {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::from_raw(BNCreateFunctionTypeBuilder(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -555,7 +542,6 @@ impl TypeBuilder {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
@@ -943,12 +929,12 @@ impl Type {
}
// TODO: FunctionBuilder
- pub fn function<'a, T: Into<Conf<&'a Type>>>(
- return_type: T,
+ pub fn function<'a, T: Into<ReturnValue>>(
+ return_value: T,
parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Ref<Self> {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -967,15 +953,9 @@ impl Type {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -985,12 +965,12 @@ impl Type {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
+ ReturnValue::free_rust_raw(owned_raw_return_value);
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
@@ -1001,16 +981,16 @@ impl Type {
// TODO: FunctionBuilder
pub fn function_with_opts<
'a,
- T: Into<Conf<&'a Type>>,
+ T: Into<ReturnValue>,
C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
- return_type: T,
+ return_value: T,
parameters: &[FunctionParameter],
variable_arguments: bool,
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Ref<Self> {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -1029,15 +1009,9 @@ impl Type {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -1047,12 +1021,12 @@ impl Type {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
+ ReturnValue::free_rust_raw(owned_raw_return_value);
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
@@ -1110,6 +1084,10 @@ impl Type {
QualifiedName::free_raw(raw_name);
type_id
}
+
+ pub fn deref_named_type_reference(&self, view: &BinaryView) -> Ref<Type> {
+ unsafe { Self::ref_from_raw(BNDerefNamedTypeReference(view.handle, self.handle)) }
+ }
}
impl Display for Type {
@@ -1207,10 +1185,285 @@ unsafe impl CoreArrayProviderInner for Type {
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ValueLocationComponent {
+ pub variable: Variable,
+ pub offset: i64,
+ pub size: Option<u64>,
+}
+
+impl ValueLocationComponent {
+ pub(crate) fn from_raw(value: &BNValueLocationComponent) -> Self {
+ let variable = Variable::from(&value.variable);
+ let size = if value.sizeValid {
+ Some(value.size)
+ } else {
+ None
+ };
+ Self {
+ variable,
+ offset: value.offset,
+ size,
+ }
+ }
+
+ pub(crate) fn into_raw(value: &Self) -> BNValueLocationComponent {
+ BNValueLocationComponent {
+ variable: value.variable.into(),
+ offset: value.offset,
+ sizeValid: value.size.is_some(),
+ size: value.size.unwrap_or(0),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ValueLocation {
+ pub components: Vec<ValueLocationComponent>,
+ pub indirect: bool,
+ pub returned_pointer: Option<Variable>,
+}
+
+impl ValueLocation {
+ pub fn from_variable(var: Variable) -> Self {
+ Self {
+ components: vec![ValueLocationComponent {
+ variable: var,
+ offset: 0,
+ size: None,
+ }],
+ indirect: false,
+ returned_pointer: None,
+ }
+ }
+
+ pub fn from_register(reg: impl Register) -> Self {
+ Self::from_variable(Variable::from_register(reg))
+ }
+
+ pub fn from_register_id(reg: RegisterId) -> Self {
+ Self::from_variable(Variable::from_register_id(reg))
+ }
+
+ pub fn from_stack_offset(offset: i64) -> Self {
+ Self::from_variable(Variable::from_stack_offset(offset))
+ }
+
+ pub fn is_valid(&self) -> bool {
+ !self.components.is_empty()
+ }
+
+ pub fn variable_for_return_value(&self) -> Option<Variable> {
+ let value_raw = Self::into_rust_raw(&self);
+ let mut var_raw = BNVariable::default();
+ let valid = unsafe { BNGetValueLocationVariableForReturnValue(&value_raw, &mut var_raw) };
+ Self::free_rust_raw(value_raw);
+ if valid {
+ Some(var_raw.into())
+ } else {
+ None
+ }
+ }
+
+ pub fn variable_for_parameter(&self, idx: usize) -> Option<Variable> {
+ let value_raw = Self::into_rust_raw(&self);
+ let mut var_raw = BNVariable::default();
+ let valid =
+ unsafe { BNGetValueLocationVariableForParameter(&value_raw, &mut var_raw, idx) };
+ Self::free_rust_raw(value_raw);
+ if valid {
+ Some(var_raw.into())
+ } else {
+ None
+ }
+ }
+
+ pub(crate) fn from_raw(loc: &BNValueLocation) -> Self {
+ let components_raw: &[BNValueLocationComponent] =
+ unsafe { crate::ffi::slice_from_raw_parts(loc.components, loc.count) };
+ Self {
+ components: components_raw
+ .iter()
+ .map(|component| ValueLocationComponent::from_raw(component))
+ .collect(),
+ indirect: loc.indirect,
+ returned_pointer: if loc.returnedPointerValid {
+ Some(Variable::from(&loc.returnedPointer))
+ } else {
+ None
+ },
+ }
+ }
+
+ pub fn into_rust_raw(value: &Self) -> BNValueLocation {
+ let components: Box<[BNValueLocationComponent]> = value
+ .components
+ .iter()
+ .map(|component| ValueLocationComponent::into_raw(component))
+ .collect();
+ BNValueLocation {
+ count: components.len(),
+ components: Box::leak(components).as_mut_ptr(),
+ indirect: value.indirect,
+ returnedPointerValid: value.returned_pointer.is_some(),
+ returnedPointer: if let Some(ptr) = value.returned_pointer {
+ ptr.into()
+ } else {
+ Variable::new(VariableSourceType::RegisterVariableSourceType, 0, 0).into()
+ },
+ }
+ }
+
+ /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
+ pub fn free_rust_raw(value: BNValueLocation) {
+ let raw_components =
+ unsafe { std::slice::from_raw_parts_mut(value.components, value.count) };
+ let _ = unsafe { Box::from_raw(raw_components) };
+ }
+}
+
+impl Into<ValueLocation> for Variable {
+ fn into(self) -> ValueLocation {
+ ValueLocation {
+ components: vec![ValueLocationComponent {
+ variable: self,
+ offset: 0,
+ size: None,
+ }],
+ indirect: false,
+ returned_pointer: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ReturnValue {
+ pub ty: Conf<Ref<Type>>,
+ pub location: Option<Conf<ValueLocation>>,
+}
+
+impl ReturnValue {
+ pub(crate) fn from_raw(value: &BNReturnValue) -> Self {
+ Self {
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
+ ),
+ location: match value.defaultLocation {
+ false => Some(Conf::new(
+ ValueLocation::from_raw(&value.location),
+ value.locationConfidence,
+ )),
+ true => None,
+ },
+ }
+ }
+
+ /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
+ pub(crate) fn from_owned_core_raw(mut value: BNReturnValue) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_core_raw(&mut value);
+ owned
+ }
+
+ pub(crate) fn into_rust_raw(value: Self) -> BNReturnValue {
+ BNReturnValue {
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ typeConfidence: value.ty.confidence,
+ defaultLocation: value.location.is_none(),
+ location: ValueLocation::into_rust_raw(
+ value
+ .location
+ .as_ref()
+ .map(|v| &v.contents)
+ .unwrap_or(&ValueLocation {
+ components: Vec::new(),
+ indirect: false,
+ returned_pointer: None,
+ }),
+ ),
+ locationConfidence: value.location.as_ref().map(|v| v.confidence).unwrap_or(0),
+ }
+ }
+
+ /// Free a CORE ALLOCATED possible value set. Do not use this with [Self::into_rust_raw] values.
+ pub(crate) fn free_core_raw(value: &mut BNReturnValue) {
+ unsafe { BNFreeReturnValue(value) }
+ }
+
+ /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
+ pub(crate) fn free_rust_raw(value: BNReturnValue) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ ValueLocation::free_rust_raw(value.location);
+ }
+}
+
+impl Into<ReturnValue> for Ref<Type> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Ref<Type> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.clone().into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Type {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.to_owned().into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for Conf<Ref<Type>> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self,
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Conf<Ref<Type>> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.clone(),
+ location: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub enum ValueLocationSource {
+ Default,
+ PassByValue,
+ PassByReference,
+ Custom(ValueLocation),
+}
+
+impl From<Option<ValueLocation>> for ValueLocationSource {
+ fn from(loc: Option<ValueLocation>) -> Self {
+ match loc {
+ Some(loc) => ValueLocationSource::Custom(loc),
+ None => ValueLocationSource::Default,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FunctionParameter {
pub ty: Conf<Ref<Type>>,
pub name: String,
- pub location: Option<Variable>,
+ pub location: ValueLocationSource,
}
impl FunctionParameter {
@@ -1218,13 +1471,7 @@ impl FunctionParameter {
// TODO: I copied this from the original `from_raw` function.
// TODO: So this actually needs to be audited later.
let name = if value.name.is_null() {
- if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
- format!("reg_{}", value.location.storage)
- } else if value.location.type_ == VariableSourceType::StackVariableSourceType {
- format!("arg_{}", value.location.storage)
- } else {
- String::new()
- }
+ String::new()
} else {
raw_to_string(value.name as *const _).unwrap()
};
@@ -1235,9 +1482,17 @@ impl FunctionParameter {
value.typeConfidence,
),
name,
- location: match value.defaultLocation {
- false => Some(Variable::from(value.location)),
- true => None,
+ location: match value.locationSource {
+ BNValueLocationSource::DefaultLocationSource => ValueLocationSource::Default,
+ BNValueLocationSource::PassByValueLocationSource => {
+ ValueLocationSource::PassByValue
+ }
+ BNValueLocationSource::PassByReferenceLocationSource => {
+ ValueLocationSource::PassByReference
+ }
+ BNValueLocationSource::CustomLocationSource => {
+ ValueLocationSource::Custom(ValueLocation::from_raw(&value.location))
+ }
},
}
}
@@ -1255,21 +1510,42 @@ impl FunctionParameter {
name: BnString::into_raw(bn_name),
type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
typeConfidence: value.ty.confidence,
- defaultLocation: value.location.is_none(),
- location: value.location.map(Into::into).unwrap_or_default(),
+ locationSource: match value.location {
+ ValueLocationSource::Default => BNValueLocationSource::DefaultLocationSource,
+ ValueLocationSource::PassByValue => {
+ BNValueLocationSource::PassByValueLocationSource
+ }
+ ValueLocationSource::PassByReference => {
+ BNValueLocationSource::PassByReferenceLocationSource
+ }
+ ValueLocationSource::Custom(_) => BNValueLocationSource::CustomLocationSource,
+ },
+ location: match &value.location {
+ ValueLocationSource::Custom(loc) => ValueLocation::into_rust_raw(loc),
+ _ => ValueLocation::into_rust_raw(&ValueLocation {
+ components: Vec::new(),
+ indirect: false,
+ returned_pointer: None,
+ }),
+ },
}
}
pub(crate) fn free_raw(value: BNFunctionParameter) {
unsafe { BnString::free_raw(value.name) };
let _ = unsafe { Type::ref_from_raw(value.type_) };
+ ValueLocation::free_rust_raw(value.location);
}
- pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
+ pub fn new<T: Into<Conf<Ref<Type>>>>(
+ ty: T,
+ name: String,
+ location: impl Into<ValueLocationSource>,
+ ) -> Self {
Self {
ty: ty.into(),
name,
- location,
+ location: location.into(),
}
}
}
diff --git a/rust/src/variable.rs b/rust/src/variable.rs
index f9384b5d..1eefc9a8 100644
--- a/rust/src/variable.rs
+++ b/rust/src/variable.rs
@@ -1,6 +1,6 @@
#![allow(unused)]
-use crate::architecture::{Architecture, CoreArchitecture, CoreRegister, RegisterId};
+use crate::architecture::{Architecture, CoreArchitecture, CoreRegister, Register, RegisterId};
use crate::confidence::Conf;
use crate::function::{Function, Location};
use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
@@ -405,6 +405,30 @@ impl Variable {
unsafe { BNFromVariableIdentifier(ident) }.into()
}
+ pub fn from_register(reg: impl Register) -> Self {
+ Self {
+ ty: VariableSourceType::RegisterVariableSourceType,
+ index: 0,
+ storage: reg.id().0 as i64,
+ }
+ }
+
+ pub fn from_register_id(reg: RegisterId) -> Self {
+ Self {
+ ty: VariableSourceType::RegisterVariableSourceType,
+ index: 0,
+ storage: reg.0 as i64,
+ }
+ }
+
+ pub fn from_stack_offset(offset: i64) -> Self {
+ Self {
+ ty: VariableSourceType::StackVariableSourceType,
+ index: 0,
+ storage: offset,
+ }
+ }
+
pub fn to_identifier(&self) -> u64 {
let raw = BNVariable::from(*self);
unsafe { BNToVariableIdentifier(&raw) }
@@ -417,6 +441,8 @@ impl Variable {
}
VariableSourceType::StackVariableSourceType => None,
VariableSourceType::FlagVariableSourceType => None,
+ VariableSourceType::CompositeReturnValueSourceType => None,
+ VariableSourceType::CompositeParameterSourceType => None,
}
}
}
@@ -674,6 +700,13 @@ pub enum PossibleValueSet {
StackFrameOffset {
value: i64,
},
+ ResultPointer {
+ offset: i64,
+ },
+ ParameterPointer {
+ index: u64,
+ offset: i64,
+ },
ReturnAddressValue,
ImportedAddressValue {
value: i64,
@@ -730,6 +763,13 @@ impl PossibleValueSet {
offset: value.offset,
},
RegisterValueType::StackFrameOffset => Self::StackFrameOffset { value: value.value },
+ RegisterValueType::ResultPointerValue => Self::ResultPointer {
+ offset: value.value,
+ },
+ RegisterValueType::ParameterPointerValue => Self::ParameterPointer {
+ index: value.value as u64,
+ offset: value.offset,
+ },
RegisterValueType::ReturnAddressValue => Self::ReturnAddressValue,
RegisterValueType::ImportedAddressValue => {
Self::ImportedAddressValue { value: value.value }
@@ -815,6 +855,13 @@ impl PossibleValueSet {
PossibleValueSet::StackFrameOffset { value } => {
raw.value = value;
}
+ PossibleValueSet::ResultPointer { offset } => {
+ raw.value = offset;
+ }
+ PossibleValueSet::ParameterPointer { index, offset } => {
+ raw.value = index as i64;
+ raw.offset = offset;
+ }
PossibleValueSet::ReturnAddressValue => {}
PossibleValueSet::ImportedAddressValue { value } => {
raw.value = value;
@@ -910,6 +957,8 @@ impl PossibleValueSet {
RegisterValueType::ExternalPointerValue
}
PossibleValueSet::StackFrameOffset { .. } => RegisterValueType::StackFrameOffset,
+ PossibleValueSet::ResultPointer { .. } => RegisterValueType::ResultPointerValue,
+ PossibleValueSet::ParameterPointer { .. } => RegisterValueType::ParameterPointerValue,
PossibleValueSet::ReturnAddressValue => RegisterValueType::ReturnAddressValue,
PossibleValueSet::ImportedAddressValue { .. } => {
RegisterValueType::ImportedAddressValue