diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index e854d53b81..73298714a9 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -26,7 +26,7 @@ use crate::{ calling_convention::CoreCallingConvention, data_buffer::DataBuffer, disassembly::InstructionTextToken, - function::Function, + function::{Function, Location, NativeBlock}, platform::Platform, rc::*, relocation::CoreRelocationHandler, @@ -34,6 +34,7 @@ use crate::{ types::{NameAndType, Type}, Endianness, }; +use std::collections::{HashMap, HashSet}; use std::ops::Deref; use std::{ borrow::Borrow, @@ -47,7 +48,9 @@ use std::ptr::NonNull; use crate::function_recognizer::FunctionRecognizer; use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler}; +use crate::basic_block::BasicBlock; use crate::confidence::Conf; +use crate::logger::Logger; use crate::low_level_il::expression::ValueExpr; use crate::low_level_il::lifting::{ get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp, @@ -591,13 +594,133 @@ pub trait ArchitectureWithFunctionContext: Architecture { pub struct FunctionLifterContext { pub(crate) handle: *mut BNFunctionLifterContext, + pub function: *mut BNLowLevelILFunction, + pub platform: Ref, + pub logger: Ref, + pub blocks: Vec>>, + pub no_return_calls: HashSet, + pub contextual_returns: HashMap, + pub inlined_remapping: HashMap, + pub user_indirect_branches: HashMap>, + pub auto_indirect_branches: HashMap>, + //pub inlined_calls: HashSet, +} + +unsafe fn lifter_context_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] { + if len == 0 { + &[] + } else { + debug_assert!(!ptr.is_null()); + unsafe { std::slice::from_raw_parts(ptr, len) } + } } impl FunctionLifterContext { - pub unsafe fn from_raw(handle: *mut BNFunctionLifterContext) -> Self { + pub unsafe fn from_raw( + function: *mut BNLowLevelILFunction, + handle: *mut BNFunctionLifterContext, + ) -> Self { + debug_assert!(!function.is_null()); debug_assert!(!handle.is_null()); + let flc_ref = &*handle; + let platform = unsafe { Platform::ref_from_raw(BNNewPlatformReference(flc_ref.platform)) }; + let logger = unsafe { Logger::ref_from_raw(BNNewLoggerReference(flc_ref.logger)) }; + + let mut blocks = Vec::new(); + for i in 0..flc_ref.basicBlockCount { + let block = unsafe { + Some(BasicBlock::ref_from_raw( + BNNewBasicBlockReference(*flc_ref.basicBlocks.add(i)), + NativeBlock::new(), + )) + }; + + blocks.push(block.unwrap()); + } + + let raw_no_return_calls: &[BNArchitectureAndAddress] = + lifter_context_slice(flc_ref.noReturnCalls, flc_ref.noReturnCallsCount); + let no_return_calls: HashSet = + raw_no_return_calls.iter().map(Location::from).collect(); + + let raw_contextual_return_locs: &[BNArchitectureAndAddress] = unsafe { + lifter_context_slice( + flc_ref.contextualFunctionReturnLocations, + flc_ref.contextualFunctionReturnCount, + ) + }; + let raw_contextual_return_vals: &[bool] = unsafe { + lifter_context_slice( + flc_ref.contextualFunctionReturnValues, + flc_ref.contextualFunctionReturnCount, + ) + }; + let contextual_returns: HashMap = raw_contextual_return_locs + .iter() + .map(Location::from) + .zip(raw_contextual_return_vals.iter().copied()) + .collect(); + + let inlined_remapping: HashMap = { + let raw_inline_remap_locs: &[BNArchitectureAndAddress] = lifter_context_slice( + flc_ref.inlinedRemappingKeys, + flc_ref.inlinedRemappingEntryCount, + ); + + let raw_inline_remap_dests: &[BNArchitectureAndAddress] = lifter_context_slice( + flc_ref.inlinedRemappingValues, + flc_ref.inlinedRemappingEntryCount, + ); + + raw_inline_remap_locs + .iter() + .map(Location::from) + .zip(raw_inline_remap_dests.iter().map(Location::from)) + .collect() + }; - FunctionLifterContext { handle } + let mut user_indirect_branches: HashMap> = HashMap::new(); + let mut auto_indirect_branches: HashMap> = HashMap::new(); + for i in 0..flc_ref.indirectBranchesCount { + let entry = unsafe { *flc_ref.indirectBranches.add(i) }; + let src = Location::new( + Some(CoreArchitecture::from_raw(entry.sourceArch)), + entry.sourceAddr, + ); + let dest = Location::new( + Some(CoreArchitecture::from_raw(entry.destArch)), + entry.destAddr, + ); + if entry.autoDefined { + auto_indirect_branches.entry(src).or_default().insert(dest); + } else { + user_indirect_branches.entry(src).or_default().insert(dest); + } + } + + FunctionLifterContext { + handle, + function: BNNewLowLevelILFunctionReference(function), + platform, + logger, + blocks, + no_return_calls, + contextual_returns, + inlined_remapping, + user_indirect_branches, + auto_indirect_branches, + } + } + + pub fn prepare_block_translation( + &self, + func: &LowLevelILMutableFunction, + arch: &CoreArchitecture, + address: u64, + ) { + unsafe { + BNPrepareBlockTranslation(func.handle, arch.handle, address); + } } pub fn get_function_arch_context( @@ -615,6 +738,14 @@ impl FunctionLifterContext { } } +impl Drop for FunctionLifterContext { + fn drop(&mut self) { + if !self.function.is_null() { + unsafe { BNFreeLowLevelILFunction(self.function) }; + } + } +} + // TODO: WTF?!?!?!? pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize); @@ -1622,12 +1753,12 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let function = unsafe { + let llil = unsafe { LowLevelILMutableFunction::from_raw_with_arch(function, Some(*custom_arch.as_ref())) }; - let mut context: FunctionLifterContext = - unsafe { FunctionLifterContext::from_raw(context) }; - custom_arch.lift_function(function, &mut context) + + let mut ctx = unsafe { FunctionLifterContext::from_raw(function, context) }; + custom_arch.lift_function(llil, &mut ctx) } extern "C" fn cb_reg_name(ctxt: *mut c_void, reg: u32) -> *mut c_char @@ -2622,7 +2753,6 @@ where unsafe { let res = BNRegisterArchitecture(name.as_ptr(), &mut custom_arch as *mut _); - assert!(!res.is_null()); (*raw).arch.assume_init_mut() diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 8d49e55ea0..b573cd0f62 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -1807,17 +1807,22 @@ impl BinaryView { address: u64, platform: &Platform, ) -> Option> { - self.add_auto_function_ext(address, platform, None) + self.add_auto_function_ext(address, platform, None, false) } /// Add an auto function at the given `address` with the `platform` and function type. /// + /// The `auto_discovered` flag is used to prevent or allow this created function to be deleted if + /// it is never used (the function has no xrefs), if you are confident that this is a valid function + /// set this to `false`. + /// /// NOTE: If the view's default platform is not set, this will set it to `platform`. pub fn add_auto_function_ext( &self, address: u64, platform: &Platform, func_type: Option<&Type>, + auto_discovered: bool, ) -> Option> { unsafe { let func_type = match func_type { @@ -1825,8 +1830,13 @@ impl BinaryView { None => std::ptr::null_mut(), }; - let handle = - BNAddFunctionForAnalysis(self.handle, platform.handle, address, true, func_type); + let handle = BNAddFunctionForAnalysis( + self.handle, + platform.handle, + address, + auto_discovered, + func_type, + ); if handle.is_null() { return None; diff --git a/rust/src/function.rs b/rust/src/function.rs index 320382de55..519e492f6b 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -514,7 +514,8 @@ impl Function { let arch = arch.unwrap_or_else(|| self.arch()); let mut result = 0; unsafe { - BNGetFunctionBlockSortHint(self.handle, arch.handle, addr, &mut result).then_some(result) + BNGetFunctionBlockSortHint(self.handle, arch.handle, addr, &mut result) + .then_some(result) } } diff --git a/rust/src/logger.rs b/rust/src/logger.rs index 66e594fdb2..d2903a5a46 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -57,6 +57,14 @@ impl Logger { Self::new_with_session(name, LOGGER_DEFAULT_SESSION_ID) } + pub fn ref_from_raw(handle: *mut BNLogger) -> Ref { + unsafe { + Ref::new(Logger { + handle: NonNull::new(handle).unwrap(), + }) + } + } + /// Create a logger scoped with the specific [`SessionId`], hiding the logs when the session /// is not active in the UI. /// diff --git a/rust/src/low_level_il.rs b/rust/src/low_level_il.rs index 12a7410648..13c649b232 100644 --- a/rust/src/low_level_il.rs +++ b/rust/src/low_level_il.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::borrow::Cow; +use std::collections::HashSet; use std::fmt; use std::fmt::{Debug, Display}; // TODO : provide some way to forbid emitting register reads for certain registers @@ -316,3 +317,42 @@ pub enum VisitorAction { Sibling, Halt, } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum ILInstructionAttribute { + ILAllowDeadStoreElimination, + ILPreventDeadStoreElimination, + MLILAssumePossibleUse, + MLILUnknownSize, + SrcInstructionUsesPointerAuth, + ILPreventAliasAnalysis, + ILIsCFGProtected, + MLILPossiblyUnusedIntermediate, + HLILFoldableExpr, + HLILInvertableCondition, + HLILEarlyReturnPossible, + HLILSwitchRecoveryPossible, + ILTransparentCopy, +} + +impl ILInstructionAttribute { + pub fn value(&self) -> u32 { + match self { + Self::ILAllowDeadStoreElimination => 1, + Self::ILPreventDeadStoreElimination => 2, + Self::MLILAssumePossibleUse => 4, + Self::MLILUnknownSize => 8, + Self::SrcInstructionUsesPointerAuth => 16, + Self::ILPreventAliasAnalysis => 32, + Self::ILIsCFGProtected => 64, + Self::MLILPossiblyUnusedIntermediate => 128, + Self::HLILFoldableExpr => 256, + Self::HLILInvertableCondition => 512, + Self::HLILEarlyReturnPossible => 1024, + Self::HLILSwitchRecoveryPossible => 2048, + Self::ILTransparentCopy => 4096, + } + } +} + +pub type ILInstructionAttributeSet = HashSet; diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 32e1f9213f..a0db838b8a 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -209,6 +209,20 @@ where Some(unsafe { BasicBlock::ref_from_raw(block, LowLevelILBlock { function: self }) }) } } + + pub fn set_indirect_branches(&self, branches: &[Location]) { + let mut bn_branches: Box<[BNArchitectureAndAddress]> = branches + .iter() + .map(|loc| BNArchitectureAndAddress { + address: loc.addr, + arch: loc.arch.unwrap_or_else(|| self.arch()).handle, + }) + .collect(); + + unsafe { + BNLowLevelILSetIndirectBranches(self.handle, bn_branches.as_mut_ptr(), branches.len()); + } + } } impl LowLevelILFunction { diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index d162b3f601..202c9ed69d 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -14,8 +14,10 @@ use std::marker::PhantomData; -use binaryninjacore_sys::{BNAddLowLevelILLabelForAddress, BNLowLevelILOperation}; -use binaryninjacore_sys::{BNLowLevelILLabel, BNRegisterOrConstant}; +use binaryninjacore_sys::{ + BNAddLowLevelILLabelForAddress, BNLowLevelILClearIndirectBranches, BNLowLevelILLabel, + BNLowLevelILOperation, BNRegisterOrConstant, BNSetLowLevelILExprAttributes, +}; use super::*; use crate::architecture::{Architecture, FlagWriteId, RegisterId}; @@ -23,7 +25,8 @@ use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::architecture::{ Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic, }; -use crate::function::Location; +use crate::basic_block::BasicBlock; +use crate::function::{Location, NativeBlock}; pub trait LiftableLowLevelIL<'func> { type Result: ExpressionResultType; @@ -1512,6 +1515,13 @@ impl LowLevelILMutableFunction { } } + pub fn set_current_source_block(&self, source: &BasicBlock) { + use binaryninjacore_sys::BNLowLevelILSetCurrentSourceBlock; + unsafe { + BNLowLevelILSetCurrentSourceBlock(self.handle, source.handle); + } + } + pub fn label_for_address>(&self, loc: L) -> Option { use binaryninjacore_sys::BNGetLowLevelILLabelForAddress; @@ -1561,6 +1571,25 @@ impl LowLevelILMutableFunction { } *label = new_label; } + + pub fn set_expr_attributes( + &self, + expr: LowLevelExpressionIndex, + value: &ILInstructionAttributeSet, + ) { + let mut result = 0u32; + for flag in value { + result |= flag.value(); + } + + unsafe { + BNSetLowLevelILExprAttributes(self.handle, expr.0, result); + } + } + + pub fn clear_indirect_branches(&self) { + unsafe { BNLowLevelILClearIndirectBranches(self.handle) }; + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/rust/src/platform.rs b/rust/src/platform.rs index e70e127792..9de125a1c3 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -20,8 +20,8 @@ use crate::{ rc::*, string::*, types::{ - QualifiedNameAndType, TypeContainer, TypeLibrary, TypeParserError, TypeParserErrorSeverity, - TypeParserResult, + QualifiedName, QualifiedNameAndType, Type, TypeContainer, TypeLibrary, TypeParserError, + TypeParserErrorSeverity, TypeParserResult, }, }; use binaryninjacore_sys::*; @@ -279,6 +279,22 @@ impl Platform { } } + pub fn function_by_name>( + &self, + name: T, + exact_match: bool, + ) -> Option> { + let mut raw_name = QualifiedName::into_raw(name.into()); + unsafe { + let type_handle = BNGetPlatformFunctionByName(self.handle, &mut raw_name, exact_match); + QualifiedName::free_raw(raw_name); + if type_handle.is_null() { + return None; + } + Some(Type::ref_from_raw(type_handle)) + } + } + // TODO: system_calls // TODO: add a helper function to define a system call (platform function with a specific type) diff --git a/rust/tests/platform.rs b/rust/tests/platform.rs index 36a04d7f23..09022ec1c3 100644 --- a/rust/tests/platform.rs +++ b/rust/tests/platform.rs @@ -21,6 +21,17 @@ fn test_platform_types() { assert_ne!(platform_types.len(), 0); } +#[test] +fn test_platform_function_by_name() { + let _session = Session::new().expect("Failed to initialize session"); + let platform = Platform::by_name("windows-x86_64").expect("windows-x86_64 exists"); + let platform_functions = platform.functions(); + assert_ne!(platform_functions.len(), 0); + + let function = platform_functions.get(0); + assert!(platform.function_by_name(function.name, true).is_some()); +} + #[test] fn test_platform_calling_conventions() { let _session = Session::new().expect("Failed to initialize session"); diff --git a/view/elf/elfview.cpp b/view/elf/elfview.cpp index abf860a247..c54663d485 100644 --- a/view/elf/elfview.cpp +++ b/view/elf/elfview.cpp @@ -1338,8 +1338,16 @@ bool ElfView::Init() DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding); break; case ELF_STT_FUNC: - DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding); - break; + { + auto symbolType = FunctionSymbol; + if (m_plat && m_plat->GetName() == "tms320c6x" && + (entry->name.find('$') != std::string::npos || entry->name == "LOOP")) { + // TMS320C6x ELFs use ELF_STT_FUNC *$* and LOOP symbols for labeling blocks + symbolType = LocalLabelSymbol; + } + DefineElfSymbol(symbolType, entry->name, entry->value, false, entry->binding); + break; + } case ELF_STT_TLS: /* - only create Binja symbols for .symtab (not .dynsym) symbols - ignore mapping symbols, all is assumed data @@ -2617,9 +2625,9 @@ void ElfView::DefineElfSymbol(BNSymbolType type, const string& incomingName, uin } } - if (!typeRef && m_arch && m_arch->GetName() == "hexagon") + if (!typeRef && m_arch && (m_arch->GetName() == "hexagon" || m_arch->GetName() == "tms320c6x")) { - // Apply platform types for statically linked Hexagon binaries + // Apply platform types for statically linked Hexagon and TMS320C6x binaries typeRef = GetDefaultPlatform()->GetFunctionByName(rawName); }