diff options
| author | Rubens Brandao <git@rubens.io> | 2024-05-07 09:52:19 -0300 |
|---|---|---|
| committer | Kyle Martin <krm504@nyu.edu> | 2024-05-20 15:43:59 -0400 |
| commit | 27bc08fa90d4381b4fd5d896dda991824504b0fd (patch) | |
| tree | 842d477d932439765e94783f65f46dc66afd661c /rust/src/types.rs | |
| parent | 82dd5d4b6fb97f4754d80aefe514d74b61c79054 (diff) | |
Implement python Function methods to rust
Squashed:
add Function::add_tag method
add Function::{add_user_code_ref,remove_user_code_ref} methods
add Function::{add_user_type_field_ref, remove_user_type_field_ref} methods
add Function::{add_user_type_ref, remove_user_type_ref} methods
add Function::apply_auto_discovered_type
add Function/MediumLevelILFunction user_var_values and related functions
simplify UserVariableValues::values_from_variable
cargo fmt fix
fix doc and QualifiedName params
fix MediumLevelILFunction::is_var_user_defined parameter
Remove unecessary Safety comment
add Function::{create_auto_stack_var,delete_auto_stack_var} methods
add MediumLevelILFunction::create_auto_var method
move Function::{create_auto_stack_var,delete_auto_stack_var} methods to MediumLevelILFunction
add MediumLevelILFunction::{create_user_stack_var,delete_user_stack_var} methods
add Function::block_annotations method
add Function::{call_stack_adjustment, call_type_adjustment} method
add Function::{constant_data, constants_referenced_by, constants_referenced_by_address_if_available} methods
add Function::function_tags method
add Function::{indirect_branches, indirect_branches_at} methods
add Function::instr_highlight method
add Function::instruction_containing_address method
add Function::{int_display_type,int_enum_display_typeid,int_display_type_and_typeid} methods
add MediumLevelILFunction::{var_refs, var_refs_from} methods
add Function::{parameter_at, parameter_at_low_level_il_instruction} methods
rebase GAT changes
add Function::{reg_value_at, reg_value_after, reg_value_at_exit} methods
Add alpha to HighlightColor::NoHighlightColor
add Function::{regs_read_by, regs_written_by} methods
add Function::{stack_contents_at, stack_contents_after} methods
add Function::{stack_vars_referenced_by, stack_vars_referenced_by_address_if_available} methods
add Function::{tags_at, tags_at_range} methods
add Function::type_tokens method
add Function::variables method
add Function::{is_call_instruction, is_var_user_defined} methods
add Function::{mark_updates_required, mark_caller_updates_required, mark_recent_use} methods
add Function::{merge_vars, unmerge_vars, split_var, unsplit_var} methods
add Function::reanalyze method
add Function::request_debug_report method
add Function::remove_tag method
add Function::remove_tags_of_type method
add Function::analysis_performance_info method
add Function::call_sites method
add Function::caller_sites method
add Function::{calling_convention, set_calling_convention} methods
add Function::{can_return, set_can_return} methods
add Function::comments method
add Function::{clobbered_regs, set_clobbered_regs} methods
add Function::{has_explicitly_defined_type, has_user_annotations, has_user_type, has_variable_arguments} methods
fix Function::set_can_return_user function
add Function::{high_level_il_if_available, medium_level_il_if_available, low_level_il_if_available, lifted_il_if_available} methods
add Function::{global_pointer_value, has_unresolved_indirect_branches} methods
add Function::lowest_address method
add Function::{inline_during_analysis, set_auto_inline_during_analysis, set_user_inline_during_analysis} methods
add Function::{is_pure, is_too_large, is_update_needed} methods
add Function::{provenance, stack_adjustment, set_user_stack_adjustment, set_auto_stack_adjustment} methods
add Function::{set_user_pure, set_auto_pure} methods
add Function::set_auto_type method
add Function::{return_regs, set_return_regs} methods
add Function::{set_auto_return_type, set_user_return_type} methods
add Function::unresolved_stack_adjustment_graph method
add Function::create_graph method
add Function::tags method
add Function::split_variables method
add Function::{reg_stack_adjustments, set_reg_stack_adjustments} methods
add Function::{mapped_medium_level_il, merged_variables} methods
add Function::{set_auto_instr_highlight, set_user_instr_highlight} methods
add stack_adjustments methods
add Function::set_user_call_stack_adjustment
add Function::set_auto_call_stack_adjustment
add Function::call_type_adjustment
add Function::set_user_call_type_adjustment
add Function::set_auto_call_type_adjustment
add Function::call_reg_stack_adjustment
add Function::set_user_call_reg_stack_adjustment
add Function::set_auto_call_reg_stack_adjustment
add Function::call_reg_stack_adjustment_for_reg_stack
add Function::set_user_call_reg_stack_adjustment_for_reg_stack
add Function::set_auto_call_reg_stack_adjustment_for_reg_stack
add Function::set_user_reg_stack_adjustments
add Function::set_auto_reg_stack_adjustments
add Function::set_auto_reg_stack_adjustments
add Function::set_auto_calling_convention method
add Function::set_auto_can_return method
add Function::{set_user_has_variable_arguments, set_auto_has_variable_arguments} methods
add Function::{set_user_indirect_branches, set_auto_indirect_branches} methods
add Function::set_int_display_type method
add Function::{set_user_parameter_variables, set_auto_parameter_variables} methods
fix documentation
add Function::unresolved_indirect_branches method
add Function::mapped_medium_level_il_if_available method
change methods `Function::{set_user_type, set_auto_type}` to receive `&Type`
merge RegisterList and RegisterSet into CoreRegister impl
fix function names
fix function names
fix documentation syntax
fix documentation syntax
fix Function documentation by adding MediumLevelILInstruction::get_split_var_for_definition
fix documentation links
rename `VariableDefinitions` to `MediumLevelILInstructionList`
fix `PossibleValueSet` switched `NotInSetOfValues` and `ReturnAddressValue`
Diffstat (limited to 'rust/src/types.rs')
| -rw-r--r-- | rust/src/types.rs | 872 |
1 files changed, 864 insertions, 8 deletions
diff --git a/rust/src/types.rs b/rust/src/types.rs index 8292db07..1a591801 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -31,15 +31,14 @@ use crate::{ use lazy_static::lazy_static; use std::{ - borrow::Cow, - collections::HashSet, + borrow::{Borrow, Cow}, + collections::{HashMap, HashSet}, ffi::CStr, - fmt, - fmt::{Debug, Display, Formatter}, + fmt::{self, Debug, Display, Formatter}, hash::{Hash, Hasher}, iter::{zip, IntoIterator}, - mem, - mem::ManuallyDrop, + mem::{self, ManuallyDrop}, + ops::Range, os::raw::c_char, ptr, result, slice, sync::Mutex, @@ -215,6 +214,8 @@ impl<T: Clone> Clone for Conf<T> { } } +impl<T: Copy> Copy for Conf<T> {} + impl<T> From<T> for Conf<T> { fn from(contents: T) -> Self { Self::new(contents, max_confidence()) @@ -1378,6 +1379,9 @@ impl Variable { storage: var.storage, } } + pub(crate) unsafe fn from_identifier(var: u64) -> Self { + Self::from_raw(unsafe { BNFromVariableIdentifier(var) }) + } pub(crate) fn raw(&self) -> BNVariable { BNVariable { @@ -1388,6 +1392,43 @@ impl Variable { } } +impl CoreArrayProvider for Variable { + type Raw = BNVariable; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for Variable { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeVariableList(raw) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Variable::from_raw(*raw) + } +} + +// Name, Variable and Type +impl CoreArrayProvider for (&str, Variable, &Type) { + type Raw = BNVariableNameAndType; + type Context = (); + type Wrapped<'a> = (&'a str, Variable, &'a Type) where Self: 'a; +} + +unsafe impl CoreArrayProviderInner for (&str, Variable, &Type) { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeVariableNameAndTypeList(raw, count) + } + unsafe fn wrap_raw<'a>( + raw: &'a Self::Raw, + _context: &'a Self::Context, + ) -> (&'a str, Variable, &'a Type) { + let name = CStr::from_ptr(raw.name).to_str().unwrap(); + let var = Variable::from_raw(raw.var); + let var_type = core::mem::transmute(&raw.type_); + (name, var, var_type) + } +} + ////////////// // SSAVariable @@ -1805,7 +1846,7 @@ impl StructureBuilder { &self, members: impl IntoIterator<Item = (T, S)>, ) -> &Self { - for (t, name) in members.into_iter() { + for (t, name) in members { self.append(t, name, MemberAccess::NoAccess, MemberScope::NoScope); } self @@ -2496,7 +2537,7 @@ pub struct NameAndType(pub(crate) BNNameAndType); impl NameAndType { pub(crate) unsafe fn from_raw(raw: &BNNameAndType) -> Self { - Self ( *raw ) + Self(*raw) } } @@ -2851,3 +2892,818 @@ impl ConstantData { // mem::transmute(raw) // } // } + +///////////////////////// +// ValueRange + +#[repr(transparent)] +#[derive(Copy, Clone, Debug)] +pub struct ValueRange<T> { + raw: BNValueRange, + _t: core::marker::PhantomData<T>, +} + +impl<T> ValueRange<T> { + fn from_raw(value: BNValueRange) -> Self { + Self { + raw: value, + _t: core::marker::PhantomData, + } + } + fn into_raw(self) -> BNValueRange { + self.raw + } +} + +impl IntoIterator for ValueRange<u64> { + type Item = u64; + type IntoIter = core::iter::StepBy<Range<u64>>; + + fn into_iter(self) -> Self::IntoIter { + (self.raw.start..self.raw.end).step_by(self.raw.step.try_into().unwrap()) + } +} +impl IntoIterator for ValueRange<i64> { + type Item = i64; + type IntoIter = core::iter::StepBy<Range<i64>>; + + fn into_iter(self) -> Self::IntoIter { + (self.raw.start as i64..self.raw.end as i64).step_by(self.raw.step.try_into().unwrap()) + } +} + +///////////////////////// +// PossibleValueSet + +#[derive(Clone, Debug)] +pub enum PossibleValueSet { + UndeterminedValue, + EntryValue { + reg: i64, + }, + ConstantValue { + value: i64, + }, + ConstantPointerValue { + value: i64, + }, + ExternalPointerValue, + StackFrameOffset { + offset: i64, + }, + ReturnAddressValue, + ImportedAddressValue, + SignedRangeValue { + offset: i64, + ranges: Vec<ValueRange<i64>>, + }, + UnsignedRangeValue { + offset: i64, + ranges: Vec<ValueRange<u64>>, + }, + LookupTableValue { + tables: Vec<LookupTableEntry>, + }, + InSetOfValues { + values: HashSet<i64>, + }, + NotInSetOfValues { + values: HashSet<i64>, + }, + ConstantDataValue { + value_type: ConstantDataType, + value: i64, + }, +} + +#[derive(Copy, Clone, Debug)] +pub enum ConstantDataType { + Value, + ZeroExtend, + SignExtend, + Aggregate, +} + +impl PossibleValueSet { + pub(crate) unsafe fn from_raw(value: BNPossibleValueSet) -> Self { + unsafe fn from_range<T>(value: BNPossibleValueSet) -> Vec<ValueRange<T>> { + core::slice::from_raw_parts(value.ranges, value.count) + .iter() + .copied() + .map(|range| ValueRange::from_raw(range)) + .collect() + } + let from_sets = |value: BNPossibleValueSet| { + unsafe { core::slice::from_raw_parts(value.valueSet, value.count) } + .iter() + .copied() + .collect() + }; + use BNRegisterValueType::*; + match value.state { + UndeterminedValue => Self::UndeterminedValue, + EntryValue => Self::EntryValue { reg: value.value }, + ConstantValue => Self::ConstantValue { value: value.value }, + ConstantPointerValue => Self::ConstantPointerValue { value: value.value }, + StackFrameOffset => Self::StackFrameOffset { + offset: value.value, + }, + ConstantDataValue => Self::ConstantDataValue { + value_type: ConstantDataType::Value, + value: value.value, + }, + ConstantDataZeroExtendValue => Self::ConstantDataValue { + value_type: ConstantDataType::ZeroExtend, + value: value.value, + }, + ConstantDataSignExtendValue => Self::ConstantDataValue { + value_type: ConstantDataType::SignExtend, + value: value.value, + }, + ConstantDataAggregateValue => Self::ConstantDataValue { + value_type: ConstantDataType::Aggregate, + value: value.value, + }, + SignedRangeValue => Self::SignedRangeValue { + offset: value.value, + ranges: from_range(value), + }, + UnsignedRangeValue => Self::UnsignedRangeValue { + offset: value.value, + ranges: from_range(value), + }, + LookupTableValue => { + let raw_tables = unsafe { core::slice::from_raw_parts(value.table, value.count) }; + let raw_from_tables = |i: &BNLookupTableEntry| unsafe { + core::slice::from_raw_parts(i.fromValues, i.fromCount) + }; + let tables = raw_tables + .iter() + .map(|table| LookupTableEntry { + from_values: raw_from_tables(table).to_vec(), + to_value: table.toValue, + }) + .collect(); + Self::LookupTableValue { tables } + } + NotInSetOfValues => Self::NotInSetOfValues { + values: from_sets(value), + }, + InSetOfValues => Self::InSetOfValues { + values: from_sets(value), + }, + ImportedAddressValue => Self::ImportedAddressValue, + ReturnAddressValue => Self::ReturnAddressValue, + ExternalPointerValue => Self::ExternalPointerValue, + } + } + pub(crate) fn into_raw(self) -> PossibleValueSetRaw { + let mut raw: BNPossibleValueSet = unsafe { core::mem::zeroed() }; + // set the state field + raw.state = self.value_type().into_raw_value(); + // set all other fields + match self { + PossibleValueSet::UndeterminedValue + | PossibleValueSet::ExternalPointerValue + | PossibleValueSet::ReturnAddressValue + | PossibleValueSet::ImportedAddressValue => {} + PossibleValueSet::EntryValue { reg: value } + | PossibleValueSet::ConstantValue { value } + | PossibleValueSet::ConstantPointerValue { value } + | PossibleValueSet::ConstantDataValue { value, .. } + | PossibleValueSet::StackFrameOffset { offset: value } => raw.value = value, + PossibleValueSet::NotInSetOfValues { values } + | PossibleValueSet::InSetOfValues { values } => { + let values = Box::leak(values.into_iter().collect()); + raw.valueSet = values.as_mut_ptr(); + raw.count = values.len(); + } + PossibleValueSet::SignedRangeValue { offset, ranges } => { + let ranges = Box::leak(ranges.into_iter().map(|x| x.into_raw()).collect()); + raw.value = offset; + raw.ranges = ranges.as_mut_ptr(); + raw.count = ranges.len(); + } + PossibleValueSet::UnsignedRangeValue { offset, ranges } => { + let ranges = Box::leak(ranges.into_iter().map(|x| x.into_raw()).collect()); + raw.value = offset; + raw.ranges = ranges.as_mut_ptr(); + raw.count = ranges.len(); + } + PossibleValueSet::LookupTableValue { tables } => { + let tables = Box::leak(tables.into_iter().map(|table| table.into_raw()).collect()); + // SAFETY: BNLookupTableEntry and LookupTableEntryRaw are transparent + raw.table = tables.as_mut_ptr() as *mut BNLookupTableEntry; + raw.count = tables.len(); + } + } + PossibleValueSetRaw(raw) + } + + pub fn value_type(&self) -> RegisterValueType { + use RegisterValueType::*; + match self { + PossibleValueSet::UndeterminedValue => UndeterminedValue, + PossibleValueSet::EntryValue { .. } => EntryValue, + PossibleValueSet::ConstantValue { .. } => ConstantValue, + PossibleValueSet::ConstantPointerValue { .. } => ConstantPointerValue, + PossibleValueSet::ExternalPointerValue => ExternalPointerValue, + PossibleValueSet::StackFrameOffset { .. } => StackFrameOffset, + PossibleValueSet::ReturnAddressValue => ReturnAddressValue, + PossibleValueSet::ImportedAddressValue => ImportedAddressValue, + PossibleValueSet::SignedRangeValue { .. } => SignedRangeValue, + PossibleValueSet::UnsignedRangeValue { .. } => UnsignedRangeValue, + PossibleValueSet::LookupTableValue { .. } => LookupTableValue, + PossibleValueSet::InSetOfValues { .. } => InSetOfValues, + PossibleValueSet::NotInSetOfValues { .. } => NotInSetOfValues, + PossibleValueSet::ConstantDataValue { + value_type: ConstantDataType::Value, + .. + } => ConstantDataValue, + PossibleValueSet::ConstantDataValue { + value_type: ConstantDataType::ZeroExtend, + .. + } => ConstantDataZeroExtendValue, + PossibleValueSet::ConstantDataValue { + value_type: ConstantDataType::SignExtend, + .. + } => ConstantDataSignExtendValue, + PossibleValueSet::ConstantDataValue { + value_type: ConstantDataType::Aggregate, + .. + } => ConstantDataAggregateValue, + } + } +} + +/// The owned version of the BNPossibleValueSet +#[repr(transparent)] +pub(crate) struct PossibleValueSetRaw(BNPossibleValueSet); + +impl PossibleValueSetRaw { + pub fn as_ffi(&self) -> &BNPossibleValueSet { + &self.0 + } +} + +impl Drop for PossibleValueSetRaw { + fn drop(&mut self) { + use BNRegisterValueType::*; + match self.0.state { + UndeterminedValue + | ExternalPointerValue + | ReturnAddressValue + | ImportedAddressValue + | EntryValue + | ConstantValue + | ConstantPointerValue + | StackFrameOffset + | ConstantDataValue + | ConstantDataZeroExtendValue + | ConstantDataSignExtendValue + | ConstantDataAggregateValue => {} + InSetOfValues | NotInSetOfValues => { + let _values: Box<[i64]> = unsafe { + Box::from_raw(ptr::slice_from_raw_parts_mut(self.0.valueSet, self.0.count)) + }; + } + SignedRangeValue | UnsignedRangeValue => { + let _ranges: Box<[BNValueRange]> = unsafe { + Box::from_raw(ptr::slice_from_raw_parts_mut(self.0.ranges, self.0.count)) + }; + } + LookupTableValue => { + // SAFETY: LookupTableEntryRaw and BNLookupTableEntry can be safely transmuted + let table_ptr = self.0.table as *mut LookupTableEntryRaw; + let _table: Box<[LookupTableEntryRaw]> = unsafe { + Box::from_raw(ptr::slice_from_raw_parts_mut(table_ptr, self.0.count)) + }; + } + } + } +} + +///////////////////////// +// LookupTableEntry + +#[derive(Clone, Debug)] +pub struct LookupTableEntry { + pub from_values: Vec<i64>, + pub to_value: i64, +} + +impl LookupTableEntry { + fn into_raw(self) -> LookupTableEntryRaw { + let from_value = Box::leak(self.from_values.into_boxed_slice()); + LookupTableEntryRaw(BNLookupTableEntry { + toValue: self.to_value, + fromValues: from_value.as_mut_ptr(), + fromCount: from_value.len(), + }) + } +} + +/// The owned version of the BNLookupTableEntry +#[repr(transparent)] +struct LookupTableEntryRaw(BNLookupTableEntry); +impl Drop for LookupTableEntryRaw { + fn drop(&mut self) { + let _from_value: Box<[i64]> = unsafe { + Box::from_raw(ptr::slice_from_raw_parts_mut( + self.0.fromValues, + self.0.fromCount, + )) + }; + } +} + +///////////////////////// +// ArchAndAddr + +#[derive(Copy, Clone, Eq, Hash, PartialEq)] +pub struct ArchAndAddr { + pub arch: CoreArchitecture, + pub address: u64, +} + +///////////////////////// +// UserVariableValues + +pub struct UserVariableValues { + pub(crate) vars: *const [BNUserVariableValue], +} + +impl UserVariableValues { + pub fn into_hashmap(self) -> HashMap<Variable, HashMap<ArchAndAddr, PossibleValueSet>> { + let mut result: HashMap<Variable, HashMap<ArchAndAddr, PossibleValueSet>> = HashMap::new(); + for (var, def_site, possible_val) in self.all() { + result + .entry(var) + .or_default() + .entry(def_site) + .or_insert(possible_val); + } + result + } + pub fn all(&self) -> impl Iterator<Item = (Variable, ArchAndAddr, PossibleValueSet)> { + unsafe { &*self.vars }.iter().map(|var_val| { + let var = unsafe { Variable::from_raw(var_val.var) }; + let def_site = ArchAndAddr { + arch: unsafe { CoreArchitecture::from_raw(var_val.defSite.arch) }, + address: var_val.defSite.address, + }; + let possible_val = unsafe { PossibleValueSet::from_raw(var_val.value) }; + (var, def_site, possible_val) + }) + } + pub fn values_from_variable( + &self, + var: Variable, + ) -> impl Iterator<Item = (ArchAndAddr, PossibleValueSet)> { + self.all() + .filter(move |(t_var, _, _)| t_var == &var) + .map(|(_var, def_site, possible_val)| (def_site, possible_val)) + } +} + +impl Drop for UserVariableValues { + fn drop(&mut self) { + unsafe { BNFreeUserVariableValues(self.vars as *mut BNUserVariableValue) }; + } +} + +///////////////////////// +// ConstantReference + +#[derive(Copy, Clone, Eq, Hash, PartialEq)] +pub struct ConstantReference { + pub value: i64, + pub size: usize, + pub pointer: bool, + pub intermediate: bool, +} + +impl ConstantReference { + pub fn from_raw(value: BNConstantReference) -> Self { + Self { + value: value.value, + size: value.size, + pointer: value.pointer, + intermediate: value.intermediate, + } + } + pub fn into_raw(self) -> BNConstantReference { + BNConstantReference { + value: self.value, + size: self.size, + pointer: self.pointer, + intermediate: self.intermediate, + } + } +} + +impl CoreArrayProvider for ConstantReference { + type Raw = BNConstantReference; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for ConstantReference { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeConstantReferenceList(raw) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from_raw(*raw) + } +} + +///////////////////////// +// IndirectBranchInfo + +pub struct IndirectBranchInfo { + pub source_arch: CoreArchitecture, + pub source_addr: u64, + pub dest_arch: CoreArchitecture, + pub dest_addr: u64, + pub auto_defined: bool, +} + +impl IndirectBranchInfo { + pub fn from_raw(value: BNIndirectBranchInfo) -> Self { + Self { + source_arch: unsafe { CoreArchitecture::from_raw(value.sourceArch) }, + source_addr: value.sourceAddr, + dest_arch: unsafe { CoreArchitecture::from_raw(value.destArch) }, + dest_addr: value.destAddr, + auto_defined: value.autoDefined, + } + } + pub fn into_raw(self) -> BNIndirectBranchInfo { + BNIndirectBranchInfo { + sourceArch: self.source_arch.0, + sourceAddr: self.source_addr, + destArch: self.dest_arch.0, + destAddr: self.dest_addr, + autoDefined: self.auto_defined, + } + } +} + +impl CoreArrayProvider for IndirectBranchInfo { + type Raw = BNIndirectBranchInfo; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for IndirectBranchInfo { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeIndirectBranchList(raw) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from_raw(*raw) + } +} + +///////////////////////// +// HighlightStandardColor + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum HighlightStandardColor { + //NoHighlightColor, + BlueHighlightColor, + GreenHighlightColor, + CyanHighlightColor, + RedHighlightColor, + MagentaHighlightColor, + YellowHighlightColor, + OrangeHighlightColor, + WhiteHighlightColor, + BlackHighlightColor, +} + +impl HighlightStandardColor { + pub fn from_raw(value: BNHighlightStandardColor) -> Option<Self> { + Some(match value { + BNHighlightStandardColor::NoHighlightColor => return None, + BNHighlightStandardColor::BlueHighlightColor => Self::BlueHighlightColor, + BNHighlightStandardColor::GreenHighlightColor => Self::GreenHighlightColor, + BNHighlightStandardColor::CyanHighlightColor => Self::CyanHighlightColor, + BNHighlightStandardColor::RedHighlightColor => Self::RedHighlightColor, + BNHighlightStandardColor::MagentaHighlightColor => Self::MagentaHighlightColor, + BNHighlightStandardColor::YellowHighlightColor => Self::YellowHighlightColor, + BNHighlightStandardColor::OrangeHighlightColor => Self::OrangeHighlightColor, + BNHighlightStandardColor::WhiteHighlightColor => Self::WhiteHighlightColor, + BNHighlightStandardColor::BlackHighlightColor => Self::BlackHighlightColor, + }) + } + pub fn into_raw(self) -> BNHighlightStandardColor { + match self { + //Self::NoHighlightColor => BNHighlightStandardColor::NoHighlightColor, + Self::BlueHighlightColor => BNHighlightStandardColor::BlueHighlightColor, + Self::GreenHighlightColor => BNHighlightStandardColor::GreenHighlightColor, + Self::CyanHighlightColor => BNHighlightStandardColor::CyanHighlightColor, + Self::RedHighlightColor => BNHighlightStandardColor::RedHighlightColor, + Self::MagentaHighlightColor => BNHighlightStandardColor::MagentaHighlightColor, + Self::YellowHighlightColor => BNHighlightStandardColor::YellowHighlightColor, + Self::OrangeHighlightColor => BNHighlightStandardColor::OrangeHighlightColor, + Self::WhiteHighlightColor => BNHighlightStandardColor::WhiteHighlightColor, + Self::BlackHighlightColor => BNHighlightStandardColor::BlackHighlightColor, + } + } +} + +///////////////////////// +// HighlightColor + +#[derive(Debug, Copy, Clone)] +pub enum HighlightColor { + NoHighlightColor { + alpha: u8, + }, + StandardHighlightColor { + color: HighlightStandardColor, + alpha: u8, + }, + MixedHighlightColor { + color: HighlightStandardColor, + mix_color: HighlightStandardColor, + mix: u8, + alpha: u8, + }, + CustomHighlightColor { + r: u8, + g: u8, + b: u8, + alpha: u8, + }, +} + +impl HighlightColor { + pub fn from_raw(raw: BNHighlightColor) -> Self { + const HIGHLIGHT_COLOR: u32 = BNHighlightColorStyle::StandardHighlightColor as u32; + const MIXED_HIGHLIGHT_COLOR: u32 = BNHighlightColorStyle::MixedHighlightColor as u32; + const CUSTOM_HIGHLIHGT_COLOR: u32 = BNHighlightColorStyle::CustomHighlightColor as u32; + match raw.style as u32 { + HIGHLIGHT_COLOR => { + let Some(color) = HighlightStandardColor::from_raw(raw.color) else { + // StandardHighlightColor with NoHighlightColor, is no color + return Self::NoHighlightColor { alpha: raw.alpha }; + }; + Self::StandardHighlightColor { + color, + alpha: raw.alpha, + } + } + MIXED_HIGHLIGHT_COLOR => { + let Some(color) = HighlightStandardColor::from_raw(raw.color) else { + panic!("Highlight mixed color with no color"); + }; + let Some(mix_color) = HighlightStandardColor::from_raw(raw.mixColor) else { + panic!("Highlight mixed color with no mix_color"); + }; + Self::MixedHighlightColor { + color, + mix_color, + mix: raw.mix, + alpha: raw.alpha, + } + } + CUSTOM_HIGHLIHGT_COLOR => Self::CustomHighlightColor { + r: raw.r, + g: raw.g, + b: raw.b, + alpha: raw.alpha, + }, + // other color style is just no color + _ => Self::NoHighlightColor { alpha: u8::MAX }, + } + } + + pub fn into_raw(self) -> BNHighlightColor { + let zeroed: BNHighlightColor = unsafe { core::mem::zeroed() }; + match self { + Self::NoHighlightColor { alpha } => BNHighlightColor { + style: BNHighlightColorStyle::StandardHighlightColor, + color: BNHighlightStandardColor::NoHighlightColor, + alpha, + ..zeroed + }, + Self::StandardHighlightColor { color, alpha } => BNHighlightColor { + style: BNHighlightColorStyle::StandardHighlightColor, + color: color.into_raw(), + alpha, + ..zeroed + }, + Self::MixedHighlightColor { + color, + mix_color, + mix, + alpha, + } => BNHighlightColor { + color: color.into_raw(), + mixColor: mix_color.into_raw(), + mix, + alpha, + ..zeroed + }, + Self::CustomHighlightColor { r, g, b, alpha } => BNHighlightColor { + r, + g, + b, + alpha, + ..zeroed + }, + } + } +} + +///////////////////////// +// IntegerDisplayType + +pub type IntegerDisplayType = binaryninjacore_sys::BNIntegerDisplayType; + +///////////////////////// +// StackVariableReference + +#[derive(Debug, Clone)] +pub struct StackVariableReference { + _source_operand: u32, + var_type: Conf<Ref<Type>>, + name: BnString, + var: Variable, + offset: i64, + size: usize, +} + +impl StackVariableReference { + pub fn from_raw(value: BNStackVariableReference) -> Self { + let var_type = Conf::new( + unsafe { Type::ref_from_raw(value.type_) }, + value.typeConfidence, + ); + let name = unsafe { BnString::from_raw(value.name) }; + let var = unsafe { Variable::from_identifier(value.varIdentifier) }; + let offset = value.referencedOffset; + let size = value.size; + Self { + _source_operand: value.sourceOperand, + var_type, + name, + var, + offset, + size, + } + } + pub fn variable(&self) -> &Variable { + &self.var + } + pub fn variable_type(&self) -> Conf<&Type> { + self.var_type.as_ref() + } + pub fn name(&self) -> &str { + self.name.as_str() + } + pub fn offset(&self) -> i64 { + self.offset + } + pub fn size(&self) -> usize { + self.size + } +} + +impl CoreArrayProvider for StackVariableReference { + type Raw = BNStackVariableReference; + type Context = (); + type Wrapped<'a> = Guard<'a, Self>; +} + +unsafe impl CoreArrayProviderInner for StackVariableReference { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeStackVariableReferenceList(raw, count) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Guard::new(Self::from_raw(*raw), context) + } +} + +///////////////////////// +// RegisterStackAdjustment + +#[derive(Debug, Copy, Clone)] +pub struct RegisterStackAdjustment<A: Architecture> { + reg_id: u32, + adjustment: Conf<i32>, + arch: A::Handle, +} + +impl<A: Architecture> RegisterStackAdjustment<A> { + pub(crate) unsafe fn from_raw(value: BNRegisterStackAdjustment, arch: A::Handle) -> Self { + RegisterStackAdjustment { + reg_id: value.regStack, + adjustment: Conf::new(value.adjustment, value.confidence), + arch, + } + } + pub(crate) fn into_raw(self) -> BNRegisterStackAdjustment { + BNRegisterStackAdjustment { + regStack: self.reg_id, + adjustment: self.adjustment.contents, + confidence: self.adjustment.confidence, + } + } + pub fn new<I>(reg_id: u32, adjustment: I, arch_handle: A::Handle) -> Self + where + I: Into<Conf<i32>>, + { + Self { + reg_id, + adjustment: adjustment.into(), + arch: arch_handle, + } + } + pub const fn register_id(&self) -> u32 { + self.reg_id + } + pub fn register(&self) -> A::Register { + self.arch.borrow().register_from_id(self.reg_id).unwrap() + } +} + +impl<A: Architecture> CoreArrayProvider for RegisterStackAdjustment<A> { + type Raw = BNRegisterStackAdjustment; + type Context = A::Handle; + type Wrapped<'a> = Self; +} + +unsafe impl<A: Architecture> CoreArrayProviderInner for RegisterStackAdjustment<A> { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeRegisterStackAdjustments(raw) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from_raw(*raw, context.clone()) + } +} + +///////////////////////// +// RegisterStackAdjustment + +// NOTE only exists as part of an Array, never owned +pub struct MergedVariable { + target: Variable, + // droped by the CoreArrayProviderInner::free + sources: ManuallyDrop<Array<Variable>>, +} + +impl MergedVariable { + pub fn target(&self) -> Variable { + self.target + } + pub fn sources(&self) -> &Array<Variable> { + &self.sources + } +} + +impl CoreArrayProvider for MergedVariable { + type Raw = BNMergedVariable; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for MergedVariable { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeMergedVariableList(raw, count) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self { + target: Variable::from_raw(raw.target), + sources: ManuallyDrop::new(Array::new(raw.sources, raw.sourceCount, ())), + } + } +} + +///////////////////////// +// UnresolvedIndirectBranches + +// NOTE only exists as part of an Array, never owned +pub struct UnresolvedIndirectBranches(u64); + +impl UnresolvedIndirectBranches { + pub fn address(&self) -> u64 { + self.0 + } +} + +impl CoreArrayProvider for UnresolvedIndirectBranches { + type Raw = u64; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for UnresolvedIndirectBranches { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeAddressList(raw) + } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self(*raw) + } +} |
