From 05b7a18f68ececaadae75dccd75f7e15280b4b66 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 19 Jan 2025 16:24:04 -0500 Subject: [PATCH] More rust cleanup - Updated README to clarify offline documentation - Refactored settings api - Added settings example to show dumping settings value and specific properties - Use the workspace to depend on binaryninja and binaryninjacore-sys - Remove binaryninjacore-sys as a workspace member (its not really required) --- Cargo.lock | 1 - Cargo.toml | 5 +- arch/msp430/Cargo.toml | 4 +- arch/riscv/Cargo.toml | 4 +- plugins/dwarf/dwarf_export/Cargo.toml | 6 +- plugins/dwarf/dwarf_import/Cargo.toml | 6 +- plugins/dwarf/dwarf_import/src/helpers.rs | 35 +- plugins/dwarf/dwarf_import/src/lib.rs | 2 +- plugins/dwarf/dwarfdump/Cargo.toml | 4 +- .../dwarf/dwarfdump/{readme.md => README.md} | 0 plugins/dwarf/shared/Cargo.toml | 4 +- plugins/dwarf/shared/src/lib.rs | 5 +- plugins/idb_import/Cargo.toml | 6 +- plugins/pdb-ng/Cargo.toml | 6 +- plugins/pdb-ng/demo/Cargo.toml | 2 +- plugins/pdb-ng/src/lib.rs | 38 +- plugins/pdb-ng/src/parser.rs | 24 +- plugins/pdb-ng/src/symbol_parser.rs | 20 +- plugins/pdb-ng/src/type_parser.rs | 8 +- plugins/warp/Cargo.toml | 25 +- plugins/warp/src/bin/sigem.rs | 5 +- plugins/warp/src/matcher.rs | 13 +- rust/README.md | 4 +- rust/examples/dump_settings.rs | 21 + rust/src/download_provider.rs | 4 +- rust/src/function.rs | 4 +- rust/src/project.rs | 1 - rust/src/settings.rs | 485 +++++++++++------- rust/src/type_printer.rs | 4 +- view/bintxt/Cargo.toml | 6 +- view/bintxt/src/ihex.rs | 5 +- view/minidump/Cargo.toml | 6 +- 32 files changed, 475 insertions(+), 288 deletions(-) rename plugins/dwarf/dwarfdump/{readme.md => README.md} (100%) create mode 100644 rust/examples/dump_settings.rs diff --git a/Cargo.lock b/Cargo.lock index a8a0bfb3c..aedd08d6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2908,7 +2908,6 @@ dependencies = [ "arboard", "binaryninja", "binaryninjacore-sys", - "cc", "clap", "criterion", "dashmap", diff --git a/Cargo.toml b/Cargo.toml index 4cd2ace9f..41a208d86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ resolver = "2" members = [ "rust", - "rust/binaryninjacore-sys", "arch/riscv", "arch/msp430", "view/bintxt", @@ -20,6 +19,10 @@ members = [ "plugins/warp" ] +[workspace.dependencies] +binaryninja = { path = "rust" } +binaryninjacore-sys = { path = "rust/binaryninjacore-sys" } + [profile.release] lto = true debug = "full" diff --git a/arch/msp430/Cargo.toml b/arch/msp430/Cargo.toml index c2bf70608..ddc442e8a 100644 --- a/arch/msp430/Cargo.toml +++ b/arch/msp430/Cargo.toml @@ -5,8 +5,8 @@ authors = ["jrozner"] edition = "2021" [dependencies] -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true log = "0.4" msp430-asm = "^0.2" diff --git a/arch/riscv/Cargo.toml b/arch/riscv/Cargo.toml index ee3dbb71c..1c0979e91 100644 --- a/arch/riscv/Cargo.toml +++ b/arch/riscv/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Ryan Snyder "] edition = "2021" [dependencies] -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true riscv-dis = { path = "disasm" } log = "0.4" rayon = { version = "1.0", optional = true } diff --git a/plugins/dwarf/dwarf_export/Cargo.toml b/plugins/dwarf/dwarf_export/Cargo.toml index 29dee106c..a3d0e75b3 100644 --- a/plugins/dwarf/dwarf_export/Cargo.toml +++ b/plugins/dwarf/dwarf_export/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -binaryninja = { path = "../../../rust" } -binaryninjacore-sys = { path = "../../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true gimli = "^0.31" -log = "^0.4" +log = "0.4" object = { version = "0.32.1", features = ["write"] } diff --git a/plugins/dwarf/dwarf_import/Cargo.toml b/plugins/dwarf/dwarf_import/Cargo.toml index b8fb09b7b..52f89a469 100644 --- a/plugins/dwarf/dwarf_import/Cargo.toml +++ b/plugins/dwarf/dwarf_import/Cargo.toml @@ -8,10 +8,10 @@ crate-type = ["cdylib"] [dependencies] dwarfreader = { path = "../shared/" } -binaryninja = { path = "../../../rust" } -binaryninjacore-sys = { path = "../../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true gimli = "0.31" -log = "0.4.20" +log = "0.4" iset = "0.2.2" cpp_demangle = "0.4.3" regex = "1" diff --git a/plugins/dwarf/dwarf_import/src/helpers.rs b/plugins/dwarf/dwarf_import/src/helpers.rs index 40f105723..0a0b90a7e 100644 --- a/plugins/dwarf/dwarf_import/src/helpers.rs +++ b/plugins/dwarf/dwarf_import/src/helpers.rs @@ -33,6 +33,7 @@ use gimli::{ DebuggingInformationEntry, Operation, Unit, UnitOffset, UnitSectionOffset, }; +use binaryninja::settings::QueryOptions; use log::warn; pub(crate) fn get_uid( @@ -414,9 +415,10 @@ pub(crate) fn download_debug_info( build_id: &str, view: &BinaryView, ) -> Result, String> { - let settings = Settings::new(""); - - let debug_server_urls = settings.get_string_list("network.debuginfodServers", Some(view), None); + let mut settings_query_opts = QueryOptions::new_with_view(view); + let settings = Settings::new(); + let debug_server_urls = + settings.get_string_list_with_opts("network.debuginfodServers", &mut settings_query_opts); for debug_server_url in debug_server_urls.iter() { let artifact_url = format!("{}/buildid/{}/debuginfo", debug_server_url, build_id); @@ -487,19 +489,21 @@ pub(crate) fn find_local_debug_file_for_build_id( build_id: &str, view: &BinaryView, ) -> Option { - let settings = Settings::new(""); - let debug_dirs_enabled = settings.get_bool( + let mut settings_query_opts = QueryOptions::new_with_view(view); + let settings = Settings::new(); + let debug_dirs_enabled = settings.get_bool_with_opts( "analysis.debugInfo.enableDebugDirectories", - Some(view), - None, + &mut settings_query_opts, ); if !debug_dirs_enabled { return None; } - let debug_info_paths = - settings.get_string_list("analysis.debugInfo.debugDirectories", Some(view), None); + let debug_info_paths = settings.get_string_list_with_opts( + "analysis.debugInfo.debugDirectories", + &mut settings_query_opts, + ); if debug_info_paths.is_empty() { return None; @@ -530,6 +534,8 @@ pub(crate) fn load_debug_info_for_build_id( build_id: &str, view: &BinaryView, ) -> (Option>, bool) { + let mut settings_query_opts = QueryOptions::new_with_view(view); + let settings = Settings::new(); if let Some(debug_file_path) = find_local_debug_file_for_build_id(build_id, view) { return ( binaryninja::load_with_options( @@ -539,16 +545,19 @@ pub(crate) fn load_debug_info_for_build_id( ), false, ); - } else if Settings::new("").get_bool("network.enableDebuginfod", Some(view), None) { + } else if settings.get_bool_with_opts("network.enableDebuginfod", &mut settings_query_opts) { return (download_debug_info(build_id, view).ok(), true); } (None, false) } pub(crate) fn find_sibling_debug_file(view: &BinaryView) -> Option { - let settings = Settings::new(""); - let load_sibling_debug = - settings.get_bool("analysis.debugInfo.loadSiblingDebugFiles", Some(view), None); + let mut settings_query_opts = QueryOptions::new_with_view(view); + let settings = Settings::new(); + let load_sibling_debug = settings.get_bool_with_opts( + "analysis.debugInfo.loadSiblingDebugFiles", + &mut settings_query_opts, + ); if !load_sibling_debug { return None; diff --git a/plugins/dwarf/dwarf_import/src/lib.rs b/plugins/dwarf/dwarf_import/src/lib.rs index 4ef0e1b87..6497cde83 100644 --- a/plugins/dwarf/dwarf_import/src/lib.rs +++ b/plugins/dwarf/dwarf_import/src/lib.rs @@ -693,7 +693,7 @@ impl CustomDebugInfoParser for DWARFParser { pub extern "C" fn CorePluginInit() -> bool { Logger::new("DWARF").init(); - let settings = Settings::new(""); + let settings = Settings::new(); settings.register_setting_json( "network.enableDebuginfod", diff --git a/plugins/dwarf/dwarfdump/Cargo.toml b/plugins/dwarf/dwarfdump/Cargo.toml index 815f25fef..a58e2e33a 100644 --- a/plugins/dwarf/dwarfdump/Cargo.toml +++ b/plugins/dwarf/dwarfdump/Cargo.toml @@ -9,6 +9,6 @@ crate-type = ["cdylib"] [dependencies] dwarfreader = { path = "../shared/" } -binaryninja = { path = "../../../rust" } -binaryninjacore-sys = { path = "../../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true gimli = "0.31" diff --git a/plugins/dwarf/dwarfdump/readme.md b/plugins/dwarf/dwarfdump/README.md similarity index 100% rename from plugins/dwarf/dwarfdump/readme.md rename to plugins/dwarf/dwarfdump/README.md diff --git a/plugins/dwarf/shared/Cargo.toml b/plugins/dwarf/shared/Cargo.toml index 7e3a6d936..93ed004de 100644 --- a/plugins/dwarf/shared/Cargo.toml +++ b/plugins/dwarf/shared/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Kyle Martin "] edition = "2021" [dependencies] -binaryninja = { path = "../../../rust" } -binaryninjacore-sys = { path = "../../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true gimli = "0.31" zstd = "0.13.2" thiserror = "1.0" diff --git a/plugins/dwarf/shared/src/lib.rs b/plugins/dwarf/shared/src/lib.rs index a75558b50..f955852bb 100644 --- a/plugins/dwarf/shared/src/lib.rs +++ b/plugins/dwarf/shared/src/lib.rs @@ -20,8 +20,8 @@ use binaryninja::{ Endianness, }; +use binaryninja::settings::QueryOptions; use std::rc::Rc; - ////////////////////// // Dwarf Validation @@ -63,8 +63,9 @@ pub fn is_raw_dwo_dwarf(view: &BinaryView) -> bool { } pub fn can_use_debuginfod(view: &BinaryView) -> bool { + let mut query_options = QueryOptions::new_with_view(view); has_build_id_section(view) - && Settings::new("").get_bool("network.enableDebuginfod", Some(view), None) + && Settings::new().get_bool_with_opts("network.enableDebuginfod", &mut query_options) } pub fn has_build_id_section(view: &BinaryView) -> bool { diff --git a/plugins/idb_import/Cargo.toml b/plugins/idb_import/Cargo.toml index 0c946f410..661190810 100644 --- a/plugins/idb_import/Cargo.toml +++ b/plugins/idb_import/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] anyhow = { version = "1.0.86", features = ["backtrace"] } -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.6" } -log = "0.4.20" \ No newline at end of file +log = "0.4" \ No newline at end of file diff --git a/plugins/pdb-ng/Cargo.toml b/plugins/pdb-ng/Cargo.toml index de9b958e3..2025de133 100644 --- a/plugins/pdb-ng/Cargo.toml +++ b/plugins/pdb-ng/Cargo.toml @@ -8,10 +8,10 @@ crate-type = ["cdylib"] [dependencies] anyhow = "^1.0" -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true itertools = "^0.11" -log = "^0.4" +log = "0.4" pdb = { git = "https://github.com/Vector35/pdb-rs", rev = "6016177" } regex = "1" diff --git a/plugins/pdb-ng/demo/Cargo.toml b/plugins/pdb-ng/demo/Cargo.toml index 1ecd29d87..f9f446b56 100644 --- a/plugins/pdb-ng/demo/Cargo.toml +++ b/plugins/pdb-ng/demo/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "^1.0" binaryninja = {path = "../../../"} home = "^0.5.5" itertools = "^0.11" -log = "^0.4" +log = "0.4" pdb = { git = "https://github.com/Vector35/pdb-rs", branch = "master" } cab = "^0.4" regex = "1" diff --git a/plugins/pdb-ng/src/lib.rs b/plugins/pdb-ng/src/lib.rs index 326558e97..fb19fcbbd 100644 --- a/plugins/pdb-ng/src/lib.rs +++ b/plugins/pdb-ng/src/lib.rs @@ -30,7 +30,7 @@ use binaryninja::debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser}; use binaryninja::download_provider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}; use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet}; use binaryninja::logger::Logger; -use binaryninja::settings::Settings; +use binaryninja::settings::{QueryOptions, Settings}; use binaryninja::string::BnString; use binaryninja::{interaction, user_directory}; use parser::PDBParserInstance; @@ -87,12 +87,14 @@ fn default_local_cache() -> Result { fn active_local_cache(view: Option<&BinaryView>) -> Result { // Check the local symbol store - let mut local_store_path = Settings::new("") - .get_string("pdb.files.localStoreAbsolute", view, None) + let mut settings_query_options = view.map(QueryOptions::new_with_view).unwrap_or_default(); + let settings = Settings::new(); + let mut local_store_path = settings + .get_string_with_opts("pdb.files.localStoreAbsolute", &mut settings_query_options) .to_string(); if local_store_path.is_empty() { - let relative_local_store = Settings::new("") - .get_string("pdb.files.localStoreRelative", view, None) + let relative_local_store = settings + .get_string_with_opts("pdb.files.localStoreRelative", &mut settings_query_options) .to_string(); local_store_path = user_directory() .join(relative_local_store) @@ -168,7 +170,8 @@ fn read_from_sym_store(bv: &BinaryView, path: &str) -> Result<(bool, Vec)> { return Ok((false, conts)); } - if !Settings::new("").get_bool("network.pdbAutoDownload", Some(bv), None) { + let mut query_options = QueryOptions::new_with_view(bv); + if !Settings::new().get_bool_with_opts("network.pdbAutoDownload", &mut query_options) { return Err(anyhow!("Auto download disabled")); } @@ -359,7 +362,8 @@ impl PDBParser { ) -> Result<()> { let mut pdb = PDB::open(Cursor::new(&conts))?; - let settings = Settings::new(""); + let settings = Settings::new(); + let mut settings_query_opts = QueryOptions::new_with_view(view); if let Some(info) = parse_pdb_info(view) { let pdb_info = &pdb.pdb_information()?; @@ -367,8 +371,10 @@ impl PDBParser { if check_guid { return Err(anyhow!("PDB GUID does not match")); } else { - let ask = - settings.get_string("pdb.features.loadMismatchedPDB", Some(view), None); + let ask = settings.get_string_with_opts( + "pdb.features.loadMismatchedPDB", + &mut settings_query_opts, + ); match ask.as_str() { "true" => {}, @@ -400,7 +406,7 @@ impl PDBParser { } } - if did_download && settings.get_bool("pdb.files.localStoreCache", None, None) { + if did_download && settings.get_bool("pdb.files.localStoreCache") { match active_local_cache(Some(view)) { Ok(cache) => { let mut cab_path = PathBuf::from(&cache); @@ -479,7 +485,10 @@ impl PDBParser { if check_guid { return Err(anyhow!("File not compiled with PDB information")); } else { - let ask = settings.get_string("pdb.features.loadMismatchedPDB", Some(view), None); + let ask = settings.get_string_with_opts( + "pdb.features.loadMismatchedPDB", + &mut settings_query_opts, + ); match ask.as_str() { "true" => {}, @@ -644,8 +653,9 @@ impl CustomDebugInfoParser for PDBParser { } // Next, try downloading from all symbol servers in the server list - let server_list = - Settings::new("").get_string_list("pdb.files.symbolServerList", Some(view), None); + let mut query_options = QueryOptions::new_with_view(view); + let server_list = Settings::new() + .get_string_list_with_opts("pdb.files.symbolServerList", &mut query_options); for server in server_list.iter() { match search_sym_store(view, server.to_string(), &info) { @@ -688,7 +698,7 @@ fn init_plugin() -> bool { Logger::new("PDB").init(); DebugInfoParser::register("PDB", PDBParser {}); - let settings = Settings::new(""); + let settings = Settings::new(); settings.register_group("pdb", "PDB Loader"); settings.register_setting_json( "pdb.files.localStoreAbsolute", diff --git a/plugins/pdb-ng/src/parser.rs b/plugins/pdb-ng/src/parser.rs index 3bfde5538..b46969ae6 100644 --- a/plugins/pdb-ng/src/parser.rs +++ b/plugins/pdb-ng/src/parser.rs @@ -30,7 +30,7 @@ use binaryninja::confidence::{Conf, MIN_CONFIDENCE}; use binaryninja::debuginfo::{DebugFunctionInfo, DebugInfo}; use binaryninja::platform::Platform; use binaryninja::rc::Ref; -use binaryninja::settings::Settings; +use binaryninja::settings::{QueryOptions, Settings}; use binaryninja::types::{ EnumerationBuilder, NamedTypeReference, NamedTypeReferenceClass, QualifiedName, StructureBuilder, StructureType, Type, TypeClass, @@ -61,6 +61,8 @@ pub struct PDBParserInstance<'a, S: Source<'a> + 'a> { pub(crate) address_map: AddressMap<'a>, /// Binja Settings instance (for optimization) pub(crate) settings: Ref, + /// Binja Settings query instance (for optimization) + pub(crate) settings_query_opts: QueryOptions<'a>, /// type_parser.rs @@ -139,7 +141,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { platform, pdb, address_map, - settings: Settings::new(""), + settings: Settings::new(), + settings_query_opts: QueryOptions::new_with_view(bv), indexed_types: Default::default(), named_types: Default::default(), full_type_indices: Default::default(), @@ -175,15 +178,15 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { if self .settings - .get_bool("pdb.features.parseSymbols", Some(self.bv), None) + .get_bool_with_opts("pdb.features.parseSymbols", &mut self.settings_query_opts) { let (symbols, functions) = self.parse_symbols(Self::split_progress(&progress, 1, &[1.0, 3.0, 0.5, 0.5]))?; - if self - .settings - .get_bool("pdb.features.createMissingNamedTypes", Some(self.bv), None) - { + if self.settings.get_bool_with_opts( + "pdb.features.createMissingNamedTypes", + &mut self.settings_query_opts, + ) { self.resolve_missing_ntrs( &symbols, Self::split_progress(&progress, 2, &[1.0, 3.0, 0.5, 0.5]), @@ -198,9 +201,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { info!("PDB found {} data variables", symbols.len()); info!("PDB found {} functions", functions.len()); - let allow_void = - self.settings - .get_bool("pdb.features.allowVoidGlobals", Some(self.bv), None); + let allow_void = self.settings.get_bool_with_opts( + "pdb.features.allowVoidGlobals", + &mut self.settings_query_opts, + ); let min_confidence_type = Conf::new(Type::void(), MIN_CONFIDENCE); for sym in symbols { diff --git a/plugins/pdb-ng/src/symbol_parser.rs b/plugins/pdb-ng/src/symbol_parser.rs index 8eaaad2a1..3bcbb6206 100644 --- a/plugins/pdb-ng/src/symbol_parser.rs +++ b/plugins/pdb-ng/src/symbol_parser.rs @@ -204,9 +204,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { } } - let use_public = - self.settings - .get_bool("pdb.features.loadGlobalSymbols", Some(self.bv), None); + let use_public = self.settings.get_bool_with_opts( + "pdb.features.loadGlobalSymbols", + &mut self.settings_query_opts, + ); let mut best_symbols = HashMap::::new(); for sym in &self.parsed_symbols { @@ -795,10 +796,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { let data_type = t.merge(self.lookup_type_conf(&data.type_index, false)?); // Ignore symbols with no name and no type - if !self - .settings - .get_bool("pdb.features.allowUnnamedVoidSymbols", Some(self.bv), None) - && name.is_none() + if !self.settings.get_bool_with_opts( + "pdb.features.allowUnnamedVoidSymbols", + &mut self.settings_query_opts, + ) && name.is_none() { if let Some(ty) = &data_type { if ty.contents.type_class() == TypeClass::VoidTypeClass { @@ -1856,10 +1857,9 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { DEMANGLE_CONFIDENCE, )); - if self.settings.get_bool( + if self.settings.get_bool_with_opts( "pdb.features.expandRTTIStructures", - Some(self.bv), - None, + &mut self.settings_query_opts.clone(), ) { if let Some((lengthy_type, length)) = self.make_lengthy_type(ty, self.bv.start() + rva.0 as u64)? diff --git a/plugins/pdb-ng/src/type_parser.rs b/plugins/pdb-ng/src/type_parser.rs index 0d08fce9f..1b1a34bc4 100644 --- a/plugins/pdb-ng/src/type_parser.rs +++ b/plugins/pdb-ng/src/type_parser.rs @@ -1031,10 +1031,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { } structure.base_structures(&bases); - if self - .settings - .get_bool("pdb.features.generateVTables", Some(self.bv), None) - && !virt_methods.is_empty() + if self.settings.get_bool_with_opts( + "pdb.features.generateVTables", + &mut self.settings_query_opts, + ) && !virt_methods.is_empty() { let mut vt = StructureBuilder::new(); diff --git a/plugins/warp/Cargo.toml b/plugins/warp/Cargo.toml index 2726a332e..e7634075b 100644 --- a/plugins/warp/Cargo.toml +++ b/plugins/warp/Cargo.toml @@ -7,9 +7,8 @@ edition = "2021" crate-type = ["lib", "cdylib"] [dependencies] -binaryninja = { path = "../../rust", features = ["rayon"] } -# Used to link with for tests. -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja = { workspace = true, features = ["rayon"] } +binaryninjacore-sys.workspace = true warp = { git = "https://github.com/Vector35/warp/", rev = "0ee5a6f" } log = "0.4" arboard = "3.4" @@ -17,20 +16,26 @@ rayon = "1.10" dashmap = "6.1" walkdir = "2.5" rfd = "0.15" -# For sigem -env_logger = "0.11.5" -clap = { version = "4.5.16", features = ["derive"] } -ar = { git = "https://github.com/mdsteele/rust-ar" } -tempdir = "0.3.7" serde_json = "1.0" -[build-dependencies] -cc = "1.1.28" +# For sigem +env_logger = { version = "0.11", optional = true } +clap = { version = "4.5", features = ["derive"], optional = true } +ar = { git = "https://github.com/mdsteele/rust-ar", optional = true } +tempdir = { version = "0.3.7", optional = true } [dev-dependencies] criterion = "0.5.1" insta = { version = "1.38.0", features = ["yaml"] } +[features] +default = ["sigem"] +sigem = ["env_logger", "clap", "ar", "tempdir"] + +[[bin]] +name = "sigem" +required-features = ["sigem"] + [[bench]] name = "guid" harness = false diff --git a/plugins/warp/src/bin/sigem.rs b/plugins/warp/src/bin/sigem.rs index a500fd5b5..a455f1e8e 100644 --- a/plugins/warp/src/bin/sigem.rs +++ b/plugins/warp/src/bin/sigem.rs @@ -96,7 +96,6 @@ fn main() { binaryninja::headless::Session::new().expect("Failed to initialize session"); // Adjust the amount of worker threads so that we can actually free BinaryViews. - let bn_settings = Settings::new(""); let worker_count = rayon::current_num_threads() * 4; log::debug!("Adjusting Binary Ninja worker count to {}...", worker_count); binaryninja::worker_thread::set_worker_thread_count(worker_count); @@ -104,6 +103,7 @@ fn main() { // Make sure caches are flushed when the views get destructed. register_cache_destructor(); + let bn_settings = Settings::new(); let settings = default_settings(&bn_settings); log::info!("Creating functions for {:?}...", args.path); @@ -223,7 +223,6 @@ fn data_from_directory(settings: &Value, dir: PathBuf) -> Option { } } -// TODO: Pass settings. fn data_from_file(settings: &Value, path: &Path) -> Option { match path.extension() { Some(ext) if ext == "a" || ext == "lib" || ext == "rlib" => { @@ -256,7 +255,7 @@ mod tests { let out_dir = env!("OUT_DIR").parse::().unwrap(); let _headless_session = binaryninja::headless::Session::new().expect("Failed to initialize session"); - let bn_settings = Settings::new(""); + let bn_settings = Settings::new(); let settings = default_settings(&bn_settings); for entry in std::fs::read_dir(out_dir).expect("Failed to read OUT_DIR") { let entry = entry.expect("Failed to read directory entry"); diff --git a/plugins/warp/src/matcher.rs b/plugins/warp/src/matcher.rs index adc8f09ec..81458f8da 100644 --- a/plugins/warp/src/matcher.rs +++ b/plugins/warp/src/matcher.rs @@ -398,7 +398,7 @@ impl MatcherSettings { /// NOTE: If you are using this as a library then just modify the MatcherSettings directly /// in the matcher instance, that way you don't need to round-trip through Binary Ninja. pub fn register() { - let bn_settings = binaryninja::settings::Settings::new(""); + let bn_settings = binaryninja::settings::Settings::new(); let trivial_function_len_props = json!({ "title" : "Trivial Function Length", @@ -463,25 +463,24 @@ impl MatcherSettings { pub fn global() -> Self { let mut settings = MatcherSettings::default(); - let bn_settings = binaryninja::settings::Settings::new(""); + let bn_settings = binaryninja::settings::Settings::new(); if bn_settings.contains(Self::TRIVIAL_FUNCTION_LEN_SETTING) { settings.trivial_function_len = - bn_settings.get_integer(Self::TRIVIAL_FUNCTION_LEN_SETTING, None, None); + bn_settings.get_integer(Self::TRIVIAL_FUNCTION_LEN_SETTING); } if bn_settings.contains(Self::MINIMUM_FUNCTION_LEN_SETTING) { settings.minimum_function_len = - bn_settings.get_integer(Self::MINIMUM_FUNCTION_LEN_SETTING, None, None); + bn_settings.get_integer(Self::MINIMUM_FUNCTION_LEN_SETTING); } if bn_settings.contains(Self::MAXIMUM_FUNCTION_LEN_SETTING) { - match bn_settings.get_integer(Self::MAXIMUM_FUNCTION_LEN_SETTING, None, None) { + match bn_settings.get_integer(Self::MAXIMUM_FUNCTION_LEN_SETTING) { 0 => settings.maximum_function_len = None, len => settings.maximum_function_len = Some(len), } } if bn_settings.contains(Self::MINIMUM_MATCHED_CONSTRAINTS_SETTING) { settings.minimum_matched_constraints = - bn_settings.get_integer(Self::MINIMUM_MATCHED_CONSTRAINTS_SETTING, None, None) - as usize; + bn_settings.get_integer(Self::MINIMUM_MATCHED_CONSTRAINTS_SETTING) as usize; } settings } diff --git a/rust/README.md b/rust/README.md index 0d627f6f2..eac531e66 100644 --- a/rust/README.md +++ b/rust/README.md @@ -5,6 +5,7 @@ Official Rust bindings for [Binary Ninja]. - [Getting Started](#getting-started) - [Examples](https://github.com/Vector35/binaryninja-api/tree/dev/rust/examples) - [Documentation](https://dev-rust.binary.ninja/) +- [Offline Documentation](#offline-documentation) ## WARNING @@ -123,7 +124,8 @@ Offline documentation can be generated like any other rust crate, using `cargo d ```shell git clone https://github.com/Vector35/binaryninja-api -cd rust && cargo doc --open +cd binaryninja-api +cargo doc --no-deps --open -p binaryninja ``` ## Contributing diff --git a/rust/examples/dump_settings.rs b/rust/examples/dump_settings.rs new file mode 100644 index 000000000..51452ca7d --- /dev/null +++ b/rust/examples/dump_settings.rs @@ -0,0 +1,21 @@ +use binaryninja::settings::Settings; + +fn main() { + println!("Starting session..."); + // This loads all the core architecture, platform, etc plugins + let _headless_session = + binaryninja::headless::Session::new().expect("Failed to initialize session"); + + let settings = Settings::new(); + for key in &settings.keys() { + let value = settings.get_string(key); + let default_value = settings.get_property_string(key, "default"); + let title = settings.get_property_string(key, "title"); + let description = settings.get_property_string(key, "description"); + println!("{}:", key); + println!(" value: {}", value); + println!(" default_value: {}", default_value); + println!(" title: {}", title); + println!(" description: {}", description); + } +} diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index 19a6dd190..1e61c87de 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -38,8 +38,8 @@ impl DownloadProvider { /// TODO : We may want to `impl Default`....excessive error checking might be preventing us from doing so pub fn try_default() -> Result { - let s = Settings::new(""); - let dp_name = s.get_string("network.downloadProviderName", None, None); + let s = Settings::new(); + let dp_name = s.get_string("network.downloadProviderName"); Self::get(dp_name).ok_or(()) } diff --git a/rust/src/function.rs b/rust/src/function.rs index 10c49db0f..a4c4a1adb 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -2066,7 +2066,7 @@ impl Function { /// Splits a variable at the definition site. The given `var` must be the /// variable unique to the definition and should be obtained by using - /// [crate::mlil::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. + /// [crate::medium_level_il::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. /// /// This function is not meant to split variables that have been previously merged. Use /// [Function::unmerge_variables] to split previously merged variables. @@ -2089,7 +2089,7 @@ impl Function { /// Undoes variable splitting performed with [Function::split_variable]. The given `var` /// must be the variable unique to the definition and should be obtained by using - /// [crate::mlil::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. + /// [crate::medium_level_il::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. /// /// * `var` - variable to unsplit pub fn unsplit_variable(&self, var: &Variable) { diff --git a/rust/src/project.rs b/rust/src/project.rs index 3e8b45a41..8d8132cac 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -677,7 +677,6 @@ impl Project { 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 diff --git a/rust/src/settings.rs b/rust/src/settings.rs index ac5e58dad..8bc8565f1 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -14,38 +14,41 @@ //! An interface for reading, writing, and creating new settings -pub use binaryninjacore_sys::BNSettingsScope as SettingsScope; use binaryninjacore_sys::*; -use std::os::raw::c_char; +use std::ffi::c_char; +use std::fmt::Debug; use crate::binary_view::BinaryView; use crate::rc::*; use crate::string::{BnStrCompatible, BnString}; -use std::ptr; +use crate::function::Function; + +pub type SettingsScope = BNSettingsScope; + +pub const DEFAULT_INSTANCE_ID: &str = "default"; +pub const GLOBAL_INSTANCE_ID: &str = ""; #[derive(PartialEq, Eq, Hash)] pub struct Settings { pub(crate) handle: *mut BNSettings, } -unsafe impl Send for Settings {} -unsafe impl Sync for Settings {} - impl Settings { pub(crate) unsafe fn from_raw(handle: *mut BNSettings) -> Ref { debug_assert!(!handle.is_null()); - Ref::new(Self { handle }) } - pub fn new(instance_id: S) -> Ref { + pub fn new() -> Ref { + Self::new_with_id(GLOBAL_INSTANCE_ID) + } + + pub fn new_with_id(instance_id: S) -> Ref { let instance_id = instance_id.into_bytes_with_nul(); unsafe { let handle = BNCreateSettings(instance_id.as_ref().as_ptr() as *mut _); - debug_assert!(!handle.is_null()); - Ref::new(Self { handle }) } } @@ -60,12 +63,20 @@ impl Settings { } pub fn deserialize_schema(&self, schema: S) -> bool { + self.deserialize_schema_with_scope(schema, SettingsScope::SettingsAutoScope) + } + + pub fn deserialize_schema_with_scope( + &self, + schema: S, + scope: SettingsScope, + ) -> bool { let schema = schema.into_bytes_with_nul(); unsafe { BNSettingsDeserializeSchema( self.handle, schema.as_ref().as_ptr() as *mut _, - BNSettingsScope::SettingsAutoScope, + scope, true, ) } @@ -77,126 +88,148 @@ impl Settings { unsafe { BNSettingsContains(self.handle, key.as_ref().as_ptr() as *mut _) } } + pub fn keys(&self) -> Array { + let mut count = 0; + let result = unsafe { BNSettingsKeysList(self.handle, &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result as *mut *mut c_char, count, ()) } + } + // TODO Update the settings API to take an optional BinaryView or Function. Separate functions or...? - pub fn get_bool( + pub fn get_bool(&self, key: S) -> bool { + self.get_bool_with_opts(key, &mut QueryOptions::default()) + } + + pub fn get_bool_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> bool { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsGetBool( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, ) } } - pub fn get_double( + pub fn get_double(&self, key: S) -> f64 { + self.get_double_with_opts(key, &mut QueryOptions::default()) + } + + pub fn get_double_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> f64 { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsGetDouble( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, ) } } - pub fn get_integer( + pub fn get_integer(&self, key: S) -> u64 { + self.get_integer_with_opts(key, &mut QueryOptions::default()) + } + + pub fn get_integer_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> u64 { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsGetUInt64( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, ) } } - pub fn get_string( + pub fn get_string(&self, key: S) -> BnString { + self.get_string_with_opts(key, &mut QueryOptions::default()) + } + + pub fn get_string_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> BnString { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BnString::from_raw(BNSettingsGetString( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, )) } } - pub fn get_string_list( + pub fn get_string_list(&self, key: S) -> Array { + self.get_string_list_with_opts(key, &mut QueryOptions::default()) + } + + pub fn get_string_list_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> Array { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; let mut size: usize = 0; unsafe { @@ -204,9 +237,9 @@ impl Settings { BNSettingsGetStringList( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, &mut size, ) as *mut *mut c_char, size, @@ -215,161 +248,153 @@ impl Settings { } } - pub fn get_property_string_list( - &self, - key: S, - property: S, - ) -> Array { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); - let mut size: usize = 0; - unsafe { - Array::new( - BNSettingsQueryPropertyStringList( - self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - &mut size, - ) as *mut *mut c_char, - size, - (), - ) - } + pub fn get_json(&self, key: S) -> BnString { + self.get_json_with_opts(key, &mut QueryOptions::default()) } - pub fn get_json( + pub fn get_json_with_opts( &self, key: S, - view: Option<&BinaryView>, - scope: Option>, + options: &mut QueryOptions, ) -> BnString { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BnString::from_raw(BNSettingsGetJson( self.handle, key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, + view_ptr, + func_ptr, + &mut options.scope, )) } } - pub fn set_bool( + pub fn set_bool(&self, key: S, value: bool) { + self.set_bool_with_opts(key, value, &QueryOptions::default()) + } + + pub fn set_bool_with_opts( &self, key: S, value: bool, - view: Option<&BinaryView>, - scope: Option, + options: &QueryOptions, ) { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsSetBool( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, value, ); } } - pub fn set_double( + pub fn set_double(&self, key: S, value: f64) { + self.set_double_with_opts(key, value, &QueryOptions::default()) + } + pub fn set_double_with_opts( &self, key: S, value: f64, - view: Option<&BinaryView>, - scope: Option, + options: &QueryOptions, ) { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsSetDouble( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, value, ); } } - pub fn set_integer( + pub fn set_integer(&self, key: S, value: u64) { + self.set_integer_with_opts(key, value, &QueryOptions::default()) + } + + pub fn set_integer_with_opts( &self, key: S, value: u64, - view: Option<&BinaryView>, - scope: Option, + options: &QueryOptions, ) { let key = key.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsSetUInt64( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, value, ); } } - pub fn set_string( + pub fn set_string(&self, key: S1, value: S2) { + self.set_string_with_opts(key, value, &QueryOptions::default()) + } + + pub fn set_string_with_opts( &self, key: S1, value: S2, - view: Option<&BinaryView>, - scope: Option, + options: &QueryOptions, ) { let key = key.into_bytes_with_nul(); let value = value.into_bytes_with_nul(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; unsafe { BNSettingsSetString( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, value.as_ref().as_ptr() as *mut _, ); @@ -380,69 +405,114 @@ impl Settings { &self, key: S1, value: I, - view: Option<&BinaryView>, - scope: Option, + ) -> bool { + self.set_string_list_with_opts(key, value, &QueryOptions::default()) + } + + pub fn set_string_list_with_opts< + S1: BnStrCompatible, + S2: BnStrCompatible, + I: Iterator, + >( + &self, + key: S1, + value: I, + options: &QueryOptions, ) -> bool { let key = key.into_bytes_with_nul(); - let mut list: Vec<_> = value - .map(|s| s.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) + let raw_list: Vec<_> = value.map(|s| s.into_bytes_with_nul()).collect(); + let mut raw_list_ptr: Vec<_> = raw_list + .iter() + .map(|s| s.as_ref().as_ptr() as *const c_char) .collect(); - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - None => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - - let scope = match scope { - Some(scope) => scope, - None => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; - unsafe { BNSettingsSetStringList( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, - list.as_mut_ptr(), - list.len(), + raw_list_ptr.as_mut_ptr(), + raw_list_ptr.len(), ) } } - pub fn set_json( + pub fn set_json(&self, key: S1, value: S2) -> bool { + self.set_json_with_opts(key, value, &QueryOptions::default()) + } + + pub fn set_json_with_opts( &self, key: S1, value: S2, - view: Option<&BinaryView>, - scope: Option, + options: &QueryOptions, ) -> bool { let key = key.into_bytes_with_nul(); let value = value.into_bytes_with_nul(); - - let view_handle = match view { + let view_ptr = match options.view.as_ref() { Some(view) => view.handle, - None => ptr::null_mut() as *mut _, + _ => std::ptr::null_mut(), }; - - let scope = match scope { - Some(scope) => scope, - None => SettingsScope::SettingsAutoScope, + let func_ptr = match options.function.as_ref() { + Some(func) => func.handle, + _ => std::ptr::null_mut(), }; - unsafe { BNSettingsSetJson( self.handle, - view_handle, - std::ptr::null_mut(), - scope, + view_ptr, + func_ptr, + options.scope, key.as_ref().as_ptr() as *mut _, value.as_ref().as_ptr() as *mut _, ) } } + pub fn get_property_string(&self, key: S, property: S) -> BnString { + let key = key.into_bytes_with_nul(); + let property = property.into_bytes_with_nul(); + unsafe { + BnString::from_raw(BNSettingsQueryPropertyString( + self.handle, + key.as_ref().as_ptr() as *mut _, + property.as_ref().as_ptr() as *mut _, + )) + } + } + + pub fn get_property_string_list( + &self, + key: S, + property: S, + ) -> Array { + let key = key.into_bytes_with_nul(); + let property = property.into_bytes_with_nul(); + let mut size: usize = 0; + unsafe { + Array::new( + BNSettingsQueryPropertyStringList( + self.handle, + key.as_ref().as_ptr() as *mut _, + property.as_ref().as_ptr() as *mut _, + &mut size, + ) as *mut *mut c_char, + size, + (), + ) + } + } + pub fn update_bool_property(&self, key: S, property: S, value: bool) { let key = key.into_bytes_with_nul(); let property = property.into_bytes_with_nul(); @@ -504,8 +574,10 @@ impl Settings { ) { let key = key.into_bytes_with_nul(); let property = property.into_bytes_with_nul(); - let mut list: Vec<_> = value - .map(|s| s.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) + let raw_list: Vec<_> = value.map(|s| s.into_bytes_with_nul()).collect(); + let mut raw_list_ptr: Vec<_> = raw_list + .iter() + .map(|s| s.as_ref().as_ptr() as *const c_char) .collect(); unsafe { @@ -513,8 +585,8 @@ impl Settings { self.handle, key.as_ref().as_ptr() as *mut _, property.as_ref().as_ptr() as *mut _, - list.as_mut_ptr(), - list.len(), + raw_list_ptr.as_mut_ptr(), + raw_list_ptr.len(), ); } } @@ -556,6 +628,15 @@ impl Settings { // TODO: register_setting but type-safely turn it into json } +impl Default for Ref { + fn default() -> Self { + Settings::new_with_id(DEFAULT_INSTANCE_ID) + } +} + +unsafe impl Send for Settings {} +unsafe impl Sync for Settings {} + impl ToOwned for Settings { type Owned = Ref; @@ -575,3 +656,57 @@ unsafe impl RefCountable for Settings { BNFreeSettings(handle.handle); } } + +#[derive(Debug, Clone)] +pub struct QueryOptions<'a> { + pub scope: SettingsScope, + pub view: Option<&'a BinaryView>, + pub function: Option>, +} + +impl<'a> QueryOptions<'a> { + pub fn new() -> Self { + Self::default() + } + + pub fn new_with_view(view: &'a BinaryView) -> Self { + Self { + view: Some(view), + ..Default::default() + } + } + + pub fn new_with_func(func: Ref) -> Self { + Self { + function: Some(func), + ..Default::default() + } + } + + /// Set the query to target a specific view, this will be overridden if a function is targeted. + pub fn with_view(mut self, view: &'a BinaryView) -> Self { + self.view = Some(view); + self + } + + pub fn with_scope(mut self, scope: SettingsScope) -> Self { + self.scope = scope; + self + } + + /// Set the query to target a specific function, this will override the target view. + pub fn with_function(mut self, function: Ref) -> Self { + self.function = Some(function); + self + } +} + +impl Default for QueryOptions<'_> { + fn default() -> Self { + Self { + view: None, + scope: SettingsScope::SettingsDefaultScope, + function: None, + } + } +} diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 93c9cbe43..12c716458 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -365,8 +365,8 @@ impl CoreTypePrinter { impl Default for CoreTypePrinter { fn default() -> Self { // TODO: Remove this entirely, there is no "default", its view specific lets not make this some defined behavior. - let default_settings = crate::settings::Settings::new("default"); - let name = default_settings.get_string("analysis.types.printerName", None, None); + let default_settings = crate::settings::Settings::new(); + let name = default_settings.get_string("analysis.types.printerName"); Self::printer_by_name(name).unwrap() } } diff --git a/view/bintxt/Cargo.toml b/view/bintxt/Cargo.toml index 02f463dc2..47740dbd4 100644 --- a/view/bintxt/Cargo.toml +++ b/view/bintxt/Cargo.toml @@ -5,10 +5,10 @@ authors = ["Rubens Brandao "] edition = "2021" [dependencies] -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path = "../../rust/binaryninjacore-sys" } +binaryninja.workspace = true +binaryninjacore-sys.workspace = true ihex = "3.0.0" -log = "*" +log = "0.4" srec = "0.2.0" [lib] diff --git a/view/bintxt/src/ihex.rs b/view/bintxt/src/ihex.rs index 99a5b7af0..0264aa2aa 100644 --- a/view/bintxt/src/ihex.rs +++ b/view/bintxt/src/ihex.rs @@ -8,7 +8,7 @@ use binaryninja::custom_binary_view::*; use binaryninja::platform::Platform; use binaryninja::rc::Ref; use binaryninja::segment::SegmentBuilder; -use binaryninja::settings::Settings; +use binaryninja::settings::{QueryOptions, Settings}; use ihex::Record; fn parse_ihex(string: &str) -> Result<(Vec, IHexViewData)> { @@ -218,8 +218,9 @@ unsafe impl CustomBinaryView for IHexView { } // TODO: Because we detached from the raw view this setting will never be set. + let mut settings_query_opts = QueryOptions::new_with_view(&self.core); let _ = self.core.load_settings(self.type_name()).map(|s| { - let platform_name = s.get_string("loader.platform", Some(&self.core), None); + let platform_name = s.get_string_with_opts("loader.platform", &mut settings_query_opts); if let Some(platform) = Platform::by_name(platform_name) { self.set_default_platform(&platform); } diff --git a/view/minidump/Cargo.toml b/view/minidump/Cargo.toml index 9b224f48d..276080b4c 100644 --- a/view/minidump/Cargo.toml +++ b/view/minidump/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -binaryninja = { path = "../../rust" } -binaryninjacore-sys = { path="../../rust/binaryninjacore-sys" } -log = "0.4.20" +binaryninja.workspace = true +binaryninjacore-sys.workspace = true +log = "0.4" minidump = "0.23.0" \ No newline at end of file