diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index 797146767..938e9ec58 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -19,8 +19,8 @@ use msp430_asm::{ use binaryninja::architecture::{ BranchKind, FlagClassId, FlagGroupId, FlagId, FlagWriteId, RegisterId, }; -use binaryninja::lowlevelil::expression::ValueExpr; -use binaryninja::lowlevelil::{MutableLiftedILExpr, MutableLiftedILFunction}; +use binaryninja::low_level_il::expression::ValueExpr; +use binaryninja::low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}; use log::error; const MIN_MNEMONIC: usize = 9; diff --git a/arch/msp430/src/lib.rs b/arch/msp430/src/lib.rs index c8428209f..b54655547 100644 --- a/arch/msp430/src/lib.rs +++ b/arch/msp430/src/lib.rs @@ -5,8 +5,8 @@ extern crate msp430_asm; use binaryninja::{ add_optional_plugin_dependency, architecture::ArchitectureExt, - callingconvention, - custombinaryview::{BinaryViewType, BinaryViewTypeExt}, + calling_convention, + custom_binary_view::{BinaryViewType, BinaryViewTypeExt}, Endianness, }; use log::LevelFilter; @@ -36,13 +36,13 @@ pub extern "C" fn CorePluginInit() -> bool { // https://www.ti.com/lit/an/slaa664/slaa664.pdf?ts=1613210655081. MSPGCC // appears to be a legacy calling convention while EABI is the newer // standardized one that is compatible with TI's compiler - let default = callingconvention::ConventionBuilder::new(arch) + let default = calling_convention::ConventionBuilder::new(arch) .is_eligible_for_heuristics(true) .int_arg_registers(&["r15", "r14", "r13", "r12"]) .return_int_reg("r15") .return_hi_int_reg("r14") .register("default"); - callingconvention::ConventionBuilder::new(arch) + calling_convention::ConventionBuilder::new(arch) .is_eligible_for_heuristics(true) .return_int_reg("r15") .return_hi_int_reg("r14") diff --git a/arch/msp430/src/lift.rs b/arch/msp430/src/lift.rs index 164433096..4fcc146a1 100644 --- a/arch/msp430/src/lift.rs +++ b/arch/msp430/src/lift.rs @@ -3,7 +3,7 @@ use crate::flag::{Flag, FlagWrite}; use crate::register::Register; use crate::Msp430; -use binaryninja::{architecture::FlagCondition, lowlevelil::lifting::Label}; +use binaryninja::{architecture::FlagCondition, low_level_il::lifting::Label}; use msp430_asm::emulate::Emulated; use msp430_asm::instruction::Instruction; @@ -12,8 +12,8 @@ use msp430_asm::operand::{Operand, OperandWidth}; use msp430_asm::single_operand::SingleOperand; use msp430_asm::two_operand::TwoOperand; -use binaryninja::lowlevelil::expression::ValueExpr; -use binaryninja::lowlevelil::{MutableLiftedILExpr, MutableLiftedILFunction}; +use binaryninja::low_level_il::expression::ValueExpr; +use binaryninja::low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}; use log::info; macro_rules! auto_increment { diff --git a/arch/msp430/src/register.rs b/arch/msp430/src/register.rs index 826a6ed6d..0886e537b 100644 --- a/arch/msp430/src/register.rs +++ b/arch/msp430/src/register.rs @@ -1,7 +1,7 @@ use binaryninja::architecture; use binaryninja::architecture::{ImplicitRegisterExtend, RegisterId}; -use binaryninja::lowlevelil::LowLevelILRegister; +use binaryninja::low_level_il::LowLevelILRegister; use std::borrow::Cow; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 8fb29c186..b470c36e2 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -14,12 +14,12 @@ use binaryninja::{ LlvmServicesRelocMode, Register as Reg, RegisterInfo, UnusedFlag, UnusedRegisterStack, UnusedRegisterStackInfo, }, - binaryview::{BinaryView, BinaryViewExt}, - callingconvention::{register_calling_convention, CallingConventionBase, ConventionBuilder}, - custombinaryview::{BinaryViewType, BinaryViewTypeExt}, + binary_view::{BinaryView, BinaryViewExt}, + calling_convention::{register_calling_convention, CallingConventionBase, ConventionBuilder}, + custom_binary_view::{BinaryViewType, BinaryViewTypeExt}, disassembly::{InstructionTextToken, InstructionTextTokenKind}, function::Function, - functionrecognizer::FunctionRecognizer, + function_recognizer::FunctionRecognizer, rc::Ref, relocation::{ CoreRelocationHandler, CustomRelocationHandlerHandle, RelocationHandler, RelocationInfo, @@ -37,10 +37,10 @@ use std::marker::PhantomData; use binaryninja::architecture::{BranchKind, IntrinsicId, RegisterId}; use binaryninja::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE}; use binaryninja::logger::Logger; -use binaryninja::lowlevelil::expression::{LowLevelILExpressionKind, ValueExpr}; -use binaryninja::lowlevelil::instruction::LowLevelILInstructionKind; -use binaryninja::lowlevelil::lifting::{Label, LiftableLowLevelIL, LiftableLowLevelILWithSize}; -use binaryninja::lowlevelil::{ +use binaryninja::low_level_il::expression::{LowLevelILExpressionKind, ValueExpr}; +use binaryninja::low_level_il::instruction::LowLevelILInstructionKind; +use binaryninja::low_level_il::lifting::{Label, LiftableLowLevelIL, LiftableLowLevelILWithSize}; +use binaryninja::low_level_il::{ expression::ExpressionHandler, instruction::InstructionHandler, LowLevelILRegister, MutableLiftedILExpr, MutableLiftedILFunction, RegularLowLevelILFunction, }; diff --git a/plugins/dwarf/dwarf_export/src/lib.rs b/plugins/dwarf/dwarf_export/src/lib.rs index a5d67321d..2a3cfa023 100644 --- a/plugins/dwarf/dwarf_export/src/lib.rs +++ b/plugins/dwarf/dwarf_export/src/lib.rs @@ -12,7 +12,7 @@ use std::fs; use binaryninja::logger::Logger; use binaryninja::{ - binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}, command::{register, Command}, confidence::Conf, interaction, diff --git a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs index f85d1724b..6bf714893 100644 --- a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -18,12 +18,12 @@ use crate::{ }; use binaryninja::{ - binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}, debuginfo::{DebugFunctionInfo, DebugInfo}, platform::Platform, rc::*, symbol::SymbolType, - templatesimplifier::simplify_str_to_fqn, + template_simplifier::simplify_str_to_fqn, types::{FunctionParameter, Type}, variable::NamedVariableWithType, }; diff --git a/plugins/dwarf/dwarf_import/src/functions.rs b/plugins/dwarf/dwarf_import/src/functions.rs index 800d281e8..478295032 100644 --- a/plugins/dwarf/dwarf_import/src/functions.rs +++ b/plugins/dwarf/dwarf_import/src/functions.rs @@ -18,7 +18,7 @@ use crate::dwarfdebuginfo::{DebugInfoBuilder, DebugInfoBuilderContext, TypeUID}; use crate::types::get_type; use crate::{helpers::*, ReaderType}; -use binaryninja::templatesimplifier::simplify_str_to_str; +use binaryninja::template_simplifier::simplify_str_to_str; use cpp_demangle::DemangleOptions; use gimli::{constants, AttributeValue, DebuggingInformationEntry, Dwarf, Operation, Unit}; use log::{debug, error}; diff --git a/plugins/dwarf/dwarf_import/src/helpers.rs b/plugins/dwarf/dwarf_import/src/helpers.rs index 54b5f4b26..40f105723 100644 --- a/plugins/dwarf/dwarf_import/src/helpers.rs +++ b/plugins/dwarf/dwarf_import/src/helpers.rs @@ -17,12 +17,12 @@ use std::path::{Path, PathBuf}; use std::{collections::HashMap, ops::Deref, str::FromStr, sync::mpsc}; use crate::{DebugInfoBuilderContext, ReaderType}; -use binaryninja::binaryview::BinaryViewBase; -use binaryninja::filemetadata::FileMetadata; +use binaryninja::binary_view::BinaryViewBase; +use binaryninja::file_metadata::FileMetadata; use binaryninja::Endianness; use binaryninja::{ - binaryview::{BinaryView, BinaryViewExt}, - downloadprovider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}, + binary_view::{BinaryView, BinaryViewExt}, + download_provider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}, rc::Ref, settings::Settings, }; diff --git a/plugins/dwarf/dwarf_import/src/lib.rs b/plugins/dwarf/dwarf_import/src/lib.rs index f2c066421..4ef0e1b87 100644 --- a/plugins/dwarf/dwarf_import/src/lib.rs +++ b/plugins/dwarf/dwarf_import/src/lib.rs @@ -25,12 +25,12 @@ use crate::functions::parse_function_entry; use crate::helpers::{get_attr_die, get_name, get_uid, DieReference}; use crate::types::parse_variable; -use binaryninja::binaryview::BinaryViewBase; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::{ - binaryview::{BinaryView, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewExt}, debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser}, settings::Settings, - templatesimplifier::simplify_str_to_str, + template_simplifier::simplify_str_to_str, }; use dwarfreader::{ create_section_reader, get_endian, is_dwo_dwarf, is_non_dwo_dwarf, is_raw_dwo_dwarf, diff --git a/plugins/dwarf/dwarfdump/src/lib.rs b/plugins/dwarf/dwarfdump/src/lib.rs index f24ce000d..bdd6bfbb9 100644 --- a/plugins/dwarf/dwarfdump/src/lib.rs +++ b/plugins/dwarf/dwarfdump/src/lib.rs @@ -13,7 +13,7 @@ // limitations under the License. use binaryninja::{ - binaryview::{BinaryView, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewExt}, command::{register, Command}, disassembly::{DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind}, flowgraph::{BranchType, EdgeStyle, FlowGraph, FlowGraphNode, FlowGraphOption}, diff --git a/plugins/dwarf/shared/src/lib.rs b/plugins/dwarf/shared/src/lib.rs index de1f65357..a75558b50 100644 --- a/plugins/dwarf/shared/src/lib.rs +++ b/plugins/dwarf/shared/src/lib.rs @@ -15,7 +15,7 @@ use gimli::{EndianRcSlice, Endianity, RunTimeEndian, SectionId}; use binaryninja::{ - binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}, settings::Settings, Endianness, }; diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs index 2245703e3..ddd22ea57 100644 --- a/plugins/idb_import/src/lib.rs +++ b/plugins/idb_import/src/lib.rs @@ -3,7 +3,7 @@ use types::*; mod addr_info; use addr_info::*; -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; use binaryninja::debuginfo::{ CustomDebugInfoParser, DebugFunctionInfo, DebugInfo, DebugInfoParser, }; diff --git a/plugins/idb_import/src/types.rs b/plugins/idb_import/src/types.rs index 34b04c588..4999eea49 100644 --- a/plugins/idb_import/src/types.rs +++ b/plugins/idb_import/src/types.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use anyhow::{anyhow, Result}; use binaryninja::architecture::CoreArchitecture; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::binaryninjacore_sys::{BNMemberAccess, BNMemberScope}; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::confidence::Conf; use binaryninja::rc::Ref; use binaryninja::types::{ diff --git a/plugins/pdb-ng/src/lib.rs b/plugins/pdb-ng/src/lib.rs index d7faef1f5..326558e97 100644 --- a/plugins/pdb-ng/src/lib.rs +++ b/plugins/pdb-ng/src/lib.rs @@ -25,9 +25,9 @@ use anyhow::{anyhow, Result}; use log::{debug, error, info}; use pdb::PDB; -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; use binaryninja::debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser}; -use binaryninja::downloadprovider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}; +use binaryninja::download_provider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}; use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet}; use binaryninja::logger::Logger; use binaryninja::settings::Settings; diff --git a/plugins/pdb-ng/src/parser.rs b/plugins/pdb-ng/src/parser.rs index a1083527d..3bfde5538 100644 --- a/plugins/pdb-ng/src/parser.rs +++ b/plugins/pdb-ng/src/parser.rs @@ -24,8 +24,8 @@ use pdb::*; use crate::symbol_parser::{ParsedDataSymbol, ParsedProcedure, ParsedSymbol}; use crate::type_parser::ParsedType; use binaryninja::architecture::{Architecture, CoreArchitecture}; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; -use binaryninja::callingconvention::CallingConvention; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::calling_convention::CallingConvention; use binaryninja::confidence::{Conf, MIN_CONFIDENCE}; use binaryninja::debuginfo::{DebugFunctionInfo, DebugInfo}; use binaryninja::platform::Platform; diff --git a/plugins/pdb-ng/src/symbol_parser.rs b/plugins/pdb-ng/src/symbol_parser.rs index bdc12ca63..8eaaad2a1 100644 --- a/plugins/pdb-ng/src/symbol_parser.rs +++ b/plugins/pdb-ng/src/symbol_parser.rs @@ -37,7 +37,7 @@ use pdb::{ use crate::PDBParserInstance; use binaryninja::architecture::{Architecture, ArchitectureExt, Register, RegisterId}; -use binaryninja::binaryview::BinaryViewBase; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE}; use binaryninja::demangle::demangle_ms; use binaryninja::rc::Ref; diff --git a/plugins/pdb-ng/src/type_parser.rs b/plugins/pdb-ng/src/type_parser.rs index febf83bd6..0d08fce9f 100644 --- a/plugins/pdb-ng/src/type_parser.rs +++ b/plugins/pdb-ng/src/type_parser.rs @@ -19,8 +19,8 @@ use crate::struct_grouper::group_structure; use crate::PDBParserInstance; use anyhow::{anyhow, Result}; use binaryninja::architecture::{Architecture, CoreArchitecture}; -use binaryninja::binaryview::BinaryViewExt; -use binaryninja::callingconvention::CallingConvention; +use binaryninja::binary_view::BinaryViewExt; +use binaryninja::calling_convention::CallingConvention; use binaryninja::confidence::{Conf, MAX_CONFIDENCE}; use binaryninja::platform::Platform; use binaryninja::rc::Ref; diff --git a/plugins/warp/benches/convert.rs b/plugins/warp/benches/convert.rs index c06092719..d368745b7 100644 --- a/plugins/warp/benches/convert.rs +++ b/plugins/warp/benches/convert.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::BinaryViewExt; +use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use criterion::{criterion_group, criterion_main, Criterion}; use std::path::PathBuf; diff --git a/plugins/warp/benches/function.rs b/plugins/warp/benches/function.rs index 6aeea6f42..0ddf9ce21 100644 --- a/plugins/warp/benches/function.rs +++ b/plugins/warp/benches/function.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::BinaryViewExt; +use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use criterion::{criterion_group, criterion_main, Criterion}; use rayon::prelude::*; diff --git a/plugins/warp/benches/guid.rs b/plugins/warp/benches/guid.rs index f9f80c95d..046886b51 100644 --- a/plugins/warp/benches/guid.rs +++ b/plugins/warp/benches/guid.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::BinaryViewExt; +use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use criterion::{criterion_group, criterion_main, Criterion}; use warp_ninja::function_guid; diff --git a/plugins/warp/src/bin/sigem.rs b/plugins/warp/src/bin/sigem.rs index 097bc0ef3..a500fd5b5 100644 --- a/plugins/warp/src/bin/sigem.rs +++ b/plugins/warp/src/bin/sigem.rs @@ -7,7 +7,7 @@ use ar::Archive; use clap::{arg, Parser}; use rayon::prelude::*; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::function::Function as BNFunction; use binaryninja::rc::Guard as BNGuard; use binaryninja::settings::Settings; @@ -99,12 +99,7 @@ fn main() { let bn_settings = Settings::new(""); let worker_count = rayon::current_num_threads() * 4; log::debug!("Adjusting Binary Ninja worker count to {}...", worker_count); - bn_settings.set_integer( - "analysis.limits.workerThreadCount", - worker_count as u64, - None, - None, - ); + binaryninja::worker_thread::set_worker_thread_count(worker_count); // Make sure caches are flushed when the views get destructed. register_cache_destructor(); diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index 94d7a4d5c..4b1df5af7 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -1,13 +1,13 @@ use crate::convert::{from_bn_symbol, from_bn_type_internal}; use crate::{build_function, function_guid}; use binaryninja::architecture::Architecture; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::confidence::MAX_CONFIDENCE; use binaryninja::function::Function as BNFunction; -use binaryninja::lowlevelil::function::{ +use binaryninja::low_level_il::function::{ FunctionMutability, LowLevelILFunction, NonSSA, RegularNonSSA, }; -use binaryninja::lowlevelil::RegularLowLevelILFunction; +use binaryninja::low_level_il::RegularLowLevelILFunction; use binaryninja::rc::Guard; use binaryninja::rc::Ref as BNRef; use binaryninja::symbol::Symbol as BNSymbol; diff --git a/plugins/warp/src/convert.rs b/plugins/warp/src/convert.rs index b96260866..1376b4d05 100644 --- a/plugins/warp/src/convert.rs +++ b/plugins/warp/src/convert.rs @@ -2,8 +2,8 @@ use std::collections::HashSet; use binaryninja::architecture::Architecture as BNArchitecture; use binaryninja::architecture::ArchitectureExt; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; -use binaryninja::callingconvention::CallingConvention as BNCallingConvention; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::calling_convention::CallingConvention as BNCallingConvention; use binaryninja::confidence::{Conf as BNConf, MAX_CONFIDENCE}; use binaryninja::rc::Ref as BNRef; use binaryninja::symbol::{Symbol as BNSymbol, SymbolType as BNSymbolType}; @@ -573,7 +573,7 @@ pub fn to_bn_type(arch: &A, ty: &Type) -> BNRef { #[cfg(test)] mod tests { use super::*; - use binaryninja::binaryview::BinaryViewExt; + use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use std::path::PathBuf; use std::sync::OnceLock; diff --git a/plugins/warp/src/lib.rs b/plugins/warp/src/lib.rs index 8df82c9b2..b54f2f88b 100644 --- a/plugins/warp/src/lib.rs +++ b/plugins/warp/src/lib.rs @@ -5,18 +5,18 @@ use crate::convert::{from_bn_symbol, from_bn_type}; use binaryninja::architecture::{ Architecture, ImplicitRegisterExtend, Register as BNRegister, RegisterInfo, }; -use binaryninja::basicblock::BasicBlock as BNBasicBlock; -use binaryninja::binaryview::BinaryViewExt; +use binaryninja::basic_block::BasicBlock as BNBasicBlock; +use binaryninja::binary_view::BinaryViewExt; use binaryninja::confidence::MAX_CONFIDENCE; use binaryninja::function::{Function as BNFunction, NativeBlock}; -use binaryninja::lowlevelil::expression::{ExpressionHandler, LowLevelILExpressionKind}; -use binaryninja::lowlevelil::function::{ +use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpressionKind}; +use binaryninja::low_level_il::function::{ FunctionMutability, LowLevelILFunction, NonSSA, RegularNonSSA, }; -use binaryninja::lowlevelil::instruction::{ +use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstruction, LowLevelILInstructionKind, }; -use binaryninja::lowlevelil::{LowLevelILRegister, VisitorAction}; +use binaryninja::low_level_il::{LowLevelILRegister, VisitorAction}; use binaryninja::rc::Ref as BNRef; use std::path::PathBuf; use warp::signature::basic_block::BasicBlockGUID; @@ -183,7 +183,7 @@ pub fn basic_block_guid( #[cfg(test)] mod tests { use crate::cache::cached_function_guid; - use binaryninja::binaryview::BinaryViewExt; + use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use std::path::PathBuf; use std::sync::OnceLock; diff --git a/plugins/warp/src/matcher.rs b/plugins/warp/src/matcher.rs index c3dfba10d..adc8f09ec 100644 --- a/plugins/warp/src/matcher.rs +++ b/plugins/warp/src/matcher.rs @@ -1,5 +1,5 @@ use binaryninja::architecture::Architecture as BNArchitecture; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::function::Function as BNFunction; use binaryninja::platform::Platform; use binaryninja::rc::Guard; diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs index 1b2d8b7ac..a06a23780 100644 --- a/plugins/warp/src/plugin.rs +++ b/plugins/warp/src/plugin.rs @@ -6,7 +6,7 @@ use crate::matcher::{ invalidate_function_matcher_cache, Matcher, MatcherSettings, PlatformID, PLAT_MATCHER_CACHE, }; use crate::{build_function, cache}; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::{Command, FunctionCommand}; use binaryninja::function::{Function, FunctionUpdateType}; use binaryninja::logger::Logger; diff --git a/plugins/warp/src/plugin/add.rs b/plugins/warp/src/plugin/add.rs index 19cf7115c..2f76c8b5b 100644 --- a/plugins/warp/src/plugin/add.rs +++ b/plugins/warp/src/plugin/add.rs @@ -1,7 +1,7 @@ use crate::cache::{cached_function, cached_type_references}; use crate::matcher::invalidate_function_matcher_cache; use crate::user_signature_dir; -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::command::FunctionCommand; use binaryninja::function::Function; use std::thread; diff --git a/plugins/warp/src/plugin/copy.rs b/plugins/warp/src/plugin/copy.rs index d539a4309..18da7dfb7 100644 --- a/plugins/warp/src/plugin/copy.rs +++ b/plugins/warp/src/plugin/copy.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::command::FunctionCommand; use binaryninja::function::Function; diff --git a/plugins/warp/src/plugin/create.rs b/plugins/warp/src/plugin/create.rs index a936074af..4beba1952 100644 --- a/plugins/warp/src/plugin/create.rs +++ b/plugins/warp/src/plugin/create.rs @@ -1,7 +1,7 @@ use crate::cache::{cached_function, cached_type_references}; use crate::matcher::invalidate_function_matcher_cache; use crate::user_signature_dir; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; use binaryninja::function::Function; use binaryninja::rc::Guard; @@ -30,11 +30,10 @@ impl Command for CreateSignatureFile { thread::spawn(move || { let total_functions = view.functions().len(); let done_functions = AtomicUsize::default(); - let background_task = binaryninja::backgroundtask::BackgroundTask::new( + let background_task = binaryninja::background_task::BackgroundTask::new( format!("Generating signatures... ({}/{})", 0, total_functions), true, - ) - .unwrap(); + ); let start = Instant::now(); diff --git a/plugins/warp/src/plugin/find.rs b/plugins/warp/src/plugin/find.rs index f54b4a4c4..b2102e5e2 100644 --- a/plugins/warp/src/plugin/find.rs +++ b/plugins/warp/src/plugin/find.rs @@ -1,5 +1,5 @@ use crate::cache::try_cached_function_guid; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; use binaryninja::function::Function as BNFunction; use binaryninja::rc::Guard as BNGuard; @@ -26,11 +26,10 @@ impl Command for FindFunctionFromGUID { log::info!("Searching functions for GUID... {}", searched_guid); let funcs = view.functions(); thread::spawn(move || { - let background_task = binaryninja::backgroundtask::BackgroundTask::new( + let background_task = binaryninja::background_task::BackgroundTask::new( format!("Searching functions for GUID... {}", searched_guid), false, - ) - .unwrap(); + ); // Only run this for functions which have already generated a GUID. let matched = funcs diff --git a/plugins/warp/src/plugin/load.rs b/plugins/warp/src/plugin/load.rs index 03356444c..8c4a0cf4f 100644 --- a/plugins/warp/src/plugin/load.rs +++ b/plugins/warp/src/plugin/load.rs @@ -1,5 +1,5 @@ use crate::matcher::{Matcher, PlatformID, PLAT_MATCHER_CACHE}; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; pub struct LoadSignatureFile; diff --git a/plugins/warp/src/plugin/types.rs b/plugins/warp/src/plugin/types.rs index fb030bfe2..8065ea2bc 100644 --- a/plugins/warp/src/plugin/types.rs +++ b/plugins/warp/src/plugin/types.rs @@ -1,5 +1,5 @@ use crate::convert::to_bn_type; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; use std::time::Instant; @@ -31,11 +31,10 @@ impl Command for LoadTypes { let view = view.to_owned(); std::thread::spawn(move || { - let background_task = binaryninja::backgroundtask::BackgroundTask::new( + let background_task = binaryninja::background_task::BackgroundTask::new( format!("Applying {} types...", data.types.len()), true, - ) - .unwrap(); + ); let start = Instant::now(); for comp_ty in data.types { diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs index 85290c3f9..fbd50dc8c 100644 --- a/plugins/warp/src/plugin/workflow.rs +++ b/plugins/warp/src/plugin/workflow.rs @@ -1,9 +1,9 @@ use crate::cache::cached_function_guid; use crate::matcher::cached_function_matcher; -use binaryninja::backgroundtask::BackgroundTask; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::background_task::BackgroundTask; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; -use binaryninja::lowlevelil::function::RegularNonSSA; +use binaryninja::low_level_il::function::RegularNonSSA; use binaryninja::workflow::{Activity, AnalysisContext, Workflow}; use std::time::Instant; @@ -37,7 +37,7 @@ impl Command for RunMatcher { // TODO: Check to see if the GUID cache is empty and ask the user if they want to regenerate the guids. std::thread::spawn(move || { let undo_id = view.file().begin_undo_actions(true); - let background_task = BackgroundTask::new("Matching on functions...", false).unwrap(); + let background_task = BackgroundTask::new("Matching on functions...", false); let start = Instant::now(); view.functions() .iter() @@ -59,7 +59,7 @@ pub fn insert_workflow() { let matcher_activity = |ctx: &AnalysisContext| { let view = ctx.view(); let undo_id = view.file().begin_undo_actions(true); - let background_task = BackgroundTask::new("Matching on functions...", false).unwrap(); + let background_task = BackgroundTask::new("Matching on functions...", false); let start = Instant::now(); view.functions() .iter() diff --git a/rust/examples/decompile.rs b/rust/examples/decompile.rs index a79f99574..d3ceb8545 100644 --- a/rust/examples/decompile.rs +++ b/rust/examples/decompile.rs @@ -1,7 +1,7 @@ -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings}; use binaryninja::function::Function; -use binaryninja::linearview::{LinearViewCursor, LinearViewObject}; +use binaryninja::linear_view::{LinearViewCursor, LinearViewObject}; fn decompile_to_c(view: &BinaryView, func: &Function) { let settings = DisassemblySettings::new(); diff --git a/rust/examples/demangler.rs b/rust/examples/demangler.rs index 8b40c3545..b2e5eb66c 100644 --- a/rust/examples/demangler.rs +++ b/rust/examples/demangler.rs @@ -1,5 +1,5 @@ use binaryninja::architecture::CoreArchitecture; -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::demangle::{CustomDemangler, Demangler}; use binaryninja::rc::Ref; use binaryninja::types::{QualifiedName, Type}; diff --git a/rust/examples/flowgraph.rs b/rust/examples/flowgraph.rs index 8ef35cbda..f8ff64353 100644 --- a/rust/examples/flowgraph.rs +++ b/rust/examples/flowgraph.rs @@ -1,5 +1,5 @@ use binaryninja::{ - binaryview::{BinaryView, BinaryViewExt}, + binary_view::{BinaryView, BinaryViewExt}, disassembly::{DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind}, flowgraph::{BranchType, EdgePenStyle, EdgeStyle, FlowGraph, FlowGraphNode, ThemeColor}, }; diff --git a/rust/examples/hlil.rs b/rust/examples/hlil.rs index dbdc7540e..18eaeb8a4 100644 --- a/rust/examples/hlil.rs +++ b/rust/examples/hlil.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; fn main() { println!("Starting session..."); diff --git a/rust/examples/mlil.rs b/rust/examples/mlil.rs index d4520abbe..3535ce001 100644 --- a/rust/examples/mlil.rs +++ b/rust/examples/mlil.rs @@ -1,4 +1,4 @@ -use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; fn main() { println!("Starting session..."); diff --git a/rust/examples/simple.rs b/rust/examples/simple.rs index 7ca3a5b17..f41cbf344 100644 --- a/rust/examples/simple.rs +++ b/rust/examples/simple.rs @@ -1,5 +1,5 @@ use binaryninja::architecture::Architecture; -use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; fn main() { println!("Starting session..."); diff --git a/rust/examples/type_printer.rs b/rust/examples/type_printer.rs index 104aecd42..ea9c6a4db 100644 --- a/rust/examples/type_printer.rs +++ b/rust/examples/type_printer.rs @@ -1,4 +1,4 @@ -use binaryninja::typeprinter::{CoreTypePrinter, TokenEscapingType}; +use binaryninja::type_printer::{CoreTypePrinter, TokenEscapingType}; use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureMember, Type}; fn main() { diff --git a/rust/examples/workflow.rs b/rust/examples/workflow.rs index 9279a02f9..59678cad8 100644 --- a/rust/examples/workflow.rs +++ b/rust/examples/workflow.rs @@ -1,7 +1,7 @@ -use binaryninja::binaryview::BinaryViewExt; -use binaryninja::lowlevelil::expression::{ExpressionHandler, LowLevelILExpressionKind}; -use binaryninja::lowlevelil::instruction::InstructionHandler; -use binaryninja::lowlevelil::VisitorAction; +use binaryninja::binary_view::BinaryViewExt; +use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpressionKind}; +use binaryninja::low_level_il::instruction::InstructionHandler; +use binaryninja::low_level_il::VisitorAction; use binaryninja::workflow::{Activity, AnalysisContext, Workflow}; const RUST_ACTIVITY_NAME: &str = "analysis.plugins.rustexample"; diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index dd51ddfa2..325802d9a 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -20,10 +20,10 @@ use binaryninjacore_sys::*; use std::fmt::{Debug, Formatter}; use crate::{ - callingconvention::CallingConvention, - databuffer::DataBuffer, + calling_convention::CallingConvention, + data_buffer::DataBuffer, disassembly::InstructionTextToken, - lowlevelil::{MutableLiftedILExpr, MutableLiftedILFunction}, + low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}, platform::Platform, rc::*, relocation::CoreRelocationHandler, @@ -42,12 +42,12 @@ use std::{ mem::MaybeUninit, }; -use crate::functionrecognizer::FunctionRecognizer; +use crate::function_recognizer::FunctionRecognizer; use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler}; use crate::confidence::Conf; -use crate::lowlevelil::expression::ValueExpr; -use crate::lowlevelil::lifting::{ +use crate::low_level_il::expression::ValueExpr; +use crate::low_level_il::lifting::{ get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp, }; pub use binaryninjacore_sys::BNFlagRole as FlagRole; @@ -2023,7 +2023,7 @@ pub trait ArchitectureExt: Architecture { where R: 'static + FunctionRecognizer + Send + Sync + Sized, { - crate::functionrecognizer::register_arch_function_recognizer(self.as_ref(), recognizer); + crate::function_recognizer::register_arch_function_recognizer(self.as_ref(), recognizer); } } diff --git a/rust/src/backgroundtask.rs b/rust/src/background_task.rs similarity index 81% rename from rust/src/backgroundtask.rs rename to rust/src/background_task.rs index 5c9a68515..0420afbfc 100644 --- a/rust/src/backgroundtask.rs +++ b/rust/src/background_task.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Background tasks provide plugins the ability to run tasks in the background so they don't hand the UI +//! Background tasks provide plugins the ability to inform the core of long-running background tasks. use binaryninjacore_sys::*; @@ -23,6 +23,14 @@ use crate::string::*; pub type Result = result::Result; +/// A [`BackgroundTask`] does not actually execute any code, only act as a handler, primarily to query +/// the status of the task, and to cancel the task. +/// +/// If you are looking to execute code in the background consider using rusts threading API, or if you +/// want the core to execute the task on a worker thread, use the [`crate::worker_thread`] API. +/// +/// NOTE: If you do not call [`BackgroundTask::finish`] or [`BackgroundTask::cancel`] the task will +/// persist even _after_ it has been dropped. #[derive(PartialEq, Eq, Hash)] pub struct BackgroundTask { pub(crate) handle: *mut BNBackgroundTask, @@ -35,16 +43,12 @@ impl BackgroundTask { Self { handle } } - pub fn new(initial_text: S, can_cancel: bool) -> Result> { + pub fn new(initial_text: S, can_cancel: bool) -> Ref { let text = initial_text.into_bytes_with_nul(); - let handle = unsafe { BNBeginBackgroundTask(text.as_ref().as_ptr() as *mut _, can_cancel) }; - - if handle.is_null() { - return Err(()); - } - - unsafe { Ok(Ref::new(Self { handle })) } + // We should always be returned a valid task. + assert!(!handle.is_null()); + unsafe { Ref::new(Self { handle }) } } pub fn can_cancel(&self) -> bool { @@ -55,25 +59,24 @@ impl BackgroundTask { unsafe { BNIsBackgroundTaskCancelled(self.handle) } } - pub fn is_finished(&self) -> bool { - unsafe { BNIsBackgroundTaskFinished(self.handle) } - } - - pub fn progress_text(&self) -> BnString { - unsafe { BnString::from_raw(BNGetBackgroundTaskProgressText(self.handle)) } - } - pub fn cancel(&self) { unsafe { BNCancelBackgroundTask(self.handle) } } + pub fn is_finished(&self) -> bool { + unsafe { BNIsBackgroundTaskFinished(self.handle) } + } + pub fn finish(&self) { unsafe { BNFinishBackgroundTask(self.handle) } } + pub fn progress_text(&self) -> BnString { + unsafe { BnString::from_raw(BNGetBackgroundTaskProgressText(self.handle)) } + } + pub fn set_progress_text(&self, text: S) { let progress_text = text.into_bytes_with_nul(); - unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ref().as_ptr() as *mut _) } diff --git a/rust/src/basicblock.rs b/rust/src/basic_block.rs similarity index 100% rename from rust/src/basicblock.rs rename to rust/src/basic_block.rs diff --git a/rust/src/binaryreader.rs b/rust/src/binary_reader.rs similarity index 98% rename from rust/src/binaryreader.rs rename to rust/src/binary_reader.rs index db681e744..7ad167126 100644 --- a/rust/src/binaryreader.rs +++ b/rust/src/binary_reader.rs @@ -16,7 +16,7 @@ use binaryninjacore_sys::*; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::Endianness; use std::io::{Read, Seek, SeekFrom}; diff --git a/rust/src/binaryview.rs b/rust/src/binary_view.rs similarity index 93% rename from rust/src/binaryview.rs rename to rust/src/binary_view.rs index 99eddf784..824803145 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binary_view.rs @@ -24,18 +24,21 @@ use binaryninjacore_sys::*; use crate::architecture::{Architecture, CoreArchitecture}; -use crate::basicblock::BasicBlock; +use crate::basic_block::BasicBlock; use crate::component::{Component, ComponentBuilder, IntoComponentGuid}; use crate::confidence::Conf; -use crate::databuffer::DataBuffer; +use crate::data_buffer::DataBuffer; use crate::debuginfo::DebugInfo; -use crate::fileaccessor::FileAccessor; -use crate::filemetadata::FileMetadata; +use crate::external_library::{ExternalLibrary, ExternalLocation}; +use crate::file_accessor::FileAccessor; +use crate::file_metadata::FileMetadata; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; -use crate::linearview::{LinearDisassemblyLine, LinearViewCursor}; +use crate::linear_view::{LinearDisassemblyLine, LinearViewCursor}; use crate::metadata::Metadata; use crate::platform::Platform; +use crate::progress::ProgressExecutor; +use crate::project::file::ProjectFile; use crate::rc::*; use crate::references::{CodeReference, DataReference}; use crate::relocation::Relocation; @@ -45,15 +48,15 @@ use crate::settings::Settings; use crate::string::*; use crate::symbol::{Symbol, SymbolType}; use crate::tags::{Tag, TagType}; -use crate::typecontainer::TypeContainer; -use crate::typelibrary::TypeLibrary; +use crate::type_container::TypeContainer; +use crate::type_library::TypeLibrary; use crate::types::{ NamedTypeReference, QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type, }; use crate::variable::DataVariable; use crate::Endianness; use std::collections::HashMap; -use std::ffi::{c_char, c_void}; +use std::ffi::c_char; use std::ops::Range; use std::path::Path; use std::ptr::NonNull; @@ -173,24 +176,11 @@ pub struct AnalysisProgress { pub total: usize, } -// TODO: Copied from debuginfo.rs, this should be consolidated -struct ProgressContext(Option Result<()>>>); - -extern "C" fn cb_progress(ctxt: *mut c_void, cur: usize, max: usize) -> bool { - ffi_wrap!("BinaryViewExt::cb_progress", unsafe { - let progress = ctxt as *mut ProgressContext; - match &(*progress).0 { - Some(func) => (func)(cur, max).is_ok(), - None => true, - } - }) -} - pub trait BinaryViewExt: BinaryViewBase { fn file(&self) -> Ref { unsafe { let raw = BNGetFileForView(self.as_ref().handle); - Ref::new(FileMetadata::from_raw(raw)) + FileMetadata::ref_from_raw(raw) } } @@ -637,13 +627,13 @@ pub trait BinaryViewExt: BinaryViewBase { T: Iterator, I: Into, { - self.define_auto_types_with_progress(names_sources_and_types, None) + self.define_auto_types_with_progress(names_sources_and_types, ProgressExecutor::default()) } fn define_auto_types_with_progress( &self, names_sources_and_types: T, - progress: Option Result<()>>>, + progress: impl Into, ) -> HashMap where T: Iterator, @@ -653,7 +643,6 @@ pub trait BinaryViewExt: BinaryViewBase { .map(Into::into) .map(QualifiedNameTypeAndId::into_raw) .collect(); - let mut progress_raw = ProgressContext(progress); let mut result_ids: *mut *mut c_char = std::ptr::null_mut(); let mut result_names: *mut BNQualifiedName = std::ptr::null_mut(); let result_count = unsafe { @@ -661,8 +650,8 @@ pub trait BinaryViewExt: BinaryViewBase { self.as_ref().handle, types.as_mut_ptr(), types.len(), - Some(cb_progress), - &mut progress_raw as *mut _ as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), &mut result_ids as *mut _, &mut result_names as *mut _, ) @@ -686,13 +675,13 @@ pub trait BinaryViewExt: BinaryViewBase { T: Iterator, I: Into, { - self.define_user_types_with_progress(names_and_types, None); + self.define_user_types_with_progress(names_and_types, ProgressExecutor::default()); } fn define_user_types_with_progress( &self, names_and_types: T, - progress: Option Result<()>>>, + progress: impl Into, ) where T: Iterator, I: Into, @@ -701,14 +690,13 @@ pub trait BinaryViewExt: BinaryViewBase { .map(Into::into) .map(QualifiedNameAndType::into_raw) .collect(); - let mut progress_raw = ProgressContext(progress); unsafe { BNDefineUserAnalysisTypes( self.as_ref().handle, types.as_mut_ptr(), types.len(), - Some(cb_progress), - &mut progress_raw as *mut _ as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; for ty in types { @@ -1485,6 +1473,101 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { Array::new(result, count, ()) } } + fn external_libraries(&self) -> Array { + let mut count = 0; + let result = unsafe { BNBinaryViewGetExternalLibraries(self.as_ref().handle, &mut count) }; + unsafe { Array::new(result, count, ()) } + } + + fn external_library(&self, name: S) -> Option> { + let name_ptr = name.into_bytes_with_nul(); + let result = unsafe { + BNBinaryViewGetExternalLibrary( + self.as_ref().handle, + name_ptr.as_ref().as_ptr() as *const c_char, + ) + }; + let result_ptr = NonNull::new(result)?; + Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) + } + + fn remove_external_library(&self, name: S) { + let name_ptr = name.into_bytes_with_nul(); + unsafe { + BNBinaryViewRemoveExternalLibrary( + self.as_ref().handle, + name_ptr.as_ref().as_ptr() as *const c_char, + ) + }; + } + + fn add_external_library( + &self, + name: S, + backing_file: Option<&ProjectFile>, + auto: bool, + ) -> Option> { + let name_ptr = name.into_bytes_with_nul(); + let result = unsafe { + BNBinaryViewAddExternalLibrary( + self.as_ref().handle, + name_ptr.as_ref().as_ptr() as *const c_char, + backing_file + .map(|b| b.handle.as_ptr()) + .unwrap_or(std::ptr::null_mut()), + auto, + ) + }; + NonNull::new(result).map(|h| unsafe { ExternalLibrary::ref_from_raw(h) }) + } + + fn external_locations(&self) -> Array { + let mut count = 0; + let result = unsafe { BNBinaryViewGetExternalLocations(self.as_ref().handle, &mut count) }; + unsafe { Array::new(result, count, ()) } + } + + fn external_location_from_symbol(&self, symbol: &Symbol) -> Option> { + let result = + unsafe { BNBinaryViewGetExternalLocation(self.as_ref().handle, symbol.handle) }; + let result_ptr = NonNull::new(result)?; + Some(unsafe { ExternalLocation::ref_from_raw(result_ptr) }) + } + + fn remove_external_location(&self, location: &ExternalLocation) { + self.remove_external_location_from_symbol(&location.source_symbol()) + } + + fn remove_external_location_from_symbol(&self, symbol: &Symbol) { + unsafe { BNBinaryViewRemoveExternalLocation(self.as_ref().handle, symbol.handle) }; + } + + // TODO: This is awful, rewrite this. + fn add_external_location( + &self, + symbol: &Symbol, + library: &ExternalLibrary, + target_symbol_name: S, + target_address: Option, + target_is_auto: bool, + ) -> Option> { + let target_symbol_name = target_symbol_name.into_bytes_with_nul(); + let target_address_ptr = target_address + .map(|a| a as *mut u64) + .unwrap_or(std::ptr::null_mut()); + let result = unsafe { + BNBinaryViewAddExternalLocation( + self.as_ref().handle, + symbol.handle, + library.handle.as_ptr(), + target_symbol_name.as_ref().as_ptr() as *const c_char, + target_address_ptr, + target_is_auto, + ) + }; + NonNull::new(result).map(|h| unsafe { ExternalLocation::ref_from_raw(h) }) + } + /// Type container for all types (user and auto) in the Binary View. /// /// NOTE: Modifying an auto type will promote it to a user type. @@ -1935,7 +2018,7 @@ pub trait BinaryViewEventHandler: 'static + Sync { /// # Example /// /// ```no_run -/// use binaryninja::binaryview::{ +/// use binaryninja::binary_view::{ /// register_binary_view_event, BinaryView, BinaryViewEventHandler, BinaryViewEventType, /// }; /// diff --git a/rust/src/binarywriter.rs b/rust/src/binary_writer.rs similarity index 98% rename from rust/src/binarywriter.rs rename to rust/src/binary_writer.rs index 802a9b373..41c0faaf5 100644 --- a/rust/src/binarywriter.rs +++ b/rust/src/binary_writer.rs @@ -16,7 +16,7 @@ use binaryninjacore_sys::*; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::Endianness; use std::io::{Seek, SeekFrom, Write}; diff --git a/rust/src/callingconvention.rs b/rust/src/calling_convention.rs similarity index 100% rename from rust/src/callingconvention.rs rename to rust/src/calling_convention.rs diff --git a/rust/src/command.rs b/rust/src/command.rs index e682baeef..98009a8fa 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -40,7 +40,7 @@ use binaryninjacore_sys::{ use std::ops::Range; use std::os::raw::c_void; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::function::Function; use crate::string::BnStrCompatible; @@ -68,7 +68,7 @@ where /// # Example /// ```no_run /// # use binaryninja::command::Command; -/// # use binaryninja::binaryview::BinaryView; +/// # use binaryninja::binary_view::BinaryView; /// struct MyCommand; /// /// impl Command for MyCommand { @@ -169,7 +169,7 @@ where /// # Example /// ```no_run /// # use binaryninja::command::AddressCommand; -/// # use binaryninja::binaryview::BinaryView; +/// # use binaryninja::binary_view::BinaryView; /// struct MyCommand; /// /// impl AddressCommand for MyCommand { @@ -271,7 +271,7 @@ where /// ```no_run /// # use std::ops::Range; /// # use binaryninja::command::RangeCommand; -/// # use binaryninja::binaryview::BinaryView; +/// # use binaryninja::binary_view::BinaryView; /// struct MyCommand; /// /// impl RangeCommand for MyCommand { @@ -377,7 +377,7 @@ where /// # Example /// ```no_run /// # use binaryninja::command::FunctionCommand; -/// # use binaryninja::binaryview::BinaryView; +/// # use binaryninja::binary_view::BinaryView; /// # use binaryninja::function::Function; /// # use binaryninja::command::register_for_function; /// struct MyCommand; diff --git a/rust/src/component.rs b/rust/src/component.rs index 668c2036b..d03a6ace8 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -1,6 +1,6 @@ use core::{ffi, mem, ptr}; -use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; use crate::function::Function; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::string::{BnStrCompatible, BnString}; diff --git a/rust/src/confidence.rs b/rust/src/confidence.rs index 4d9152c5f..8e8406ec9 100644 --- a/rust/src/confidence.rs +++ b/rust/src/confidence.rs @@ -1,7 +1,7 @@ #![allow(unused)] use crate::architecture::{Architecture, CoreArchitecture}; -use crate::callingconvention::CallingConvention; +use crate::calling_convention::CallingConvention; use crate::rc::{Ref, RefCountable}; use crate::types::Type; use binaryninjacore_sys::{ diff --git a/rust/src/custombinaryview.rs b/rust/src/custom_binary_view.rs similarity index 99% rename from rust/src/custombinaryview.rs rename to rust/src/custom_binary_view.rs index cffea7471..fbd4cfc19 100644 --- a/rust/src/custombinaryview.rs +++ b/rust/src/custom_binary_view.rs @@ -25,7 +25,7 @@ use std::ptr; use std::slice; use crate::architecture::Architecture; -use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt, Result}; +use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt, Result}; use crate::platform::Platform; use crate::settings::Settings; use crate::Endianness; diff --git a/rust/src/databuffer.rs b/rust/src/data_buffer.rs similarity index 100% rename from rust/src/databuffer.rs rename to rust/src/data_buffer.rs diff --git a/rust/src/database.rs b/rust/src/database.rs index 3274c9c0e..77a5a2288 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -1,115 +1,120 @@ -use std::collections::HashMap; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use std::{ffi, mem, ptr}; +pub mod kvs; +pub mod snapshot; +pub mod undo; use binaryninjacore_sys::*; - -use crate::binaryview::BinaryView; -use crate::databuffer::DataBuffer; -use crate::disassembly::InstructionTextToken; -use crate::filemetadata::FileMetadata; -use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; +use std::collections::HashMap; +use std::ffi::c_char; +use std::fmt::Debug; +use std::ptr::NonNull; + +use crate::binary_view::BinaryView; +use crate::data_buffer::DataBuffer; +use crate::database::kvs::KeyValueStore; +use crate::database::snapshot::{Snapshot, SnapshotId}; +use crate::file_metadata::FileMetadata; +use crate::progress::ProgressExecutor; +use crate::rc::{Array, Ref, RefCountable}; use crate::string::{BnStrCompatible, BnString}; -#[repr(transparent)] pub struct Database { - handle: ptr::NonNull, + handle: NonNull, } impl Database { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { Self { handle } } - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNDatabase { - &mut *self.handle.as_ptr() + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) } /// Get a snapshot by its id, or None if no snapshot with that id exists - pub fn snapshot(&self, id: i64) -> Option { - let result = unsafe { BNGetDatabaseSnapshot(self.as_raw(), id) }; - ptr::NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) + pub fn snapshot_by_id(&self, id: SnapshotId) -> Option> { + let result = unsafe { BNGetDatabaseSnapshot(self.handle.as_ptr(), id.0) }; + NonNull::new(result).map(|handle| unsafe { Snapshot::ref_from_raw(handle) }) } /// Get a list of all snapshots in the database pub fn snapshots(&self) -> Array { let mut count = 0; - let result = unsafe { BNGetDatabaseSnapshots(self.as_raw(), &mut count) }; + let result = unsafe { BNGetDatabaseSnapshots(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } /// Get the current snapshot - pub fn current_snapshot(&self) -> Option { - let result = unsafe { BNGetDatabaseCurrentSnapshot(self.as_raw()) }; - ptr::NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) + pub fn current_snapshot(&self) -> Option> { + let result = unsafe { BNGetDatabaseCurrentSnapshot(self.handle.as_ptr()) }; + NonNull::new(result).map(|handle| unsafe { Snapshot::ref_from_raw(handle) }) } + /// Equivalent to [`Self::set_current_snapshot_id`]. pub fn set_current_snapshot(&self, value: &Snapshot) { - unsafe { BNSetDatabaseCurrentSnapshot(self.as_raw(), value.id()) } + self.set_current_snapshot_id(value.id()) + } + + /// Sets the current snapshot to the [`SnapshotId`]. + /// + /// **No** validation is done to ensure that the id is valid. + pub fn set_current_snapshot_id(&self, id: SnapshotId) { + unsafe { BNSetDatabaseCurrentSnapshot(self.handle.as_ptr(), id.0) } } pub fn write_snapshot_data( &self, - parents: &[i64], + parents: &[SnapshotId], file: &BinaryView, name: N, data: &KeyValueStore, auto_save: bool, - ) -> i64 { - let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { - BNWriteDatabaseSnapshotData( - self.as_raw(), - parents.as_ptr() as *mut _, - parents.len(), - file.handle, - name_ptr, - data.as_raw(), - auto_save, - ptr::null_mut(), - Some(cb_progress_nop), - ) - } - } - - pub fn write_snapshot_data_with_progress( + ) -> SnapshotId { + self.write_snapshot_data_with_progress( + parents, + file, + name, + data, + auto_save, + ProgressExecutor::default(), + ) + } + + pub fn write_snapshot_data_with_progress( &self, - parents: &[i64], + parents: &[SnapshotId], file: &BinaryView, name: N, data: &KeyValueStore, auto_save: bool, - mut progress: F, - ) -> i64 + progress: impl Into, + ) -> SnapshotId where N: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - unsafe { + let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; + let new_id = unsafe { BNWriteDatabaseSnapshotData( - self.as_raw(), + self.handle.as_ptr(), + // SAFETY: SnapshotId is just i64 parents.as_ptr() as *mut _, parents.len(), file.handle, name_ptr, - data.as_raw(), + data.handle.as_ptr(), auto_save, - ctxt, - Some(cb_progress::), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ) - } + }; + SnapshotId(new_id) } /// Trim a snapshot's contents in the database by id, but leave the parent/child /// hierarchy intact. Future references to this snapshot will return False for has_contents - pub fn trim_snapshot(&self, id: i64) -> Result<(), ()> { - if unsafe { BNTrimDatabaseSnapshot(self.as_raw(), id) } { + pub fn trim_snapshot(&self, id: SnapshotId) -> Result<(), ()> { + if unsafe { BNTrimDatabaseSnapshot(self.handle.as_ptr(), id.0) } { Ok(()) } else { Err(()) @@ -118,8 +123,8 @@ impl Database { /// Remove a snapshot in the database by id, deleting its contents and references. /// Attempting to remove a snapshot with children will raise an exception. - pub fn remove_snapshot(&self, id: i64) -> Result<(), ()> { - if unsafe { BNRemoveDatabaseSnapshot(self.as_raw(), id) } { + pub fn remove_snapshot(&self, id: SnapshotId) -> Result<(), ()> { + if unsafe { BNRemoveDatabaseSnapshot(self.handle.as_ptr(), id.0) } { Ok(()) } else { Err(()) @@ -127,14 +132,14 @@ impl Database { } pub fn has_global(&self, key: S) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNDatabaseHasGlobal(self.as_raw(), key_ptr) != 0 } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_ptr) != 0 } } /// Get a list of keys for all globals in the database pub fn global_keys(&self) -> Array { let mut count = 0; - let result = unsafe { BNGetDatabaseGlobalKeys(self.as_raw(), &mut count) }; + let result = unsafe { BNGetDatabaseGlobalKeys(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -150,505 +155,91 @@ impl Database { /// Get a specific global by key pub fn read_global(&self, key: S) -> Option { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNReadDatabaseGlobal(self.as_raw(), key_ptr) }; - unsafe { ptr::NonNull::new(result).map(|_| BnString::from_raw(result)) } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_ptr) }; + unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database pub fn write_global(&self, key: K, value: V) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let value_raw = value.into_bytes_with_nul(); - let value_ptr = value_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNWriteDatabaseGlobal(self.as_raw(), key_ptr, value_ptr) } + let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_ptr, value_ptr) } } /// Get a specific global by key, as a binary buffer pub fn read_global_data(&self, key: S) -> Option { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNReadDatabaseGlobalData(self.as_raw(), key_ptr) }; - ptr::NonNull::new(result).map(|_| DataBuffer::from_raw(result)) + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_ptr) }; + NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNWriteDatabaseGlobalData(self.as_raw(), key_ptr, value.as_raw()) } + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_ptr, value.as_raw()) } } /// Get the owning FileMetadata pub fn file(&self) -> Ref { - let result = unsafe { BNGetDatabaseFile(self.as_raw()) }; + let result = unsafe { BNGetDatabaseFile(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { Ref::new(FileMetadata::from_raw(result)) } + FileMetadata::ref_from_raw(result) } /// Get the backing analysis cache kvs - pub fn analysis_cache(&self) -> KeyValueStore { - let result = unsafe { BNReadDatabaseAnalysisCache(self.as_raw()) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } + pub fn analysis_cache(&self) -> Ref { + let result = unsafe { BNReadDatabaseAnalysisCache(self.handle.as_ptr()) }; + unsafe { KeyValueStore::ref_from_raw(NonNull::new(result).unwrap()) } } pub fn reload_connection(&self) { - unsafe { BNDatabaseReloadConnection(self.as_raw()) } + unsafe { BNDatabaseReloadConnection(self.handle.as_ptr()) } } pub fn write_analysis_cache(&self, val: &KeyValueStore) -> Result<(), ()> { - if unsafe { BNWriteDatabaseAnalysisCache(self.as_raw(), val.as_raw()) } { + if unsafe { BNWriteDatabaseAnalysisCache(self.handle.as_ptr(), val.handle.as_ptr()) } { Ok(()) } else { Err(()) } } - pub fn snapshot_has_data(&self, id: i64) -> bool { - unsafe { BNSnapshotHasData(self.as_raw(), id) } - } -} - -impl Clone for Database { - fn clone(&self) -> Self { - unsafe { Self::from_raw(ptr::NonNull::new(BNNewDatabaseReference(self.as_raw())).unwrap()) } - } -} - -impl Drop for Database { - fn drop(&mut self) { - unsafe { BNFreeDatabase(self.as_raw()) } - } -} - -#[repr(transparent)] -pub struct Snapshot { - handle: ptr::NonNull, -} - -impl Snapshot { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNSnapshot) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNSnapshot { - &mut *self.handle.as_ptr() - } - - /// Get the owning database - pub fn database(&self) -> Database { - unsafe { - Database::from_raw(ptr::NonNull::new(BNGetSnapshotDatabase(self.as_raw())).unwrap()) - } - } - - /// Get the numerical id (read-only) - pub fn id(&self) -> i64 { - unsafe { BNGetSnapshotId(self.as_raw()) } - } - - /// Get the displayed snapshot name - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetSnapshotName(self.as_raw())) } - } - - /// Set the displayed snapshot name - pub fn set_name(&self, value: S) { - let value_raw = value.into_bytes_with_nul(); - let value_ptr = value_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNSetSnapshotName(self.as_raw(), value_ptr) } - } - - /// If the snapshot was the result of an auto-save - pub fn is_auto_save(&self) -> bool { - unsafe { BNIsSnapshotAutoSave(self.as_raw()) } - } - - /// If the snapshot has contents, and has not been trimmed - pub fn has_contents(&self) -> bool { - unsafe { BNSnapshotHasContents(self.as_raw()) } - } - - /// If the snapshot has undo data - pub fn has_undo(&self) -> bool { - unsafe { BNSnapshotHasUndo(self.as_raw()) } - } - - /// Get the first parent of the snapshot, or None if it has no parents - pub fn first_parent(&self) -> Option { - let result = unsafe { BNGetSnapshotFirstParent(self.as_raw()) }; - ptr::NonNull::new(result).map(|s| unsafe { Snapshot::from_raw(s) }) - } - - /// Get a list of all parent snapshots of the snapshot - pub fn parents(&self) -> Array { - let mut count = 0; - let result = unsafe { BNGetSnapshotParents(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get a list of all child snapshots of the snapshot - pub fn children(&self) -> Array { - let mut count = 0; - let result = unsafe { BNGetSnapshotChildren(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get a buffer of the raw data at the time of the snapshot - pub fn file_contents(&self) -> Option { - self.has_contents().then(|| unsafe { - let result = BNGetSnapshotFileContents(self.as_raw()); - assert!(!result.is_null()); - DataBuffer::from_raw(result) - }) - } - - /// Get a hash of the data at the time of the snapshot - pub fn file_contents_hash(&self) -> Option { - self.has_contents().then(|| unsafe { - let result = BNGetSnapshotFileContentsHash(self.as_raw()); - assert!(!result.is_null()); - DataBuffer::from_raw(result) - }) - } - - /// Get a list of undo entries at the time of the snapshot - pub fn undo_entries(&self) -> Array { - assert!(self.has_undo()); - let mut count = 0; - let result = unsafe { BNGetSnapshotUndoEntries(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - pub fn undo_entries_with_progress bool>( - &self, - mut progress: F, - ) -> Array { - assert!(self.has_undo()); - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - let mut count = 0; - let result = unsafe { - BNGetSnapshotUndoEntriesWithProgress( - self.as_raw(), - ctxt, - Some(cb_progress::), - &mut count, - ) - }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get the backing kvs data with snapshot fields - pub fn read_data(&self) -> KeyValueStore { - let result = unsafe { BNReadSnapshotData(self.as_raw()) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } - } - - pub fn read_data_with_progress bool>( - &self, - mut progress: F, - ) -> KeyValueStore { - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - let result = - unsafe { BNReadSnapshotDataWithProgress(self.as_raw(), ctxt, Some(cb_progress::)) }; - unsafe { KeyValueStore::from_raw(ptr::NonNull::new(result).unwrap()) } - } - - pub fn undo_data(&self) -> DataBuffer { - let result = unsafe { BNGetSnapshotUndoData(self.as_raw()) }; - assert!(!result.is_null()); - DataBuffer::from_raw(result) - } - - pub fn store_data bool>( - &self, - data: KeyValueStore, - mut progress: F, - ) -> bool { - let ctxt = &mut progress as *mut _ as *mut ffi::c_void; - unsafe { BNSnapshotStoreData(self.as_raw(), data.as_raw(), ctxt, Some(cb_progress::)) } - } - - /// Determine if this snapshot has another as an ancestor - pub fn has_ancestor(self, other: &Snapshot) -> bool { - unsafe { BNSnapshotHasAncestor(self.as_raw(), other.as_raw()) } - } -} - -impl Clone for Snapshot { - fn clone(&self) -> Self { - unsafe { Self::from_raw(ptr::NonNull::new(BNNewSnapshotReference(self.as_raw())).unwrap()) } - } -} - -impl Drop for Snapshot { - fn drop(&mut self) { - unsafe { BNFreeSnapshot(self.as_raw()) } - } -} - -impl CoreArrayProvider for Snapshot { - type Raw = *mut BNSnapshot; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for Snapshot { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeSnapshotList(raw, count); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -#[repr(transparent)] -pub struct KeyValueStore { - handle: ptr::NonNull, -} - -impl KeyValueStore { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNKeyValueStore { - &mut *self.handle.as_ptr() - } - - /// Get a list of all keys stored in the kvs - pub fn keys(&self) -> Array { - let mut count = 0; - let result = unsafe { BNGetKeyValueStoreKeys(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - /// Get the value for a single key - pub fn value(&self, key: S) -> Option { - let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - let result = unsafe { BNGetKeyValueStoreBuffer(self.as_raw(), key_ptr) }; - ptr::NonNull::new(result).map(|_| DataBuffer::from_raw(result)) - } - - /// Set the value for a single key - pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { - let key_raw = key.into_bytes_with_nul(); - let key_ptr = key_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNSetKeyValueStoreBuffer(self.as_raw(), key_ptr, value.as_raw()) } - } - - /// Get the stored representation of the kvs - pub fn serialized_data(&self) -> DataBuffer { - let result = unsafe { BNGetKeyValueStoreSerializedData(self.as_raw()) }; - assert!(!result.is_null()); - DataBuffer::from_raw(result) - } - - /// Begin storing new keys into a namespace - pub fn begin_namespace(&self, name: S) { - let name_raw = name.into_bytes_with_nul(); - let name_ptr = name_raw.as_ref().as_ptr() as *const ffi::c_char; - unsafe { BNBeginKeyValueStoreNamespace(self.as_raw(), name_ptr) } - } - - /// End storing new keys into a namespace - pub fn end_namespace(&self) { - unsafe { BNEndKeyValueStoreNamespace(self.as_raw()) } - } - - /// If the kvs is empty - pub fn empty(&self) -> bool { - unsafe { BNIsKeyValueStoreEmpty(self.as_raw()) } - } - - /// Number of values in the kvs - pub fn value_size(&self) -> usize { - unsafe { BNGetKeyValueStoreValueSize(self.as_raw()) } - } - - /// Length of serialized data - pub fn data_size(&self) -> usize { - unsafe { BNGetKeyValueStoreDataSize(self.as_raw()) } - } - - /// Size of all data in storage - pub fn value_storage_size(self) -> usize { - unsafe { BNGetKeyValueStoreValueStorageSize(self.as_raw()) } - } - - /// Number of namespaces pushed with begin_namespace - pub fn namespace_size(self) -> usize { - unsafe { BNGetKeyValueStoreNamespaceSize(self.as_raw()) } - } -} - -impl Clone for KeyValueStore { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewKeyValueStoreReference(self.as_raw())).unwrap()) - } - } -} - -impl Drop for KeyValueStore { - fn drop(&mut self) { - unsafe { BNFreeKeyValueStore(self.as_raw()) } + pub fn snapshot_has_data(&self, id: SnapshotId) -> bool { + unsafe { BNSnapshotHasData(self.handle.as_ptr(), id.0) } } } -#[repr(transparent)] -pub struct UndoEntry { - handle: ptr::NonNull, -} - -impl UndoEntry { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNUndoEntry) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNUndoEntry { - &mut *self.handle.as_ptr() +impl Debug for Database { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Database") + .field("current_snapshot", &self.current_snapshot()) + .field("globals", &self.globals()) + .field("analysis_cache", &self.analysis_cache()) + .finish() } - - pub fn id(&self) -> BnString { - let result = unsafe { BNUndoEntryGetId(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } - } - - pub fn actions(&self) -> Array { - let mut count = 0; - let result = unsafe { BNUndoEntryGetActions(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - pub fn time(&self) -> SystemTime { - let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.as_raw()) }); - UNIX_EPOCH + m - } -} - -impl Clone for UndoEntry { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewUndoEntryReference(self.as_raw())).unwrap()) - } - } -} - -impl Drop for UndoEntry { - fn drop(&mut self) { - unsafe { BNFreeUndoEntry(self.as_raw()) } - } -} - -impl CoreArrayProvider for UndoEntry { - type Raw = *mut BNUndoEntry; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for UndoEntry { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeUndoEntryList(raw, count); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -#[repr(transparent)] -pub struct UndoAction { - handle: ptr::NonNull, } -impl UndoAction { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNUndoAction) -> &Self { - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNUndoAction { - &mut *self.handle.as_ptr() - } - - pub fn summary_text(&self) -> BnString { - let result = unsafe { BNUndoActionGetSummaryText(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } - } - - pub fn summary(&self) -> Array { - let mut count = 0; - let result = unsafe { BNUndoActionGetSummary(self.as_raw(), &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } -} +impl ToOwned for Database { + type Owned = Ref; -impl Clone for UndoAction { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewUndoActionReference(self.as_raw())).unwrap()) - } + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } -impl Drop for UndoAction { - fn drop(&mut self) { - unsafe { BNFreeUndoAction(self.as_raw()) } - } -} - -impl CoreArrayProvider for UndoAction { - type Raw = *mut BNUndoAction; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for UndoAction { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeUndoActionList(raw, count); +unsafe impl RefCountable for Database { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewDatabaseReference(handle.handle.as_ptr())).unwrap(), + }) } - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe fn dec_ref(handle: &Self) { + BNFreeDatabase(handle.handle.as_ptr()); } } - -unsafe extern "C" fn cb_progress bool>( - ctxt: *mut ffi::c_void, - arg1: usize, - arg2: usize, -) -> bool { - let ctxt: &mut F = &mut *(ctxt as *mut F); - ctxt(arg1, arg2) -} - -unsafe extern "C" fn cb_progress_nop(_ctxt: *mut ffi::c_void, _arg1: usize, _arg2: usize) -> bool { - true -} diff --git a/rust/src/database/kvs.rs b/rust/src/database/kvs.rs new file mode 100644 index 000000000..4b77bbdbf --- /dev/null +++ b/rust/src/database/kvs.rs @@ -0,0 +1,135 @@ +use crate::data_buffer::DataBuffer; +use crate::rc::{Array, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use binaryninjacore_sys::{ + BNBeginKeyValueStoreNamespace, BNEndKeyValueStoreNamespace, BNFreeKeyValueStore, + BNGetKeyValueStoreBuffer, BNGetKeyValueStoreDataSize, BNGetKeyValueStoreKeys, + BNGetKeyValueStoreNamespaceSize, BNGetKeyValueStoreSerializedData, BNGetKeyValueStoreValueSize, + BNGetKeyValueStoreValueStorageSize, BNIsKeyValueStoreEmpty, BNKeyValueStore, + BNNewKeyValueStoreReference, BNSetKeyValueStoreBuffer, +}; +use std::collections::HashMap; +use std::ffi::c_char; +use std::fmt::Debug; +use std::ptr::NonNull; + +#[repr(transparent)] +pub struct KeyValueStore { + pub(crate) handle: NonNull, +} + +impl KeyValueStore { + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + pub fn to_hashmap(&self) -> HashMap { + let mut hashmap = HashMap::with_capacity(self.keys().len()); + for key in self.keys().iter() { + if let Some(value) = self.value(key) { + hashmap.insert(key.to_string(), value); + } + } + hashmap + } + + /// Get a list of all keys stored in the kvs + pub fn keys(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetKeyValueStoreKeys(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Get the value for a single key + pub fn value(&self, key: S) -> Option { + let key_raw = key.into_bytes_with_nul(); + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNGetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr) }; + NonNull::new(result).map(|_| DataBuffer::from_raw(result)) + } + + /// Set the value for a single key + pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { + let key_raw = key.into_bytes_with_nul(); + let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNSetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr, value.as_raw()) } + } + + /// Get the stored representation of the kvs + pub fn serialized_data(&self) -> DataBuffer { + let result = unsafe { BNGetKeyValueStoreSerializedData(self.handle.as_ptr()) }; + assert!(!result.is_null()); + DataBuffer::from_raw(result) + } + + /// Begin storing new keys into a namespace + pub fn begin_namespace(&self, name: S) { + let name_raw = name.into_bytes_with_nul(); + let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNBeginKeyValueStoreNamespace(self.handle.as_ptr(), name_ptr) } + } + + /// End storing new keys into a namespace + pub fn end_namespace(&self) { + unsafe { BNEndKeyValueStoreNamespace(self.handle.as_ptr()) } + } + + /// If the kvs is empty + pub fn is_empty(&self) -> bool { + unsafe { BNIsKeyValueStoreEmpty(self.handle.as_ptr()) } + } + + /// Number of values in the kvs + pub fn value_size(&self) -> usize { + unsafe { BNGetKeyValueStoreValueSize(self.handle.as_ptr()) } + } + + /// Length of serialized data + pub fn data_size(&self) -> usize { + unsafe { BNGetKeyValueStoreDataSize(self.handle.as_ptr()) } + } + + /// Size of all data in storage + pub fn value_storage_size(&self) -> usize { + unsafe { BNGetKeyValueStoreValueStorageSize(self.handle.as_ptr()) } + } + + /// Number of namespaces pushed with begin_namespace + pub fn namespace_size(&self) -> usize { + unsafe { BNGetKeyValueStoreNamespaceSize(self.handle.as_ptr()) } + } +} + +impl ToOwned for KeyValueStore { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for KeyValueStore { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewKeyValueStoreReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeKeyValueStore(handle.handle.as_ptr()); + } +} + +impl Debug for KeyValueStore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("KeyValueStore") + .field("keys", &self.keys().to_vec()) + .field("is_empty", &self.is_empty()) + .field("value_size", &self.value_size()) + .field("data_size", &self.data_size()) + .field("value_storage_size", &self.value_storage_size()) + .field("namespace_size", &self.namespace_size()) + .finish() + } +} diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs new file mode 100644 index 000000000..fd678c4f1 --- /dev/null +++ b/rust/src/database/snapshot.rs @@ -0,0 +1,258 @@ +use crate::data_buffer::DataBuffer; +use crate::database::kvs::KeyValueStore; +use crate::database::undo::UndoEntry; +use crate::database::Database; +use crate::progress::ProgressExecutor; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use binaryninjacore_sys::{ + BNFreeSnapshot, BNFreeSnapshotList, BNGetSnapshotChildren, BNGetSnapshotDatabase, + BNGetSnapshotFileContents, BNGetSnapshotFileContentsHash, BNGetSnapshotFirstParent, + BNGetSnapshotId, BNGetSnapshotName, BNGetSnapshotParents, BNGetSnapshotUndoData, + BNGetSnapshotUndoEntries, BNGetSnapshotUndoEntriesWithProgress, BNIsSnapshotAutoSave, + BNNewSnapshotReference, BNReadSnapshotData, BNReadSnapshotDataWithProgress, BNSetSnapshotName, + BNSnapshot, BNSnapshotHasAncestor, BNSnapshotHasContents, BNSnapshotHasUndo, + BNSnapshotStoreData, +}; +use std::ffi::c_char; +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; +use std::ptr::NonNull; + +#[repr(transparent)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SnapshotId(pub i64); + +impl Display for SnapshotId { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + +pub struct Snapshot { + handle: NonNull, +} + +impl Snapshot { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + /// Get the owning database + pub fn database(&self) -> Database { + unsafe { + Database::from_raw(NonNull::new(BNGetSnapshotDatabase(self.handle.as_ptr())).unwrap()) + } + } + + /// Get the numerical id + pub fn id(&self) -> SnapshotId { + SnapshotId(unsafe { BNGetSnapshotId(self.handle.as_ptr()) }) + } + + /// Get the displayed snapshot name + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNGetSnapshotName(self.handle.as_ptr())) } + } + + /// Set the displayed snapshot name + pub fn set_name(&self, value: S) { + let value_raw = value.into_bytes_with_nul(); + let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; + unsafe { BNSetSnapshotName(self.handle.as_ptr(), value_ptr) } + } + + /// If the snapshot was the result of an auto-save + pub fn is_auto_save(&self) -> bool { + unsafe { BNIsSnapshotAutoSave(self.handle.as_ptr()) } + } + + /// If the snapshot has contents, and has not been trimmed + pub fn has_contents(&self) -> bool { + unsafe { BNSnapshotHasContents(self.handle.as_ptr()) } + } + + /// If the snapshot has undo data + pub fn has_undo(&self) -> bool { + unsafe { BNSnapshotHasUndo(self.handle.as_ptr()) } + } + + /// Get the first parent of the snapshot, or None if it has no parents + pub fn first_parent(&self) -> Option { + let result = unsafe { BNGetSnapshotFirstParent(self.handle.as_ptr()) }; + NonNull::new(result).map(|s| unsafe { Snapshot::from_raw(s) }) + } + + /// Get a list of all parent snapshots of the snapshot + pub fn parents(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetSnapshotParents(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Get a list of all child snapshots of the snapshot + pub fn children(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetSnapshotChildren(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Get a buffer of the raw data at the time of the snapshot + pub fn file_contents(&self) -> Option { + self.has_contents().then(|| unsafe { + let result = BNGetSnapshotFileContents(self.handle.as_ptr()); + assert!(!result.is_null()); + DataBuffer::from_raw(result) + }) + } + + /// Get a hash of the data at the time of the snapshot + pub fn file_contents_hash(&self) -> Option { + self.has_contents().then(|| unsafe { + let result = BNGetSnapshotFileContentsHash(self.handle.as_ptr()); + assert!(!result.is_null()); + DataBuffer::from_raw(result) + }) + } + + /// Get a list of undo entries at the time of the snapshot + pub fn undo_entries(&self) -> Array { + assert!(self.has_undo()); + let mut count = 0; + let result = unsafe { BNGetSnapshotUndoEntries(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + pub fn undo_entries_with_progress( + &self, + progress: impl Into, + ) -> Array { + assert!(self.has_undo()); + let mut count = 0; + let result = unsafe { + BNGetSnapshotUndoEntriesWithProgress( + self.handle.as_ptr(), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + &mut count, + ) + }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Get the backing kvs data with snapshot fields + pub fn read_data(&self) -> Ref { + let result = unsafe { BNReadSnapshotData(self.handle.as_ptr()) }; + unsafe { KeyValueStore::ref_from_raw(NonNull::new(result).unwrap()) } + } + + pub fn read_data_with_progress( + &self, + progress: impl Into, + ) -> Ref { + let result = unsafe { + BNReadSnapshotDataWithProgress( + self.handle.as_ptr(), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + ) + }; + unsafe { KeyValueStore::ref_from_raw(NonNull::new(result).unwrap()) } + } + + pub fn undo_data(&self) -> DataBuffer { + let result = unsafe { BNGetSnapshotUndoData(self.handle.as_ptr()) }; + assert!(!result.is_null()); + DataBuffer::from_raw(result) + } + + pub fn store_data(&self, data: &KeyValueStore) -> bool { + unsafe { + BNSnapshotStoreData( + self.handle.as_ptr(), + data.handle.as_ptr(), + std::ptr::null_mut(), + None, + ) + } + } + + pub fn store_data_with_progress( + &self, + data: &KeyValueStore, + progress: impl Into, + ) -> bool { + unsafe { + BNSnapshotStoreData( + self.handle.as_ptr(), + data.handle.as_ptr(), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + ) + } + } + + /// Determine if this snapshot has another as an ancestor + pub fn has_ancestor(self, other: &Snapshot) -> bool { + unsafe { BNSnapshotHasAncestor(self.handle.as_ptr(), other.handle.as_ptr()) } + } +} + +impl Debug for Snapshot { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Snapshot") + .field("id", &self.id()) + .field("name", &self.name()) + .field("is_auto_save", &self.is_auto_save()) + .field("has_contents", &self.has_contents()) + .field("has_undo", &self.has_undo()) + // TODO: This might be too much. + .field("children", &self.children().to_vec()) + .finish() + } +} + +impl ToOwned for Snapshot { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for Snapshot { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewSnapshotReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeSnapshot(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for Snapshot { + type Raw = *mut BNSnapshot; + type Context = (); + type Wrapped<'a> = Guard<'a, Snapshot>; +} + +unsafe impl CoreArrayProviderInner for Snapshot { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeSnapshotList(raw, count); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} diff --git a/rust/src/database/undo.rs b/rust/src/database/undo.rs new file mode 100644 index 000000000..727a777ba --- /dev/null +++ b/rust/src/database/undo.rs @@ -0,0 +1,168 @@ +use crate::disassembly::InstructionTextToken; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::BnString; +use binaryninjacore_sys::{ + BNFreeUndoAction, BNFreeUndoActionList, BNFreeUndoEntry, BNFreeUndoEntryList, + BNNewUndoActionReference, BNNewUndoEntryReference, BNUndoAction, BNUndoActionGetSummary, + BNUndoActionGetSummaryText, BNUndoEntry, BNUndoEntryGetActions, BNUndoEntryGetId, + BNUndoEntryGetTimestamp, +}; +use std::fmt::Debug; +use std::ptr::NonNull; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +#[repr(transparent)] +pub struct UndoEntry { + handle: NonNull, +} + +impl UndoEntry { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + #[allow(dead_code)] + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + pub fn id(&self) -> BnString { + let result = unsafe { BNUndoEntryGetId(self.handle.as_ptr()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } + + pub fn actions(&self) -> Array { + let mut count = 0; + let result = unsafe { BNUndoEntryGetActions(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + pub fn time(&self) -> SystemTime { + let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.handle.as_ptr()) }); + UNIX_EPOCH + m + } +} + +impl Debug for UndoEntry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UndoEntry") + .field("id", &self.id()) + .field("time", &self.time()) + .field("actions", &self.actions().to_vec()) + .finish() + } +} + +impl ToOwned for UndoEntry { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for UndoEntry { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewUndoEntryReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeUndoEntry(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for UndoEntry { + type Raw = *mut BNUndoEntry; + type Context = (); + type Wrapped<'a> = Guard<'a, UndoEntry>; +} + +unsafe impl CoreArrayProviderInner for UndoEntry { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeUndoEntryList(raw, count); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} + +#[repr(transparent)] +pub struct UndoAction { + handle: NonNull, +} + +impl UndoAction { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + #[allow(dead_code)] + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + pub fn summary(&self) -> Array { + let mut count = 0; + let result = unsafe { BNUndoActionGetSummary(self.handle.as_ptr(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Gets the [`UndoAction`] summary as text rather than [`InstructionTextToken`]'s. + pub fn summary_as_string(&self) -> BnString { + let result = unsafe { BNUndoActionGetSummaryText(self.handle.as_ptr()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } +} + +impl Debug for UndoAction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UndoAction") + .field("summary", &self.summary_as_string()) + .finish() + } +} + +impl ToOwned for UndoAction { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for UndoAction { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewUndoActionReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeUndoAction(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for UndoAction { + type Raw = *mut BNUndoAction; + type Context = (); + type Wrapped<'a> = Guard<'a, UndoAction>; +} + +unsafe impl CoreArrayProviderInner for UndoAction { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeUndoActionList(raw, count); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 832f0d457..42fa598e7 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -29,7 +29,7 @@ //! Here's a minimal, complete example boilerplate-plugin: //! ```no_run //! use binaryninja::{ -//! binaryview::BinaryView, +//! binary_view::BinaryView, //! debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser}, //! }; //! @@ -62,11 +62,11 @@ //! `DebugInfo` will then be automatically applied to binary views that contain debug information (via the setting `analysis.debugInfo.internal`), binary views that provide valid external debug info files (`analysis.debugInfo.external`), or manually fetched/applied as below: //! ```no_run //! # use binaryninja::debuginfo::DebugInfoParser; -//! # use binaryninja::binaryview::BinaryViewExt; +//! # use binaryninja::binary_view::BinaryViewExt; //! let bv = binaryninja::load("example").unwrap(); //! let valid_parsers = DebugInfoParser::parsers_for_view(&bv); //! let parser = valid_parsers.get(0); -//! let debug_info = parser.parse_debug_info(&bv, &bv, None, None).unwrap(); +//! let debug_info = parser.parse_debug_info(&bv, &bv, None).unwrap(); //! bv.apply_debug_info(&debug_info); //! ``` //! @@ -77,20 +77,28 @@ use binaryninjacore_sys::*; use std::ffi::c_void; +use crate::progress::ProgressExecutor; +use crate::variable::{NamedDataVariableWithType, NamedVariableWithType}; use crate::{ - binaryview::BinaryView, + binary_view::BinaryView, platform::Platform, rc::*, string::{raw_to_string, BnStrCompatible, BnString}, types::{NameAndType, Type}, }; -use crate::variable::{NamedDataVariableWithType, NamedVariableWithType}; - -struct ProgressContext(Option Result<(), ()>>>); +/// Implement this trait to implement a debug info parser. See `DebugInfoParser` for more details. +pub trait CustomDebugInfoParser: 'static + Sync { + fn is_valid(&self, view: &BinaryView) -> bool; -////////////////////// -// DebugInfoParser + fn parse_info( + &self, + debug_info: &mut DebugInfo, + view: &BinaryView, + debug_file: &BinaryView, + progress: Box Result<(), ()>>, + ) -> bool; +} /// Represents the registered parsers and providers of debug information to Binary Ninja. /// See `binaryninja::debuginfo` for more information @@ -142,25 +150,33 @@ impl DebugInfoParser { unsafe { BNIsDebugInfoParserValidForView(self.handle, view.handle) } } - extern "C" fn cb_progress(ctxt: *mut c_void, cur: usize, max: usize) -> bool { - ffi_wrap!("DebugInfoParser::cb_progress", unsafe { - let progress = ctxt as *mut ProgressContext; - match &(*progress).0 { - Some(func) => (func)(cur, max).is_ok(), - None => true, - } - }) - } - - /// Returns a `DebugInfo` object populated with debug info by this debug-info parser. Only provide a `DebugInfo` object if you wish to append to the existing debug info + /// Returns [`DebugInfo`] populated with debug info by this debug-info parser. + /// + /// Only provide a `DebugInfo` object if you wish to append to the existing debug info pub fn parse_debug_info( &self, view: &BinaryView, debug_file: &BinaryView, existing_debug_info: Option<&DebugInfo>, - progress: Option Result<(), ()>>>, ) -> Option> { - let mut progress_raw = ProgressContext(progress); + self.parse_debug_info_with_progress( + view, + debug_file, + existing_debug_info, + ProgressExecutor::default(), + ) + } + + /// Returns [`DebugInfo`] populated with debug info by this debug-info parser. + /// + /// Only provide a `DebugInfo` object if you wish to append to the existing debug info + pub fn parse_debug_info_with_progress( + &self, + view: &BinaryView, + debug_file: &BinaryView, + existing_debug_info: Option<&DebugInfo>, + progress: impl Into, + ) -> Option> { let info: *mut BNDebugInfo = match existing_debug_info { Some(debug_info) => unsafe { BNParseDebugInfo( @@ -168,8 +184,8 @@ impl DebugInfoParser { view.handle, debug_file.handle, debug_info.handle, - Some(Self::cb_progress), - &mut progress_raw as *mut _ as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }, None => unsafe { @@ -178,8 +194,8 @@ impl DebugInfoParser { view.handle, debug_file.handle, std::ptr::null_mut(), - Some(Self::cb_progress), - &mut progress_raw as *mut _ as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }, }; @@ -893,18 +909,3 @@ impl ToOwned for DebugInfo { unsafe { RefCountable::inc_ref(self) } } } - -//////////////////////////// -// CustomDebugInfoParser - -/// Implement this trait to implement a debug info parser. See `DebugInfoParser` for more details. -pub trait CustomDebugInfoParser: 'static + Sync { - fn is_valid(&self, view: &BinaryView) -> bool; - fn parse_info( - &self, - debug_info: &mut DebugInfo, - view: &BinaryView, - debug_file: &BinaryView, - progress: Box Result<(), ()>>, - ) -> bool; -} diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index 3a3d924dd..6e303fac0 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -18,7 +18,7 @@ use binaryninjacore_sys::*; use std::ffi::{c_char, c_void}; use crate::architecture::CoreArchitecture; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::string::{raw_to_string, BnStrCompatible, BnString}; use crate::types::{QualifiedName, Type}; diff --git a/rust/src/downloadprovider.rs b/rust/src/download_provider.rs similarity index 100% rename from rust/src/downloadprovider.rs rename to rust/src/download_provider.rs diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs new file mode 100644 index 000000000..2b3594b64 --- /dev/null +++ b/rust/src/external_library.rs @@ -0,0 +1,224 @@ +use crate::project::file::ProjectFile; +use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use crate::symbol::Symbol; +use binaryninjacore_sys::*; +use std::ffi::c_char; +use std::fmt::Debug; +use std::ptr::NonNull; + +/// An ExternalLibrary is an abstraction for a library that is optionally backed +/// by a [ProjectFile]. +#[repr(transparent)] +pub struct ExternalLibrary { + pub(crate) handle: NonNull, +} + +impl ExternalLibrary { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + /// Get the name of this external library + pub fn name(&self) -> BnString { + let result = unsafe { BNExternalLibraryGetName(self.handle.as_ptr()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } + + /// Get the file backing this external library + pub fn backing_file(&self) -> Option> { + let result = unsafe { BNExternalLibraryGetBackingFile(self.handle.as_ptr()) }; + let handle = NonNull::new(result)?; + Some(unsafe { ProjectFile::ref_from_raw(handle) }) + } + + /// Set the file backing this external library + pub fn set_backing_file(&self, file: Option<&ProjectFile>) { + let file_handle = file + .map(|x| x.handle.as_ptr()) + .unwrap_or(std::ptr::null_mut()); + unsafe { BNExternalLibrarySetBackingFile(self.handle.as_ptr(), file_handle) } + } +} + +impl ToOwned for ExternalLibrary { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for ExternalLibrary { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewExternalLibraryReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeExternalLibrary(handle.handle.as_ptr()); + } +} + +impl Debug for ExternalLibrary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ExternalLibrary") + .field("name", &self.name()) + .field("backing_file", &self.backing_file()) + .finish() + } +} + +impl CoreArrayProvider for ExternalLibrary { + type Raw = *mut BNExternalLibrary; + type Context = (); + type Wrapped<'a> = Guard<'a, ExternalLibrary>; +} + +unsafe impl CoreArrayProviderInner for ExternalLibrary { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeExternalLibraryList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} + +/// An [`ExternalLocation`] is an association from a source symbol in a binary view +/// to a target symbol and/or address in an [`ExternalLibrary`]. +#[repr(transparent)] +pub struct ExternalLocation { + handle: NonNull, +} + +impl ExternalLocation { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + /// Get the source symbol for this ExternalLocation + pub fn source_symbol(&self) -> Ref { + let result = unsafe { BNExternalLocationGetSourceSymbol(self.handle.as_ptr()) }; + assert!(!result.is_null()); + unsafe { Symbol::ref_from_raw(result) } + } + + /// Get the ExternalLibrary that this ExternalLocation targets + pub fn library(&self) -> Option> { + let result = unsafe { BNExternalLocationGetExternalLibrary(self.handle.as_ptr()) }; + let handle = NonNull::new(result)?; + Some(unsafe { ExternalLibrary::ref_from_raw(handle) }) + } + + /// Set the ExternalLibrary that this ExternalLocation targets + pub fn set_external_library(&self, lib: Option<&ExternalLibrary>) { + let lib_handle = lib + .map(|x| x.handle.as_ptr()) + .unwrap_or(std::ptr::null_mut()); + unsafe { BNExternalLocationSetExternalLibrary(self.handle.as_ptr(), lib_handle) } + } + + /// Check if this ExternalLocation has a target address + pub fn has_target_address(&self) -> bool { + unsafe { BNExternalLocationHasTargetAddress(self.handle.as_ptr()) } + } + + /// Check if this ExternalLocation has a target symbol + pub fn has_target_symbol(&self) -> bool { + unsafe { BNExternalLocationHasTargetSymbol(self.handle.as_ptr()) } + } + + /// Get the address pointed to by this ExternalLocation, if any + pub fn target_address(&self) -> Option { + self.has_target_address() + .then(|| unsafe { BNExternalLocationGetTargetAddress(self.handle.as_ptr()) }) + } + + /// Set the address pointed to by this ExternalLocation. + /// ExternalLocations must have a valid target address and/or symbol set. + pub fn set_target_address(&self, address: Option) -> bool { + match address { + Some(mut addr) => unsafe { + BNExternalLocationSetTargetAddress(self.handle.as_ptr(), &mut addr) + }, + None => unsafe { + BNExternalLocationSetTargetAddress(self.handle.as_ptr(), std::ptr::null_mut()) + }, + } + } + + /// Get the symbol pointed to by this ExternalLocation, if any + pub fn target_symbol(&self) -> Option { + let result = unsafe { BNExternalLocationGetTargetSymbol(self.handle.as_ptr()) }; + (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + } + + /// Set the symbol pointed to by this ExternalLocation. + /// ExternalLocations must have a valid target address and/or symbol set. + pub fn set_target_symbol(&self, symbol: Option) -> bool { + let symbol = symbol + .map(|x| x.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) + .unwrap_or(std::ptr::null_mut()); + unsafe { BNExternalLocationSetTargetSymbol(self.handle.as_ptr(), symbol) } + } +} + +impl Debug for ExternalLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ExternalLocation") + .field("source_symbol", &self.source_symbol()) + .field("library", &self.library()) + .field("target_address", &self.target_address()) + .field("target_symbol", &self.target_symbol()) + .finish() + } +} + +impl ToOwned for ExternalLocation { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for ExternalLocation { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewExternalLocationReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeExternalLocation(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for ExternalLocation { + type Raw = *mut BNExternalLocation; + type Context = (); + type Wrapped<'a> = Guard<'a, Self>; +} + +unsafe impl CoreArrayProviderInner for ExternalLocation { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeExternalLocationList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} diff --git a/rust/src/externallibrary.rs b/rust/src/externallibrary.rs deleted file mode 100644 index 9d2158410..000000000 --- a/rust/src/externallibrary.rs +++ /dev/null @@ -1,204 +0,0 @@ -use core::{ffi, mem, ptr}; - -use binaryninjacore_sys::*; - -use crate::project::ProjectFile; -use crate::rc::{CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{BnStrCompatible, BnString}; -use crate::symbol::Symbol; - -/// An ExternalLibrary is an abstraction for a library that is optionally backed -/// by a [ProjectFile]. -#[repr(transparent)] -pub struct ExternalLibrary { - handle: ptr::NonNull, -} - -impl Drop for ExternalLibrary { - fn drop(&mut self) { - unsafe { BNFreeExternalLibrary(self.as_raw()) } - } -} - -impl Clone for ExternalLibrary { - fn clone(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewExternalLibraryReference(self.as_raw())).unwrap()) - } - } -} - -impl ExternalLibrary { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNExternalLibrary) -> &Self { - assert!(!handle.is_null()); - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNExternalLibrary { - &mut *self.handle.as_ptr() - } - - /// Get the name of this external library - pub fn name(&self) -> BnString { - let result = unsafe { BNExternalLibraryGetName(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } - } - - /// Get the file backing this external library - pub fn backing_file(&self) -> Option { - let result = unsafe { BNExternalLibraryGetBackingFile(self.as_raw()) }; - let handle = ptr::NonNull::new(result)?; - Some(unsafe { ProjectFile::from_raw(handle) }) - } - - /// Set the file backing this external library - pub fn set_backing_file(&self, file: Option<&ProjectFile>) { - let file_handle = file - .map(|x| unsafe { x.as_raw() as *mut _ }) - .unwrap_or(ptr::null_mut()); - unsafe { BNExternalLibrarySetBackingFile(self.as_raw(), file_handle) } - } -} - -impl CoreArrayProvider for ExternalLibrary { - type Raw = *mut BNExternalLibrary; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for ExternalLibrary { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeExternalLibraryList(raw, count) - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -/// An ExternalLocation is an association from a source symbol in a binary view -/// to a target symbol and/or address in an [ExternalLibrary]. -#[repr(transparent)] -pub struct ExternalLocation { - handle: ptr::NonNull, -} - -impl Drop for ExternalLocation { - fn drop(&mut self) { - unsafe { BNFreeExternalLocation(self.as_raw()) } - } -} - -impl Clone for ExternalLocation { - fn clone(&self) -> Self { - unsafe { - Self::from_raw( - ptr::NonNull::new(BNNewExternalLocationReference(self.as_raw())).unwrap(), - ) - } - } -} - -impl ExternalLocation { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNExternalLocation) -> &Self { - assert!(!handle.is_null()); - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNExternalLocation { - &mut *self.handle.as_ptr() - } - - /// Get the source symbol for this ExternalLocation - pub fn source_symbol(&self) -> Symbol { - let result = unsafe { BNExternalLocationGetSourceSymbol(self.as_raw()) }; - assert!(!result.is_null()); - unsafe { Symbol::from_raw(result) } - } - - /// Get the ExternalLibrary that this ExternalLocation targets - pub fn library(&self) -> Option { - let result = unsafe { BNExternalLocationGetExternalLibrary(self.as_raw()) }; - let handle = ptr::NonNull::new(result)?; - Some(unsafe { ExternalLibrary::from_raw(handle) }) - } - - /// Set the ExternalLibrary that this ExternalLocation targets - pub fn set_external_library(&self, lib: Option<&ExternalLibrary>) { - let lib_handle = lib - .map(|x| unsafe { x.as_raw() as *mut _ }) - .unwrap_or(ptr::null_mut()); - unsafe { BNExternalLocationSetExternalLibrary(self.as_raw(), lib_handle) } - } - - /// Check if this ExternalLocation has a target address - pub fn has_target_address(&self) -> bool { - unsafe { BNExternalLocationHasTargetAddress(self.as_raw()) } - } - - /// Check if this ExternalLocation has a target symbol - pub fn has_target_symbol(&self) -> bool { - unsafe { BNExternalLocationHasTargetSymbol(self.as_raw()) } - } - - /// Get the address pointed to by this ExternalLocation, if any - pub fn target_address(&self) -> Option { - self.has_target_address() - .then(|| unsafe { BNExternalLocationGetTargetAddress(self.as_raw()) }) - } - - /// Set the address pointed to by this ExternalLocation. - /// ExternalLocations must have a valid target address and/or symbol set. - pub fn set_target_address(&self, mut address: Option) -> bool { - let address_ptr = address - .as_mut() - .map(|x| x as *mut u64) - .unwrap_or(ptr::null_mut()); - unsafe { BNExternalLocationSetTargetAddress(self.as_raw(), address_ptr) } - } - - /// Get the symbol pointed to by this ExternalLocation, if any - pub fn target_symbol(&self) -> Option { - self.has_target_symbol().then(|| unsafe { - let result = BNExternalLocationGetTargetSymbol(self.as_raw()); - assert!(!result.is_null()); - BnString::from_raw(result) - }) - } - - /// Set the symbol pointed to by this ExternalLocation. - /// ExternalLocations must have a valid target address and/or symbol set. - pub fn set_target_symbol(&self, symbol: Option) -> bool { - let symbol = symbol - .map(|x| x.into_bytes_with_nul().as_ref().as_ptr() as *const ffi::c_char) - .unwrap_or(ptr::null_mut()); - unsafe { BNExternalLocationSetTargetSymbol(self.as_raw(), symbol) } - } -} - -impl CoreArrayProvider for ExternalLocation { - type Raw = *mut BNExternalLocation; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for ExternalLocation { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeExternalLocationList(raw, count) - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} diff --git a/rust/src/fileaccessor.rs b/rust/src/file_accessor.rs similarity index 100% rename from rust/src/fileaccessor.rs rename to rust/src/file_accessor.rs diff --git a/rust/src/filemetadata.rs b/rust/src/file_metadata.rs similarity index 76% rename from rust/src/filemetadata.rs rename to rust/src/file_metadata.rs index a770c491d..8be2c402f 100644 --- a/rust/src/filemetadata.rs +++ b/rust/src/file_metadata.rs @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::database::Database; -use crate::project::ProjectFile; use binaryninjacore_sys::{ BNBeginUndoActions, BNCloseFile, BNCommitUndoActions, BNCreateDatabase, BNCreateFileMetadata, BNFileMetadata, BNFileMetadataGetSessionId, BNFreeFileMetadata, BNGetCurrentOffset, @@ -25,12 +24,13 @@ use binaryninjacore_sys::{ BNSaveAutoSnapshot, BNSetFilename, BNUndo, }; use binaryninjacore_sys::{BNCreateDatabaseWithProgress, BNOpenExistingDatabaseWithProgress}; -use std::ffi::c_void; use std::fmt::Debug; use crate::rc::*; use crate::string::*; +use crate::progress::ProgressExecutor; +use crate::project::file::ProjectFile; use std::ptr::{self, NonNull}; #[derive(PartialEq, Eq, Hash)] @@ -43,12 +43,12 @@ impl FileMetadata { Self { handle } } + pub(crate) fn ref_from_raw(handle: *mut BNFileMetadata) -> Ref { + unsafe { Ref::new(Self { handle }) } + } + pub fn new() -> Ref { - unsafe { - Ref::new(Self { - handle: BNCreateFileMetadata(), - }) - } + Self::ref_from_raw(unsafe { BNCreateFileMetadata() }) } pub fn with_filename(name: S) -> Ref { @@ -102,7 +102,11 @@ impl FileMetadata { unsafe { BNIsAnalysisChanged(self.handle) } } - pub fn is_database_backed(&self, view_type: S) -> bool { + pub fn is_database_backed(&self) -> bool { + self.is_database_backed_for_view_type("") + } + + pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { let view_type = view_type.into_bytes_with_nul(); unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } @@ -188,17 +192,31 @@ impl FileMetadata { } } - pub fn project_file(&self) -> Option { + /// Get the [`ProjectFile`] for the [`FileMetadata`]. + pub fn project_file(&self) -> Option> { unsafe { let res = NonNull::new(BNGetProjectFile(self.handle))?; - Some(ProjectFile::from_raw(res)) + Some(ProjectFile::ref_from_raw(res)) } } - pub fn create_database( + // TODO: filename can be AsRef imo + pub fn create_database(&self, filename: S) -> bool { + let filename = filename.into_bytes_with_nul(); + let filename_ptr = filename.as_ref().as_ptr() as *mut _; + + // Databases are created with the root view (Raw). + let Some(raw_view) = self.view_of_type("Raw") else { + return false; + }; + + unsafe { BNCreateDatabase(raw_view.handle, filename_ptr, ptr::null_mut()) } + } + + pub fn create_database_with_progress( &self, filename: S, - progress_func: Option bool>, + progress: impl Into, ) -> bool { let filename = filename.into_bytes_with_nul(); let filename_ptr = filename.as_ref().as_ptr() as *mut _; @@ -208,17 +226,14 @@ impl FileMetadata { return false; }; - match progress_func { - None => unsafe { BNCreateDatabase(raw_view.handle, filename_ptr, ptr::null_mut()) }, - Some(func) => unsafe { - BNCreateDatabaseWithProgress( - raw_view.handle, - filename_ptr, - func as *mut c_void, - Some(cb_progress_func), - ptr::null_mut(), - ) - }, + unsafe { + BNCreateDatabaseWithProgress( + raw_view.handle, + filename_ptr, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + ptr::null_mut(), + ) } } @@ -248,24 +263,34 @@ impl FileMetadata { } } - pub fn open_database( + pub fn open_database(&self, filename: S) -> Result, ()> { + let filename = filename.into_bytes_with_nul(); + let filename_ptr = filename.as_ref().as_ptr() as *mut _; + + let view = unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }; + + if view.is_null() { + Err(()) + } else { + Ok(unsafe { BinaryView::ref_from_raw(view) }) + } + } + + pub fn open_database_with_progress( &self, filename: S, - progress_func: Option bool>, + progress: impl Into, ) -> Result, ()> { let filename = filename.into_bytes_with_nul(); let filename_ptr = filename.as_ref().as_ptr() as *mut _; - let view = match progress_func { - None => unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }, - Some(func) => unsafe { - BNOpenExistingDatabaseWithProgress( - self.handle, - filename_ptr, - func as *mut c_void, - Some(cb_progress_func), - ) - }, + let view = unsafe { + BNOpenExistingDatabaseWithProgress( + self.handle, + filename_ptr, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + ) }; if view.is_null() { @@ -276,9 +301,9 @@ impl FileMetadata { } /// Get the current database - pub fn database(&self) -> Option { + pub fn database(&self) -> Option> { let result = unsafe { BNGetFileMetadataDatabase(self.handle) }; - NonNull::new(result).map(|handle| unsafe { Database::from_raw(handle) }) + NonNull::new(result).map(|handle| unsafe { Database::ref_from_raw(handle) }) } } @@ -317,12 +342,3 @@ unsafe impl RefCountable for FileMetadata { BNFreeFileMetadata(handle.handle); } } - -unsafe extern "C" fn cb_progress_func( - ctxt: *mut ::std::os::raw::c_void, - progress: usize, - total: usize, -) -> bool { - let func: fn(usize, usize) -> bool = core::mem::transmute(ctxt); - func(progress, total) -} diff --git a/rust/src/function.rs b/rust/src/function.rs index 655f4f005..10c49db0f 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -16,13 +16,13 @@ use binaryninjacore_sys::*; use crate::{ architecture::{Architecture, CoreArchitecture, CoreRegister, Register}, - basicblock::{BasicBlock, BlockContext}, - binaryview::{BinaryView, BinaryViewExt}, - callingconvention::CallingConvention, + basic_block::{BasicBlock, BlockContext}, + binary_view::{BinaryView, BinaryViewExt}, + calling_convention::CallingConvention, component::Component, disassembly::{DisassemblySettings, DisassemblyTextLine}, flowgraph::FlowGraph, - mlil::FunctionGraphType, + medium_level_il::FunctionGraphType, platform::Platform, references::CodeReference, string::*, @@ -30,7 +30,7 @@ use crate::{ tags::{Tag, TagReference, TagType}, types::{IntegerDisplayType, QualifiedName, Type}, }; -use crate::{databuffer::DataBuffer, disassembly::InstructionTextToken, rc::*}; +use crate::{data_buffer::DataBuffer, disassembly::InstructionTextToken, rc::*}; pub use binaryninjacore_sys::BNAnalysisSkipReason as AnalysisSkipReason; pub use binaryninjacore_sys::BNBuiltinType as BuiltinType; pub use binaryninjacore_sys::BNFunctionAnalysisSkipOverride as FunctionAnalysisSkipOverride; @@ -39,9 +39,9 @@ pub use binaryninjacore_sys::BNHighlightStandardColor as HighlightStandardColor; use crate::architecture::RegisterId; use crate::confidence::Conf; -use crate::hlil::HighLevelILFunction; -use crate::lowlevelil::{LiftedILFunction, RegularLowLevelILFunction}; -use crate::mlil::MediumLevelILFunction; +use crate::high_level_il::HighLevelILFunction; +use crate::low_level_il::{LiftedILFunction, RegularLowLevelILFunction}; +use crate::medium_level_il::MediumLevelILFunction; use crate::variable::{ IndirectBranchInfo, MergedVariable, NamedVariableWithType, RegisterValue, RegisterValueType, StackVariableReference, Variable, @@ -1046,7 +1046,7 @@ impl Function { /// # Example /// /// ```no_run - /// # use binaryninja::binaryview::{BinaryView, BinaryViewExt}; + /// # use binaryninja::binary_view::{BinaryView, BinaryViewExt}; /// # use binaryninja::function::Function; /// # let fun: Function = todo!(); /// # let bv: BinaryView = todo!(); diff --git a/rust/src/functionrecognizer.rs b/rust/src/function_recognizer.rs similarity index 92% rename from rust/src/functionrecognizer.rs rename to rust/src/function_recognizer.rs index 5ab68e8f1..64e33806b 100644 --- a/rust/src/functionrecognizer.rs +++ b/rust/src/function_recognizer.rs @@ -1,7 +1,7 @@ -use crate::lowlevelil::function::LowLevelILFunction; -use crate::lowlevelil::RegularLowLevelILFunction; -use crate::mlil::MediumLevelILFunction; -use crate::{architecture::CoreArchitecture, binaryview::BinaryView, function::Function}; +use crate::low_level_il::function::LowLevelILFunction; +use crate::low_level_il::RegularLowLevelILFunction; +use crate::medium_level_il::MediumLevelILFunction; +use crate::{architecture::CoreArchitecture, binary_view::BinaryView, function::Function}; use binaryninjacore_sys::*; use std::os::raw::c_void; diff --git a/rust/src/headless.rs b/rust/src/headless.rs index 327535587..02e918fb0 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::{ - binaryview, bundled_plugin_directory, enterprise, is_license_validated, is_main_thread, + binary_view, bundled_plugin_directory, enterprise, is_license_validated, is_main_thread, license_path, set_bundled_plugin_directory, set_license, string::IntoJson, }; use std::io; @@ -279,7 +279,7 @@ impl Session { /// .load("/bin/cat") /// .expect("Couldn't open `/bin/cat`"); /// ``` - pub fn load(&self, file_path: impl AsRef) -> Option> { + pub fn load(&self, file_path: impl AsRef) -> Option> { crate::load(file_path) } @@ -300,7 +300,7 @@ impl Session { file_path: impl AsRef, update_analysis_and_wait: bool, options: Option, - ) -> Option> { + ) -> Option> { crate::load_with_options(file_path, update_analysis_and_wait, options) } } diff --git a/rust/src/hlil/mod.rs b/rust/src/high_level_il.rs similarity index 100% rename from rust/src/hlil/mod.rs rename to rust/src/high_level_il.rs diff --git a/rust/src/hlil/block.rs b/rust/src/high_level_il/block.rs similarity index 97% rename from rust/src/hlil/block.rs rename to rust/src/high_level_il/block.rs index a82f3e121..e7f834255 100644 --- a/rust/src/hlil/block.rs +++ b/rust/src/high_level_il/block.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::basicblock::{BasicBlock, BlockContext}; +use crate::basic_block::{BasicBlock, BlockContext}; use crate::rc::Ref; use super::{HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex}; diff --git a/rust/src/hlil/function.rs b/rust/src/high_level_il/function.rs similarity index 99% rename from rust/src/hlil/function.rs rename to rust/src/high_level_il/function.rs index f6508be69..3ce5e2d94 100644 --- a/rust/src/hlil/function.rs +++ b/rust/src/high_level_il/function.rs @@ -4,7 +4,7 @@ use std::hash::{Hash, Hasher}; use binaryninjacore_sys::*; use super::{HighLevelILBlock, HighLevelILInstruction, HighLevelInstructionIndex}; -use crate::basicblock::BasicBlock; +use crate::basic_block::BasicBlock; use crate::function::{Function, Location}; use crate::rc::{Array, Ref, RefCountable}; use crate::variable::{SSAVariable, Variable}; diff --git a/rust/src/hlil/instruction.rs b/rust/src/high_level_il/instruction.rs similarity index 100% rename from rust/src/hlil/instruction.rs rename to rust/src/high_level_il/instruction.rs diff --git a/rust/src/hlil/lift.rs b/rust/src/high_level_il/lift.rs similarity index 100% rename from rust/src/hlil/lift.rs rename to rust/src/high_level_il/lift.rs diff --git a/rust/src/hlil/operation.rs b/rust/src/high_level_il/operation.rs similarity index 100% rename from rust/src/hlil/operation.rs rename to rust/src/high_level_il/operation.rs diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 15a47daec..151e9f7c6 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -19,7 +19,7 @@ use binaryninjacore_sys::*; use std::ffi::{c_char, c_void, CStr}; use std::path::PathBuf; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::rc::Ref; use crate::string::{BnStrCompatible, BnString}; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8df7c45fc..06f0381fc 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -44,39 +44,40 @@ mod ffi; mod operand_iter; pub mod architecture; -pub mod backgroundtask; -pub mod basicblock; -pub mod binaryreader; -pub mod binaryview; -pub mod binarywriter; -pub mod callingconvention; +pub mod background_task; +pub mod basic_block; +pub mod binary_reader; +pub mod binary_view; +pub mod binary_writer; +pub mod calling_convention; pub mod command; pub mod component; pub mod confidence; -pub mod custombinaryview; +pub mod custom_binary_view; +pub mod data_buffer; pub mod database; -pub mod databuffer; pub mod debuginfo; pub mod demangle; pub mod disassembly; -pub mod downloadprovider; +pub mod download_provider; pub mod enterprise; -pub mod externallibrary; -pub mod fileaccessor; -pub mod filemetadata; +pub mod external_library; +pub mod file_accessor; +pub mod file_metadata; pub mod flowgraph; pub mod function; -pub mod functionrecognizer; +pub mod function_recognizer; pub mod headless; -pub mod hlil; +pub mod high_level_il; pub mod interaction; -pub mod linearview; +pub mod linear_view; pub mod logger; -pub mod lowlevelil; +pub mod low_level_il; pub mod mainthread; +pub mod medium_level_il; pub mod metadata; -pub mod mlil; pub mod platform; +mod progress; pub mod project; pub mod rc; pub mod references; @@ -87,21 +88,22 @@ pub mod settings; pub mod string; pub mod symbol; pub mod tags; -pub mod templatesimplifier; -pub mod typearchive; -pub mod typecontainer; -pub mod typelibrary; -pub mod typeparser; -pub mod typeprinter; +pub mod template_simplifier; +pub mod type_archive; +pub mod type_container; +pub mod type_library; +pub mod type_parser; +pub mod type_printer; pub mod types; pub mod update; pub mod variable; +pub mod worker_thread; pub mod workflow; -use crate::filemetadata::FileMetadata; +use crate::file_metadata::FileMetadata; use crate::function::Function; +use binary_view::BinaryView; use binaryninjacore_sys::*; -use binaryview::BinaryView; use metadata::Metadata; use metadata::MetadataType; use rc::Ref; @@ -112,6 +114,7 @@ use string::BnStrCompatible; use string::BnString; use string::IntoJson; +use crate::progress::ProgressExecutor; pub use binaryninjacore_sys::BNBranchType as BranchType; pub use binaryninjacore_sys::BNDataFlowQueryOption as DataFlowQueryOption; pub use binaryninjacore_sys::BNEndianness as Endianness; @@ -122,41 +125,22 @@ pub const BN_INVALID_EXPR: usize = usize::MAX; /// The main way to open and load files into Binary Ninja. Make sure you've properly initialized the core before calling this function. See [`crate::headless::init()`] pub fn load(file_path: impl AsRef) -> Option> { - let file_path = file_path.as_ref().into_bytes_with_nul(); - let options = c""; - let handle = unsafe { - BNLoadFilename( - file_path.as_ptr() as *mut _, - true, - options.as_ptr() as *mut c_char, - Some(cb_progress_nop), - std::ptr::null_mut(), - ) - }; - if handle.is_null() { - None - } else { - Some(unsafe { BinaryView::ref_from_raw(handle) }) - } + load_with_progress(file_path, ProgressExecutor::default()) } -pub fn load_with_progress( +pub fn load_with_progress( file_path: impl AsRef, - mut progress: F, -) -> Option> -where - F: FnMut(usize, usize) -> bool, -{ + progress: impl Into, +) -> Option> { let file_path = file_path.as_ref().into_bytes_with_nul(); let options = c""; - let progress_ctx = &mut progress as *mut F as *mut c_void; let handle = unsafe { BNLoadFilename( file_path.as_ptr() as *mut _, true, options.as_ptr() as *mut c_char, - Some(cb_progress_func::), - progress_ctx, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; if handle.is_null() { @@ -191,48 +175,22 @@ pub fn load_with_options( where O: IntoJson, { - let file_path = file_path.as_ref().into_bytes_with_nul(); - let options_or_default = if let Some(opt) = options { - opt.get_json_string() - .ok()? - .into_bytes_with_nul() - .as_ref() - .to_vec() - } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) - .get_json_string() - .ok()? - .as_ref() - .to_vec() - }; - - let handle = unsafe { - BNLoadFilename( - file_path.as_ptr() as *mut _, - update_analysis_and_wait, - options_or_default.as_ptr() as *mut c_char, - Some(cb_progress_nop), - std::ptr::null_mut(), - ) - }; - - if handle.is_null() { - None - } else { - Some(unsafe { BinaryView::ref_from_raw(handle) }) - } + load_with_options_and_progress( + file_path, + update_analysis_and_wait, + options, + ProgressExecutor::default(), + ) } -pub fn load_with_options_and_progress( +pub fn load_with_options_and_progress( file_path: impl AsRef, update_analysis_and_wait: bool, options: Option, - progress: Option, + progress: impl Into, ) -> Option> where - S: BnStrCompatible, O: IntoJson, - F: FnMut(usize, usize) -> bool, { let file_path = file_path.as_ref().into_bytes_with_nul(); let options_or_default = if let Some(opt) = options { @@ -249,18 +207,13 @@ where .to_vec() }; - let progress_ctx = match progress { - Some(mut x) => &mut x as *mut F as *mut c_void, - None => std::ptr::null_mut(), - }; - let handle = unsafe { BNLoadFilename( file_path.as_ptr() as *mut _, update_analysis_and_wait, options_or_default.as_ptr() as *mut c_char, - Some(cb_progress_func::), - progress_ctx, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; @@ -279,46 +232,22 @@ pub fn load_view( where O: IntoJson, { - let options_or_default = if let Some(opt) = options { - opt.get_json_string() - .ok()? - .into_bytes_with_nul() - .as_ref() - .to_vec() - } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) - .get_json_string() - .ok()? - .as_ref() - .to_vec() - }; - - let handle = unsafe { - BNLoadBinaryView( - bv.handle as *mut _, - update_analysis_and_wait, - options_or_default.as_ptr() as *mut c_char, - Some(cb_progress_nop), - std::ptr::null_mut(), - ) - }; - - if handle.is_null() { - None - } else { - Some(unsafe { BinaryView::ref_from_raw(handle) }) - } + load_view_with_progress( + bv, + update_analysis_and_wait, + options, + ProgressExecutor::default(), + ) } -pub fn load_view_with_progress( +pub fn load_view_with_progress( bv: &BinaryView, update_analysis_and_wait: bool, options: Option, - progress: Option, + progress: impl Into, ) -> Option> where O: IntoJson, - F: FnMut(usize, usize) -> bool, { let options_or_default = if let Some(opt) = options { opt.get_json_string() @@ -334,18 +263,13 @@ where .to_vec() }; - let progress_ctx = match progress { - Some(mut x) => &mut x as *mut F as *mut c_void, - None => std::ptr::null_mut(), - }; - let handle = unsafe { BNLoadBinaryView( bv.handle as *mut _, update_analysis_and_wait, options_or_default.as_ptr() as *mut c_char, - Some(cb_progress_func::), - progress_ctx, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; @@ -635,22 +559,6 @@ pub fn add_optional_plugin_dependency(name: S) { }; } -unsafe extern "C" fn cb_progress_func bool>( - ctxt: *mut c_void, - progress: usize, - total: usize, -) -> bool { - if ctxt.is_null() { - return true; - } - let closure = &mut *(ctxt as *mut F); - closure(progress, total) -} - -unsafe extern "C" fn cb_progress_nop(_ctxt: *mut c_void, _arg1: usize, _arg2: usize) -> bool { - true -} - // Provide ABI version automatically so that the core can verify binary compatibility #[cfg(not(feature = "no_exports"))] #[no_mangle] diff --git a/rust/src/linearview.rs b/rust/src/linear_view.rs similarity index 99% rename from rust/src/linearview.rs rename to rust/src/linear_view.rs index 0590410b9..e133ce0f0 100644 --- a/rust/src/linearview.rs +++ b/rust/src/linear_view.rs @@ -16,7 +16,7 @@ use binaryninjacore_sys::*; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::disassembly::{DisassemblySettings, DisassemblyTextLine}; use crate::function::Function; diff --git a/rust/src/lowlevelil.rs b/rust/src/low_level_il.rs similarity index 100% rename from rust/src/lowlevelil.rs rename to rust/src/low_level_il.rs diff --git a/rust/src/lowlevelil/block.rs b/rust/src/low_level_il/block.rs similarity index 98% rename from rust/src/lowlevelil/block.rs rename to rust/src/low_level_il/block.rs index 51a732d05..057fe8569 100644 --- a/rust/src/lowlevelil/block.rs +++ b/rust/src/low_level_il/block.rs @@ -16,7 +16,7 @@ use std::fmt::Debug; use std::ops::Range; use crate::architecture::Architecture; -use crate::basicblock::{BasicBlock, BlockContext}; +use crate::basic_block::{BasicBlock, BlockContext}; use super::*; diff --git a/rust/src/lowlevelil/expression.rs b/rust/src/low_level_il/expression.rs similarity index 99% rename from rust/src/lowlevelil/expression.rs rename to rust/src/low_level_il/expression.rs index 33c3eba44..95a31da79 100644 --- a/rust/src/lowlevelil/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -36,10 +36,11 @@ pub trait ExpressionResultType: 'static {} impl ExpressionResultType for ValueExpr {} impl ExpressionResultType for VoidExpr {} +#[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct LowLevelILExpressionIndex(pub usize); +pub struct LowLevelExpressionIndex(pub usize); -impl Display for LowLevelILExpressionIndex { +impl Display for LowLevelExpressionIndex { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{}", self.0)) } @@ -67,7 +68,7 @@ where R: ExpressionResultType, { pub(crate) function: &'func LowLevelILFunction, - pub index: LowLevelILExpressionIndex, + pub index: LowLevelExpressionIndex, // tag the 'return' type of this expression pub(crate) _ty: PhantomData, @@ -82,7 +83,7 @@ where { pub(crate) fn new( function: &'func LowLevelILFunction, - index: LowLevelILExpressionIndex, + index: LowLevelExpressionIndex, ) -> Self { // TODO: Validate expression here? Self { diff --git a/rust/src/lowlevelil/function.rs b/rust/src/low_level_il/function.rs similarity index 98% rename from rust/src/lowlevelil/function.rs rename to rust/src/low_level_il/function.rs index 56cd91a1a..fea467d00 100644 --- a/rust/src/lowlevelil/function.rs +++ b/rust/src/low_level_il/function.rs @@ -23,9 +23,9 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use crate::architecture::CoreArchitecture; -use crate::basicblock::BasicBlock; +use crate::basic_block::BasicBlock; use crate::function::Function; -use crate::lowlevelil::block::LowLevelILBlock; +use crate::low_level_il::block::LowLevelILBlock; use crate::rc::*; use super::*; diff --git a/rust/src/lowlevelil/instruction.rs b/rust/src/low_level_il/instruction.rs similarity index 99% rename from rust/src/lowlevelil/instruction.rs rename to rust/src/low_level_il/instruction.rs index a96107651..bd54c1597 100644 --- a/rust/src/lowlevelil/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -23,6 +23,7 @@ use std::fmt::{Debug, Display, Formatter}; use super::VisitorAction; +#[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct LowLevelInstructionIndex(pub usize); @@ -299,7 +300,7 @@ where // The conversion from instruction index to expression index is safe here. _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new( function, - LowLevelILExpressionIndex(index.0), + LowLevelExpressionIndex(index.0), )), } } diff --git a/rust/src/lowlevelil/lifting.rs b/rust/src/low_level_il/lifting.rs similarity index 97% rename from rust/src/lowlevelil/lifting.rs rename to rust/src/low_level_il/lifting.rs index ff2d6dbf5..0803d41d9 100644 --- a/rust/src/lowlevelil/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -487,7 +487,7 @@ where ) }; - LowLevelILExpression::new(il, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(il, LowLevelExpressionIndex(expr_idx)) } pub fn get_default_flag_cond_llil<'func, A>( @@ -510,7 +510,7 @@ where il.handle, ); - LowLevelILExpression::new(il, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(il, LowLevelExpressionIndex(expr_idx)) } } @@ -669,7 +669,7 @@ impl<'a, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> ) -> MutableLiftedILExpr<'a, A, Self::Result> { #[cfg(debug_assertions)] { - use crate::lowlevelil::ExpressionHandler; + use crate::low_level_il::ExpressionHandler; if let Some(expr_size) = expr.kind().size() { if expr_size != _size { log::warn!( @@ -763,7 +763,7 @@ where ) }; - LowLevelILExpression::new(self.function, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self.function, LowLevelExpressionIndex(expr_idx)) } pub fn with_source_operand( @@ -831,7 +831,7 @@ macro_rules! no_arg_lifter { let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, $op, 0, 0, 0, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } }; } @@ -874,7 +874,7 @@ macro_rules! unsized_unary_op_lifter { BNLowLevelILAddExpr(self.handle, $op, 0, 0, expr.index.0 as u64, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } }; } @@ -1021,7 +1021,7 @@ where pub unsafe fn replace_expression<'a, E: LiftableLowLevelIL<'a, A>>( &'a self, - replaced_expr_index: LowLevelILExpressionIndex, + replaced_expr_index: LowLevelExpressionIndex, replacement: E, ) -> bool { use binaryninjacore_sys::BNReplaceLowLevelILExpr; @@ -1045,7 +1045,7 @@ where let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST, size, 0, val, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn const_ptr_sized( @@ -1059,7 +1059,7 @@ where let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST_PTR, size, 0, val, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn const_ptr( @@ -1078,7 +1078,7 @@ where let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_TRAP, 0, 0, val, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } no_arg_lifter!(unimplemented, LLIL_UNIMPL, ValueExpr); @@ -1122,7 +1122,7 @@ where *true_label = Label::from(raw_true_label); *false_label = Label::from(raw_false_label); - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } // TODO: Wtf are these lifetimes?? @@ -1138,7 +1138,7 @@ where // Update the labels after they have been resolved. *label = Label::from(raw_label); - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn reg>>( @@ -1155,7 +1155,7 @@ where let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, reg.0 as u64, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn reg_split< @@ -1187,7 +1187,7 @@ where ) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn set_reg<'a, R, E>( @@ -1267,7 +1267,7 @@ where BNLowLevelILAddExpr(self.handle, LLIL_FLAG, 0, 0, flag.id().0 as u64, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn flag_cond( @@ -1281,7 +1281,7 @@ where let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG_COND, 0, 0, cond as u64, 0, 0, 0) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn flag_group( @@ -1305,7 +1305,7 @@ where ) }; - LowLevelILExpression::new(self, LowLevelILExpressionIndex(expr_idx)) + LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } pub fn set_flag<'a, E>( @@ -1597,7 +1597,7 @@ pub struct Label { pub resolved: bool, // TODO: This expr_ref is not actually a valid one sometimes... // TODO: We should make these non public and only accessible if resolved is true. - pub expr_ref: LowLevelILExpressionIndex, + pub expr_ref: LowLevelExpressionIndex, // TODO: If this is 7 this label is not valid. pub operand: usize, } @@ -1616,7 +1616,7 @@ impl From for Label { fn from(value: BNLowLevelILLabel) -> Self { Self { resolved: value.resolved, - expr_ref: LowLevelILExpressionIndex(value.ref_), + expr_ref: LowLevelExpressionIndex(value.ref_), operand: value.operand, } } diff --git a/rust/src/lowlevelil/operation.rs b/rust/src/low_level_il/operation.rs similarity index 95% rename from rust/src/lowlevelil/operation.rs rename to rust/src/low_level_il/operation.rs index a1cc1a927..dcc761dd4 100644 --- a/rust/src/lowlevelil/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -193,7 +193,7 @@ where pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } } @@ -272,7 +272,7 @@ where pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[2] as usize), + LowLevelExpressionIndex(self.op.operands[2] as usize), ) } } @@ -315,7 +315,7 @@ where pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } } @@ -351,7 +351,7 @@ where pub fn source_mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } } @@ -387,14 +387,14 @@ where pub fn dest_mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } } @@ -577,7 +577,7 @@ where pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } } @@ -637,7 +637,7 @@ where pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } @@ -688,7 +688,7 @@ where pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } @@ -729,7 +729,7 @@ where pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } } @@ -759,7 +759,7 @@ where pub fn condition(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } @@ -1083,14 +1083,14 @@ where pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } } @@ -1126,21 +1126,21 @@ where pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } pub fn carry(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[2] as usize), + LowLevelExpressionIndex(self.op.operands[2] as usize), ) } } @@ -1177,14 +1177,14 @@ where pub fn high(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } pub fn low(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } @@ -1192,7 +1192,7 @@ where pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[2] as usize), + LowLevelExpressionIndex(self.op.operands[2] as usize), ) } } @@ -1231,7 +1231,7 @@ where pub fn operand(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } } @@ -1266,14 +1266,14 @@ where pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[1] as usize), + LowLevelExpressionIndex(self.op.operands[1] as usize), ) } } @@ -1309,7 +1309,7 @@ where pub fn mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { LowLevelILExpression::new( self.function, - LowLevelILExpressionIndex(self.op.operands[0] as usize), + LowLevelExpressionIndex(self.op.operands[0] as usize), ) } } diff --git a/rust/src/mainthread.rs b/rust/src/mainthread.rs index f7e1466c1..f6fdc7cf3 100644 --- a/rust/src/mainthread.rs +++ b/rust/src/mainthread.rs @@ -12,7 +12,7 @@ pub struct MainThreadActionExecutor { impl MainThreadActionExecutor { unsafe extern "C" fn cb_execute(ctx: *mut c_void) { - let f: Box = Box::from_raw(ctx as *mut MainThreadActionExecutor); + let f: Box = Box::from_raw(ctx as *mut Self); f.execute(); } diff --git a/rust/src/mlil/mod.rs b/rust/src/medium_level_il.rs similarity index 100% rename from rust/src/mlil/mod.rs rename to rust/src/medium_level_il.rs diff --git a/rust/src/mlil/block.rs b/rust/src/medium_level_il/block.rs similarity index 97% rename from rust/src/mlil/block.rs rename to rust/src/medium_level_il/block.rs index c3fa18b08..4cf614fc1 100644 --- a/rust/src/mlil/block.rs +++ b/rust/src/medium_level_il/block.rs @@ -1,4 +1,4 @@ -use crate::basicblock::{BasicBlock, BlockContext}; +use crate::basic_block::{BasicBlock, BlockContext}; use crate::rc::Ref; use std::ops::Range; diff --git a/rust/src/mlil/function.rs b/rust/src/medium_level_il/function.rs similarity index 99% rename from rust/src/mlil/function.rs rename to rust/src/medium_level_il/function.rs index aea2ffbb3..c24f862c0 100644 --- a/rust/src/mlil/function.rs +++ b/rust/src/medium_level_il/function.rs @@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher}; use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelInstructionIndex}; use crate::architecture::CoreArchitecture; -use crate::basicblock::BasicBlock; +use crate::basic_block::BasicBlock; use crate::confidence::Conf; use crate::disassembly::DisassemblySettings; use crate::flowgraph::FlowGraph; diff --git a/rust/src/mlil/instruction.rs b/rust/src/medium_level_il/instruction.rs similarity index 99% rename from rust/src/mlil/instruction.rs rename to rust/src/medium_level_il/instruction.rs index 7fa0ad31a..b929fb58d 100644 --- a/rust/src/mlil/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -6,7 +6,7 @@ use super::lift::*; use super::operation::*; use super::{MediumLevelILBlock, MediumLevelILFunction}; use crate::architecture::{CoreIntrinsic, IntrinsicId}; -use crate::basicblock::BasicBlock; +use crate::basic_block::BasicBlock; use crate::confidence::Conf; use crate::disassembly::InstructionTextToken; use crate::operand_iter::OperandIter; diff --git a/rust/src/mlil/lift.rs b/rust/src/medium_level_il/lift.rs similarity index 100% rename from rust/src/mlil/lift.rs rename to rust/src/medium_level_il/lift.rs diff --git a/rust/src/mlil/operation.rs b/rust/src/medium_level_il/operation.rs similarity index 100% rename from rust/src/mlil/operation.rs rename to rust/src/medium_level_il/operation.rs diff --git a/rust/src/operand_iter.rs b/rust/src/operand_iter.rs index 680ccb241..c5f65a76e 100644 --- a/rust/src/operand_iter.rs +++ b/rust/src/operand_iter.rs @@ -3,8 +3,12 @@ use binaryninjacore_sys::BNGetMediumLevelILByIndex; use binaryninjacore_sys::BNHighLevelILOperation; use binaryninjacore_sys::BNMediumLevelILOperation; -use crate::hlil::{HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex}; -use crate::mlil::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelInstructionIndex}; +use crate::high_level_il::{ + HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex, +}; +use crate::medium_level_il::{ + MediumLevelILFunction, MediumLevelILInstruction, MediumLevelInstructionIndex, +}; use crate::rc::{Ref, RefCountable}; use crate::variable::{SSAVariable, Variable}; diff --git a/rust/src/platform.rs b/rust/src/platform.rs index a192dfa75..f8f00a968 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -14,14 +14,14 @@ //! Contains all information related to the execution environment of the binary, mainly the calling conventions used -use crate::typecontainer::TypeContainer; -use crate::typeparser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult}; +use crate::type_container::TypeContainer; +use crate::type_parser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult}; use crate::{ architecture::{Architecture, CoreArchitecture}, - callingconvention::CallingConvention, + calling_convention::CallingConvention, rc::*, string::*, - typelibrary::TypeLibrary, + type_library::TypeLibrary, types::QualifiedNameAndType, }; use binaryninjacore_sys::*; diff --git a/rust/src/progress.rs b/rust/src/progress.rs new file mode 100644 index 000000000..7a4391162 --- /dev/null +++ b/rust/src/progress.rs @@ -0,0 +1,42 @@ +use std::ffi::c_void; + +pub struct ProgressExecutor { + func: Box bool>, +} + +impl ProgressExecutor { + pub fn new bool + 'static>(func: F) -> Self { + Self { + func: Box::new(func), + } + } + + /// Leak the executor and return an opaque pointer. + pub fn into_raw_context(self) -> *mut c_void { + Box::into_raw(Box::new(self)) as *mut c_void + } + + pub unsafe extern "C" fn cb_execute(ctx: *mut c_void, progress: usize, total: usize) -> bool { + if ctx.is_null() { + return true; + } + let f: Box = Box::from_raw(ctx as *mut Self); + f.execute(progress, total) + } + + pub fn execute(&self, progress: usize, total: usize) -> bool { + (self.func)(progress, total) + } +} + +impl bool + 'static> From for ProgressExecutor { + fn from(func: F) -> Self { + Self::new(func) + } +} + +impl Default for ProgressExecutor { + fn default() -> Self { + Self::new(|_, _| true) + } +} diff --git a/rust/src/project.rs b/rust/src/project.rs index 9ea8ba3cd..49bd32c82 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -1,14 +1,20 @@ +pub mod file; +pub mod folder; + +use std::ffi::c_char; +use std::fmt::Debug; use std::ptr::{null_mut, NonNull}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use std::{ffi, mem}; use binaryninjacore_sys::*; use crate::metadata::Metadata; -use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; +use crate::progress::ProgressExecutor; +use crate::project::file::ProjectFile; +use crate::project::folder::ProjectFolder; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnStrCompatible, BnString}; -#[repr(C)] pub struct Project { handle: NonNull, } @@ -18,14 +24,8 @@ impl Project { Project { handle } } - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNProject) -> &Self { - debug_assert!(!handle.is_null()); - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNProject { - &mut *self.handle.as_ptr() + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) } pub fn all_open() -> Array { @@ -39,35 +39,35 @@ impl Project { /// /// * `path` - Path to the project directory (.bnpr) /// * `name` - Name of the new project - pub fn create(path: P, name: S) -> Self { + pub fn create(path: P, name: S) -> Ref { let path_raw = path.into_bytes_with_nul(); let name_raw = name.into_bytes_with_nul(); let handle = unsafe { BNCreateProject( - path_raw.as_ref().as_ptr() as *const ffi::c_char, - name_raw.as_ref().as_ptr() as *const ffi::c_char, + path_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ref().as_ptr() as *const c_char, ) }; - unsafe { Self::from_raw(NonNull::new(handle).unwrap()) } + unsafe { Self::ref_from_raw(NonNull::new(handle).unwrap()) } } /// Open an existing project /// /// * `path` - Path to the project directory (.bnpr) or project metadata file (.bnpm) - pub fn open_project(path: P) -> Self { + pub fn open_project(path: P) -> Ref { let path_raw = path.into_bytes_with_nul(); - let handle = unsafe { BNOpenProject(path_raw.as_ref().as_ptr() as *const ffi::c_char) }; - unsafe { Self::from_raw(NonNull::new(handle).unwrap()) } + let handle = unsafe { BNOpenProject(path_raw.as_ref().as_ptr() as *const c_char) }; + unsafe { Self::ref_from_raw(NonNull::new(handle).unwrap()) } } /// Check if the project is currently open pub fn is_open(&self) -> bool { - unsafe { BNProjectIsOpen(self.as_raw()) } + unsafe { BNProjectIsOpen(self.handle.as_ptr()) } } /// Open a closed project pub fn open(&self) -> Result<(), ()> { - if unsafe { BNProjectOpen(self.as_raw()) } { + if unsafe { BNProjectOpen(self.handle.as_ptr()) } { Ok(()) } else { Err(()) @@ -76,7 +76,7 @@ impl Project { /// Close a open project pub fn close(&self) -> Result<(), ()> { - if unsafe { BNProjectClose(self.as_raw()) } { + if unsafe { BNProjectClose(self.handle.as_ptr()) } { Ok(()) } else { Err(()) @@ -85,35 +85,43 @@ impl Project { /// Get the unique id of this project pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetId(self.as_raw())) } + unsafe { BnString::from_raw(BNProjectGetId(self.handle.as_ptr())) } } /// Get the path of the project pub fn path(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetPath(self.as_raw())) } + unsafe { BnString::from_raw(BNProjectGetPath(self.handle.as_ptr())) } } /// Get the name of the project pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetName(self.as_raw())) } + unsafe { BnString::from_raw(BNProjectGetName(self.handle.as_ptr())) } } /// Set the name of the project pub fn set_name(&self, value: S) { let value = value.into_bytes_with_nul(); - unsafe { BNProjectSetName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) } + unsafe { + BNProjectSetName( + self.handle.as_ptr(), + value.as_ref().as_ptr() as *const c_char, + ) + } } /// Get the description of the project pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetDescription(self.as_raw())) } + unsafe { BnString::from_raw(BNProjectGetDescription(self.handle.as_ptr())) } } /// Set the description of the project pub fn set_description(&self, value: S) { let value = value.into_bytes_with_nul(); unsafe { - BNProjectSetDescription(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) + BNProjectSetDescription( + self.handle.as_ptr(), + value.as_ref().as_ptr() as *const c_char, + ) } } @@ -121,7 +129,7 @@ impl Project { pub fn query_metadata(&self, key: S) -> Ref { let key = key.into_bytes_with_nul(); let result = unsafe { - BNProjectQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) + BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; unsafe { Metadata::ref_from_raw(result) } } @@ -134,8 +142,8 @@ impl Project { let key_raw = key.into_bytes_with_nul(); unsafe { BNProjectStoreMetadata( - self.as_raw(), - key_raw.as_ref().as_ptr() as *const ffi::c_char, + self.handle.as_ptr(), + key_raw.as_ref().as_ptr() as *const c_char, value.handle, ) } @@ -146,14 +154,14 @@ impl Project { let key_raw = key.into_bytes_with_nul(); unsafe { BNProjectRemoveMetadata( - self.as_raw(), - key_raw.as_ref().as_ptr() as *const ffi::c_char, + self.handle.as_ptr(), + key_raw.as_ref().as_ptr() as *const c_char, ) } } pub fn push_folder(&self, file: &ProjectFolder) { - unsafe { BNProjectPushFolder(self.as_raw(), file.as_raw()) } + unsafe { BNProjectPushFolder(self.handle.as_ptr(), file.handle.as_ptr()) } } /// Recursively create files and folders in the project from a path on disk @@ -166,28 +174,17 @@ impl Project { path: P, parent: Option<&ProjectFolder>, description: D, - ) -> Result + ) -> Result, ()> where P: BnStrCompatible, D: BnStrCompatible, { - let path_raw = path.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - let parent_ptr = parent - .map(|p| unsafe { p.as_raw() as *mut _ }) - .unwrap_or(null_mut()); - - unsafe { - let result = BNProjectCreateFolderFromPath( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, - parent_ptr, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - null_mut(), - Some(cb_progress_func_nop), - ); - Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) - } + self.create_folder_from_path_with_progress( + path, + parent, + description, + ProgressExecutor::default(), + ) } /// Recursively create files and folders in the project from a path on disk @@ -195,36 +192,32 @@ impl Project { /// * `path` - Path to folder on disk /// * `parent` - Parent folder in the project that will contain the new contents /// * `description` - Description for created root folder - /// * `progress_func` - Progress function that will be called - pub fn create_folder_from_path_with_progress( + /// * `progress` - [`ProgressExecutor`] that will be called as the [`ProjectFolder`] is being created + pub fn create_folder_from_path_with_progress( &self, path: P, parent: Option<&ProjectFolder>, description: D, - mut progress_func: F, - ) -> Result + progress: impl Into, + ) -> Result, ()> where P: BnStrCompatible, D: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let path_raw = path.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); - let parent_ptr = parent - .map(|p| unsafe { p.as_raw() as *mut _ }) - .unwrap_or(null_mut()); + let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; unsafe { let result = BNProjectCreateFolderFromPath( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + self.handle.as_ptr(), + path_raw.as_ref().as_ptr() as *const c_char, parent_ptr, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - progress_ctx, - Some(cb_progress_func::), + description_raw.as_ref().as_ptr() as *const c_char, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ); - Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFolder::ref_from_raw(NonNull::new(result).ok_or(())?)) } } @@ -238,24 +231,22 @@ impl Project { parent: Option<&ProjectFolder>, name: N, description: D, - ) -> Result + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, { let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); - let parent_ptr = parent - .map(|p| unsafe { p.as_raw() as *mut _ }) - .unwrap_or(null_mut()); + let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFolder( - self.as_raw(), + self.handle.as_ptr(), parent_ptr, - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, ); - Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFolder::ref_from_raw(NonNull::new(result).ok_or(())?)) } } @@ -271,7 +262,7 @@ impl Project { name: N, description: D, id: I, - ) -> Result + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, @@ -279,26 +270,24 @@ impl Project { { let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); - let parent_ptr = parent - .map(|p| unsafe { p.as_raw() as *mut _ }) - .unwrap_or(null_mut()); + let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); let id_raw = id.into_bytes_with_nul(); unsafe { let result = BNProjectCreateFolderUnsafe( - self.as_raw(), + self.handle.as_ptr(), parent_ptr, - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - id_raw.as_ref().as_ptr() as *const ffi::c_char, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, + id_raw.as_ref().as_ptr() as *const c_char, ); - Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFolder::ref_from_raw(NonNull::new(result).ok_or(())?)) } } /// Get a list of folders in the project pub fn folders(&self) -> Result, ()> { let mut count = 0; - let result = unsafe { BNProjectGetFolders(self.as_raw(), &mut count) }; + let result = unsafe { BNProjectGetFolders(self.handle.as_ptr(), &mut count) }; if result.is_null() { return Err(()); } @@ -307,53 +296,36 @@ impl Project { } /// Retrieve a folder in the project by unique folder `id` - pub fn folder_by_id(&self, id: S) -> Option { + pub fn folder_by_id(&self, id: S) -> Option> { let id_raw = id.into_bytes_with_nul(); - let id_ptr = id_raw.as_ref().as_ptr() as *const ffi::c_char; - - let result = unsafe { BNProjectGetFolderById(self.as_raw(), id_ptr) }; + let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; + let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), id_ptr) }; let handle = NonNull::new(result)?; - Some(unsafe { ProjectFolder::from_raw(handle) }) + Some(unsafe { ProjectFolder::ref_from_raw(handle) }) } - /// Recursively delete a folder from the project + /// Recursively delete a [`ProjectFolder`] from the [`Project`]. /// - /// * `folder` - Folder to delete recursively + /// * `folder` - [`ProjectFolder`] to delete recursively pub fn delete_folder(&self, folder: &ProjectFolder) -> Result<(), ()> { - let result = unsafe { - BNProjectDeleteFolder( - self.as_raw(), - folder.as_raw(), - null_mut(), - Some(cb_progress_func_nop), - ) - }; - if result { - Ok(()) - } else { - Err(()) - } + self.delete_folder_with_progress(folder, ProgressExecutor::default()) } - /// Recursively delete a folder from the project + /// Recursively delete a [`ProjectFolder`] from the [`Project`]. /// - /// * `folder` - Folder to delete recursively - /// * `progress_func` - Progress function that will be called as objects get deleted - pub fn delete_folder_with_progress( + /// * `folder` - [`ProjectFolder`] to delete recursively + /// * `progress` - [`ProgressExecutor`] that will be called as objects get deleted + pub fn delete_folder_with_progress( &self, folder: &ProjectFolder, - mut progress_func: F, - ) -> Result<(), ()> - where - F: FnMut(usize, usize) -> bool, - { - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; + progress: impl Into, + ) -> Result<(), ()> { let result = unsafe { BNProjectDeleteFolder( - self.as_raw(), - folder.as_raw(), - progress_ctx, - Some(cb_progress_func::), + self.handle.as_ptr(), + folder.handle.as_ptr(), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ) }; if result { @@ -364,7 +336,7 @@ impl Project { } pub fn push_file(&self, file: &ProjectFile) { - unsafe { BNProjectPushFile(self.as_raw(), file.as_raw()) } + unsafe { BNProjectPushFile(self.handle.as_ptr(), file.handle.as_ptr()) } } /// Create a file in the project from a path on disk @@ -379,27 +351,19 @@ impl Project { folder: Option<&ProjectFolder>, name: N, description: D, - ) -> Result + ) -> Result, ()> where P: BnStrCompatible, N: BnStrCompatible, D: BnStrCompatible, { - let path_raw = path.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - unsafe { - let result = BNProjectCreateFileFromPath( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - null_mut(), - Some(cb_progress_func_nop), - ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) - } + self.create_file_from_path_with_progress( + path, + folder, + name, + description, + ProgressExecutor::default(), + ) } /// Create a file in the project from a path on disk @@ -408,36 +372,35 @@ impl Project { /// * `folder` - Folder to place the created file in /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file - /// * `progress_func` - Progress function that will be called as the file is being added - pub fn create_file_from_path_with_progress( + /// * `progress` - [`ProgressExecutor`] that will be called as the [`ProjectFile`] is being added + pub fn create_file_from_path_with_progress( &self, path: P, folder: Option<&ProjectFolder>, name: N, description: D, - mut progress_func: F, - ) -> Result + progress: impl Into, + ) -> Result, ()> where P: BnStrCompatible, N: BnStrCompatible, D: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let path_raw = path.into_bytes_with_nul(); let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; + let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFileFromPath( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - progress_ctx, - Some(cb_progress_func::), + self.handle.as_ptr(), + path_raw.as_ref().as_ptr() as *const c_char, + folder_ptr, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } } @@ -457,31 +420,22 @@ impl Project { description: D, id: I, creation_time: SystemTime, - ) -> Result + ) -> Result, ()> where P: BnStrCompatible, N: BnStrCompatible, D: BnStrCompatible, I: BnStrCompatible, { - let path_raw = path.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - let id_raw = id.into_bytes_with_nul(); - unsafe { - let result = BNProjectCreateFileFromPathUnsafe( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - id_raw.as_ref().as_ptr() as *const ffi::c_char, - systime_to_bntime(creation_time).unwrap(), - null_mut(), - Some(cb_progress_func_nop), - ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) - } + self.create_file_from_path_unsafe_with_progress( + path, + folder, + name, + description, + id, + creation_time, + ProgressExecutor::default(), + ) } /// Create a file in the project from a path on disk @@ -492,9 +446,9 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - /// * `progress_func` - Progress function that will be called as the file is being added + /// * `progress` - [`ProgressExecutor`] that will be called as the [`ProjectFile`] is being created #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_from_path_with_progress_unsafe( + pub unsafe fn create_file_from_path_unsafe_with_progress( &self, path: P, folder: Option<&ProjectFolder>, @@ -502,33 +456,32 @@ impl Project { description: D, id: I, creation_time: SystemTime, - mut progress_func: F, - ) -> Result + progress: impl Into, + ) -> Result, ()> where P: BnStrCompatible, N: BnStrCompatible, D: BnStrCompatible, I: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let path_raw = path.into_bytes_with_nul(); let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); let id_raw = id.into_bytes_with_nul(); - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; + let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFileFromPathUnsafe( - self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - id_raw.as_ref().as_ptr() as *const ffi::c_char, + self.handle.as_ptr(), + path_raw.as_ref().as_ptr() as *const c_char, + folder_ptr, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, + id_raw.as_ref().as_ptr() as *const c_char, systime_to_bntime(creation_time).unwrap(), - progress_ctx, - Some(cb_progress_func::), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } } @@ -544,26 +497,18 @@ impl Project { folder: Option<&ProjectFolder>, name: N, description: D, - ) -> Result + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - unsafe { - let result = BNProjectCreateFile( - self.as_raw(), - contents.as_ptr(), - contents.len(), - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - null_mut(), - Some(cb_progress_func_nop), - ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) - } + self.create_file_with_progress( + contents, + folder, + name, + description, + ProgressExecutor::default(), + ) } /// Create a file in the project @@ -572,35 +517,34 @@ impl Project { /// * `folder` - Folder to place the created file in /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file - /// * `progress_func` - Progress function that will be called as the file is being added - pub fn create_file_with_progress( + /// * `progress` - [`ProgressExecutor`] that will be called as the [`ProjectFile`] is being created + pub fn create_file_with_progress( &self, contents: &[u8], folder: Option<&ProjectFolder>, name: N, description: D, - mut progress_func: F, - ) -> Result + progress: impl Into, + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; + let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFile( - self.as_raw(), + self.handle.as_ptr(), contents.as_ptr(), contents.len(), - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - progress_ctx, - Some(cb_progress_func::), + folder_ptr, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } } @@ -620,30 +564,21 @@ impl Project { description: D, id: I, creation_time: SystemTime, - ) -> Result + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, I: BnStrCompatible, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - let id_raw = id.into_bytes_with_nul(); - unsafe { - let result = BNProjectCreateFileUnsafe( - self.as_raw(), - contents.as_ptr(), - contents.len(), - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - id_raw.as_ref().as_ptr() as *const ffi::c_char, - systime_to_bntime(creation_time).unwrap(), - null_mut(), - Some(cb_progress_func_nop), - ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) - } + self.create_file_unsafe_with_progress( + contents, + folder, + name, + description, + id, + creation_time, + ProgressExecutor::default(), + ) } /// Create a file in the project @@ -654,9 +589,9 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - /// * `progress_func` - Progress function that will be called as the file is being added + /// * `progress` - [`ProgressExecutor`] that will be called as the [`ProjectFile`] is being created #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_with_progress_unsafe( + pub unsafe fn create_file_unsafe_with_progress( &self, contents: &[u8], folder: Option<&ProjectFolder>, @@ -664,68 +599,68 @@ impl Project { description: D, id: I, creation_time: SystemTime, - mut progress_func: F, - ) -> Result + progress: impl Into, + ) -> Result, ()> where N: BnStrCompatible, D: BnStrCompatible, I: BnStrCompatible, - F: FnMut(usize, usize) -> bool, { let name_raw = name.into_bytes_with_nul(); let description_raw = description.into_bytes_with_nul(); let id_raw = id.into_bytes_with_nul(); - let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; + let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFileUnsafe( - self.as_raw(), + self.handle.as_ptr(), contents.as_ptr(), contents.len(), - folder.map(|x| x.as_raw() as *mut _).unwrap_or(null_mut()), - name_raw.as_ref().as_ptr() as *const ffi::c_char, - description_raw.as_ref().as_ptr() as *const ffi::c_char, - id_raw.as_ref().as_ptr() as *const ffi::c_char, + folder_ptr, + name_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ref().as_ptr() as *const c_char, + id_raw.as_ref().as_ptr() as *const c_char, systime_to_bntime(creation_time).unwrap(), - progress_ctx, - Some(cb_progress_func::), + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), ); - Ok(ProjectFile::from_raw(NonNull::new(result).ok_or(())?)) + Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } } /// Get a list of files in the project pub fn files(&self) -> Result, ()> { let mut count = 0; - let result = unsafe { BNProjectGetFiles(self.as_raw(), &mut count) }; + let result = unsafe { BNProjectGetFiles(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); Ok(unsafe { Array::new(result, count, ()) }) } /// Retrieve a file in the project by unique `id` - pub fn file_by_id(&self, id: S) -> Option { + pub fn file_by_id(&self, id: S) -> Option> { let id_raw = id.into_bytes_with_nul(); - let id_ptr = id_raw.as_ref().as_ptr() as *const ffi::c_char; + let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; - let result = unsafe { BNProjectGetFileById(self.as_raw(), id_ptr) }; + let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), id_ptr) }; let handle = NonNull::new(result)?; - Some(unsafe { ProjectFile::from_raw(handle) }) + Some(unsafe { ProjectFile::ref_from_raw(handle) }) } /// Retrieve a file in the project by the `path` on disk - pub fn file_by_path(&self, path: S) -> Option { + pub fn file_by_path(&self, path: S) -> Option> { let path_raw = path.into_bytes_with_nul(); - let path_ptr = path_raw.as_ref().as_ptr() as *const ffi::c_char; + let path_ptr = path_raw.as_ref().as_ptr() as *const c_char; - let result = unsafe { BNProjectGetFileByPathOnDisk(self.as_raw(), path_ptr) }; + let result = unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_ptr) }; let handle = NonNull::new(result)?; - Some(unsafe { ProjectFile::from_raw(handle) }) + Some(unsafe { ProjectFile::ref_from_raw(handle) }) } /// Delete a file from the project pub fn delete_file(&self, file: &ProjectFile) -> bool { - unsafe { BNProjectDeleteFile(self.as_raw(), file.as_raw()) } + unsafe { BNProjectDeleteFile(self.handle.as_ptr(), file.handle.as_ptr()) } } + // TODO: Is this even usable? You cant touch the project when taking &mut self... /// A context manager to speed up bulk project operations. /// Project modifications are synced to disk in chunks, /// and the project on disk vs in memory may not agree on state @@ -733,7 +668,7 @@ impl Project { /// /// ```no_run /// # use binaryninja::project::Project; - /// # let project: Project = todo!(); + /// # let mut project: Project = todo!(); /// if let Ok(bulk) = project.bulk_operation() { /// for file in std::fs::read_dir("/bin/").unwrap().into_iter() { /// let file = file.unwrap(); @@ -751,22 +686,40 @@ impl Project { } } -impl Drop for Project { - fn drop(&mut self) { - unsafe { BNFreeProject(self.as_raw()) } +impl Debug for Project { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Project") + .field("id", &self.id()) + .field("name", &self.name()) + .field("description", &self.description()) + .finish() } } -impl Clone for Project { - fn clone(&self) -> Self { - unsafe { Self::from_raw(NonNull::new(BNNewProjectReference(self.as_raw())).unwrap()) } +impl ToOwned for Project { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for Project { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewProjectReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeProject(handle.handle.as_ptr()); } } impl CoreArrayProvider for Project { type Raw = *mut BNProject; type Context = (); - type Wrapped<'a> = &'a Project; + type Wrapped<'a> = Guard<'a, Project>; } unsafe impl CoreArrayProviderInner for Project { @@ -774,18 +727,20 @@ unsafe impl CoreArrayProviderInner for Project { BNFreeProjectList(raw, count) } - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) } } +// TODO: Rename to bulk operation guard? pub struct ProjectBulkOperationLock<'a> { lock: &'a mut Project, } impl<'a> ProjectBulkOperationLock<'a> { pub fn lock(project: &'a mut Project) -> Self { - unsafe { BNProjectBeginBulkOperation(project.as_raw()) }; + unsafe { BNProjectBeginBulkOperation(project.handle.as_ptr()) }; Self { lock: project } } @@ -803,282 +758,7 @@ impl std::ops::Deref for ProjectBulkOperationLock<'_> { impl Drop for ProjectBulkOperationLock<'_> { fn drop(&mut self) { - unsafe { BNProjectEndBulkOperation(self.lock.as_raw()) }; - } -} - -#[repr(transparent)] -pub struct ProjectFolder { - handle: NonNull, -} - -impl ProjectFolder { - pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNProjectFolder) -> &Self { - debug_assert!(!handle.is_null()); - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNProjectFolder { - &mut *self.handle.as_ptr() - } - - /// Get the project that owns this folder - pub fn project(&self) -> Project { - unsafe { - Project::from_raw(NonNull::new(BNProjectFolderGetProject(self.as_raw())).unwrap()) - } - } - - /// Get the unique id of this folder - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetId(self.as_raw())) } - } - - /// Get the name of this folder - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetName(self.as_raw())) } - } - - /// Set the name of this folder - pub fn set_name(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); - unsafe { - BNProjectFolderSetName( - self.as_raw(), - value_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } - } - - /// Get the description of this folder - pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetDescription(self.as_raw())) } - } - - /// Set the description of this folder - pub fn set_description(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); - unsafe { - BNProjectFolderSetDescription( - self.as_raw(), - value_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } - } - - /// Get the folder that contains this folder - pub fn parent(&self) -> Option { - let result = unsafe { BNProjectFolderGetParent(self.as_raw()) }; - NonNull::new(result).map(|handle| unsafe { ProjectFolder::from_raw(handle) }) - } - - /// Set the folder that contains this folder - pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool { - let folder_handle = folder - .map(|x| unsafe { x.as_raw() as *mut _ }) - .unwrap_or(null_mut()); - unsafe { BNProjectFolderSetParent(self.as_raw(), folder_handle) } - } - - /// Recursively export this folder to disk, returns `true' if the export succeeded - /// - /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { - let dest_raw = dest.into_bytes_with_nul(); - unsafe { - BNProjectFolderExport( - self.as_raw(), - dest_raw.as_ref().as_ptr() as *const ffi::c_char, - null_mut(), - Some(cb_progress_func_nop), - ) - } - } - - /// Recursively export this folder to disk, returns `true' if the export succeeded - /// - /// * `dest` - Destination path for the exported contents - /// * `progress_func` - Progress function that will be called as contents are exporting - pub fn export_with_progress(&self, dest: S, mut progress: F) -> bool - where - S: BnStrCompatible, - F: FnMut(usize, usize) -> bool, - { - let dest_raw = dest.into_bytes_with_nul(); - unsafe { - BNProjectFolderExport( - self.as_raw(), - dest_raw.as_ref().as_ptr() as *const ffi::c_char, - &mut progress as *mut _ as *mut ffi::c_void, - Some(cb_progress_func::), - ) - } - } -} - -impl Drop for ProjectFolder { - fn drop(&mut self) { - unsafe { BNFreeProjectFolder(self.as_raw()) } - } -} - -impl Clone for ProjectFolder { - fn clone(&self) -> Self { - unsafe { Self::from_raw(NonNull::new(BNNewProjectFolderReference(self.as_raw())).unwrap()) } - } -} - -impl CoreArrayProvider for ProjectFolder { - type Raw = *mut BNProjectFolder; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for ProjectFolder { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeProjectFolderList(raw, count) - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) - } -} - -#[repr(transparent)] -pub struct ProjectFile { - handle: NonNull, -} - -impl ProjectFile { - pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNProjectFile) -> &Self { - debug_assert!(!handle.is_null()); - mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNProjectFile { - &mut *self.handle.as_ptr() - } - - /// Get the project that owns this file - pub fn project(&self) -> Project { - unsafe { Project::from_raw(NonNull::new(BNProjectFileGetProject(self.as_raw())).unwrap()) } - } - - /// Get the path on disk to this file's contents - pub fn path_on_disk(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetPathOnDisk(self.as_raw())) } - } - - /// Check if this file's contents exist on disk - pub fn exists_on_disk(&self) -> bool { - unsafe { BNProjectFileExistsOnDisk(self.as_raw()) } - } - - /// Get the unique id of this file - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetId(self.as_raw())) } - } - - /// Get the name of this file - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetName(self.as_raw())) } - } - - /// Set the name of this file - pub fn set_name(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); - unsafe { - BNProjectFileSetName( - self.as_raw(), - value_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } - } - - /// Get the description of this file - pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetDescription(self.as_raw())) } - } - - /// Set the description of this file - pub fn set_description(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); - unsafe { - BNProjectFileSetDescription( - self.as_raw(), - value_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } - } - - /// Get the file creation time - pub fn creation_time(&self) -> SystemTime { - systime_from_bntime(unsafe { BNProjectFileGetCreationTimestamp(self.as_raw()) }).unwrap() - } - - /// Get the folder that contains this file - pub fn folder(&self) -> Option { - let result = unsafe { BNProjectFileGetFolder(self.as_raw()) }; - NonNull::new(result).map(|handle| unsafe { ProjectFolder::from_raw(handle) }) - } - - /// Set the folder that contains this file - pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool { - let folder_handle = folder - .map(|x| unsafe { x.as_raw() as *mut _ }) - .unwrap_or(null_mut()); - unsafe { BNProjectFileSetFolder(self.as_raw(), folder_handle) } - } - - /// Export this file to disk, `true' if the export succeeded - /// - /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { - let dest_raw = dest.into_bytes_with_nul(); - unsafe { - BNProjectFileExport( - self.as_raw(), - dest_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } - } -} - -impl Drop for ProjectFile { - fn drop(&mut self) { - unsafe { BNFreeProjectFile(self.as_raw()) } - } -} - -impl Clone for ProjectFile { - fn clone(&self) -> Self { - unsafe { Self::from_raw(NonNull::new(BNNewProjectFileReference(self.as_raw())).unwrap()) } - } -} - -impl CoreArrayProvider for ProjectFile { - type Raw = *mut BNProjectFile; - type Context = (); - type Wrapped<'a> = &'a Self; -} - -unsafe impl CoreArrayProviderInner for ProjectFile { - unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - BNFreeProjectFileList(raw, count) - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe { BNProjectEndBulkOperation(self.lock.handle.as_ptr()) }; } } @@ -1094,23 +774,3 @@ fn systime_to_bntime(time: SystemTime) -> Option { .try_into() .ok() } - -unsafe extern "C" fn cb_progress_func bool>( - ctxt: *mut ffi::c_void, - progress: usize, - total: usize, -) -> bool { - if ctxt.is_null() { - return true; - } - let closure = &mut *(ctxt as *mut F); - closure(progress, total) -} - -unsafe extern "C" fn cb_progress_func_nop( - _ctxt: *mut ffi::c_void, - _progress: usize, - _total: usize, -) -> bool { - true -} diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs new file mode 100644 index 000000000..dfa19a7dc --- /dev/null +++ b/rust/src/project/file.rs @@ -0,0 +1,167 @@ +use crate::project::{systime_from_bntime, Project, ProjectFolder}; +use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use binaryninjacore_sys::{ + BNFreeProjectFile, BNFreeProjectFileList, BNNewProjectFileReference, BNProjectFile, + BNProjectFileExistsOnDisk, BNProjectFileExport, BNProjectFileGetCreationTimestamp, + BNProjectFileGetDescription, BNProjectFileGetFolder, BNProjectFileGetId, BNProjectFileGetName, + BNProjectFileGetPathOnDisk, BNProjectFileGetProject, BNProjectFileSetDescription, + BNProjectFileSetFolder, BNProjectFileSetName, +}; +use std::ffi::c_char; +use std::fmt::Debug; +use std::ptr::{null_mut, NonNull}; +use std::time::SystemTime; + +#[repr(transparent)] +pub struct ProjectFile { + pub(crate) handle: NonNull, +} + +impl ProjectFile { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + /// Get the project that owns this file + pub fn project(&self) -> Ref { + unsafe { + Project::ref_from_raw( + NonNull::new(BNProjectFileGetProject(self.handle.as_ptr())).unwrap(), + ) + } + } + + /// Get the path on disk to this file's contents + pub fn path_on_disk(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFileGetPathOnDisk(self.handle.as_ptr())) } + } + + /// Check if this file's contents exist on disk + pub fn exists_on_disk(&self) -> bool { + unsafe { BNProjectFileExistsOnDisk(self.handle.as_ptr()) } + } + + /// Get the unique id of this file + pub fn id(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFileGetId(self.handle.as_ptr())) } + } + + /// Get the name of this file + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFileGetName(self.handle.as_ptr())) } + } + + /// Set the name of this file + pub fn set_name(&self, value: S) -> bool { + let value_raw = value.into_bytes_with_nul(); + unsafe { + BNProjectFileSetName( + self.handle.as_ptr(), + value_raw.as_ref().as_ptr() as *const c_char, + ) + } + } + + /// Get the description of this file + pub fn description(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFileGetDescription(self.handle.as_ptr())) } + } + + /// Set the description of this file + pub fn set_description(&self, value: S) -> bool { + let value_raw = value.into_bytes_with_nul(); + unsafe { + BNProjectFileSetDescription( + self.handle.as_ptr(), + value_raw.as_ref().as_ptr() as *const c_char, + ) + } + } + + /// Get the file creation time + pub fn creation_time(&self) -> SystemTime { + systime_from_bntime(unsafe { BNProjectFileGetCreationTimestamp(self.handle.as_ptr()) }) + .unwrap() + } + + /// Get the folder that contains this file + pub fn folder(&self) -> Option { + let result = unsafe { BNProjectFileGetFolder(self.handle.as_ptr()) }; + NonNull::new(result).map(|handle| unsafe { ProjectFolder::from_raw(handle) }) + } + + /// Set the folder that contains this file + pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool { + let folder_handle = folder.map(|x| x.handle.as_ptr()).unwrap_or(null_mut()); + unsafe { BNProjectFileSetFolder(self.handle.as_ptr(), folder_handle) } + } + + /// Export this file to disk, `true' if the export succeeded + /// + /// * `dest` - Destination path for the exported contents + pub fn export(&self, dest: S) -> bool { + let dest_raw = dest.into_bytes_with_nul(); + unsafe { + BNProjectFileExport( + self.handle.as_ptr(), + dest_raw.as_ref().as_ptr() as *const c_char, + ) + } + } +} + +impl Debug for ProjectFile { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ProjectFile") + .field("id", &self.id()) + .field("name", &self.name()) + .field("description", &self.description()) + .field("creation_time", &self.creation_time()) + .field("exists_on_disk", &self.exists_on_disk()) + .field("project", &self.project()) + .field("folder", &self.folder()) + .finish() + } +} + +impl ToOwned for ProjectFile { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for ProjectFile { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewProjectFileReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeProjectFile(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for ProjectFile { + type Raw = *mut BNProjectFile; + type Context = (); + type Wrapped<'a> = Guard<'a, Self>; +} + +unsafe impl CoreArrayProviderInner for ProjectFile { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeProjectFileList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs new file mode 100644 index 000000000..01d9f992a --- /dev/null +++ b/rust/src/project/folder.rs @@ -0,0 +1,161 @@ +use crate::progress::ProgressExecutor; +use crate::project::Project; +use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use binaryninjacore_sys::{ + BNFreeProjectFolder, BNFreeProjectFolderList, BNNewProjectFolderReference, BNProjectFolder, + BNProjectFolderExport, BNProjectFolderGetDescription, BNProjectFolderGetId, + BNProjectFolderGetName, BNProjectFolderGetParent, BNProjectFolderGetProject, + BNProjectFolderSetDescription, BNProjectFolderSetName, BNProjectFolderSetParent, +}; +use std::ffi::c_char; +use std::fmt::Debug; +use std::ptr::{null_mut, NonNull}; + +#[repr(transparent)] +pub struct ProjectFolder { + pub(crate) handle: NonNull, +} + +impl ProjectFolder { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) + } + + /// Get the project that owns this folder + pub fn project(&self) -> Project { + unsafe { + Project::from_raw( + NonNull::new(BNProjectFolderGetProject(self.handle.as_ptr())).unwrap(), + ) + } + } + + /// Get the unique id of this folder + pub fn id(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFolderGetId(self.handle.as_ptr())) } + } + + /// Get the name of this folder + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFolderGetName(self.handle.as_ptr())) } + } + + /// Set the name of this folder + pub fn set_name(&self, value: S) -> bool { + let value_raw = value.into_bytes_with_nul(); + unsafe { + BNProjectFolderSetName( + self.handle.as_ptr(), + value_raw.as_ref().as_ptr() as *const c_char, + ) + } + } + + /// Get the description of this folder + pub fn description(&self) -> BnString { + unsafe { BnString::from_raw(BNProjectFolderGetDescription(self.handle.as_ptr())) } + } + + /// Set the description of this folder + pub fn set_description(&self, value: S) -> bool { + let value_raw = value.into_bytes_with_nul(); + unsafe { + BNProjectFolderSetDescription( + self.handle.as_ptr(), + value_raw.as_ref().as_ptr() as *const c_char, + ) + } + } + + /// Get the folder that contains this folder + pub fn parent(&self) -> Option> { + let result = unsafe { BNProjectFolderGetParent(self.handle.as_ptr()) }; + NonNull::new(result).map(|handle| unsafe { ProjectFolder::ref_from_raw(handle) }) + } + + /// Set the folder that contains this folder + pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool { + let folder_handle = folder.map(|x| x.handle.as_ptr()).unwrap_or(null_mut()); + unsafe { BNProjectFolderSetParent(self.handle.as_ptr(), folder_handle) } + } + + // TODO: Take Path? + /// Recursively export this folder to disk, returns `true' if the export succeeded + /// + /// * `dest` - Destination path for the exported contents + pub fn export(&self, dest: S) -> bool { + self.export_with_progress(dest, ProgressExecutor::default()) + } + + // TODO: Take Path? + /// Recursively export this folder to disk, returns `true' if the export succeeded + /// + /// * `dest` - Destination path for the exported contents + /// * `progress` - [`ProgressExecutor`] that will be called as contents are exporting + pub fn export_with_progress(&self, dest: S, progress: impl Into) -> bool + where + S: BnStrCompatible, + { + let dest_raw = dest.into_bytes_with_nul(); + unsafe { + BNProjectFolderExport( + self.handle.as_ptr(), + dest_raw.as_ref().as_ptr() as *const c_char, + progress.into().into_raw_context(), + Some(ProgressExecutor::cb_execute), + ) + } + } +} + +impl Debug for ProjectFolder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ProjectFolder") + .field("id", &self.id()) + .field("name", &self.name()) + .field("description", &self.description()) + .finish() + } +} + +impl ToOwned for ProjectFolder { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for ProjectFolder { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewProjectFolderReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeProjectFolder(handle.handle.as_ptr()); + } +} + +impl CoreArrayProvider for ProjectFolder { + type Raw = *mut BNProjectFolder; + type Context = (); + type Wrapped<'a> = Guard<'a, Self>; +} + +unsafe impl CoreArrayProviderInner for ProjectFolder { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeProjectFolderList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) + } +} diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index 9bc52d23d..8fa9a86b0 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -1,9 +1,9 @@ -use crate::lowlevelil::RegularLowLevelILFunction; +use crate::low_level_il::RegularLowLevelILFunction; use crate::rc::Guard; use crate::string::BnStrCompatible; use crate::{ architecture::CoreArchitecture, - binaryview::BinaryView, + binary_view::BinaryView, rc::{CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}, symbol::Symbol, }; diff --git a/rust/src/section.rs b/rust/src/section.rs index 80ee35cca..1a03ca36d 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -19,7 +19,7 @@ use std::ops::Range; use binaryninjacore_sys::*; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::rc::*; use crate::string::*; @@ -80,7 +80,7 @@ impl Section { /// /// ```no_run /// # use binaryninja::section::Section; - /// # use binaryninja::binaryview::BinaryViewExt; + /// # use binaryninja::binary_view::BinaryViewExt; /// let bv = binaryninja::load("example").unwrap(); /// bv.add_section(Section::builder("example", 0..1024).align(4).entry_size(4)) /// ``` diff --git a/rust/src/segment.rs b/rust/src/segment.rs index 4ab943d7e..c6ad0c347 100644 --- a/rust/src/segment.rs +++ b/rust/src/segment.rs @@ -19,7 +19,7 @@ use std::fmt::{Debug, Formatter}; use std::ops::Range; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::rc::*; fn set_bit(val: u32, bit_mask: u32, new_val: bool) -> u32 { @@ -126,7 +126,7 @@ impl Segment { /// /// ```no_run /// # use binaryninja::segment::Segment; - /// # use binaryninja::binaryview::BinaryViewExt; + /// # use binaryninja::binary_view::BinaryViewExt; /// let bv = binaryninja::load("example").unwrap(); /// bv.add_segment(Segment::builder(0..0x1000).writable(true).readable(true)) /// ``` diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 2462de83d..ac5e58dad 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -18,7 +18,7 @@ pub use binaryninjacore_sys::BNSettingsScope as SettingsScope; use binaryninjacore_sys::*; use std::os::raw::c_char; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::rc::*; use crate::string::{BnStrCompatible, BnString}; diff --git a/rust/src/tags.rs b/rust/src/tags.rs index f0369625c..b378f7edf 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -18,7 +18,7 @@ use binaryninjacore_sys::*; use std::fmt::{Debug, Formatter}; use crate::architecture::CoreArchitecture; -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::function::Function; use crate::rc::*; diff --git a/rust/src/templatesimplifier.rs b/rust/src/template_simplifier.rs similarity index 100% rename from rust/src/templatesimplifier.rs rename to rust/src/template_simplifier.rs diff --git a/rust/src/typearchive.rs b/rust/src/type_archive.rs similarity index 66% rename from rust/src/typearchive.rs rename to rust/src/type_archive.rs index 058c6f446..1930b3372 100644 --- a/rust/src/typearchive.rs +++ b/rust/src/type_archive.rs @@ -1,19 +1,55 @@ use binaryninjacore_sys::*; use std::ffi::{c_char, c_void, CStr}; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::Hash; use std::path::{Path, PathBuf}; use std::ptr::NonNull; -use crate::databuffer::DataBuffer; +use crate::data_buffer::DataBuffer; use crate::metadata::Metadata; use crate::platform::Platform; -use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::progress::ProgressExecutor; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type}; +#[repr(transparent)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct TypeArchiveSnapshotId(pub String); + +impl TypeArchiveSnapshotId { + pub fn unset() -> Self { + Self("".to_string()) + } +} + +impl Display for TypeArchiveSnapshotId { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + +impl CoreArrayProvider for TypeArchiveSnapshotId { + type Raw = *mut c_char; + type Context = (); + type Wrapped<'a> = TypeArchiveSnapshotId; +} + +unsafe impl CoreArrayProviderInner for TypeArchiveSnapshotId { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeStringList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + let str = CStr::from_ptr(*raw).to_str().unwrap().to_string(); + TypeArchiveSnapshotId(str) + } +} + /// Type Archives are a collection of types which can be shared between different analysis /// sessions and are backed by a database file on disk. Their types can be modified, and /// a history of previous versions of types is stored in snapshots in the archive. -#[repr(transparent)] pub struct TypeArchive { handle: NonNull, } @@ -23,31 +59,25 @@ impl TypeArchive { Self { handle } } - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNTypeArchive) -> &Self { - assert!(!handle.is_null()); - std::mem::transmute(handle) - } - - #[allow(clippy::mut_from_ref)] - pub(crate) unsafe fn as_raw(&self) -> &mut BNTypeArchive { - &mut *self.handle.as_ptr() + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) } /// Open the Type Archive at the given path, if it exists. - pub fn open(path: impl AsRef) -> Option { + pub fn open(path: impl AsRef) -> Option> { let raw_path = path.as_ref().into_bytes_with_nul(); let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr() as *const c_char) }; - NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) + NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } /// Create a Type Archive at the given path, returning `None` if it could not be created. /// /// If the file has already been created and is not a valid type archive this will return `None`. - pub fn create(path: impl AsRef, platform: &Platform) -> Option { + pub fn create(path: impl AsRef, platform: &Platform) -> Option> { let raw_path = path.as_ref().into_bytes_with_nul(); let handle = unsafe { BNCreateTypeArchive(raw_path.as_ptr() as *const c_char, platform.handle) }; - NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) + NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } /// Create a Type Archive at the given path and id, returning None if it could not be created. @@ -57,7 +87,7 @@ impl TypeArchive { path: impl AsRef, id: I, platform: &Platform, - ) -> Option { + ) -> Option> { let raw_path = path.as_ref().into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let handle = unsafe { @@ -67,19 +97,19 @@ impl TypeArchive { id.as_ref().as_ptr() as *const c_char, ) }; - NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) + NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } /// Get a reference to the Type Archive with the known id, if one exists. - pub fn lookup_by_id(id: S) -> Option { + pub fn lookup_by_id(id: S) -> Option> { let id = id.into_bytes_with_nul(); let handle = unsafe { BNLookupTypeArchiveById(id.as_ref().as_ptr() as *const c_char) }; - NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) + NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } /// Get the path to the Type Archive's file pub fn path(&self) -> Option { - let result = unsafe { BNGetTypeArchivePath(self.as_raw()) }; + let result = unsafe { BNGetTypeArchivePath(self.handle.as_ptr()) }; match result.is_null() { false => { let bn_res = unsafe { BnString::from_raw(result) }; @@ -91,36 +121,35 @@ impl TypeArchive { /// Get the guid for a Type Archive pub fn id(&self) -> Option { - let result = unsafe { BNGetTypeArchiveId(self.as_raw()) }; + let result = unsafe { BNGetTypeArchiveId(self.handle.as_ptr()) }; (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) } /// Get the associated Platform for a Type Archive pub fn platform(&self) -> Ref { - let result = unsafe { BNGetTypeArchivePlatform(self.as_raw()) }; + let result = unsafe { BNGetTypeArchivePlatform(self.handle.as_ptr()) }; assert!(!result.is_null()); unsafe { Platform::ref_from_raw(result) } } /// Get the id of the current snapshot in the type archive - pub fn current_snapshot_id(&self) -> BnString { - let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.as_raw()) }; + pub fn current_snapshot_id(&self) -> TypeArchiveSnapshotId { + let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + TypeArchiveSnapshotId(unsafe { BnString::from_raw(result) }.to_string()) } /// Revert the type archive's current snapshot to the given snapshot - pub fn set_current_snapshot_id(&self, id: S) { - let id = id.into_bytes_with_nul(); + pub fn set_current_snapshot_id(&self, id: &TypeArchiveSnapshotId) { unsafe { - BNSetTypeArchiveCurrentSnapshot(self.as_raw(), id.as_ref().as_ptr() as *const c_char) + BNSetTypeArchiveCurrentSnapshot(self.handle.as_ptr(), id.0.as_ptr() as *const c_char) } } /// Get a list of every snapshot's id - pub fn all_snapshot_ids(&self) -> Array { + pub fn all_snapshot_ids(&self) -> Array { let mut count = 0; - let result = unsafe { BNGetTypeArchiveAllSnapshotIds(self.as_raw(), &mut count) }; + let result = unsafe { BNGetTypeArchiveAllSnapshotIds(self.handle.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -128,14 +157,13 @@ impl TypeArchive { /// Get the ids of the parents to the given snapshot pub fn get_snapshot_parent_ids( &self, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveSnapshotParentIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -145,14 +173,13 @@ impl TypeArchive { /// Get the ids of the children to the given snapshot pub fn get_snapshot_child_ids( &self, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveSnapshotChildIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -179,7 +206,11 @@ impl TypeArchive { .map(QualifiedNameAndType::into_raw) .collect(); let result = unsafe { - BNAddTypeArchiveTypes(self.as_raw(), new_types_raw.as_ptr(), new_types_raw.len()) + BNAddTypeArchiveTypes( + self.handle.as_ptr(), + new_types_raw.as_ptr(), + new_types_raw.len(), + ) }; for new_type in new_types_raw { QualifiedNameAndType::free_raw(new_type); @@ -192,7 +223,7 @@ impl TypeArchive { /// * `old_name` - Old type name in archive /// * `new_name` - New type name pub fn rename_type(&self, old_name: QualifiedName, new_name: QualifiedName) -> bool { - if let Some(id) = self.get_type_id(old_name, self.current_snapshot_id()) { + if let Some(id) = self.get_type_id(old_name) { self.rename_type_by_id(id, new_name) } else { false @@ -208,7 +239,7 @@ impl TypeArchive { let raw_name = QualifiedName::into_raw(new_name); let result = unsafe { BNRenameTypeArchiveType( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, &raw_name, ) @@ -219,7 +250,7 @@ impl TypeArchive { /// Delete an existing type in the type archive. pub fn delete_type(&self, name: QualifiedName) -> bool { - if let Some(type_id) = self.get_type_id(name, self.current_snapshot_id()) { + if let Some(type_id) = self.get_type_id(name) { self.delete_type_by_id(type_id) } else { false @@ -230,110 +261,138 @@ impl TypeArchive { pub fn delete_type_by_id(&self, id: S) -> bool { let id = id.into_bytes_with_nul(); let result = unsafe { - BNDeleteTypeArchiveType(self.as_raw(), id.as_ref().as_ptr() as *const c_char) + BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; result } + /// Retrieve a stored type in the archive + /// + /// * `name` - Type name + pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { + self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset()) + } + /// Retrieve a stored type in the archive /// /// * `name` - Type name /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_name( + pub fn get_type_by_name_from_snapshot( &self, name: QualifiedName, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); let raw_name = QualifiedName::into_raw(name); let result = unsafe { BNGetTypeArchiveTypeByName( - self.as_raw(), + self.handle.as_ptr(), &raw_name, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, ) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } + /// Retrieve a stored type in the archive by id + /// + /// * `id` - Type id + pub fn get_type_by_id(&self, id: I) -> Option> { + self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + /// Retrieve a stored type in the archive by id /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_id( + pub fn get_type_by_id_from_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let result = unsafe { BNGetTypeArchiveTypeById( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, ) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } + /// Retrieve a type's name by its id + /// + /// * `id` - Type id + pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { + self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + /// Retrieve a type's name by its id /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_name_by_id( + pub fn get_type_name_by_id_from_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> QualifiedName { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let result = unsafe { BNGetTypeArchiveTypeName( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, ) }; QualifiedName::from_owned_raw(result) } + /// Retrieve a type's id by its name + /// + /// * `name` - Type name + pub fn get_type_id(&self, name: QualifiedName) -> Option { + self.get_type_id_from_snapshot(name, &TypeArchiveSnapshotId::unset()) + } + /// Retrieve a type's id by its name /// /// * `name` - Type name /// * `snapshot` - Snapshot id to search for types - pub fn get_type_id( + pub fn get_type_id_from_snapshot( &self, name: QualifiedName, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Option { - let snapshot = snapshot.into_bytes_with_nul(); let raw_name = QualifiedName::into_raw(name); let result = unsafe { BNGetTypeArchiveTypeId( - self.as_raw(), + self.handle.as_ptr(), &raw_name, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, ) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) } + /// Retrieve all stored types in the archive at a snapshot + pub fn get_types_and_ids(&self) -> Array { + self.get_types_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset()) + } + /// Retrieve all stored types in the archive at a snapshot /// /// * `snapshot` - Snapshot id to search for types - pub fn get_types_and_ids( + pub fn get_types_and_ids_from_snapshot( &self, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveTypes( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -341,16 +400,20 @@ impl TypeArchive { unsafe { Array::new(result, count, ()) } } + /// Get a list of all types' ids in the archive at a snapshot + pub fn get_type_ids(&self) -> Array { + self.get_type_ids_from_snapshot(&TypeArchiveSnapshotId::unset()) + } + /// Get a list of all types' ids in the archive at a snapshot /// /// * `snapshot` - Snapshot id to search for types - pub fn get_type_ids(&self, snapshot: S) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn get_type_ids_from_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> Array { let mut count = 0; let result = unsafe { BNGetTypeArchiveTypeIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -358,16 +421,23 @@ impl TypeArchive { unsafe { Array::new(result, count, ()) } } + /// Get a list of all types' names in the archive at a snapshot + pub fn get_type_names(&self) -> Array { + self.get_type_names_from_snapshot(&TypeArchiveSnapshotId::unset()) + } + /// Get a list of all types' names in the archive at a snapshot /// /// * `snapshot` - Snapshot id to search for types - pub fn get_type_names(&self, snapshot: S) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn get_type_names_from_snapshot( + &self, + snapshot: &TypeArchiveSnapshotId, + ) -> Array { let mut count = 0; let result = unsafe { BNGetTypeArchiveTypeNames( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -375,21 +445,25 @@ impl TypeArchive { unsafe { Array::new(result, count, ()) } } - /// Get a list of all types' names and ids in the archive at a current snapshot + /// Get a list of all types' names and ids in the archive at the latest snapshot + pub fn get_type_names_and_ids(&self) -> (Array, Array) { + self.get_type_names_and_ids_from_snapshot(&TypeArchiveSnapshotId::unset()) + } + + /// Get a list of all types' names and ids in the archive at a specific snapshot /// /// * `snapshot` - Snapshot id to search for types - pub fn get_type_names_and_ids( + pub fn get_type_names_and_ids_from_snapshot( &self, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> (Array, Array) { - let snapshot = snapshot.into_bytes_with_nul(); let mut count = 0; let mut names = std::ptr::null_mut(); let mut ids = std::ptr::null_mut(); let result = unsafe { BNGetTypeArchiveTypeNamesAndIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, &mut names, &mut ids, &mut count, @@ -401,23 +475,29 @@ impl TypeArchive { }) } + /// Get all types a given type references directly + /// + /// * `id` - Source type id + pub fn get_outgoing_direct_references(&self, id: I) -> Array { + self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + /// Get all types a given type references directly /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_direct_references( + pub fn get_outgoing_direct_references_from_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingDirectTypeReferences( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -427,21 +507,27 @@ impl TypeArchive { /// Get all types a given type references, and any types that the referenced types reference /// - /// :param id: Source type id - /// :param snapshot: Snapshot id to search for types - pub fn get_outgoing_recursive_references( + /// * `id` - Source type id + pub fn get_outgoing_recursive_references(&self, id: I) -> Array { + self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + + /// Get all types a given type references, and any types that the referenced types reference + /// + /// * `id` - Source type id + /// * `snapshot` - Snapshot id to search for types + pub fn get_outgoing_recursive_references_from_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingRecursiveTypeReferences( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -449,23 +535,29 @@ impl TypeArchive { unsafe { Array::new(result, count, ()) } } + /// Get all types that reference a given type + /// + /// * `id` - Target type id + pub fn get_incoming_direct_references(&self, id: I) -> Array { + self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + /// Get all types that reference a given type /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types - pub fn get_incoming_direct_references( + pub fn get_incoming_direct_references_with_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingDirectTypeReferences( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -473,23 +565,29 @@ impl TypeArchive { unsafe { Array::new(result, count, ()) } } + /// Get all types that reference a given type, and all types that reference them, recursively + /// + /// * `id` - Target type id + pub fn get_incoming_recursive_references(&self, id: I) -> Array { + self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) + } + /// Get all types that reference a given type, and all types that reference them, recursively /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types, or empty string to search the latest snapshot - pub fn get_incoming_recursive_references( + pub fn get_incoming_recursive_references_with_snapshot( &self, id: I, - snapshot: S, + snapshot: &TypeArchiveSnapshotId, ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); let id = id.into_bytes_with_nul(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingRecursiveTypeReferences( - self.as_raw(), + self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char, - snapshot.as_ref().as_ptr() as *const c_char, + snapshot.0.as_ptr() as *const c_char, &mut count, ) }; @@ -501,7 +599,7 @@ impl TypeArchive { pub fn query_metadata(&self, key: S) -> Option> { let key = key.into_bytes_with_nul(); let result = unsafe { - BNTypeArchiveQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const c_char) + BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) } @@ -514,7 +612,7 @@ impl TypeArchive { let key = key.into_bytes_with_nul(); let result = unsafe { BNTypeArchiveStoreMetadata( - self.as_raw(), + self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char, md.handle, ) @@ -526,17 +624,22 @@ impl TypeArchive { pub fn remove_metadata(&self, key: S) -> bool { let key = key.into_bytes_with_nul(); unsafe { - BNTypeArchiveRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const c_char) + BNTypeArchiveRemoveMetadata( + self.handle.as_ptr(), + key.as_ref().as_ptr() as *const c_char, + ) } } /// Turn a given `snapshot` id into a data stream - pub fn serialize_snapshot(&self, snapshot: S) -> DataBuffer { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn serialize_snapshot( + &self, + snapshot: &TypeArchiveSnapshotId, + ) -> DataBuffer { let result = unsafe { BNTypeArchiveSerializeSnapshot( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const c_char, + self.handle.as_ptr(), + snapshot.0.as_ptr() as *const c_char, ) }; assert!(!result.is_null()); @@ -544,10 +647,11 @@ impl TypeArchive { } /// Take a serialized snapshot `data` stream and create a new snapshot from it - pub fn deserialize_snapshot(&self, data: &DataBuffer) -> BnString { - let result = unsafe { BNTypeArchiveDeserializeSnapshot(self.as_raw(), data.as_raw()) }; + pub fn deserialize_snapshot(&self, data: &DataBuffer) -> TypeArchiveSnapshotId { + let result = + unsafe { BNTypeArchiveDeserializeSnapshot(self.handle.as_ptr(), data.as_raw()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + TypeArchiveSnapshotId(unsafe { BnString::from_raw(result) }.to_string()) } /// Register a notification listener @@ -564,10 +668,10 @@ impl TypeArchive { typeRenamed: Some(cb_type_renamed::), typeDeleted: Some(cb_type_deleted::), }; - unsafe { BNRegisterTypeArchiveNotification(self.as_raw(), &mut notification) } + unsafe { BNRegisterTypeArchiveNotification(self.handle.as_ptr(), &mut notification) } TypeArchiveCallbackHandle { callback, - type_archive: self.clone(), + type_archive: self.to_owned(), } } @@ -597,23 +701,23 @@ impl TypeArchive { /// Close a type archive, disconnecting it from any active views and closing /// any open file handles - pub fn close(self) { - unsafe { BNCloseTypeArchive(self.as_raw()) } + pub fn close(&self) { + unsafe { BNCloseTypeArchive(self.handle.as_ptr()) } } + // TODO: Make this AsRef? /// Determine if `file` is a Type Archive pub fn is_type_archive(file: P) -> bool { let file = file.into_bytes_with_nul(); unsafe { BNIsTypeArchive(file.as_ref().as_ptr() as *const c_char) } } - // TODO implement TypeContainer ///// Get the TypeContainer interface for this Type Archive, presenting types ///// at the current snapshot in the archive. - //pub fn type_container(&self) -> TypeContainer { - // let result = unsafe { BNGetTypeArchiveTypeContainer(self.as_raw()) }; - // unsafe { TypeContainer::from_raw(NonNull::new(result).unwrap()) } - //} + pub fn type_container(&self) -> TypeContainer { + let result = unsafe { BNGetTypeArchiveTypeContainer(self.handle.as_ptr()) }; + unsafe { TypeContainer::from_raw(NonNull::new(result).unwrap()) } + } /// Do some function in a transaction making a new snapshot whose id is passed to func. If func throws, /// the transaction will be rolled back and the snapshot will not be created. @@ -622,25 +726,30 @@ impl TypeArchive { /// * `parents` - Parent snapshot ids /// /// Returns Created snapshot id - pub fn new_snapshot_transaction(&self, mut function: F, parents: &[BnString]) -> BnString + pub fn new_snapshot_transaction( + &self, + mut function: F, + parents: &[TypeArchiveSnapshotId], + ) -> TypeArchiveSnapshotId where P: BnStrCompatible, - F: FnMut(&str) -> bool, + F: FnMut(&TypeArchiveSnapshotId) -> bool, { - unsafe extern "C" fn cb_callback bool>( + unsafe extern "C" fn cb_callback bool>( ctxt: *mut c_void, id: *const c_char, ) -> bool { let fun: &mut F = &mut *(ctxt as *mut F); - fun(&CStr::from_ptr(id).to_string_lossy()) + let id_str = raw_to_string(id).unwrap(); + fun(&TypeArchiveSnapshotId(id_str)) } - // SAFETY BnString and `*const c_char` are transparent + // SAFETY TypeArchiveSnapshotId and `*const c_char` are transparent let parents_raw = parents.as_ptr() as *const *const c_char; let result = unsafe { BNTypeArchiveNewSnapshotTransaction( - self.as_raw(), + self.handle.as_ptr(), Some(cb_callback::), &mut function as *mut F as *mut c_void, parents_raw, @@ -648,7 +757,8 @@ impl TypeArchive { ) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + let id_str = unsafe { BnString::from_raw(result) }; + TypeArchiveSnapshotId(id_str.to_string()) } /// Merge two snapshots in the archive to produce a new snapshot @@ -661,32 +771,56 @@ impl TypeArchive { /// /// Returns Snapshot id, if merge was successful, otherwise the List of /// conflicting type ids - pub fn merge_snapshots( + pub fn merge_snapshots( &self, base_snapshot: B, first_snapshot: F, second_snapshot: S, merge_conflicts: M, - mut progress: P, ) -> Result> where B: BnStrCompatible, F: BnStrCompatible, S: BnStrCompatible, - P: FnMut(usize, usize) -> bool, M: IntoIterator, MI: BnStrCompatible, MK: BnStrCompatible, { - unsafe extern "C" fn cb_callback bool>( - ctxt: *mut c_void, - progress: usize, - total: usize, - ) -> bool { - let ctxt: &mut F = &mut *(ctxt as *mut F); - ctxt(progress, total) - } + self.merge_snapshots_with_progress( + base_snapshot, + first_snapshot, + second_snapshot, + merge_conflicts, + ProgressExecutor::default(), + ) + } + /// Merge two snapshots in the archive to produce a new snapshot + /// + /// * `base_snapshot` - Common ancestor of snapshots + /// * `first_snapshot` - First snapshot to merge + /// * `second_snapshot` - Second snapshot to merge + /// * `merge_conflicts` - List of all conflicting types, id <-> target snapshot + /// * `progress` - Function to call for progress updates + /// + /// Returns Snapshot id, if merge was successful, otherwise the List of + /// conflicting type ids + pub fn merge_snapshots_with_progress( + &self, + base_snapshot: B, + first_snapshot: F, + second_snapshot: S, + merge_conflicts: M, + progress: impl Into, + ) -> Result> + where + B: BnStrCompatible, + F: BnStrCompatible, + S: BnStrCompatible, + M: IntoIterator, + MI: BnStrCompatible, + MK: BnStrCompatible, + { let base_snapshot = base_snapshot.into_bytes_with_nul(); let first_snapshot = first_snapshot.into_bytes_with_nul(); let second_snapshot = second_snapshot.into_bytes_with_nul(); @@ -705,7 +839,7 @@ impl TypeArchive { let success = unsafe { BNTypeArchiveMergeSnapshots( - self.as_raw(), + self.handle.as_ptr(), base_snapshot.as_ref().as_ptr() as *const c_char, first_snapshot.as_ref().as_ptr() as *const c_char, second_snapshot.as_ref().as_ptr() as *const c_char, @@ -715,8 +849,8 @@ impl TypeArchive { &mut conflicts_errors, &mut conflicts_errors_count, &mut result, - Some(cb_callback::

), - (&mut progress) as *mut P as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; if success { @@ -729,15 +863,23 @@ impl TypeArchive { } } -impl Drop for TypeArchive { - fn drop(&mut self) { - unsafe { BNFreeTypeArchiveReference(self.as_raw()) } +impl ToOwned for TypeArchive { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } -impl Clone for TypeArchive { - fn clone(&self) -> Self { - unsafe { Self::from_raw(NonNull::new(BNNewTypeArchiveReference(self.as_raw())).unwrap()) } +unsafe impl RefCountable for TypeArchive { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewTypeArchiveReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeTypeArchiveReference(handle.handle.as_ptr()); } } @@ -748,13 +890,13 @@ impl PartialEq for TypeArchive { } impl Eq for TypeArchive {} -impl core::hash::Hash for TypeArchive { +impl Hash for TypeArchive { fn hash(&self, state: &mut H) { (self.handle.as_ptr() as usize).hash(state); } } -impl core::fmt::Debug for TypeArchive { +impl Debug for TypeArchive { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TypeArchive") .field("id", &self.id()) @@ -768,7 +910,7 @@ impl core::fmt::Debug for TypeArchive { impl CoreArrayProvider for TypeArchive { type Raw = *mut BNTypeArchive; type Context = (); - type Wrapped<'a> = &'a TypeArchive; + type Wrapped<'a> = Guard<'a, TypeArchive>; } unsafe impl CoreArrayProviderInner for TypeArchive { @@ -776,14 +918,15 @@ unsafe impl CoreArrayProviderInner for TypeArchive { BNFreeTypeArchiveList(raw, count) } - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + let raw_ptr = NonNull::new(*raw).unwrap(); + Guard::new(Self::from_raw(raw_ptr), context) } } pub struct TypeArchiveCallbackHandle { callback: *mut T, - type_archive: TypeArchive, + type_archive: Ref, } impl Drop for TypeArchiveCallbackHandle { @@ -797,7 +940,10 @@ impl Drop for TypeArchiveCallbackHandle { }; // unregister the notification callback unsafe { - BNUnregisterTypeArchiveNotification(self.type_archive.as_raw(), &mut notification) + BNUnregisterTypeArchiveNotification( + self.type_archive.handle.as_ptr(), + &mut notification, + ) } // free the context created at [TypeArchive::register_notification_callback] drop(unsafe { Box::from_raw(self.callback) }); @@ -906,8 +1052,10 @@ unsafe extern "C" fn cb_type_added( definition: *mut BNType, ) { let ctxt: &mut T = &mut *(ctxt as *mut T); + // `archive` is owned by the caller. + let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) }; ctxt.type_added( - unsafe { TypeArchive::ref_from_raw(&archive) }, + &archive, unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() }, &Type { handle: definition }, ) @@ -920,8 +1068,10 @@ unsafe extern "C" fn cb_type_updated( new_definition: *mut BNType, ) { let ctxt: &mut T = &mut *(ctxt as *mut T); + // `archive` is owned by the caller. + let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) }; ctxt.type_updated( - unsafe { TypeArchive::ref_from_raw(&archive) }, + &archive, unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() }, &Type { handle: old_definition, @@ -943,8 +1093,10 @@ unsafe extern "C" fn cb_type_renamed( let old_name = QualifiedName::from_raw(&*old_name); // `new_name` is freed by the caller let new_name = QualifiedName::from_raw(&*new_name); + // `archive` is owned by the caller. + let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) }; ctxt.type_renamed( - unsafe { TypeArchive::ref_from_raw(&archive) }, + &archive, unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() }, &old_name, &new_name, @@ -957,8 +1109,10 @@ unsafe extern "C" fn cb_type_deleted( definition: *mut BNType, ) { let ctxt: &mut T = &mut *(ctxt as *mut T); + // `archive` is owned by the caller. + let archive = unsafe { TypeArchive::from_raw(NonNull::new(archive).unwrap()) }; ctxt.type_deleted( - unsafe { TypeArchive::ref_from_raw(&archive) }, + &archive, unsafe { CStr::from_ptr(id).to_string_lossy().as_ref() }, &Type { handle: definition }, ) diff --git a/rust/src/typecontainer.rs b/rust/src/type_container.rs similarity index 89% rename from rust/src/typecontainer.rs rename to rust/src/type_container.rs index 6a6170779..1aa578804 100644 --- a/rust/src/typecontainer.rs +++ b/rust/src/type_container.rs @@ -9,13 +9,14 @@ // * [DebugInfo::get_type_container] use crate::platform::Platform; +use crate::progress::ProgressExecutor; use crate::rc::{Array, Ref}; use crate::string::{raw_to_string, BnStrCompatible, BnString}; -use crate::typeparser::{TypeParserError, TypeParserResult}; +use crate::type_parser::{TypeParserError, TypeParserResult}; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; use std::collections::HashMap; -use std::ffi::{c_char, c_void}; +use std::ffi::c_char; use std::fmt::{Debug, Formatter}; use std::ptr::NonNull; @@ -84,49 +85,17 @@ impl TypeContainer { I: IntoIterator, T: Into, { - // TODO: I dislike how this iter unzip looks like... but its how to avoid allocating again... - let (raw_names, mut raw_types): (Vec, Vec<_>) = types - .into_iter() - .map(|t| { - let t = t.into(); - // Leaked to be freed after the call to core. - ( - QualifiedName::into_raw(t.name), - unsafe { Ref::into_raw(t.ty) }.handle, - ) - }) - .unzip(); - - let mut result_names = std::ptr::null_mut(); - let mut result_ids = std::ptr::null_mut(); - let mut result_count = 0; - let success = unsafe { - BNTypeContainerAddTypes( - self.handle.as_ptr(), - raw_names.as_ptr(), - raw_types.as_mut_ptr(), - raw_types.len(), - Some(cb_progress_nop), - std::ptr::null_mut(), - &mut result_names, - &mut result_ids, - &mut result_count, - ) - }; - for name in raw_names { - QualifiedName::free_raw(name); - } - for ty in raw_types { - let _ = unsafe { Type::ref_from_raw(ty) }; - } - success + self.add_types_with_progress(types, ProgressExecutor::default()) } - pub fn add_types_with_progress(&self, types: I, mut progress: F) -> bool + pub fn add_types_with_progress( + &self, + types: I, + progress: impl Into, + ) -> bool where I: IntoIterator, T: Into, - F: FnMut(usize, usize) -> bool, { // TODO: I dislike how this iter unzip looks like... but its how to avoid allocating again... let (raw_names, mut raw_types): (Vec, Vec<_>) = types @@ -150,8 +119,8 @@ impl TypeContainer { raw_names.as_ptr(), raw_types.as_mut_ptr(), raw_types.len(), - Some(cb_progress::), - &mut progress as *mut F as *mut c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), &mut result_names, &mut result_ids, &mut result_count, @@ -469,20 +438,3 @@ impl Clone for TypeContainer { } } } - -unsafe extern "C" fn cb_progress_nop( - _ctxt: *mut ::std::os::raw::c_void, - _progress: usize, - _total: usize, -) -> bool { - true -} - -unsafe extern "C" fn cb_progress bool>( - ctxt: *mut ::std::os::raw::c_void, - progress: usize, - total: usize, -) -> bool { - let ctxt = &mut *(ctxt as *mut F); - ctxt(progress, total) -} diff --git a/rust/src/typelibrary.rs b/rust/src/type_library.rs similarity index 100% rename from rust/src/typelibrary.rs rename to rust/src/type_library.rs diff --git a/rust/src/typeparser.rs b/rust/src/type_parser.rs similarity index 99% rename from rust/src/typeparser.rs rename to rust/src/type_parser.rs index 7d597ea46..656f0c9d4 100644 --- a/rust/src/typeparser.rs +++ b/rust/src/type_parser.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::string::{raw_to_string, BnStrCompatible, BnString}; -use crate::typecontainer::TypeContainer; +use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity; diff --git a/rust/src/typeprinter.rs b/rust/src/type_printer.rs similarity index 99% rename from rust/src/typeprinter.rs rename to rust/src/type_printer.rs index a5c75bf06..93c9cbe43 100644 --- a/rust/src/typeprinter.rs +++ b/rust/src/type_printer.rs @@ -1,11 +1,11 @@ #![allow(unused)] -use crate::binaryview::BinaryView; +use crate::binary_view::BinaryView; use crate::disassembly::InstructionTextToken; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::string::{raw_to_string, BnStrCompatible, BnString}; -use crate::typecontainer::TypeContainer; +use crate::type_container::TypeContainer; use crate::types::{NamedTypeReference, QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; use std::ffi::{c_char, c_int, c_void}; diff --git a/rust/src/types.rs b/rust/src/types.rs index 8345f3a87..e7f2eb019 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -21,8 +21,8 @@ use binaryninjacore_sys::*; use crate::{ architecture::{Architecture, CoreArchitecture}, - binaryview::{BinaryView, BinaryViewExt}, - callingconvention::CallingConvention, + binary_view::{BinaryView, BinaryViewExt}, + calling_convention::CallingConvention, rc::*, string::{BnStrCompatible, BnString}, }; @@ -447,7 +447,7 @@ pub struct Type { } /// ```no_run -/// # use crate::binaryninja::binaryview::BinaryViewExt; +/// # use crate::binaryninja::binary_view::BinaryViewExt; /// # use binaryninja::types::Type; /// let bv = binaryninja::load("example.bin").unwrap(); /// let my_custom_type_1 = Type::named_int(5, false, "my_w"); @@ -1353,7 +1353,7 @@ pub struct StructureBuilder { /// ```no_run /// // Includes -/// # use binaryninja::binaryview::BinaryViewExt; +/// # use binaryninja::binary_view::BinaryViewExt; /// use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureBuilder, Type}; /// /// // Types to use in the members diff --git a/rust/src/update.rs b/rust/src/update.rs index 31e02cd81..85f5002dd 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -1,30 +1,88 @@ -use core::{ffi, mem, ptr}; +#![allow(dead_code)] +use std::ffi::c_char; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use binaryninjacore_sys::*; - +use crate::progress::ProgressExecutor; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::BnString; +use crate::string::{raw_to_string, BnString}; +use binaryninjacore_sys::*; pub type UpdateResult = BNUpdateResult; -#[repr(C)] +pub fn auto_updates_enabled() -> bool { + unsafe { BNAreAutoUpdatesEnabled() } +} + +pub fn set_auto_updates_enabled(enabled: bool) { + unsafe { BNSetAutoUpdatesEnabled(enabled) } +} + +pub fn time_since_last_update_check() -> Duration { + Duration::from_secs(unsafe { BNGetTimeSinceLastUpdateCheck() }) +} + +/// Whether an update has been downloaded and is waiting installation +pub fn is_update_installation_pending() -> bool { + unsafe { BNIsUpdateInstallationPending() } +} + +/// Installs any pending updates +pub fn install_pending_update() -> Result<(), BnString> { + let mut errors = std::ptr::null_mut(); + unsafe { BNInstallPendingUpdate(&mut errors) }; + if !errors.is_null() { + Err(unsafe { BnString::from_raw(errors) }) + } else { + Ok(()) + } +} + +pub fn updates_checked() { + unsafe { BNUpdatesChecked() } +} + +#[derive(Clone, Debug)] pub struct UpdateChannel { - pub name: BnString, - pub description: BnString, - pub latest_version: BnString, - // NOTE don't allow the user to create his own UpdateChannel - _lock: core::marker::PhantomData<()>, + pub name: String, + pub description: String, + pub latest_version: String, } impl UpdateChannel { - pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateChannel) -> &Self { - mem::transmute(handle) + pub(crate) fn from_raw(value: &BNUpdateChannel) -> Self { + Self { + name: raw_to_string(value.name as *mut _).unwrap(), + description: raw_to_string(value.description as *mut _).unwrap(), + latest_version: raw_to_string(value.latestVersion as *mut _).unwrap(), + } + } + + pub(crate) fn from_owned_raw(value: BNUpdateChannel) -> Self { + let owned = Self::from_raw(&value); + Self::free_raw(value); + owned + } + + pub(crate) fn into_raw(value: Self) -> BNUpdateChannel { + let bn_name = BnString::new(value.name); + let bn_description = BnString::new(value.description); + let bn_latest_version = BnString::new(value.latest_version); + BNUpdateChannel { + name: BnString::into_raw(bn_name), + description: BnString::into_raw(bn_description), + latestVersion: BnString::into_raw(bn_latest_version), + } + } + + pub(crate) fn free_raw(value: BNUpdateChannel) { + let _ = unsafe { BnString::from_raw(value.name) }; + let _ = unsafe { BnString::from_raw(value.description) }; + let _ = unsafe { BnString::from_raw(value.latestVersion) }; } pub fn all() -> Result, BnString> { let mut count = 0; - let mut errors = ptr::null_mut(); + let mut errors = std::ptr::null_mut(); let result = unsafe { BNGetUpdateChannels(&mut count, &mut errors) }; if !errors.is_null() { Err(unsafe { BnString::from_raw(errors) }) @@ -37,9 +95,10 @@ impl UpdateChannel { /// List of versions pub fn versions(&self) -> Result, BnString> { let mut count = 0; - let mut errors = ptr::null_mut(); - let result = - unsafe { BNGetUpdateChannelVersions(self.name.as_ptr(), &mut count, &mut errors) }; + let mut errors = std::ptr::null_mut(); + let result = unsafe { + BNGetUpdateChannelVersions(self.name.as_ptr() as *const c_char, &mut count, &mut errors) + }; if !errors.is_null() { Err(unsafe { BnString::from_raw(errors) }) } else { @@ -54,20 +113,20 @@ impl UpdateChannel { let versions = self.versions()?; for version in &versions { if &version.version == last_version { - return Ok(version.clone()); + return Ok(version); } } - panic!(); + Err(BnString::new("Could not find latest version")) } /// Whether updates are available pub fn updates_available(&self) -> Result { - let mut errors = ptr::null_mut(); + let mut errors = std::ptr::null_mut(); let result = unsafe { BNAreUpdatesAvailable( - self.name.as_ptr(), - ptr::null_mut(), - ptr::null_mut(), + self.name.as_ptr() as *const c_char, + std::ptr::null_mut(), + std::ptr::null_mut(), &mut errors, ) }; @@ -79,36 +138,20 @@ impl UpdateChannel { } pub fn update_to_latest(&self) -> Result { - let mut errors = ptr::null_mut(); - let result = unsafe { - BNUpdateToLatestVersion( - self.name.as_ptr(), - &mut errors, - Some(cb_progress_nop), - ptr::null_mut(), - ) - }; - if !errors.is_null() { - Err(unsafe { BnString::from_raw(errors) }) - } else { - Ok(result) - } + self.update_to_latest_with_progress(ProgressExecutor::default()) } - pub fn update_to_latest_with_progress( + pub fn update_to_latest_with_progress( &self, - mut progress: F, - ) -> Result - where - F: FnMut(usize, usize) -> bool, - { - let mut errors = ptr::null_mut(); + progress: impl Into, + ) -> Result { + let mut errors = std::ptr::null_mut(); let result = unsafe { BNUpdateToLatestVersion( - self.name.as_ptr(), + self.name.as_ptr() as *const c_char, &mut errors, - Some(cb_progress::), - &mut progress as *mut _ as *mut ffi::c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; if !errors.is_null() { @@ -119,39 +162,22 @@ impl UpdateChannel { } pub fn update(&self, version: &UpdateVersion) -> Result { - let mut errors = ptr::null_mut(); - let result = unsafe { - BNUpdateToVersion( - self.name.as_ptr(), - version.version.as_ptr(), - &mut errors, - Some(cb_progress_nop), - ptr::null_mut(), - ) - }; - if !errors.is_null() { - Err(unsafe { BnString::from_raw(errors) }) - } else { - Ok(result) - } + self.update_with_progress(version, ProgressExecutor::default()) } - pub fn update_with_progress( + pub fn update_with_progress( &self, version: &UpdateVersion, - mut progress: F, - ) -> Result - where - F: FnMut(usize, usize) -> bool, - { - let mut errors = ptr::null_mut(); + progress: impl Into, + ) -> Result { + let mut errors = std::ptr::null_mut(); let result = unsafe { BNUpdateToVersion( - self.name.as_ptr(), - version.version.as_ptr(), + self.name.as_ptr() as *const c_char, + version.version.as_ptr() as *const c_char, &mut errors, - Some(cb_progress::), - &mut progress as *mut _ as *mut ffi::c_void, + Some(ProgressExecutor::cb_execute), + progress.into().into_raw_context(), ) }; if !errors.is_null() { @@ -165,7 +191,7 @@ impl UpdateChannel { impl CoreArrayProvider for UpdateChannel { type Raw = BNUpdateChannel; type Context = (); - type Wrapped<'a> = &'a Self; + type Wrapped<'a> = Self; } unsafe impl CoreArrayProviderInner for UpdateChannel { @@ -174,39 +200,53 @@ unsafe impl CoreArrayProviderInner for UpdateChannel { } unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - UpdateChannel::ref_from_raw(raw) + UpdateChannel::from_raw(raw) } } -#[repr(C)] #[derive(Clone)] pub struct UpdateVersion { - pub version: BnString, - pub notes: BnString, - time: u64, - // NOTE don't allow the user to create his own UpdateVersion - _lock: core::marker::PhantomData<()>, + pub version: String, + pub notes: String, + pub time: SystemTime, } impl UpdateVersion { - pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateVersion) -> &Self { - mem::transmute(handle) + pub(crate) fn from_raw(value: &BNUpdateVersion) -> Self { + Self { + version: raw_to_string(value.version as *mut _).unwrap(), + notes: raw_to_string(value.notes as *mut _).unwrap(), + time: UNIX_EPOCH + Duration::from_secs(value.time), + } + } + + pub(crate) fn from_owned_raw(value: BNUpdateVersion) -> Self { + let owned = Self::from_raw(&value); + Self::free_raw(value); + owned } - pub fn time(&self) -> SystemTime { - UNIX_EPOCH + Duration::from_secs(self.time) + pub(crate) fn into_raw(value: Self) -> BNUpdateVersion { + let bn_version = BnString::new(value.version); + let bn_notes = BnString::new(value.notes); + let epoch = value.time.duration_since(UNIX_EPOCH).unwrap(); + BNUpdateVersion { + version: BnString::into_raw(bn_version), + notes: BnString::into_raw(bn_notes), + time: epoch.as_secs(), + } } - pub fn set_time(&mut self, time: SystemTime) { - let epoch = time.duration_since(UNIX_EPOCH).unwrap(); - self.time = epoch.as_secs(); + pub(crate) fn free_raw(value: BNUpdateVersion) { + let _ = unsafe { BnString::from_raw(value.version) }; + let _ = unsafe { BnString::from_raw(value.notes) }; } } impl CoreArrayProvider for UpdateVersion { type Raw = BNUpdateVersion; type Context = (); - type Wrapped<'a> = &'a Self; + type Wrapped<'a> = Self; } unsafe impl CoreArrayProviderInner for UpdateVersion { @@ -215,58 +255,6 @@ unsafe impl CoreArrayProviderInner for UpdateVersion { } unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - UpdateVersion::ref_from_raw(raw) - } -} - -/// queries if auto updates are enabled. -pub fn are_auto_updates_enabled() -> bool { - unsafe { BNAreAutoUpdatesEnabled() } -} - -/// sets auto update enabled status. -pub fn set_auto_updates_enabled(enabled: bool) { - unsafe { BNSetAutoUpdatesEnabled(enabled) } -} - -/// returns the time stamp for the last time updates were checked. -pub fn get_time_since_last_update_check() -> u64 { - unsafe { BNGetTimeSinceLastUpdateCheck() } -} - -/// whether an update has been downloaded and is waiting installation -pub fn is_update_installation_pending() -> bool { - unsafe { BNIsUpdateInstallationPending() } -} - -/// installs any pending updates -pub fn install_pending_update() -> Result<(), BnString> { - let mut errors = ptr::null_mut(); - unsafe { BNInstallPendingUpdate(&mut errors) }; - if !errors.is_null() { - Err(unsafe { BnString::from_raw(errors) }) - } else { - Ok(()) + UpdateVersion::from_raw(raw) } } - -pub fn updates_checked() { - unsafe { BNUpdatesChecked() } -} - -unsafe extern "C" fn cb_progress_nop( - _ctxt: *mut ::std::os::raw::c_void, - _progress: usize, - _total: usize, -) -> bool { - true -} - -unsafe extern "C" fn cb_progress bool>( - ctxt: *mut ::std::os::raw::c_void, - progress: usize, - total: usize, -) -> bool { - let ctxt: &mut F = &mut *(ctxt as *mut F); - ctxt(progress, total) -} diff --git a/rust/src/worker_thread.rs b/rust/src/worker_thread.rs new file mode 100644 index 000000000..349456e5f --- /dev/null +++ b/rust/src/worker_thread.rs @@ -0,0 +1,71 @@ +use crate::string::BnStrCompatible; +use binaryninjacore_sys::*; +use std::ffi::{c_char, c_void}; + +pub struct WorkerThreadActionExecutor { + func: Box, +} + +impl WorkerThreadActionExecutor { + unsafe extern "C" fn cb_execute(ctx: *mut c_void) { + let f: Box = Box::from_raw(ctx as *mut Self); + f.execute(); + } + + pub fn execute(&self) { + (self.func)(); + } +} + +pub fn execute_on_worker_thread(name: S, f: F) { + let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); + let raw_executor = Box::into_raw(boxed_executor); + let name = name.into_bytes_with_nul(); + unsafe { + BNWorkerEnqueueNamed( + raw_executor as *mut c_void, + Some(WorkerThreadActionExecutor::cb_execute), + name.as_ref().as_ptr() as *const c_char, + ) + } +} + +pub fn execute_on_worker_thread_priority(name: S, f: F) { + let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); + let raw_executor = Box::into_raw(boxed_executor); + let name = name.into_bytes_with_nul(); + unsafe { + BNWorkerPriorityEnqueueNamed( + raw_executor as *mut c_void, + Some(WorkerThreadActionExecutor::cb_execute), + name.as_ref().as_ptr() as *const c_char, + ) + } +} + +pub fn execute_on_worker_thread_interactive(name: S, f: F) { + let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); + let raw_executor = Box::into_raw(boxed_executor); + let name = name.into_bytes_with_nul(); + unsafe { + BNWorkerInteractiveEnqueueNamed( + raw_executor as *mut c_void, + Some(WorkerThreadActionExecutor::cb_execute), + name.as_ref().as_ptr() as *const c_char, + ) + } +} + +/// Returns the number of worker threads that are currently running. +/// By default, this is the number of cores on the system minus one +/// +/// To set the worker thread count use [`set_worker_thread_count`]. +pub fn worker_thread_count() -> usize { + unsafe { BNGetWorkerThreadCount() } +} + +/// Sets the number of worker threads that are currently running. +/// By default, this is the number of cores on the system minus one. +pub fn set_worker_thread_count(count: usize) { + unsafe { BNSetWorkerThreadCount(count) } +} diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 16eccf09d..68cd3e18d 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -3,14 +3,14 @@ use std::ffi::{c_char, c_void}; use std::ptr::NonNull; use crate::architecture::CoreArchitecture; -use crate::basicblock::BasicBlock; -use crate::binaryview::BinaryView; +use crate::basic_block::BasicBlock; +use crate::binary_view::BinaryView; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; -use crate::hlil::HighLevelILFunction; -use crate::lowlevelil::function::{LowLevelILFunction, Mutable, NonSSA, NonSSAVariant}; -use crate::lowlevelil::MutableLiftedILFunction; -use crate::mlil::MediumLevelILFunction; +use crate::high_level_il::HighLevelILFunction; +use crate::low_level_il::function::{LowLevelILFunction, Mutable, NonSSA, NonSSAVariant}; +use crate::low_level_il::MutableLiftedILFunction; +use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnStrCompatible, BnString}; diff --git a/rust/tests/backgroundtask.rs b/rust/tests/backgroundtask.rs new file mode 100644 index 000000000..a2466d657 --- /dev/null +++ b/rust/tests/backgroundtask.rs @@ -0,0 +1,47 @@ +use binaryninja::background_task::*; +use binaryninja::headless::Session; +use rstest::*; + +#[fixture] +#[once] +fn session() -> Session { + Session::new().expect("Failed to initialize session") +} + +#[rstest] +fn test_background_task_registered(_session: &Session) { + let task = BackgroundTask::new("test task", false); + BackgroundTask::running_tasks() + .iter() + .find(|t| t.progress_text().as_str() == "test task") + .expect("Task not running"); + task.finish(); + let still_running = BackgroundTask::running_tasks() + .iter() + .find(|t| t.progress_text().as_str() == "test task") + .is_some(); + assert!(!still_running, "Task still running"); +} + +#[rstest] +fn test_background_task_cancellable(_session: &Session) { + let task = BackgroundTask::new("test task", false); + BackgroundTask::running_tasks() + .iter() + .find(|t| t.progress_text().as_str() == "test task") + .expect("Task not running"); + task.cancel(); + assert!(task.is_cancelled()); + task.finish(); +} + +#[rstest] +fn test_background_task_progress(_session: &Session) { + let task = BackgroundTask::new("test task", false); + let first_progress = task.progress_text().to_string(); + assert_eq!(first_progress, "test task"); + task.set_progress_text("new progress"); + let second_progress = task.progress_text().to_string(); + assert_eq!(second_progress, "new progress"); + task.finish(); +} diff --git a/rust/tests/databuffer.rs b/rust/tests/databuffer.rs index 441210b6e..8480ae71c 100644 --- a/rust/tests/databuffer.rs +++ b/rust/tests/databuffer.rs @@ -1,4 +1,4 @@ -use binaryninja::databuffer::DataBuffer; +use binaryninja::data_buffer::DataBuffer; const DUMMY_DATA_0: &[u8] = b"0123456789\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x09\xFF"; const DUMMY_DATA_1: &[u8] = b"qwertyuiopasdfghjkl\xE7zxcvbnm\x00\x01\x00"; diff --git a/rust/tests/demangler.rs b/rust/tests/demangler.rs index 7f4f3e01e..da57f67e0 100644 --- a/rust/tests/demangler.rs +++ b/rust/tests/demangler.rs @@ -1,5 +1,5 @@ use binaryninja::architecture::CoreArchitecture; -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::demangle::{ demangle_generic, demangle_gnu3, demangle_llvm, demangle_ms, CustomDemangler, Demangler, }; diff --git a/rust/tests/initialization.rs b/rust/tests/initialization.rs index 068f154b6..35de73ee1 100644 --- a/rust/tests/initialization.rs +++ b/rust/tests/initialization.rs @@ -1,6 +1,6 @@ -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::enterprise::release_license; -use binaryninja::filemetadata::FileMetadata; +use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::{ init, init_with_opts, shutdown, InitializationError, InitializationOptions, }; diff --git a/rust/tests/llil.rs b/rust/tests/llil.rs index a9d172372..7d87d62f0 100644 --- a/rust/tests/llil.rs +++ b/rust/tests/llil.rs @@ -1,11 +1,11 @@ use binaryninja::architecture::Register; -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::headless::Session; -use binaryninja::lowlevelil::expression::LowLevelILExpressionIndex; -use binaryninja::lowlevelil::instruction::{ +use binaryninja::low_level_il::expression::LowLevelExpressionIndex; +use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstructionKind, LowLevelInstructionIndex, }; -use binaryninja::lowlevelil::LowLevelILRegister; +use binaryninja::low_level_il::LowLevelILRegister; use binaryninja::rc::Ref; use rstest::*; use std::path::PathBuf; @@ -44,7 +44,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "edi"), _ => panic!("Expected Register::ArchReg"), } - assert_eq!(op.source_expr().index, LowLevelILExpressionIndex(0)); + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(0)); } _ => panic!("Expected SetReg"), } @@ -56,7 +56,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { match instr_1.kind() { LowLevelILInstructionKind::Push(op) => { assert_eq!(op.size(), 4); - assert_eq!(op.operand().index, LowLevelILExpressionIndex(2)); + assert_eq!(op.operand().index, LowLevelExpressionIndex(2)); } _ => panic!("Expected Push"), } @@ -72,7 +72,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "ebp"), _ => panic!("Expected Register::ArchReg"), } - assert_eq!(op.source_expr().index, LowLevelILExpressionIndex(4)); + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(4)); } _ => panic!("Expected SetReg"), } @@ -88,7 +88,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "eax"), _ => panic!("Expected Register::ArchReg"), } - assert_eq!(op.source_expr().index, LowLevelILExpressionIndex(9)); + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(9)); } _ => panic!("Expected SetReg"), } @@ -100,7 +100,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { match instr_4.kind() { LowLevelILInstructionKind::Push(op) => { assert_eq!(op.size(), 4); - assert_eq!(op.operand().index, LowLevelILExpressionIndex(11)); + assert_eq!(op.operand().index, LowLevelExpressionIndex(11)); } _ => panic!("Expected Push"), } @@ -111,7 +111,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { println!("{:?}", instr_5.kind()); match instr_5.kind() { LowLevelILInstructionKind::Call(op) => { - assert_eq!(op.target().index, LowLevelILExpressionIndex(13)); + assert_eq!(op.target().index, LowLevelExpressionIndex(13)); } _ => panic!("Expected Call"), } @@ -127,7 +127,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "esp"), _ => panic!("Expected Register::ArchReg"), } - assert_eq!(op.source_expr().index, LowLevelILExpressionIndex(17)); + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(17)); } _ => panic!("Expected SetReg"), } @@ -143,7 +143,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "ebp"), _ => panic!("Expected Register::ArchReg"), } - assert_eq!(op.source_expr().index, LowLevelILExpressionIndex(19)); + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(19)); } _ => panic!("Expected SetReg"), } @@ -154,7 +154,7 @@ fn test_llil_info(_session: &Session, view: &BinaryView) { println!("{:?}", instr_8.kind()); match instr_8.kind() { LowLevelILInstructionKind::Ret(op) => { - assert_eq!(op.target().index, LowLevelILExpressionIndex(21)); + assert_eq!(op.target().index, LowLevelExpressionIndex(21)); } _ => panic!("Expected Ret"), } diff --git a/rust/tests/mainthread.rs b/rust/tests/mainthread.rs index a067631fe..3ca236f81 100644 --- a/rust/tests/mainthread.rs +++ b/rust/tests/mainthread.rs @@ -18,7 +18,7 @@ fn test_not_main_thread(_session: &Session) { #[rstest] fn test_main_thread_different(_session: &Session) { let calling_thread = std::thread::current(); - binaryninja::mainthread::execute_on_main_thread(move || { + binaryninja::mainthread::execute_on_main_thread_and_wait(move || { let main_thread = std::thread::current(); assert_ne!( calling_thread.id(), diff --git a/rust/tests/typearchive.rs b/rust/tests/typearchive.rs index b533a60fa..dafb71787 100644 --- a/rust/tests/typearchive.rs +++ b/rust/tests/typearchive.rs @@ -1,9 +1,9 @@ -use binaryninja::binaryview::BinaryView; -use binaryninja::filemetadata::FileMetadata; +use binaryninja::binary_view::BinaryView; +use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::Session; use binaryninja::platform::Platform; use binaryninja::rc::Ref; -use binaryninja::typearchive::TypeArchive; +use binaryninja::type_archive::TypeArchive; use rstest::*; #[fixture] diff --git a/rust/tests/typecontainer.rs b/rust/tests/typecontainer.rs index d67bad1d4..d5a720318 100644 --- a/rust/tests/typecontainer.rs +++ b/rust/tests/typecontainer.rs @@ -1,5 +1,5 @@ -use binaryninja::binaryview::{BinaryView, BinaryViewExt}; -use binaryninja::filemetadata::FileMetadata; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::Session; use binaryninja::platform::Platform; use binaryninja::rc::Ref; diff --git a/rust/tests/typeparser.rs b/rust/tests/typeparser.rs index dde49896b..5726fb0a3 100644 --- a/rust/tests/typeparser.rs +++ b/rust/tests/typeparser.rs @@ -1,6 +1,6 @@ use binaryninja::headless::Session; use binaryninja::platform::Platform; -use binaryninja::typeparser::{CoreTypeParser, TypeParser, TypeParserError}; +use binaryninja::type_parser::{CoreTypeParser, TypeParser, TypeParserError}; use binaryninja::types::Type; use binaryninjacore_sys::BNTypeParserErrorSeverity::ErrorSeverity; use rstest::*; diff --git a/rust/tests/workerthread.rs b/rust/tests/workerthread.rs new file mode 100644 index 000000000..666e85ba7 --- /dev/null +++ b/rust/tests/workerthread.rs @@ -0,0 +1,45 @@ +use binaryninja::headless::Session; +use rstest::*; +use std::sync::{Arc, Barrier}; + +#[fixture] +#[once] +fn session() -> Session { + Session::new().expect("Failed to initialize session") +} + +#[rstest] +fn test_setting_worker_thread(_session: &Session) { + let original_count = binaryninja::worker_thread::worker_thread_count(); + binaryninja::worker_thread::set_worker_thread_count(original_count - 1); + assert_eq!( + binaryninja::worker_thread::worker_thread_count(), + original_count - 1 + ); + binaryninja::worker_thread::set_worker_thread_count(original_count); + assert_eq!( + binaryninja::worker_thread::worker_thread_count(), + original_count + ); +} + +#[rstest] +fn test_worker_thread_different(_session: &Session) { + let calling_thread = std::thread::current(); + + // We need both (2) threads to synchronize + let barrier = Arc::new(Barrier::new(2)); + let barrier_clone = Arc::clone(&barrier); + binaryninja::worker_thread::execute_on_worker_thread("test", move || { + let worker_thread = std::thread::current(); + assert_ne!( + calling_thread.id(), + worker_thread.id(), + "Expected calling thread to be different from the worker thread" + ); + barrier_clone.wait(); + }); + + // Wait until worker thread has finished. + barrier.wait(); +} diff --git a/rust/tests/workflow.rs b/rust/tests/workflow.rs index a234dcfa8..699f621af 100644 --- a/rust/tests/workflow.rs +++ b/rust/tests/workflow.rs @@ -9,6 +9,9 @@ fn session() -> Session { Session::new().expect("Failed to initialize session") } +// TODO: Test running a workflow activity +// TODO: Test activity insertion and removal + #[rstest] fn test_workflow_clone(_session: &Session) { let original_workflow = Workflow::new("core.function.baseAnalysis"); diff --git a/view/bintxt/src/ihex.rs b/view/bintxt/src/ihex.rs index c8ded1463..99a5b7af0 100644 --- a/view/bintxt/src/ihex.rs +++ b/view/bintxt/src/ihex.rs @@ -3,8 +3,8 @@ use crate::segment_from_address; use crate::sort_and_merge_segments; use crate::MergedSegment; use crate::UnmergedSegment; -use binaryninja::binaryview::*; -use binaryninja::custombinaryview::*; +use binaryninja::binary_view::*; +use binaryninja::custom_binary_view::*; use binaryninja::platform::Platform; use binaryninja::rc::Ref; use binaryninja::segment::SegmentBuilder; diff --git a/view/bintxt/src/lib.rs b/view/bintxt/src/lib.rs index ef806bbcd..4627c654a 100644 --- a/view/bintxt/src/lib.rs +++ b/view/bintxt/src/lib.rs @@ -16,15 +16,15 @@ use std::ops::Range; pub extern "C" fn CorePluginInit() -> bool { Logger::new("BINTXT").with_level(LevelFilter::Info).init(); - binaryninja::custombinaryview::register_view_type(c"ti-txt", c"TI-TXT", |core| { + binaryninja::custom_binary_view::register_view_type(c"ti-txt", c"TI-TXT", |core| { TiTxtViewConstructor { core } }); - binaryninja::custombinaryview::register_view_type(c"srec", c"Motorola S-record", |core| { + binaryninja::custom_binary_view::register_view_type(c"srec", c"Motorola S-record", |core| { SRecViewConstructor { core } }); - binaryninja::custombinaryview::register_view_type(c"ihex", c"Intel HEX", |core| { + binaryninja::custom_binary_view::register_view_type(c"ihex", c"Intel HEX", |core| { IHexViewConstructor { core } }); diff --git a/view/bintxt/src/srec.rs b/view/bintxt/src/srec.rs index d11e5fd54..fd2414c84 100644 --- a/view/bintxt/src/srec.rs +++ b/view/bintxt/src/srec.rs @@ -1,5 +1,5 @@ -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; -use binaryninja::custombinaryview::{ +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::custom_binary_view::{ BinaryViewType, BinaryViewTypeBase, CustomBinaryView, CustomBinaryViewType, CustomView, CustomViewBuilder, }; diff --git a/view/bintxt/src/titxt.rs b/view/bintxt/src/titxt.rs index 6cb006ab1..6e387d2fa 100644 --- a/view/bintxt/src/titxt.rs +++ b/view/bintxt/src/titxt.rs @@ -1,5 +1,5 @@ -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; -use binaryninja::custombinaryview::{ +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::custom_binary_view::{ BinaryViewType, BinaryViewTypeBase, CustomBinaryView, CustomBinaryViewType, CustomView, CustomViewBuilder, }; diff --git a/view/minidump/src/command.rs b/view/minidump/src/command.rs index e69dbdc47..8718fb9d5 100644 --- a/view/minidump/src/command.rs +++ b/view/minidump/src/command.rs @@ -3,7 +3,7 @@ use std::str; use log::{debug, error, info}; use minidump::{Minidump, MinidumpMemoryInfoList}; -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; pub fn print_memory_information(bv: &BinaryView) { debug!("Printing memory information"); diff --git a/view/minidump/src/lib.rs b/view/minidump/src/lib.rs index 8c5d4b0fa..a1a2aa6e4 100644 --- a/view/minidump/src/lib.rs +++ b/view/minidump/src/lib.rs @@ -1,6 +1,6 @@ -use binaryninja::binaryview::BinaryView; +use binaryninja::binary_view::BinaryView; use binaryninja::command::{register, Command}; -use binaryninja::custombinaryview::register_view_type; +use binaryninja::custom_binary_view::register_view_type; use binaryninja::logger::Logger; use log::{debug, LevelFilter}; diff --git a/view/minidump/src/view.rs b/view/minidump/src/view.rs index baa8a53d2..8a7946290 100644 --- a/view/minidump/src/view.rs +++ b/view/minidump/src/view.rs @@ -10,15 +10,15 @@ use minidump::{ MinidumpStream, MinidumpSystemInfo, Module, }; -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; -use binaryninja::custombinaryview::{ +use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::custom_binary_view::{ BinaryViewType, BinaryViewTypeBase, CustomBinaryView, CustomBinaryViewType, CustomView, CustomViewBuilder, }; use binaryninja::platform::Platform; use binaryninja::Endianness; -type BinaryViewResult = binaryninja::binaryview::Result; +type BinaryViewResult = binaryninja::binary_view::Result; /// The _Minidump_ binary view type, which the Rust plugin registers with the Binary Ninja core /// (via `binaryninja::custombinaryview::register_view_type`) as a possible binary view