diff --git a/rust/examples/pdb-ng/src/lib.rs b/rust/examples/pdb-ng/src/lib.rs index 0f5b72ec8..e64a2aeab 100644 --- a/rust/examples/pdb-ng/src/lib.rs +++ b/rust/examples/pdb-ng/src/lib.rs @@ -280,21 +280,21 @@ fn search_sym_store(store_path: &String, pdb_info: &PDBInfo) -> Result Option { - match view.get_metadata::("DEBUG_INFO_TYPE") { + match view.get_metadata::("DEBUG_INFO_TYPE") { Some(Ok(0x53445352 /* 'SDSR' */)) => {} _ => return None, } // This is stored in the BV by the PE loader - let file_path = match view.get_metadata::("PDB_FILENAME") { + let file_path = match view.get_metadata::("PDB_FILENAME") { Some(Ok(md)) => md, _ => return None, }; - let mut guid = match view.get_metadata::, _>("PDB_GUID") { + let mut guid = match view.get_metadata::>("PDB_GUID") { Some(Ok(md)) => md, _ => return None, }; - let age = match view.get_metadata::("PDB_AGE") { + let age = match view.get_metadata::("PDB_AGE") { Some(Ok(md)) => md as u32, _ => return None, }; diff --git a/rust/examples/pdb-ng/src/type_parser.rs b/rust/examples/pdb-ng/src/type_parser.rs index 41177c0cc..290219c79 100644 --- a/rust/examples/pdb-ng/src/type_parser.rs +++ b/rust/examples/pdb-ng/src/type_parser.rs @@ -1136,7 +1136,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { let vt_pointer = Type::pointer( &self.arch, &Conf::new( - Type::named_type_from_type(&QualifiedName::from(vt_name), vt_type.as_ref()), + Type::named_type_from_type( + QualifiedName::from(vt_name).string(), + vt_type.as_ref(), + ), max_confidence(), ), ); diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index c3ba864c6..6ecc34395 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -37,7 +37,6 @@ use crate::{ platform::Platform, rc::*, relocation::CoreRelocationHandler, - string::BnStrCompatible, string::*, types::{Conf, NameAndType, Type}, {BranchType, Endianness}, @@ -1085,8 +1084,8 @@ impl CoreArchitecture { CoreArchitectureList(archs, count) } - pub fn by_name(name: &str) -> Option { - let res = unsafe { BNGetArchitectureByName(name.into_bytes_with_nul().as_ptr() as *mut _) }; + pub fn by_name(name: impl AsCStr) -> Option { + let res = unsafe { BNGetArchitectureByName(name.as_cstr().as_ptr()) }; match res.is_null() { false => Some(CoreArchitecture(res)), @@ -1607,12 +1606,8 @@ macro_rules! cc_func { /// Contains helper methods for all types implementing 'Architecture' pub trait ArchitectureExt: Architecture { - fn register_by_name(&self, name: S) -> Option { - let name = name.into_bytes_with_nul(); - - match unsafe { - BNGetArchitectureRegisterByName(self.as_ref().0, name.as_ref().as_ptr() as *mut _) - } { + fn register_by_name(&self, name: impl AsCStr) -> Option { + match unsafe { BNGetArchitectureRegisterByName(self.as_ref().0, name.as_cstr().as_ptr()) } { 0xffff_ffff => None, reg => self.register_from_id(reg), } @@ -1677,7 +1672,7 @@ pub trait ArchitectureExt: Architecture { fn register_relocation_handler(&self, name: S, func: F) where - S: BnStrCompatible, + S: AsCStr, R: 'static + RelocationHandler> + Send @@ -1700,7 +1695,7 @@ impl ArchitectureExt for T {} pub fn register_architecture(name: S, func: F) -> &'static A where - S: BnStrCompatible, + S: AsCStr, A: 'static + Architecture> + Send + Sync + Sized, F: FnOnce(CustomArchitectureHandle, CoreArchitecture) -> A, { @@ -1889,7 +1884,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.register_from_id(reg) { - Some(reg) => BnString::new(reg.name().as_ref()).into_raw(), + Some(reg) => BnString::new(reg.name()).into_raw(), None => BnString::new("invalid_reg").into_raw(), } } @@ -1901,7 +1896,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.flag_from_id(flag) { - Some(flag) => BnString::new(flag.name().as_ref()).into_raw(), + Some(flag) => BnString::new(flag.name()).into_raw(), None => BnString::new("invalid_flag").into_raw(), } } @@ -1913,7 +1908,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.flag_write_from_id(flag_write) { - Some(flag_write) => BnString::new(flag_write.name().as_ref()).into_raw(), + Some(flag_write) => BnString::new(flag_write.name()).into_raw(), None => BnString::new("invalid_flag_write").into_raw(), } } @@ -1925,7 +1920,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.flag_class_from_id(class) { - Some(class) => BnString::new(class.name().as_ref()).into_raw(), + Some(class) => BnString::new(class.name()).into_raw(), None => BnString::new("invalid_flag_class").into_raw(), } } @@ -1937,7 +1932,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.flag_group_from_id(group) { - Some(group) => BnString::new(group.name().as_ref()).into_raw(), + Some(group) => BnString::new(group.name()).into_raw(), None => BnString::new("invalid_flag_group").into_raw(), } } @@ -2400,7 +2395,7 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.register_stack_from_id(stack) { - Some(stack) => BnString::new(stack.name().as_ref()).into_raw(), + Some(stack) => BnString::new(stack.name()).into_raw(), None => BnString::new("invalid_reg_stack").into_raw(), } } @@ -2466,7 +2461,7 @@ where { let custom_arch = unsafe { &*(ctxt as *mut A) }; match custom_arch.intrinsic_from_id(intrinsic) { - Some(intrinsic) => BnString::new(intrinsic.name().as_ref()).into_raw(), + Some(intrinsic) => BnString::new(intrinsic.name()).into_raw(), None => BnString::new("invalid_intrinsic").into_raw(), } } @@ -2752,8 +2747,6 @@ where custom_arch.skip_and_return_value(data, addr, val) } - let name = name.into_bytes_with_nul(); - let uninit_arch = ArchitectureBuilder { arch: MaybeUninit::zeroed(), func: Some(func), @@ -2841,8 +2834,7 @@ where }; unsafe { - let res = - BNRegisterArchitecture(name.as_ref().as_ptr() as *mut _, &mut custom_arch as *mut _); + let res = BNRegisterArchitecture(name.as_cstr().as_ptr(), &mut custom_arch as *mut _); assert!(!res.is_null()); diff --git a/rust/src/backgroundtask.rs b/rust/src/backgroundtask.rs index 21c6b4d1f..8bec69c97 100644 --- a/rust/src/backgroundtask.rs +++ b/rust/src/backgroundtask.rs @@ -30,10 +30,8 @@ pub struct BackgroundTask { } impl BackgroundTask { - pub fn new(initial_text: S, can_cancel: bool) -> Result> { - let text = initial_text.into_bytes_with_nul(); - - let handle = unsafe { BNBeginBackgroundTask(text.as_ref().as_ptr() as *mut _, can_cancel) }; + pub fn new(initial_text: impl AsCStr, can_cancel: bool) -> Result> { + let handle = unsafe { BNBeginBackgroundTask(initial_text.as_cstr().as_ptr(), can_cancel) }; if handle.is_null() { return Err(()); @@ -66,12 +64,8 @@ impl BackgroundTask { unsafe { BNFinishBackgroundTask(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 _) - } + pub fn set_progress_text(&self, text: impl AsCStr) { + unsafe { BNSetBackgroundTaskProgressText(self.handle, text.as_cstr().as_ptr()) } } pub fn running_tasks() -> Array { diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs index 895591813..c2a777382 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binaryview.rs @@ -205,10 +205,7 @@ pub trait BinaryViewExt: BinaryViewBase { } fn raw_view(&self) -> Result> { - let raw = "Raw".into_bytes_with_nul(); - - let handle = - unsafe { BNGetFileViewOfType(self.file().as_ref().handle, raw.as_ptr() as *mut _) }; + let handle = unsafe { BNGetFileViewOfType(self.file().as_ref().handle, c"Raw".as_ptr()) }; if handle.is_null() { return Err(()); @@ -279,13 +276,8 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNGetEndOffset(self.as_ref().handle) } } - fn add_analysis_option(&self, name: impl BnStrCompatible) { - unsafe { - BNAddAnalysisOption( - self.as_ref().handle, - name.into_bytes_with_nul().as_ref().as_ptr() as *mut _, - ) - } + fn add_analysis_option(&self, name: impl AsCStr) { + unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_cstr().as_ptr()) } } fn has_initial_analysis(&self) -> bool { @@ -410,13 +402,11 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_raw_name(&self, raw_name: S) -> Result> { - let raw_name = raw_name.into_bytes_with_nul(); - + fn symbol_by_raw_name(&self, raw_name: impl AsCStr) -> Result> { unsafe { let raw_sym = BNGetSymbolByRawName( self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, + raw_name.as_cstr().as_ptr(), ptr::null_mut(), ); @@ -437,14 +427,12 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_by_name(&self, name: S) -> Array { - let raw_name = name.into_bytes_with_nul(); - + fn symbols_by_name(&self, name: impl AsCStr) -> Array { unsafe { let mut count = 0; let handles = BNGetSymbolsByName( self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, + name.as_cstr().as_ptr(), &mut count, ptr::null_mut(), ); @@ -593,19 +581,15 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_type( + fn define_auto_type( &self, - name: S, - source: S, + name: impl AsCStr, + source: impl AsCStr, type_obj: &Type, ) -> QualifiedName { let mut qualified_name = QualifiedName::from(name); - let source_str = source.into_bytes_with_nul(); let name_handle = unsafe { - let id_str = BNGenerateAutoTypeId( - source_str.as_ref().as_ptr() as *const _, - &mut qualified_name.0, - ); + let id_str = BNGenerateAutoTypeId(source.as_cstr().as_ptr(), &mut qualified_name.0); BNDefineAnalysisType( self.as_ref().handle, id_str, @@ -616,36 +600,30 @@ pub trait BinaryViewExt: BinaryViewBase { QualifiedName(name_handle) } - fn define_user_type(&self, name: S, type_obj: &Type) { + fn define_user_type(&self, name: impl AsCStr, type_obj: &Type) { let mut qualified_name = QualifiedName::from(name); unsafe { BNDefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0, type_obj.handle) } } - fn define_auto_types( + fn define_auto_types( &self, names_sources_and_types: Vec<(S, S, &Type)>, progress: Option Result<()>>>, ) -> HashMap { - let mut names = vec![]; - let mut ids = vec![]; - let mut types = vec![]; - let mut api_types = - Vec::::with_capacity(names_sources_and_types.len()); - for (name, source, type_obj) in names_sources_and_types.into_iter() { - names.push(QualifiedName::from(name)); - ids.push(source.into_bytes_with_nul()); - types.push(type_obj); - } - - for ((name, source), type_obj) in names.iter().zip(ids.iter()).zip(types.iter()) { - api_types.push(BNQualifiedNameTypeAndId { + let names_sources_and_types = names_sources_and_types + .iter() + .map(|(name, source, type_obj)| (QualifiedName::from(name), source.as_cstr(), type_obj)) + .collect::>(); + let mut api_types = names_sources_and_types + .iter() + .map(|(name, source, type_obj)| BNQualifiedNameTypeAndId { name: name.0, - id: source.as_ref().as_ptr() as *mut _, + id: source.as_ptr() as *mut _, type_: type_obj.handle, - }); - } + }) + .collect::>(); let mut progress_raw = ProgressContext(progress); let mut result_ids: *mut *mut c_char = ptr::null_mut(); @@ -662,37 +640,32 @@ pub trait BinaryViewExt: BinaryViewBase { ) }; - let mut result = HashMap::with_capacity(result_count); - let id_array = unsafe { Array::::new(result_ids, result_count, ()) }; let name_array = unsafe { Array::::new(result_names, result_count, ()) }; - for (id, name) in id_array.iter().zip(name_array.iter()) { - result.insert(id.to_string(), name.clone()); - } - - result + id_array + .iter() + .map(|s| s.to_string()) + .zip(name_array.iter().cloned()) + .collect() } - fn define_user_types( + fn define_user_types( &self, names_and_types: Vec<(S, &Type)>, progress: Option Result<()>>>, ) { - let mut names = vec![]; - let mut types = vec![]; - let mut api_types = Vec::::with_capacity(names_and_types.len()); - for (name, type_obj) in names_and_types.into_iter() { - names.push(QualifiedName::from(name)); - types.push(type_obj); - } - - for (name, type_obj) in names.iter().zip(types.iter()) { - api_types.push(BNQualifiedNameAndType { + let names_and_types = names_and_types + .iter() + .map(|(name, type_obj)| (QualifiedName::from(name), type_obj)) + .collect::>(); + let mut api_types = names_and_types + .iter() + .map(|(name, type_obj)| BNQualifiedNameAndType { name: name.0, type_: type_obj.handle, - }); - } + }) + .collect::>(); let mut progress_raw = ProgressContext(progress); unsafe { @@ -706,14 +679,11 @@ pub trait BinaryViewExt: BinaryViewBase { }; } - fn undefine_auto_type(&self, id: S) { - let id_str = id.into_bytes_with_nul(); - unsafe { - BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _); - } + fn undefine_auto_type(&self, id: impl AsCStr) { + unsafe { BNUndefineAnalysisType(self.as_ref().handle, id.as_cstr().as_ptr()) } } - fn undefine_user_type(&self, name: S) { + fn undefine_user_type(&self, name: impl AsCStr) { let mut qualified_name = QualifiedName::from(name); unsafe { BNUndefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0) } } @@ -734,7 +704,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_type_by_name(&self, name: S) -> Option> { + fn get_type_by_name(&self, name: impl AsCStr) -> Option> { unsafe { let mut qualified_name = QualifiedName::from(name); let type_handle = BNGetAnalysisTypeByName(self.as_ref().handle, &mut qualified_name.0); @@ -755,11 +725,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_type_by_id(&self, id: S) -> Option> { + fn get_type_by_id(&self, id: impl AsCStr) -> Option> { unsafe { - let id_str = id.into_bytes_with_nul(); - let type_handle = - BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); + let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id.as_cstr().as_ptr()); if type_handle.is_null() { return None; } @@ -767,11 +735,10 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_type_name_by_id(&self, id: S) -> Option { + fn get_type_name_by_id(&self, id: impl AsCStr) -> Option { unsafe { - let id_str = id.into_bytes_with_nul(); let name_handle = - BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); + BNGetAnalysisTypeNameById(self.as_ref().handle, id.as_cstr().as_ptr()); let name = QualifiedName(name_handle); if name.strings().is_empty() { return None; @@ -780,7 +747,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_type_id(&self, name: S) -> Option { + fn get_type_id(&self, name: impl AsCStr) -> Option { unsafe { let mut qualified_name = QualifiedName::from(name); let id_cstr = BNGetAnalysisTypeId(self.as_ref().handle, &mut qualified_name.0); @@ -792,7 +759,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn is_type_auto_defined(&self, name: S) -> bool { + fn is_type_auto_defined(&self, name: impl AsCStr) -> bool { unsafe { let mut qualified_name = QualifiedName::from(name); BNIsAnalysisTypeAutoDefined(self.as_ref().handle, &mut qualified_name.0) @@ -823,33 +790,21 @@ pub trait BinaryViewExt: BinaryViewBase { segment.create(self.as_ref()); } - fn add_section(&self, section: SectionBuilder) { + fn add_section(&self, section: SectionBuilder) { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: S) { - let name = name.into_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - - unsafe { - BNRemoveAutoSection(self.as_ref().handle, name_ptr); - } + fn remove_auto_section(&self, name: impl AsCStr) { + unsafe { BNRemoveAutoSection(self.as_ref().handle, name.as_cstr().as_ptr()) } } - fn remove_user_section(&self, name: S) { - let name = name.into_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - - unsafe { - BNRemoveUserSection(self.as_ref().handle, name_ptr); - } + fn remove_user_section(&self, name: impl AsCStr) { + unsafe { BNRemoveUserSection(self.as_ref().handle, name.as_cstr().as_ptr()) } } - fn section_by_name(&self, name: S) -> Result
{ + fn section_by_name(&self, name: impl AsCStr) -> Result
{ unsafe { - let raw_name = name.into_bytes_with_nul(); - let name_ptr = raw_name.as_ref().as_ptr() as *mut _; - let raw_section = BNGetSectionByName(self.as_ref().handle, name_ptr); + let raw_section = BNGetSectionByName(self.as_ref().handle, name.as_cstr().as_ptr()); if raw_section.is_null() { return Err(()); @@ -1059,24 +1014,19 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } } - fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { - let raw_name = raw_name.into_bytes_with_nul(); + fn show_graph_report(&self, raw_name: impl AsCStr, graph: &FlowGraph) { unsafe { BNShowGraphReport( self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, + raw_name.as_cstr().as_ptr(), graph.handle, ); } } - fn load_settings(&self, view_type_name: S) -> Result> { - let view_type_name = view_type_name.into_bytes_with_nul(); + fn load_settings(&self, view_type_name: impl AsCStr) -> Result> { let settings_handle = unsafe { - BNBinaryViewGetLoadSettings( - self.as_ref().handle, - view_type_name.as_ref().as_ptr() as *mut _, - ) + BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_cstr().as_ptr()) }; if settings_handle.is_null() { @@ -1086,13 +1036,11 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_load_settings(&self, view_type_name: S, settings: &Settings) { - let view_type_name = view_type_name.into_bytes_with_nul(); - + fn set_load_settings(&self, view_type_name: impl AsCStr, settings: &Settings) { unsafe { BNBinaryViewSetLoadSettings( self.as_ref().handle, - view_type_name.as_ref().as_ptr() as *mut _, + view_type_name.as_cstr().as_ptr(), settings.handle, ) }; @@ -1103,11 +1051,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Arguments /// * `name` - the name for the tag /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag - fn create_tag_type( - &self, - name: N, - icon: I, - ) -> Ref { + fn create_tag_type(&self, name: impl AsCStr, icon: impl AsCStr) -> Ref { let tag_type = TagType::create(self.as_ref(), name, icon); unsafe { BNAddTagType(self.as_ref().handle, tag_type.handle); @@ -1121,11 +1065,9 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Get a tag type by its name. - fn get_tag_type(&self, name: S) -> Option> { - let name = name.into_bytes_with_nul(); - + fn get_tag_type(&self, name: impl AsCStr) -> Option> { unsafe { - let handle = BNGetTagType(self.as_ref().handle, name.as_ref().as_ptr() as *mut _); + let handle = BNGetTagType(self.as_ref().handle, name.as_cstr().as_ptr()); if handle.is_null() { return None; } @@ -1136,10 +1078,9 @@ pub trait BinaryViewExt: BinaryViewBase { /// Get a tag by its id. /// /// Note this does not tell you anything about where it is used. - fn get_tag(&self, id: S) -> Option> { - let id = id.into_bytes_with_nul(); + fn get_tag(&self, id: impl AsCStr) -> Option> { unsafe { - let handle = BNGetTag(self.as_ref().handle, id.as_ref().as_ptr() as *mut _); + let handle = BNGetTag(self.as_ref().handle, id.as_cstr().as_ptr()); if handle.is_null() { return None; } @@ -1150,7 +1091,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Creates and adds a tag to an address /// /// User tag creations will be added to the undo buffer - fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { + fn add_tag(&self, addr: u64, t: &TagType, data: impl AsCStr, user: bool) { let tag = Tag::new(t, data); unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) } @@ -1185,7 +1126,7 @@ pub trait BinaryViewExt: BinaryViewBase { &self, pos: &mut LinearViewCursor, ) -> Array { - let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) }; + let mut result = unsafe { Array::new(ptr::null_mut(), 0, ()) }; while result.is_empty() { result = pos.lines(); @@ -1209,7 +1150,7 @@ pub trait BinaryViewExt: BinaryViewBase { &self, pos: &mut LinearViewCursor, ) -> Array { - let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) }; + let mut result = unsafe { Array::new(ptr::null_mut(), 0, ()) }; while result.is_empty() { if !pos.previous() { return result; @@ -1221,13 +1162,9 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn query_metadata(&self, key: S) -> Option> { - let value: *mut BNMetadata = unsafe { - BNBinaryViewQueryMetadata( - self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - ) - }; + fn query_metadata(&self, key: impl AsCStr) -> Option> { + let value: *mut BNMetadata = + unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_cstr().as_ptr()) }; if value.is_null() { None } else { @@ -1235,7 +1172,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_metadata(&self, key: S) -> Option> + fn get_metadata(&self, key: impl AsCStr) -> Option> where T: for<'a> TryFrom<&'a Metadata>, { @@ -1243,7 +1180,7 @@ pub trait BinaryViewExt: BinaryViewBase { .map(|md| T::try_from(md.as_ref()).map_err(|_| ())) } - fn store_metadata(&self, key: S, value: V, is_auto: bool) + fn store_metadata(&self, key: impl AsCStr, value: V, is_auto: bool) where V: Into>, { @@ -1251,20 +1188,15 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNBinaryViewStoreMetadata( self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.as_cstr().as_ptr(), md.as_ref().handle, is_auto, ) }; } - fn remove_metadata(&self, key: S) { - unsafe { - BNBinaryViewRemoveMetadata( - self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - ) - }; + fn remove_metadata(&self, key: impl AsCStr) { + unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_cstr().as_ptr()) }; } /// Retrieves a list of [CodeReference]s pointing to a given address. @@ -1328,15 +1260,12 @@ pub trait BinaryViewExt: BinaryViewBase { /// used its name instead of this slightly-gross [QualifiedName] hack. Since the returned /// object doesn't have any [QualifiedName], I'm assuming the core does not alias /// the [QualifiedName] we pass to it and it is safe to destroy it on [Drop], as in this function. - fn get_code_refs_for_type(&self, name: B) -> Array { + fn get_code_refs_for_type(&self, name: impl AsCStr) -> Array { + let mut count = 0; + let mut q_name = QualifiedName::from(name); unsafe { - let mut count = 0; - let q_name = &mut QualifiedName::from(name).0; - let handle = BNGetCodeReferencesForType( - self.as_ref().handle, - q_name as *mut BNQualifiedName, - &mut count, - ); + let handle = + BNGetCodeReferencesForType(self.as_ref().handle, &mut q_name.0, &mut count); Array::new(handle, count, ()) } } @@ -1346,15 +1275,12 @@ pub trait BinaryViewExt: BinaryViewBase { /// used its name instead of this slightly-gross [QualifiedName] hack. Since the returned /// object doesn't have any [QualifiedName], I'm assuming the core does not alias /// the [QualifiedName] we pass to it and it is safe to destroy it on [Drop], as in this function. - fn get_data_refs_for_type(&self, name: B) -> Array { + fn get_data_refs_for_type(&self, name: impl AsCStr) -> Array { + let mut count = 0; + let mut q_name = QualifiedName::from(name); unsafe { - let mut count = 0; - let q_name = &mut QualifiedName::from(name).0; - let handle = BNGetDataReferencesForType( - self.as_ref().handle, - q_name as *mut BNQualifiedName, - &mut count, - ); + let handle = + BNGetDataReferencesForType(self.as_ref().handle, &mut q_name.0, &mut count); Array::new(handle, count, ()) } } @@ -1386,14 +1312,8 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn component_by_guid(&self, guid: S) -> Option { - let name = guid.into_bytes_with_nul(); - let result = unsafe { - BNGetComponentByGuid( - self.as_ref().handle, - name.as_ref().as_ptr() as *const core::ffi::c_char, - ) - }; + fn component_by_guid(&self, guid: impl AsCStr) -> Option { + let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, guid.as_cstr().as_ptr()) }; core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) }) } @@ -1406,14 +1326,8 @@ pub trait BinaryViewExt: BinaryViewBase { ComponentBuilder::new_from_raw(self.as_ref().handle) } - fn component_by_path(&self, path: P) -> Option { - let path = path.into_bytes_with_nul(); - let result = unsafe { - BNGetComponentByPath( - self.as_ref().handle, - path.as_ref().as_ptr() as *const core::ffi::c_char, - ) - }; + fn component_by_path(&self, path: impl AsCStr) -> Option { + let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_cstr().as_ptr()) }; core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) }) } @@ -1423,7 +1337,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn remove_component_by_guid(&self, guid: P) -> bool { let path = guid.component_guid(); - unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } + unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_cstr().as_ptr()) } } fn data_variable_parent_components(&self, data_variable: &DataVariable) -> Array { @@ -1443,14 +1357,9 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } } - fn type_library_by_name(&self, name: S) -> Option { - let name = name.into_bytes_with_nul(); - let result = unsafe { - BNGetBinaryViewTypeLibrary( - self.as_ref().handle, - name.as_ref().as_ptr() as *const core::ffi::c_char, - ) - }; + fn type_library_by_name(&self, name: impl AsCStr) -> Option { + let result = + unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_cstr().as_ptr()) }; core::ptr::NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) }) } @@ -1543,13 +1452,9 @@ pub trait BinaryViewExt: BinaryViewBase { /// contain a metadata key called "type_guids" which is a map /// Dict[string_guid, string_type_name] or /// Dict[string_guid, Tuple[string_type_name, type_library_name]] - fn import_type_by_guid(&self, guid: S) -> Option> { - let guid = guid.into_bytes_with_nul(); + fn import_type_by_guid(&self, guid: impl AsCStr) -> Option> { let result = unsafe { - BNBinaryViewImportTypeLibraryTypeByGuid( - self.as_ref().handle, - guid.as_ref().as_ptr() as *const c_char, - ) + BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_cstr().as_ptr()) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -1653,15 +1558,9 @@ impl BinaryView { Ref::new(Self { handle }) } - pub fn from_filename( - meta: &mut FileMetadata, - filename: S, - ) -> Result> { - let file = filename.into_bytes_with_nul(); - - let handle = unsafe { - BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _) - }; + pub fn from_filename(meta: &mut FileMetadata, filename: impl AsCStr) -> Result> { + let handle = + unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, filename.as_cstr().as_ptr()) }; if handle.is_null() { return Err(()); diff --git a/rust/src/callingconvention.rs b/rust/src/callingconvention.rs index e6679928c..6f181eccf 100644 --- a/rust/src/callingconvention.rs +++ b/rust/src/callingconvention.rs @@ -59,7 +59,7 @@ pub trait CallingConventionBase: Sync { pub fn register_calling_convention(arch: &A, name: N, cc: C) -> Ref> where A: Architecture, - N: BnStrCompatible, + N: AsCStr, C: 'static + CallingConventionBase, { struct CustomCallingConventionContext @@ -358,7 +358,6 @@ where ) } - let name = name.into_bytes_with_nul(); let raw = Box::into_raw(Box::new(CustomCallingConventionContext { raw_handle: ptr::null_mut(), cc, @@ -394,8 +393,7 @@ where }; unsafe { - let cc_name = name.as_ref().as_ptr() as *mut _; - let result = BNCreateCallingConvention(arch.as_ref().0, cc_name, &mut cc); + let result = BNCreateCallingConvention(arch.as_ref().0, name.as_cstr().as_ptr(), &mut cc); assert!(!result.is_null()); diff --git a/rust/src/command.rs b/rust/src/command.rs index b8a352625..3f0bb8f04 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -42,7 +42,7 @@ use std::os::raw::c_void; use crate::binaryview::BinaryView; use crate::function::Function; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; /// The trait required for generic commands. See [register] for example usage. pub trait Command: 'static + Sync { @@ -93,9 +93,8 @@ where /// true /// } /// ``` -pub fn register(name: S, desc: S, command: C) +pub fn register(name: impl AsCStr, desc: impl AsCStr, command: C) where - S: BnStrCompatible, C: Command, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView) @@ -126,18 +125,12 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); - - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; - let ctxt = Box::into_raw(Box::new(command)); unsafe { BNRegisterPluginCommand( - name_ptr, - desc_ptr, + name.as_cstr().as_ptr(), + desc.as_cstr().as_ptr(), Some(cb_action::), Some(cb_valid::), ctxt as *mut _, @@ -194,9 +187,8 @@ where /// true /// } /// ``` -pub fn register_for_address(name: S, desc: S, command: C) +pub fn register_for_address(name: impl AsCStr, desc: impl AsCStr, command: C) where - S: BnStrCompatible, C: AddressCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) @@ -227,18 +219,12 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); - - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; - let ctxt = Box::into_raw(Box::new(command)); unsafe { BNRegisterPluginCommandForAddress( - name_ptr, - desc_ptr, + name.as_cstr().as_ptr(), + desc.as_cstr().as_ptr(), Some(cb_action::), Some(cb_valid::), ctxt as *mut _, @@ -296,9 +282,8 @@ where /// true /// } /// ``` -pub fn register_for_range(name: S, desc: S, command: C) +pub fn register_for_range(name: impl AsCStr, desc: impl AsCStr, command: C) where - S: BnStrCompatible, C: RangeCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64) @@ -334,18 +319,12 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); - - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; - let ctxt = Box::into_raw(Box::new(command)); unsafe { BNRegisterPluginCommandForRange( - name_ptr, - desc_ptr, + name.as_cstr().as_ptr(), + desc.as_cstr().as_ptr(), Some(cb_action::), Some(cb_valid::), ctxt as *mut _, @@ -403,9 +382,8 @@ where /// true /// } /// ``` -pub fn register_for_function(name: S, desc: S, command: C) +pub fn register_for_function(name: impl AsCStr, desc: impl AsCStr, command: C) where - S: BnStrCompatible, C: FunctionCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction) @@ -446,18 +424,12 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); - - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; - let ctxt = Box::into_raw(Box::new(command)); unsafe { BNRegisterPluginCommandForFunction( - name_ptr, - desc_ptr, + name.as_cstr().as_ptr(), + desc.as_cstr().as_ptr(), Some(cb_action::), Some(cb_valid::), ctxt as *mut _, diff --git a/rust/src/component.rs b/rust/src/component.rs index 47d81fe4a..136aa5eb6 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -1,9 +1,9 @@ -use std::{ffi, ptr}; +use std::ptr; use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; use crate::function::Function; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::types::{ComponentReferencedTypes, DataVariable}; use binaryninjacore_sys::*; @@ -35,7 +35,7 @@ impl ComponentBuilder { self } - pub fn name(mut self, name: S) -> Self { + pub fn name(mut self, name: impl AsCStr) -> Self { self.name = Some(BnString::new(name)); self } @@ -43,10 +43,18 @@ impl ComponentBuilder { pub fn finalize(self) -> Component { let result = match (&self.parent, &self.name) { (None, None) => unsafe { BNCreateComponent(self.bv) }, - (None, Some(name)) => unsafe { BNCreateComponentWithName(self.bv, name.as_ptr()) }, - (Some(guid), None) => unsafe { BNCreateComponentWithParent(self.bv, guid.as_ptr()) }, + (None, Some(name)) => unsafe { + BNCreateComponentWithName(self.bv, name.as_cstr().as_ptr()) + }, + (Some(guid), None) => unsafe { + BNCreateComponentWithParent(self.bv, guid.as_cstr().as_ptr()) + }, (Some(guid), Some(name)) => unsafe { - BNCreateComponentWithParentAndName(self.bv, guid.as_ptr(), name.as_ptr()) + BNCreateComponentWithParentAndName( + self.bv, + guid.as_cstr().as_ptr(), + name.as_cstr().as_ptr(), + ) }, }; unsafe { Component::from_raw(ptr::NonNull::new(result).unwrap()) } @@ -155,9 +163,8 @@ impl Component { unsafe { BnString::from_raw(result) } } - pub fn set_name(&self, name: S) { - let name = name.into_bytes_with_nul(); - unsafe { BNComponentSetName(self.as_raw(), name.as_ref().as_ptr() as *const ffi::c_char) } + pub fn set_name(&self, name: impl AsCStr) { + unsafe { BNComponentSetName(self.as_raw(), name.as_cstr().as_ptr()) } } /// The component that contains this component, if it exists. @@ -284,7 +291,7 @@ impl IntoComponentGuid for &Component { } } -impl IntoComponentGuid for S { +impl IntoComponentGuid for S { fn component_guid(self) -> BnString { BnString::new(self) } diff --git a/rust/src/custombinaryview.rs b/rust/src/custombinaryview.rs index bc63aad4f..b5606c428 100644 --- a/rust/src/custombinaryview.rs +++ b/rust/src/custombinaryview.rs @@ -41,7 +41,7 @@ use crate::string::*; /// implementation of the [`CustomBinaryViewType`] must return. pub fn register_view_type(name: S, long_name: S, constructor: F) -> &'static T where - S: BnStrCompatible, + S: AsCStr, T: CustomBinaryViewType, F: FnOnce(BinaryViewType) -> T, { @@ -138,12 +138,6 @@ where }) } - let name = name.into_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - - let long_name = long_name.into_bytes_with_nul(); - let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; - let ctxt = Box::leak(Box::new(MaybeUninit::zeroed())); let mut bn_obj = BNCustomBinaryViewType { @@ -156,7 +150,11 @@ where }; unsafe { - let res = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _); + let res = BNRegisterBinaryViewType( + name.as_cstr().as_ptr(), + long_name.as_cstr().as_ptr(), + &mut bn_obj as *mut _, + ); if res.is_null() { // avoid leaking the space allocated for the type, but also @@ -275,10 +273,8 @@ impl BinaryViewType { } /// Looks up a BinaryViewType by its short name - pub fn by_name(name: N) -> Result { - let bytes = name.into_bytes_with_nul(); - - let res = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; + pub fn by_name(name: impl AsCStr) -> Result { + let res = unsafe { BNGetBinaryViewTypeByName(name.as_cstr().as_ptr()) }; match res.is_null() { false => Ok(BinaryViewType(res)), @@ -807,7 +803,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { unsafe { let res = BNCreateCustomBinaryView( - view_name.as_ptr(), + view_name.as_cstr().as_ptr(), file.handle, parent.handle, &mut bn_obj, diff --git a/rust/src/database.rs b/rust/src/database.rs index d12810e07..e1acb384d 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -9,7 +9,7 @@ use crate::databuffer::DataBuffer; use crate::disassembly::InstructionTextToken; use crate::filemetadata::FileMetadata; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct Database { @@ -50,23 +50,21 @@ impl Database { unsafe { BNSetDatabaseCurrentSnapshot(self.as_raw(), value.id()) } } - pub fn write_snapshot_data( + pub fn write_snapshot_data( &self, parents: &[i64], file: &BinaryView, - name: N, + name: impl AsCStr, 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, + name.as_cstr().as_ptr(), data.as_raw(), auto_save, ptr::null_mut(), @@ -75,21 +73,18 @@ impl Database { } } - pub fn write_snapshot_data_with_progress( + pub fn write_snapshot_data_with_progress( &self, parents: &[i64], file: &BinaryView, - name: N, + name: impl AsCStr, data: &KeyValueStore, auto_save: bool, mut progress: F, ) -> i64 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 { BNWriteDatabaseSnapshotData( @@ -97,7 +92,7 @@ impl Database { parents.as_ptr() as *mut _, parents.len(), file.handle, - name_ptr, + name.as_cstr().as_ptr(), data.as_raw(), auto_save, ctxt, @@ -125,10 +120,8 @@ impl Database { Err(()) } } - 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 } + pub fn has_global(&self, key: impl AsCStr) -> bool { + unsafe { BNDatabaseHasGlobal(self.as_raw(), key.as_cstr().as_ptr()) != 0 } } /// Get a list of keys for all globals in the database @@ -148,35 +141,31 @@ 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) }; + pub fn read_global(&self, key: impl AsCStr) -> Option { + let result = unsafe { BNReadDatabaseGlobal(self.as_raw(), key.as_cstr().as_ptr()) }; unsafe { ptr::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 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) } + pub fn write_global(&self, key: impl AsCStr, value: impl AsCStr) -> bool { + unsafe { + BNWriteDatabaseGlobal( + self.as_raw(), + key.as_cstr().as_ptr(), + value.as_cstr().as_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) }; + pub fn read_global_data(&self, key: impl AsCStr) -> Option { + let result = unsafe { BNReadDatabaseGlobalData(self.as_raw(), key.as_cstr().as_ptr()) }; 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()) } + pub fn write_global_data(&self, key: impl AsCStr, value: &DataBuffer) -> bool { + unsafe { BNWriteDatabaseGlobalData(self.as_raw(), key.as_cstr().as_ptr(), value.as_raw()) } } /// Get the owning FileMetadata @@ -258,10 +247,8 @@ impl Snapshot { } /// 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) } + pub fn set_name(&self, value: impl AsCStr) { + unsafe { BNSetSnapshotName(self.as_raw(), value.as_cstr().as_ptr()) } } /// If the snapshot was the result of an auto-save @@ -436,18 +423,14 @@ impl KeyValueStore { } /// 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) }; + pub fn value(&self, key: impl AsCStr) -> Option { + let result = unsafe { BNGetKeyValueStoreBuffer(self.as_raw(), key.as_cstr().as_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()) } + pub fn set_value(&self, key: impl AsCStr, value: &DataBuffer) -> bool { + unsafe { BNSetKeyValueStoreBuffer(self.as_raw(), key.as_cstr().as_ptr(), value.as_raw()) } } /// Get the stored representation of the kvs @@ -458,10 +441,8 @@ impl KeyValueStore { } /// 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) } + pub fn begin_namespace(&self, name: impl AsCStr) { + unsafe { BNBeginKeyValueStoreNamespace(self.as_raw(), name.as_cstr().as_ptr()) } } /// End storing new keys into a namespace diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 470ff85f4..2008e8230 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -74,11 +74,12 @@ use crate::{ binaryview::BinaryView, platform::Platform, rc::*, - string::{raw_to_string, BnStrCompatible, BnString}, + string::{raw_to_string, AsCStr, BnString}, types::{DataVariableAndName, NameAndType, NamedTypedVariable, Type}, }; -use std::{hash::Hash, os::raw::c_void, ptr, slice}; +use std::ffi::c_void; +use std::{hash::Hash, ptr, slice}; struct ProgressContext(Option Result<(), ()>>>); @@ -101,9 +102,8 @@ impl DebugInfoParser { } /// Returns debug info parser of the given name, if it exists - pub fn from_name(name: S) -> Result, ()> { - let name = name.into_bytes_with_nul(); - let parser = unsafe { BNGetDebugInfoParserByName(name.as_ref().as_ptr() as *mut _) }; + pub fn from_name(name: impl AsCStr) -> Result, ()> { + let parser = unsafe { BNGetDebugInfoParserByName(name.as_cstr().as_ptr()) }; if parser.is_null() { Err(()) @@ -184,9 +184,8 @@ impl DebugInfoParser { } // Registers a DebugInfoParser. See `binaryninja::debuginfo::DebugInfoParser` for more details. - pub fn register(name: S, parser_callbacks: C) -> Ref + pub fn register(name: impl AsCStr, parser_callbacks: C) -> Ref where - S: BnStrCompatible, C: CustomDebugInfoParser, { extern "C" fn cb_is_valid(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool @@ -236,13 +235,11 @@ impl DebugInfoParser { }) } - let name = name.into_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; let ctxt = Box::into_raw(Box::new(parser_callbacks)); unsafe { DebugInfoParser::from_raw(BNRegisterDebugInfoParser( - name_ptr, + name.as_cstr().as_ptr(), Some(cb_is_valid::), Some(cb_parse_info::), ctxt as *mut _, @@ -396,17 +393,10 @@ impl DebugInfo { } /// Returns a generator of all types provided by a named DebugInfoParser - pub fn types_by_name(&self, parser_name: S) -> Vec> { - let parser_name = parser_name.into_bytes_with_nul(); - + pub fn types_by_name(&self, parser_name: impl AsCStr) -> Vec> { let mut count: usize = 0; - let debug_types_ptr = unsafe { - BNGetDebugTypes( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let debug_types_ptr = + unsafe { BNGetDebugTypes(self.handle, parser_name.as_cstr().as_ptr(), &mut count) }; let result: Vec> = unsafe { slice::from_raw_parts_mut(debug_types_ptr, count) .iter() @@ -434,17 +424,10 @@ impl DebugInfo { } /// Returns a generator of all functions provided by a named DebugInfoParser - pub fn functions_by_name(&self, parser_name: S) -> Vec { - let parser_name = parser_name.into_bytes_with_nul(); - + pub fn functions_by_name(&self, parser_name: impl AsCStr) -> Vec { let mut count: usize = 0; - let functions_ptr = unsafe { - BNGetDebugFunctions( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let functions_ptr = + unsafe { BNGetDebugFunctions(self.handle, parser_name.as_cstr().as_ptr(), &mut count) }; let result: Vec = unsafe { slice::from_raw_parts_mut(functions_ptr, count) @@ -475,19 +458,13 @@ impl DebugInfo { } /// Returns a generator of all data variables provided by a named DebugInfoParser - pub fn data_variables_by_name( + pub fn data_variables_by_name( &self, - parser_name: S, + parser_name: impl AsCStr, ) -> Vec> { - let parser_name = parser_name.into_bytes_with_nul(); - let mut count: usize = 0; let data_variables_ptr = unsafe { - BNGetDebugDataVariables( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) + BNGetDebugDataVariables(self.handle, parser_name.as_cstr().as_ptr(), &mut count) }; let result: Vec> = unsafe { @@ -519,15 +496,12 @@ impl DebugInfo { } /// May return nullptr - pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); - + pub fn type_by_name(&self, parser_name: impl AsCStr, name: impl AsCStr) -> Option> { let result = unsafe { BNGetDebugTypeByName( self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, + parser_name.as_cstr().as_ptr(), + name.as_cstr().as_ptr(), ) }; if !result.is_null() { @@ -537,19 +511,16 @@ impl DebugInfo { } } - pub fn get_data_variable_by_name( + pub fn get_data_variable_by_name( &self, - parser_name: S, - name: S, + parser_name: impl AsCStr, + name: impl AsCStr, ) -> Option<(u64, Ref)> { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); - let result = unsafe { BNGetDebugDataVariableByName( self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, + parser_name.as_cstr().as_ptr(), + name.as_cstr().as_ptr(), ) }; @@ -561,18 +532,13 @@ impl DebugInfo { } } - pub fn get_data_variable_by_address( + pub fn get_data_variable_by_address( &self, - parser_name: S, + parser_name: impl AsCStr, address: u64, ) -> Option<(String, Ref)> { - let parser_name = parser_name.into_bytes_with_nul(); let name_and_var = unsafe { - BNGetDebugDataVariableByAddress( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - address, - ) + BNGetDebugDataVariableByAddress(self.handle, parser_name.as_cstr().as_ptr(), address) }; if !name_and_var.is_null() { @@ -590,13 +556,10 @@ impl DebugInfo { } // The tuple is (DebugInfoParserName, type) - pub fn get_types_by_name(&self, name: S) -> Vec<(String, Ref)> { - let name = name.into_bytes_with_nul(); - + pub fn get_types_by_name(&self, name: impl AsCStr) -> Vec<(String, Ref)> { let mut count: usize = 0; - let raw_names_and_types = unsafe { - BNGetDebugTypesByName(self.handle, name.as_ref().as_ptr() as *mut _, &mut count) - }; + let raw_names_and_types = + unsafe { BNGetDebugTypesByName(self.handle, name.as_cstr().as_ptr(), &mut count) }; let names_and_types: &[*mut BNNameAndType] = unsafe { slice::from_raw_parts(raw_names_and_types as *mut _, count) }; @@ -617,15 +580,10 @@ impl DebugInfo { } // The tuple is (DebugInfoParserName, address, type) - pub fn get_data_variables_by_name( - &self, - name: S, - ) -> Vec<(String, u64, Ref)> { - let name = name.into_bytes_with_nul(); - + pub fn get_data_variables_by_name(&self, name: impl AsCStr) -> Vec<(String, u64, Ref)> { let mut count: usize = 0; let raw_variables_and_names = unsafe { - BNGetDebugDataVariablesByName(self.handle, name.as_ref().as_ptr() as *mut _, &mut count) + BNGetDebugDataVariablesByName(self.handle, name.as_cstr().as_ptr(), &mut count) }; let variables_and_names: &[*mut BNDataVariableAndName] = @@ -672,99 +630,59 @@ impl DebugInfo { result } - pub fn remove_parser_info(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - - unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ref().as_ptr() as *mut _) } + pub fn remove_parser_info(&self, parser_name: impl AsCStr) -> bool { + unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_cstr().as_ptr()) } } - pub fn remove_parser_types(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - - unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ref().as_ptr() as *mut _) } + pub fn remove_parser_types(&self, parser_name: impl AsCStr) -> bool { + unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_cstr().as_ptr()) } } - pub fn remove_parser_functions(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - - unsafe { - BNRemoveDebugParserFunctions(self.handle, parser_name.as_ref().as_ptr() as *mut _) - } + pub fn remove_parser_functions(&self, parser_name: impl AsCStr) -> bool { + unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_cstr().as_ptr()) } } - pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - - unsafe { - BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ref().as_ptr() as *mut _) - } + pub fn remove_parser_data_variables(&self, parser_name: impl AsCStr) -> bool { + unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_cstr().as_ptr()) } } - pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); - + pub fn remove_type_by_name(&self, parser_name: impl AsCStr, name: impl AsCStr) -> bool { unsafe { BNRemoveDebugTypeByName( self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, + parser_name.as_cstr().as_ptr(), + name.as_cstr().as_ptr(), ) } } - pub fn remove_function_by_index( - &self, - parser_name: S, - index: usize, - ) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - - unsafe { - BNRemoveDebugFunctionByIndex( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - index, - ) - } + pub fn remove_function_by_index(&self, parser_name: impl AsCStr, index: usize) -> bool { + unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_cstr().as_ptr(), index) } } - pub fn remove_data_variable_by_address( - &self, - parser_name: S, - address: u64, - ) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - + pub fn remove_data_variable_by_address(&self, parser_name: impl AsCStr, address: u64) -> bool { unsafe { - BNRemoveDebugDataVariableByAddress( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - address, - ) + BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_cstr().as_ptr(), address) } } /// Adds a type scoped under the current parser's name to the debug info - pub fn add_type( - &self, - name: S, - new_type: &Type, - components: &[&str], - ) -> bool { - let mut components_array: Vec<*const ::std::os::raw::c_char> = - Vec::with_capacity(components.len()); - for component in components { - components_array.push(component.as_ptr() as _); - } + pub fn add_type(&self, name: impl AsCStr, new_type: &Type, components: &[&str]) -> bool { + let components = components + .iter() + .map(|component| component.as_cstr()) + .collect::>(); + let mut components_array = components + .iter() + .map(|component| component.as_ptr()) + .collect::>(); - let name = name.into_bytes_with_nul(); unsafe { BNAddDebugType( self.handle, - name.as_ref().as_ptr() as *mut _, + name.as_cstr().as_ptr(), new_type.handle, - components_array.as_ptr() as _, + components_array.as_mut_ptr(), components.len(), ) } @@ -772,50 +690,36 @@ impl DebugInfo { /// Adds a function scoped under the current parser's name to the debug info pub fn add_function(&self, new_func: DebugFunctionInfo) -> bool { - let short_name_bytes = new_func.short_name.map(|name| name.into_bytes_with_nul()); - let short_name = short_name_bytes - .as_ref() - .map_or(ptr::null_mut() as *mut _, |name| name.as_ptr() as _); - let full_name_bytes = new_func.full_name.map(|name| name.into_bytes_with_nul()); - let full_name = full_name_bytes - .as_ref() - .map_or(ptr::null_mut() as *mut _, |name| name.as_ptr() as _); - let raw_name_bytes = new_func.raw_name.map(|name| name.into_bytes_with_nul()); - let raw_name = raw_name_bytes - .as_ref() - .map_or(ptr::null_mut() as *mut _, |name| name.as_ptr() as _); - - let mut components_array: Vec<*mut ::std::os::raw::c_char> = - Vec::with_capacity(new_func.components.len()); - - let mut local_variables_array: Vec = - Vec::with_capacity(new_func.local_variables.len()); + let short_name = new_func.short_name.as_ref().map(|name| name.as_cstr()); + let full_name = new_func.full_name.as_ref().map(|name| name.as_cstr()); + let raw_name = new_func.raw_name.as_ref().map(|name| name.as_cstr()); - unsafe { - for component in &new_func.components { - components_array.push(BNAllocString( - component.clone().into_bytes_with_nul().as_ptr() as _, - )); - } + let mut components = new_func + .components + .iter() + .map(|component| unsafe { BNAllocString(component.as_cstr().as_ptr()) }) + .collect::>(); - for local_variable in &new_func.local_variables { - local_variables_array.push(BNVariableNameAndType { - var: local_variable.var.raw(), - autoDefined: local_variable.auto_defined, - typeConfidence: local_variable.ty.confidence, - name: BNAllocString( - local_variable.name.clone().into_bytes_with_nul().as_ptr() as _ - ), - type_: local_variable.ty.contents.handle, - }); - } + let mut local_variables = new_func + .local_variables + .iter() + .map(|local_var| BNVariableNameAndType { + var: local_var.var.raw(), + autoDefined: local_var.auto_defined, + typeConfidence: local_var.ty.confidence, + name: unsafe { BNAllocString(local_var.name.as_cstr().as_ptr()) }, + type_: local_var.ty.contents.handle, + }) + .collect::>(); + let null_mut = ptr::null_mut(); + unsafe { let result = BNAddDebugFunction( self.handle, &mut BNDebugFunctionInfo { - shortName: short_name, - fullName: full_name, - rawName: raw_name, + shortName: short_name.map_or(null_mut, |name| name.as_ptr() as *mut _), + fullName: full_name.map_or(null_mut, |name| name.as_ptr() as *mut _), + rawName: raw_name.map_or(null_mut, |name| name.as_ptr() as *mut _), address: new_func.address, type_: match new_func.type_ { Some(type_) => type_.handle, @@ -825,18 +729,18 @@ impl DebugInfo { Some(platform) => platform.handle, _ => ptr::null_mut(), }, - components: components_array.as_ptr() as _, + components: components.as_mut_ptr(), componentN: new_func.components.len(), - localVariables: local_variables_array.as_ptr() as _, - localVariableN: local_variables_array.len(), + localVariables: local_variables.as_mut_ptr(), + localVariableN: local_variables.len(), }, ); - for i in components_array { + for i in components { BNFreeString(i); } - for i in &local_variables_array { + for i in &local_variables { BNFreeString(i.name); } result @@ -844,55 +748,46 @@ impl DebugInfo { } /// Adds a data variable scoped under the current parser's name to the debug info - pub fn add_data_variable( + pub fn add_data_variable( &self, address: u64, t: &Type, - name: Option, + name: Option, components: &[&str], ) -> bool { - let mut components_array: Vec<*const ::std::os::raw::c_char> = - Vec::with_capacity(components.len()); - for component in components { - components_array.push(component.as_ptr() as _); - } + let name = name.as_ref().map(|name| name.as_cstr()); + let name = name.map_or(ptr::null_mut(), |name| name.as_ptr() as *mut _); - match name { - Some(name) => { - let name = name.into_bytes_with_nul(); - unsafe { - BNAddDebugDataVariable( - self.handle, - address, - t.handle, - name.as_ref().as_ptr() as *mut _, - components.as_ptr() as _, - components.len(), - ) - } - } - None => unsafe { - BNAddDebugDataVariable( - self.handle, - address, - t.handle, - ptr::null_mut(), - components.as_ptr() as _, - components.len(), - ) - }, + let components = components + .iter() + .map(|component| component.as_cstr()) + .collect::>(); + let mut components_array = components + .iter() + .map(|component| component.as_ptr()) + .collect::>(); + + unsafe { + BNAddDebugDataVariable( + self.handle, + address, + t.handle, + name, + components_array.as_mut_ptr(), + components_array.len(), + ) } } - pub fn add_data_variable_info(&self, var: DataVariableAndName) -> bool { - let name = var.name.into_bytes_with_nul(); + pub fn add_data_variable_info(&self, var: DataVariableAndName) -> bool { + let var_name = var.name.as_cstr(); unsafe { BNAddDebugDataVariableInfo( self.handle, &BNDataVariableAndName { address: var.address, type_: var.t.contents.handle, - name: name.as_ref().as_ptr() as *mut _, + name: var_name.as_ptr() as *mut _, autoDiscovered: var.auto_discovered, typeConfidence: var.t.confidence, }, diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index 2de6bab62..d7491e9a0 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -15,25 +15,24 @@ //! Interfaces for demangling and simplifying mangled names in binaries. use binaryninjacore_sys::*; -use std::os::raw::c_char; -use std::{ffi::CStr, result}; +use std::ptr; +use std::result; use crate::architecture::CoreArchitecture; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::types::Type; use crate::rc::*; pub type Result = result::Result; -pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Result> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); - let mut out_name: *mut *mut std::os::raw::c_char = unsafe { std::mem::zeroed() }; - let mut out_size: usize = 0; +pub fn demangle_llvm(mangled_name: impl AsCStr, simplify: bool) -> Result> { + let mangled_name = mangled_name.as_cstr(); + let mut out_name = ptr::null_mut(); + let mut out_size = 0; let res = unsafe { BNDemangleLLVM( - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_name, &mut out_size, simplify, @@ -41,14 +40,7 @@ pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Res }; if !res || out_size == 0 { - let cstr = match CStr::from_bytes_with_nul(mangled_name_ptr) { - Ok(cstr) => cstr, - Err(_) => { - log::error!("demangle_llvm: failed to parse mangled name"); - return Err(()); - } - }; - return Ok(vec![cstr.to_string_lossy().into_owned()]); + return Ok(vec![mangled_name.to_string_lossy().into_owned()]); } if out_name.is_null() { @@ -66,20 +58,19 @@ pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Res Ok(names) } -pub fn demangle_gnu3( +pub fn demangle_gnu3( arch: &CoreArchitecture, - mangled_name: S, + mangled_name: impl AsCStr, simplify: bool, ) -> Result<(Option>, Vec)> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); - let mut out_type: *mut BNType = std::ptr::null_mut(); - let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); - let mut out_size: usize = 0; + let mangled_name = mangled_name.as_cstr(); + let mut out_type = ptr::null_mut(); + let mut out_name = ptr::null_mut(); + let mut out_size = 0; let res = unsafe { BNDemangleGNU3( arch.0, - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_type, &mut out_name, &mut out_size, @@ -88,14 +79,7 @@ pub fn demangle_gnu3( }; if !res || out_size == 0 { - let cstr = match CStr::from_bytes_with_nul(mangled_name_ptr) { - Ok(cstr) => cstr, - Err(_) => { - log::error!("demangle_gnu3: failed to parse mangled name"); - return Err(()); - } - }; - return Ok((None, vec![cstr.to_string_lossy().into_owned()])); + return Ok((None, vec![mangled_name.to_string_lossy().into_owned()])); } let out_type = match out_type.is_null() { @@ -121,21 +105,19 @@ pub fn demangle_gnu3( Ok((out_type, names)) } -pub fn demangle_ms( +pub fn demangle_ms( arch: &CoreArchitecture, - mangled_name: S, + mangled_name: impl AsCStr, simplify: bool, ) -> Result<(Option>, Vec)> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); - - let mut out_type: *mut BNType = std::ptr::null_mut(); - let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); - let mut out_size: usize = 0; + let mangled_name = mangled_name.as_cstr(); + let mut out_type = ptr::null_mut(); + let mut out_name = ptr::null_mut(); + let mut out_size = 0; let res = unsafe { BNDemangleMS( arch.0, - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_type, &mut out_name, &mut out_size, @@ -144,14 +126,7 @@ pub fn demangle_ms( }; if !res || out_size == 0 { - let cstr = match CStr::from_bytes_with_nul(mangled_name_ptr) { - Ok(cstr) => cstr, - Err(_) => { - log::error!("demangle_ms: failed to parse mangled name"); - return Err(()); - } - }; - return Ok((None, vec![cstr.to_string_lossy().into_owned()])); + return Ok((None, vec![mangled_name.to_string_lossy().into_owned()])); } let out_type = match out_type.is_null() { diff --git a/rust/src/downloadprovider.rs b/rust/src/downloadprovider.rs index 1b4321145..ebb4ef1d7 100644 --- a/rust/src/downloadprovider.rs +++ b/rust/src/downloadprovider.rs @@ -1,6 +1,6 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; use crate::settings::Settings; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::ffi::{c_void, CStr}; @@ -14,12 +14,8 @@ pub struct DownloadProvider { } impl DownloadProvider { - pub fn get(name: S) -> Option { - let result = unsafe { - BNGetDownloadProviderByName( - name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char - ) - }; + pub fn get(name: impl AsCStr) -> Option { + let result = unsafe { BNGetDownloadProviderByName(name.as_cstr().as_ptr()) }; if result.is_null() { return None; } @@ -129,9 +125,9 @@ impl DownloadInstance { } } - pub fn perform_request( + pub fn perform_request( &mut self, - url: S, + url: impl AsCStr, callbacks: DownloadInstanceOutputCallbacks, ) -> Result<(), BnString> { let callbacks = Box::into_raw(Box::new(callbacks)); @@ -145,7 +141,7 @@ impl DownloadInstance { let result = unsafe { BNPerformDownloadRequest( self.handle, - url.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + url.as_cstr().as_ptr(), &mut cbs as *mut BNDownloadInstanceOutputCallbacks, ) }; @@ -194,33 +190,24 @@ impl DownloadInstance { } } - pub fn perform_custom_request< - M: BnStrCompatible, - U: BnStrCompatible, - HK: BnStrCompatible, - HV: BnStrCompatible, - I: IntoIterator, - >( + pub fn perform_custom_request( &mut self, - method: M, - url: U, - headers: I, + method: impl AsCStr, + url: impl AsCStr, + headers: impl IntoIterator, callbacks: DownloadInstanceInputOutputCallbacks, ) -> Result { - let mut header_keys = vec![]; - let mut header_values = vec![]; + let mut keys = vec![]; + let mut values = vec![]; for (key, value) in headers { - header_keys.push(key.into_bytes_with_nul()); - header_values.push(value.into_bytes_with_nul()); - } - - let mut header_key_ptrs = vec![]; - let mut header_value_ptrs = vec![]; - - for (key, value) in header_keys.iter().zip(header_values.iter()) { - header_key_ptrs.push(key.as_ref().as_ptr() as *const c_char); - header_value_ptrs.push(value.as_ref().as_ptr() as *const c_char); + keys.push(key.as_cstr().into_owned()); + values.push(value.as_cstr().into_owned()); } + let header_keys = keys.iter().map(|key| key.as_ptr()).collect::>(); + let header_values = values + .iter() + .map(|value| value.as_ptr()) + .collect::>(); let callbacks = Box::into_raw(Box::new(callbacks)); let mut cbs = BNDownloadInstanceInputOutputCallbacks { @@ -237,11 +224,11 @@ impl DownloadInstance { let result = unsafe { BNPerformCustomRequest( self.handle, - method.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - url.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - header_key_ptrs.len() as u64, - header_key_ptrs.as_ptr(), - header_value_ptrs.as_ptr(), + method.as_cstr().as_ptr(), + url.as_cstr().as_ptr(), + header_keys.len() as u64, + header_keys.as_ptr(), + header_values.as_ptr(), &mut response as *mut *mut BNDownloadInstanceResponse, &mut cbs as *mut BNDownloadInstanceInputOutputCallbacks, ) diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index 82d4d3794..d87cdb905 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::rc::Array; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub fn server_username() -> BnString { unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUsername()) } @@ -12,13 +12,8 @@ pub fn server_url() -> BnString { unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } } -pub fn set_server_url(url: S) -> Result<(), ()> { - let url = url.into_bytes_with_nul(); - let result = unsafe { - binaryninjacore_sys::BNSetEnterpriseServerUrl( - url.as_ref().as_ptr() as *const std::os::raw::c_char - ) - }; +pub fn set_server_url(url: impl AsCStr) -> Result<(), ()> { + let result = unsafe { binaryninjacore_sys::BNSetEnterpriseServerUrl(url.as_cstr().as_ptr()) }; if result { Ok(()) } else { @@ -69,27 +64,24 @@ pub fn is_server_license_still_activated() -> bool { unsafe { binaryninjacore_sys::BNIsEnterpriseServerLicenseStillActivated() } } -pub fn authenticate_server_with_credentials(username: U, password: P, remember: bool) -> bool -where - U: BnStrCompatible, - P: BnStrCompatible, -{ - let username = username.into_bytes_with_nul(); - let password = password.into_bytes_with_nul(); +pub fn authenticate_server_with_credentials( + username: impl AsCStr, + password: impl AsCStr, + remember: bool, +) -> bool { unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithCredentials( - username.as_ref().as_ptr() as *const std::os::raw::c_char, - password.as_ref().as_ptr() as *const std::os::raw::c_char, + username.as_cstr().as_ptr(), + password.as_cstr().as_ptr(), remember, ) } } -pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { - let method = method.into_bytes_with_nul(); +pub fn authenticate_server_with_method(method: impl AsCStr, remember: bool) -> bool { unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithMethod( - method.as_ref().as_ptr() as *const std::os::raw::c_char, + method.as_cstr().as_ptr(), remember, ) } diff --git a/rust/src/externallibrary.rs b/rust/src/externallibrary.rs index 2cbcd8e15..a02c2f893 100644 --- a/rust/src/externallibrary.rs +++ b/rust/src/externallibrary.rs @@ -1,10 +1,10 @@ -use core::{ffi, mem, ptr}; +use core::{mem, ptr}; use binaryninjacore_sys::*; use crate::project::ProjectFile; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::symbol::Symbol; /// An ExternalLibrary is an abstraction for a library that is optionally backed @@ -179,10 +179,9 @@ impl ExternalLocation { /// 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()); + pub fn set_target_symbol(&self, symbol: Option) -> bool { + let symbol = symbol.as_ref().map(|x| x.as_cstr()); + let symbol = symbol.map_or(ptr::null_mut(), |x| x.as_ptr() as *mut _); unsafe { BNExternalLocationSetTargetSymbol(self.as_raw(), symbol) } } } diff --git a/rust/src/filemetadata.rs b/rust/src/filemetadata.rs index a41adc8a4..74e5b1dae 100644 --- a/rust/src/filemetadata.rs +++ b/rust/src/filemetadata.rs @@ -73,7 +73,7 @@ impl FileMetadata { } } - pub fn with_filename(name: S) -> Ref { + pub fn with_filename(name: impl AsCStr) -> Ref { let ret = FileMetadata::new(); ret.set_filename(name); ret @@ -92,12 +92,8 @@ impl FileMetadata { } } - pub fn set_filename(&self, name: S) { - let name = name.into_bytes_with_nul(); - - unsafe { - BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _); - } + pub fn set_filename(&self, name: impl AsCStr) { + unsafe { BNSetFilename(self.handle, name.as_cstr().as_ptr()) } } pub fn modified(&self) -> bool { @@ -120,10 +116,8 @@ impl FileMetadata { unsafe { BNIsAnalysisChanged(self.handle) } } - pub fn is_database_backed(&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 _) } + pub fn is_database_backed(&self, view_type: impl AsCStr) -> bool { + unsafe { BNIsBackedByDatabase(self.handle, view_type.as_cstr().as_ptr()) } } pub fn run_undoable_transaction Result, T, E>( @@ -148,18 +142,12 @@ impl FileMetadata { unsafe { BnString::from_raw(BNBeginUndoActions(self.handle, anonymous_allowed)) } } - pub fn commit_undo_actions(&self, id: S) { - let id = id.into_bytes_with_nul(); - unsafe { - BNCommitUndoActions(self.handle, id.as_ref().as_ptr() as *const _); - } + pub fn commit_undo_actions(&self, id: impl AsCStr) { + unsafe { BNCommitUndoActions(self.handle, id.as_cstr().as_ptr()) } } - pub fn revert_undo_actions(&self, id: S) { - let id = id.into_bytes_with_nul(); - unsafe { - BNRevertUndoActions(self.handle, id.as_ref().as_ptr() as *const _); - } + pub fn revert_undo_actions(&self, id: impl AsCStr) { + unsafe { BNRevertUndoActions(self.handle, id.as_cstr().as_ptr()) } } pub fn undo(&self) { @@ -182,11 +170,9 @@ impl FileMetadata { unsafe { BNGetCurrentOffset(self.handle) } } - pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { - let view = view.into_bytes_with_nul(); - + pub fn navigate_to(&self, view: impl AsCStr, offset: u64) -> Result<(), ()> { unsafe { - if BNNavigate(self.handle, view.as_ref().as_ptr() as *const _, offset) { + if BNNavigate(self.handle, view.as_cstr().as_ptr(), offset) { Ok(()) } else { Err(()) @@ -194,11 +180,9 @@ impl FileMetadata { } } - pub fn get_view_of_type(&self, view: S) -> Result, ()> { - let view = view.into_bytes_with_nul(); - + pub fn get_view_of_type(&self, view: impl AsCStr) -> Result, ()> { unsafe { - let res = BNGetFileViewOfType(self.handle, view.as_ref().as_ptr() as *const _); + let res = BNGetFileViewOfType(self.handle, view.as_cstr().as_ptr()); if res.is_null() { Err(()) @@ -208,23 +192,20 @@ impl FileMetadata { } } - pub fn create_database( + pub fn create_database( &self, - filename: S, + filename: impl AsCStr, progress_func: Option bool>, ) -> bool { - let filename = filename.into_bytes_with_nul(); - let filename_ptr = filename.as_ref().as_ptr() as *mut _; - let raw = "Raw".into_bytes_with_nul(); - let raw_ptr = raw.as_ptr() as *mut _; + let filename = filename.as_cstr(); - let handle = unsafe { BNGetFileViewOfType(self.handle, raw_ptr) }; + let handle = unsafe { BNGetFileViewOfType(self.handle, c"Raw".as_ptr()) }; match progress_func { - None => unsafe { BNCreateDatabase(handle, filename_ptr, ptr::null_mut()) }, + None => unsafe { BNCreateDatabase(handle, filename.as_ptr(), ptr::null_mut()) }, Some(func) => unsafe { BNCreateDatabaseWithProgress( handle, - filename_ptr, + filename.as_ptr(), func as *mut c_void, Some(cb_progress_func), ptr::null_mut(), @@ -234,23 +215,20 @@ impl FileMetadata { } pub fn save_auto_snapshot(&self) -> bool { - let raw = "Raw".into_bytes_with_nul(); unsafe { BNSaveAutoSnapshot( - BNGetFileViewOfType(self.handle, raw.as_ptr() as *mut _), - ptr::null_mut() as *mut _, + BNGetFileViewOfType(self.handle, c"Raw".as_ptr()), + ptr::null_mut(), ) } } - pub fn open_database_for_configuration( + pub fn open_database_for_configuration( &self, - filename: S, + filename: impl AsCStr, ) -> Result, ()> { - let filename = filename.into_bytes_with_nul(); unsafe { - let bv = - BNOpenDatabaseForConfiguration(self.handle, filename.as_ref().as_ptr() as *const _); + let bv = BNOpenDatabaseForConfiguration(self.handle, filename.as_cstr().as_ptr()); if bv.is_null() { Err(()) @@ -260,13 +238,12 @@ impl FileMetadata { } } - pub fn open_database( + pub fn open_database( &self, - filename: S, + filename: impl AsCStr, progress_func: Option bool>, ) -> Result, ()> { - let filename = filename.into_bytes_with_nul(); - let filename_ptr = filename.as_ref().as_ptr() as *mut _; + let filename_ptr = filename.as_cstr().as_ptr(); let view = match progress_func { None => unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }, diff --git a/rust/src/function.rs b/rust/src/function.rs index 01d1fd0c5..b9395386d 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -189,12 +189,8 @@ impl Function { unsafe { BnString::from_raw(BNGetFunctionComment(self.handle)) } } - pub fn set_comment(&self, comment: S) { - let raw = comment.into_bytes_with_nul(); - - unsafe { - BNSetFunctionComment(self.handle, raw.as_ref().as_ptr() as *mut _); - } + pub fn set_comment(&self, comment: impl AsCStr) { + unsafe { BNSetFunctionComment(self.handle, comment.as_cstr().as_ptr()) } } pub fn set_can_return_auto>>(&self, can_return: T) { @@ -211,11 +207,9 @@ impl Function { unsafe { BnString::from_raw(BNGetCommentForAddress(self.handle, addr)) } } - pub fn set_comment_at(&self, addr: u64, comment: S) { - let raw = comment.into_bytes_with_nul(); - + pub fn set_comment_at(&self, addr: u64, comment: impl AsCStr) { unsafe { - BNSetCommentForAddress(self.handle, addr, raw.as_ref().as_ptr() as *mut _); + BNSetCommentForAddress(self.handle, addr, comment.as_cstr().as_ptr()); } } @@ -952,10 +946,10 @@ impl Function { /// let crash = bv.create_tag_type("Crashes", "🎯"); /// fun.add_tag(&crash, "Nullpointer dereference", Some(0x1337), false, None); /// ``` - pub fn add_tag( + pub fn add_tag( &self, tag_type: &TagType, - data: S, + data: impl AsCStr, addr: Option, user: bool, arch: Option, @@ -1489,20 +1483,18 @@ impl Function { /// * `display_type` - Desired display type /// * `arch` - (optional) Architecture of the instruction or IL line containing the token /// * `enum_display_typeid` - (optional) Whenever passing EnumDisplayType to `display_type`, passing a type ID here will specify the Enumeration display type. Must be a valid type ID and resolve to an enumeration type. - pub fn set_int_display_type( + pub fn set_int_display_type( &self, instr_addr: u64, value: u64, operand: usize, display_type: IntegerDisplayType, arch: Option, - enum_display_typeid: Option, + enum_display_typeid: Option, ) { let arch = arch.unwrap_or_else(|| self.arch()); - let enum_display_typeid = enum_display_typeid.map(BnStrCompatible::into_bytes_with_nul); - let enum_display_typeid_ptr = enum_display_typeid - .map(|x| x.as_ref().as_ptr() as *const c_char) - .unwrap_or(core::ptr::null()); + let type_id = enum_display_typeid.as_ref().map(|x| x.as_cstr()); + let type_id = type_id.map_or(std::ptr::null(), |x| x.as_ptr()); unsafe { BNSetIntegerConstantDisplayType( self.handle, @@ -1511,7 +1503,7 @@ impl Function { value, operand, display_type, - enum_display_typeid_ptr, + type_id, ) } } diff --git a/rust/src/headless.rs b/rust/src/headless.rs index e84022760..b92ec940b 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - binaryview, rc, - string::{BnStrCompatible, IntoJson}, -}; +use crate::string::{AsCStr, IntoJson}; +use crate::{binaryview, rc}; use std::env; use std::path::PathBuf; @@ -82,10 +80,9 @@ use binaryninjacore_sys::{BNInitPlugins, BNInitRepoPlugins, BNSetBundledPluginDi /// You can instead call this through [`Session`] or [`script_helper`] pub fn init() { unsafe { - let path = binja_path().join("plugins").into_os_string(); - let path = path.into_string().unwrap(); + let path = binja_path().join("plugins"); - BNSetBundledPluginDirectory(path.as_str().into_bytes_with_nul().as_ptr() as *mut _); + BNSetBundledPluginDirectory(path.to_str().unwrap().as_cstr().as_ptr()); BNInitPlugins(true); BNInitRepoPlugins(); } diff --git a/rust/src/hlil/operation.rs b/rust/src/hlil/operation.rs index c4ad476e5..50233fe88 100644 --- a/rust/src/hlil/operation.rs +++ b/rust/src/hlil/operation.rs @@ -1,11 +1,9 @@ -use core::ffi; - use binaryninjacore_sys::*; use crate::architecture::CoreIntrinsic; use crate::function::Function; use crate::rc::Ref; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::types::{ConstantData, SSAVariable, Variable}; use super::HighLevelILLiftedInstruction; @@ -21,14 +19,9 @@ impl GotoLabel { unsafe { BnString::from_raw(BNGetGotoLabelName(self.function.handle, self.target)) } } - fn set_name(&self, name: S) { - let raw = name.into_bytes_with_nul(); + fn set_name(&self, name: impl AsCStr) { unsafe { - BNSetUserGotoLabelName( - self.function.handle, - self.target, - raw.as_ref().as_ptr() as *const ffi::c_char, - ) + BNSetUserGotoLabelName(self.function.handle, self.target, name.as_cstr().as_ptr()) } } } @@ -333,7 +326,7 @@ impl LiftedLabel { self.target.name() } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: impl AsCStr) { self.target.set_name(name) } } diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 9d66730de..1f6e0c8af 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -18,19 +18,20 @@ use binaryninjacore_sys::*; use std::ffi::{c_char, c_void, CStr}; use std::path::PathBuf; +use std::ptr; use crate::binaryview::BinaryView; use crate::rc::Ref; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; -pub fn get_text_line_input(prompt: &str, title: &str) -> Option { - let mut value: *mut c_char = std::ptr::null_mut(); +pub fn get_text_line_input(prompt: impl AsCStr, title: impl AsCStr) -> Option { + let mut value = ptr::null_mut(); let result = unsafe { BNGetTextLineInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, + prompt.as_cstr().as_ptr(), + title.as_cstr().as_ptr(), ) }; if !result { @@ -40,14 +41,14 @@ pub fn get_text_line_input(prompt: &str, title: &str) -> Option { Some(unsafe { BnString::from_raw(value).to_string() }) } -pub fn get_integer_input(prompt: &str, title: &str) -> Option { +pub fn get_integer_input(prompt: impl AsCStr, title: impl AsCStr) -> Option { let mut value: i64 = 0; let result = unsafe { BNGetIntegerInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, + prompt.as_cstr().as_ptr(), + title.as_cstr().as_ptr(), ) }; @@ -58,15 +59,15 @@ pub fn get_integer_input(prompt: &str, title: &str) -> Option { Some(value) } -pub fn get_address_input(prompt: &str, title: &str) -> Option { +pub fn get_address_input(prompt: impl AsCStr, title: impl AsCStr) -> Option { let mut value: u64 = 0; let result = unsafe { BNGetAddressInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, - std::ptr::null_mut(), + prompt.as_cstr().as_ptr(), + title.as_cstr().as_ptr(), + ptr::null_mut(), 0, ) }; @@ -78,14 +79,14 @@ pub fn get_address_input(prompt: &str, title: &str) -> Option { Some(value) } -pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option { - let mut value: *mut c_char = std::ptr::null_mut(); +pub fn get_open_filename_input(prompt: impl AsCStr, extension: impl AsCStr) -> Option { + let mut value = ptr::null_mut(); let result = unsafe { BNGetOpenFileNameInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - extension.into_bytes_with_nul().as_ptr() as *mut _, + prompt.as_cstr().as_ptr(), + extension.as_cstr().as_ptr(), ) }; if !result { @@ -96,15 +97,19 @@ pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option Some(PathBuf::from(string.as_str())) } -pub fn get_save_filename_input(prompt: &str, title: &str, default_name: &str) -> Option { - let mut value: *mut c_char = std::ptr::null_mut(); +pub fn get_save_filename_input( + prompt: impl AsCStr, + title: impl AsCStr, + default_name: impl AsCStr, +) -> Option { + let mut value = ptr::null_mut(); let result = unsafe { BNGetSaveFileNameInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, - default_name.into_bytes_with_nul().as_ptr() as *mut _, + prompt.as_cstr().as_ptr(), + title.as_cstr().as_ptr(), + default_name.as_cstr().as_ptr(), ) }; if !result { @@ -115,14 +120,14 @@ pub fn get_save_filename_input(prompt: &str, title: &str, default_name: &str) -> Some(PathBuf::from(string.as_str())) } -pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option { - let mut value: *mut c_char = std::ptr::null_mut(); +pub fn get_directory_name_input(prompt: impl AsCStr, default_name: impl AsCStr) -> Option { + let mut value = ptr::null_mut(); let result = unsafe { BNGetDirectoryNameInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - default_name.into_bytes_with_nul().as_ptr() as *mut _, + prompt.as_cstr().as_ptr(), + default_name.as_cstr().as_ptr(), ) }; if !result { @@ -137,15 +142,15 @@ pub type MessageBoxButtonSet = BNMessageBoxButtonSet; pub type MessageBoxIcon = BNMessageBoxIcon; pub type MessageBoxButtonResult = BNMessageBoxButtonResult; pub fn show_message_box( - title: &str, - text: &str, + title: impl AsCStr, + text: impl AsCStr, buttons: MessageBoxButtonSet, icon: MessageBoxIcon, ) -> MessageBoxButtonResult { unsafe { BNShowMessageBox( - title.into_bytes_with_nul().as_ptr() as *mut _, - text.into_bytes_with_nul().as_ptr() as *mut _, + title.as_cstr().as_ptr(), + text.as_cstr().as_ptr(), buttons, icon, ) @@ -206,7 +211,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::LabelFormField; result.hasDefault = false; - result.prompt = text.as_ref().as_ptr() as *const c_char; + result.prompt = text.as_raw(); self.fields.push(result); self.data.push(FormData::Label { _text: text }); @@ -229,10 +234,10 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::TextLineFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_raw(); } self.fields.push(result); @@ -250,10 +255,10 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::MultilineTextFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_raw(); } self.fields.push(result); @@ -270,7 +275,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::IntegerFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); result.hasDefault = default.is_some(); if let Some(default) = default { result.intDefault = default; @@ -293,7 +298,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::AddressFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); if let Some(view) = view { // the view is being moved into result, there is no need to clone // and drop is intentionally being avoided with `Ref::into_raw` @@ -317,11 +322,9 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::ChoiceFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - let mut raw_choices: Vec<*const c_char> = choices - .iter() - .map(|c| c.as_ref().as_ptr() as *const c_char) - .collect(); + result.prompt = prompt.as_raw(); + let mut raw_choices: Vec<*const c_char> = + choices.iter().map(|c| c.as_raw() as *const _).collect(); result.choices = raw_choices.as_mut_ptr(); result.count = choices.len(); result.hasDefault = default.is_some(); @@ -355,11 +358,11 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::OpenFileNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.ext = ext.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); + result.ext = ext.as_raw(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_raw(); } self.fields.push(result); @@ -394,12 +397,12 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::SaveFileNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.ext = ext.as_ref().as_ptr() as *const c_char; - result.defaultName = default_name.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); + result.ext = ext.as_raw(); + result.defaultName = default_name.as_raw(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_raw(); } self.fields.push(result); @@ -429,11 +432,11 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::DirectoryNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.defaultName = default_name.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_raw(); + result.defaultName = default_name.as_raw(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_raw(); } self.fields.push(result); @@ -486,12 +489,12 @@ impl FormInputBuilder { /// /// println!("{} {} likes {}", &first_name, &last_name, food); /// ``` - pub fn get_form_input(&mut self, title: &str) -> Vec { + pub fn get_form_input(&mut self, title: impl AsCStr) -> Vec { if unsafe { BNGetFormInput( self.fields.as_mut_ptr(), self.fields.len(), - title.into_bytes_with_nul().as_ptr() as *const _, + title.as_cstr().as_ptr(), ) } { let result = self @@ -542,7 +545,7 @@ impl Default for FormInputBuilder { struct TaskContext Result<(), ()>>)>(F); pub fn run_progress_dialog Result<(), ()>>)>( - title: &str, + title: impl AsCStr, can_cancel: bool, task: F, ) -> Result<(), ()> { @@ -573,7 +576,7 @@ pub fn run_progress_dialog Result<(), ()>>)>( if unsafe { BNRunProgressDialog( - title.into_bytes_with_nul().as_ptr() as *mut _, + title.as_cstr().as_ptr(), can_cancel, Some(cb_task::), &mut ctxt as *mut _ as *mut c_void, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index e968ee225..f8be2a757 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -189,16 +189,16 @@ pub mod typelibrary; pub mod types; pub mod update; -use std::path::PathBuf; use std::ptr; pub use binaryninjacore_sys::BNBranchType as BranchType; pub use binaryninjacore_sys::BNEndianness as Endianness; use binaryview::BinaryView; -use metadata::Metadata; -use metadata::MetadataType; -use string::BnStrCompatible; -use string::IntoJson; +use metadata::{Metadata, MetadataType}; +use rc::Ref; +use string::{AsCStr, IntoJson}; + +use std::path::PathBuf; // Commented out to suppress unused warnings // const BN_MAX_INSTRUCTION_LENGTH: u64 = 256; @@ -241,18 +241,12 @@ unsafe extern "C" fn cb_progress_nop( } /// 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(filename: S) -> Option> -where - S: BnStrCompatible, -{ - let filename = filename.into_bytes_with_nul(); - let options = "\x00"; - +pub fn load(filename: impl AsCStr) -> Option> { let handle = unsafe { binaryninjacore_sys::BNLoadFilename( - filename.as_ref().as_ptr() as *mut _, + filename.as_cstr().as_ptr(), true, - options.as_ptr() as *mut core::ffi::c_char, + c"".as_ptr(), Some(cb_progress_nop), ptr::null_mut(), ) @@ -265,24 +259,17 @@ where } } -pub fn load_with_progress( - filename: S, - mut progress: F, -) -> Option> +pub fn load_with_progress(filename: impl AsCStr, mut progress: F) -> Option> where - S: BnStrCompatible, F: FnMut(usize, usize) -> bool, { - let filename = filename.into_bytes_with_nul(); - let options = "\x00"; - let progress_ctx = &mut progress as *mut F as *mut std::ffi::c_void; let handle = unsafe { binaryninjacore_sys::BNLoadFilename( - filename.as_ref().as_ptr() as *mut _, + filename.as_cstr().as_ptr(), true, - options.as_ptr() as *mut core::ffi::c_char, + c"".as_ptr(), Some(cb_progress_func::), progress_ctx, ) @@ -312,38 +299,26 @@ where /// let bv = binaryninja::load_with_options("/bin/cat", true, Some(json!("analysis.linearSweep.autorun": false).to_string())) /// .expect("Couldn't open `/bin/cat`"); /// ``` -pub fn load_with_options( - filename: S, +pub fn load_with_options( + filename: impl AsCStr, update_analysis_and_wait: bool, options: Option, -) -> Option> -where - S: BnStrCompatible, - O: IntoJson, -{ - let filename = filename.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() +) -> Option> { + let options_or_default: &dyn AsCStr = if let Some(opt) = options { + &opt.get_json_string().ok()? } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) + &Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() .ok()? - .as_ref() - .to_vec() }; let handle = unsafe { binaryninjacore_sys::BNLoadFilename( - filename.as_ref().as_ptr() as *mut _, + filename.as_cstr().as_ptr(), update_analysis_and_wait, - options_or_default.as_ptr() as *mut core::ffi::c_char, + options_or_default.as_cstr().as_ptr(), Some(cb_progress_nop), - core::ptr::null_mut(), + ptr::null_mut(), ) }; @@ -354,43 +329,34 @@ where } } -pub fn load_with_options_and_progress( - filename: S, +pub fn load_with_options_and_progress( + filename: impl AsCStr, update_analysis_and_wait: bool, options: Option, progress: Option, -) -> Option> +) -> Option> where - S: BnStrCompatible, O: IntoJson, F: FnMut(usize, usize) -> bool, { - let filename = filename.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() + let options_or_default: &dyn AsCStr = if let Some(opt) = options { + &opt.get_json_string().ok()? } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) + &Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() .ok()? - .as_ref() - .to_vec() }; let progress_ctx = match progress { Some(mut x) => &mut x as *mut F as *mut std::ffi::c_void, - None => core::ptr::null_mut(), + None => ptr::null_mut(), }; let handle = unsafe { binaryninjacore_sys::BNLoadFilename( - filename.as_ref().as_ptr() as *mut _, + filename.as_cstr().as_ptr(), update_analysis_and_wait, - options_or_default.as_ptr() as *mut core::ffi::c_char, + options_or_default.as_cstr().as_ptr(), Some(cb_progress_func::), progress_ctx, ) @@ -403,35 +369,26 @@ where } } -pub fn load_view( +pub fn load_view( bv: &BinaryView, update_analysis_and_wait: bool, options: Option, -) -> Option> -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() +) -> Option> { + let options_or_default: &dyn AsCStr = if let Some(opt) = options { + &opt.get_json_string().ok()? } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) + &Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() .ok()? - .as_ref() - .to_vec() }; let handle = unsafe { binaryninjacore_sys::BNLoadBinaryView( bv.handle as *mut _, update_analysis_and_wait, - options_or_default.as_ptr() as *mut core::ffi::c_char, + options_or_default.as_cstr().as_ptr(), Some(cb_progress_nop), - core::ptr::null_mut(), + ptr::null_mut(), ) }; @@ -447,35 +404,29 @@ pub fn load_view_with_progress( update_analysis_and_wait: bool, options: Option, progress: Option, -) -> Option> +) -> Option> where O: IntoJson, F: FnMut(usize, usize) -> bool, { - let options_or_default = if let Some(opt) = options { - opt.get_json_string() - .ok()? - .into_bytes_with_nul() - .as_ref() - .to_vec() + let options_or_default: &dyn AsCStr = if let Some(opt) = options { + &opt.get_json_string().ok()? } else { - Metadata::new_of_type(MetadataType::KeyValueDataType) + &Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() .ok()? - .as_ref() - .to_vec() }; let progress_ctx = match progress { Some(mut x) => &mut x as *mut F as *mut std::ffi::c_void, - None => core::ptr::null_mut(), + None => ptr::null_mut(), }; let handle = unsafe { binaryninjacore_sys::BNLoadBinaryView( - bv.handle as *mut _, + bv.handle, update_analysis_and_wait, - options_or_default.as_ptr() as *mut core::ffi::c_char, + options_or_default.as_cstr().as_ptr(), Some(cb_progress_func::), progress_ctx, ) @@ -509,12 +460,8 @@ pub fn bundled_plugin_directory() -> Result { )) } -pub fn set_bundled_plugin_directory(new_dir: S) { - unsafe { - binaryninjacore_sys::BNSetBundledPluginDirectory( - new_dir.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) - }; +pub fn set_bundled_plugin_directory(new_dir: impl AsCStr) { + unsafe { binaryninjacore_sys::BNSetBundledPluginDirectory(new_dir.as_cstr().as_ptr()) }; } pub fn user_directory() -> Result { @@ -561,13 +508,9 @@ pub fn save_last_run() { unsafe { binaryninjacore_sys::BNSaveLastRun() }; } -pub fn path_relative_to_bundled_plugin_directory( - path: S, -) -> Result { - let s: *mut std::os::raw::c_char = unsafe { - binaryninjacore_sys::BNGetPathRelativeToBundledPluginDirectory( - path.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) +pub fn path_relative_to_bundled_plugin_directory(path: impl AsCStr) -> Result { + let s = unsafe { + binaryninjacore_sys::BNGetPathRelativeToBundledPluginDirectory(path.as_cstr().as_ptr()) }; if s.is_null() { return Err(()); @@ -577,13 +520,9 @@ pub fn path_relative_to_bundled_plugin_directory( )) } -pub fn path_relative_to_user_plugin_directory( - path: S, -) -> Result { - let s: *mut std::os::raw::c_char = unsafe { - binaryninjacore_sys::BNGetPathRelativeToUserPluginDirectory( - path.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) +pub fn path_relative_to_user_plugin_directory(path: impl AsCStr) -> Result { + let s = unsafe { + binaryninjacore_sys::BNGetPathRelativeToUserPluginDirectory(path.as_cstr().as_ptr()) }; if s.is_null() { return Err(()); @@ -593,12 +532,9 @@ pub fn path_relative_to_user_plugin_directory( )) } -pub fn path_relative_to_user_directory(path: S) -> Result { - let s: *mut std::os::raw::c_char = unsafe { - binaryninjacore_sys::BNGetPathRelativeToUserDirectory( - path.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) - }; +pub fn path_relative_to_user_directory(path: impl AsCStr) -> Result { + let s = + unsafe { binaryninjacore_sys::BNGetPathRelativeToUserDirectory(path.as_cstr().as_ptr()) }; if s.is_null() { return Err(()); } @@ -649,12 +585,8 @@ pub fn license_count() -> i32 { unsafe { binaryninjacore_sys::BNGetLicenseCount() } } -pub fn set_license(license: S) { - let license = license.into_bytes_with_nul(); - let license_slice = license.as_ref(); - unsafe { - binaryninjacore_sys::BNSetLicense(license_slice.as_ptr() as *const std::os::raw::c_char) - } +pub fn set_license(license: impl AsCStr) { + unsafe { binaryninjacore_sys::BNSetLicense(license.as_cstr().as_ptr()) } } pub fn product() -> string::BnString { @@ -676,12 +608,8 @@ pub fn is_ui_enabled() -> bool { unsafe { binaryninjacore_sys::BNIsUIEnabled() } } -pub fn is_database(filename: S) -> bool { - let filename = filename.into_bytes_with_nul(); - let filename_slice = filename.as_ref(); - unsafe { - binaryninjacore_sys::BNIsDatabase(filename_slice.as_ptr() as *const std::os::raw::c_char) - } +pub fn is_database(filename: impl AsCStr) -> bool { + unsafe { binaryninjacore_sys::BNIsDatabase(filename.as_cstr().as_ptr()) } } pub fn plugin_abi_version() -> u32 { @@ -708,20 +636,12 @@ pub fn plugin_ui_abi_minimum_version() -> u32 { binaryninjacore_sys::BN_MINIMUM_UI_ABI_VERSION } -pub fn add_required_plugin_dependency(name: S) { - unsafe { - binaryninjacore_sys::BNAddRequiredPluginDependency( - name.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) - }; +pub fn add_required_plugin_dependency(name: impl AsCStr) { + unsafe { binaryninjacore_sys::BNAddRequiredPluginDependency(name.as_cstr().as_ptr()) }; } -pub fn add_optional_plugin_dependency(name: S) { - unsafe { - binaryninjacore_sys::BNAddOptionalPluginDependency( - name.into_bytes_with_nul().as_ref().as_ptr() as *const std::os::raw::c_char, - ) - }; +pub fn add_optional_plugin_dependency(name: impl AsCStr) { + unsafe { binaryninjacore_sys::BNAddOptionalPluginDependency(name.as_cstr().as_ptr()) }; } // Provide ABI version automatically so that the core can verify binary compatibility diff --git a/rust/src/llil.rs b/rust/src/llil.rs index 2b1518916..a002bcc59 100644 --- a/rust/src/llil.rs +++ b/rust/src/llil.rs @@ -66,7 +66,7 @@ impl Register { impl fmt::Debug for Register { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Register::ArchReg(ref r) => write!(f, "{}", r.name().as_ref()), + Register::ArchReg(ref r) => write!(f, "{}", r.name()), Register::Temp(id) => write!(f, "temp{}", id), } } diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index a6b2630c2..d95e2f9f3 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString, IntoJson}; +use crate::string::{AsCStr, BnString, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::os::raw::c_char; @@ -266,16 +266,11 @@ impl Metadata { Ok(Some(unsafe { Self::ref_from_raw(ptr) })) } - pub fn get(&self, key: S) -> Result>, ()> { + pub fn get(&self, key: impl AsCStr) -> Result>, ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } - let ptr: *mut BNMetadata = unsafe { - BNMetadataGetForKey( - self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - ) - }; + let ptr = unsafe { BNMetadataGetForKey(self.handle, key.as_cstr().as_ptr()) }; if ptr.is_null() { return Ok(None); } @@ -290,18 +285,12 @@ impl Metadata { Ok(()) } - pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { + pub fn insert(&self, key: impl AsCStr, value: &Metadata) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } - unsafe { - BNMetadataSetValueForKey( - self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - value.handle, - ) - }; + unsafe { BNMetadataSetValueForKey(self.handle, key.as_cstr().as_ptr(), value.handle) }; Ok(()) } @@ -314,17 +303,12 @@ impl Metadata { Ok(()) } - pub fn remove_key(&self, key: S) -> Result<(), ()> { + pub fn remove_key(&self, key: impl AsCStr) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } - unsafe { - BNMetadataRemoveKey( - self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - ) - }; + unsafe { BNMetadataRemoveKey(self.handle, key.as_cstr().as_ptr()) }; Ok(()) } } @@ -396,21 +380,13 @@ impl From for Ref { impl From for Ref { fn from(value: String) -> Self { - unsafe { - Metadata::ref_from_raw(BNCreateMetadataStringData( - value.into_bytes_with_nul().as_ptr() as *const c_char, - )) - } + unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData(value.as_cstr().as_ptr())) } } } impl From<&str> for Ref { fn from(value: &str) -> Self { - unsafe { - Metadata::ref_from_raw(BNCreateMetadataStringData( - value.into_bytes_with_nul().as_ptr() as *const c_char, - )) - } + unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData(value.as_cstr().as_ptr())) } } } @@ -444,17 +420,11 @@ impl From<&Array> for Ref { } } -impl From>> for Ref { +impl From>> for Ref { fn from(value: HashMap>) -> Self { - let data: Vec<(S::Result, Ref)> = value - .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v)) - .collect(); - let mut keys: Vec<*const c_char> = data - .iter() - .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) - .collect(); - let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); + let keys = value.keys().map(|k| k.as_cstr()).collect::>(); + let mut keys = keys.iter().map(|k| k.as_ptr()).collect::>(); + let mut values = value.values().map(|v| v.handle).collect::>(); unsafe { Metadata::ref_from_raw(BNCreateMetadataValueStore( @@ -468,19 +438,16 @@ impl From>> for Ref { impl From<&[(S, T)]> for Ref where - S: BnStrCompatible + Copy, + S: AsCStr, for<'a> &'a T: Into>, { fn from(value: &[(S, T)]) -> Self { - let data: Vec<(S::Result, Ref)> = value - .iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into())) - .collect(); - let mut keys: Vec<*const c_char> = data + let keys = value.iter().map(|(k, _)| k.as_cstr()).collect::>(); + let mut keys = keys.iter().map(|k| k.as_ptr()).collect::>(); + let mut values = value .iter() - .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) - .collect(); - let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); + .map(|(_, v)| v.into().handle) + .collect::>(); unsafe { Metadata::ref_from_raw(BNCreateMetadataValueStore( @@ -494,7 +461,7 @@ where impl From<[(S, T); N]> for Ref where - S: BnStrCompatible + Copy, + S: AsCStr, for<'a> &'a T: Into>, { fn from(value: [(S, T); N]) -> Self { @@ -548,19 +515,13 @@ impl From<&Vec> for Ref { } } -impl From> for Ref { +impl From> for Ref { fn from(value: Vec) -> Self { - let mut refs = vec![]; - for v in value { - refs.push(v.into_bytes_with_nul()); - } - let mut pointers = vec![]; - for r in &refs { - pointers.push(r.as_ref().as_ptr() as *const c_char); - } + let value = value.iter().map(|s| s.as_cstr()).collect::>(); + let mut pointers = value.iter().map(|s| s.as_ptr()).collect::>(); unsafe { Metadata::ref_from_raw(BNCreateMetadataStringListData( - pointers.as_ptr() as *mut *const c_char, + pointers.as_mut_ptr(), pointers.len(), )) } @@ -707,16 +668,18 @@ impl TryFrom<&Metadata> for HashMap> { } } -impl IntoJson for &Metadata { +impl IntoJson for Metadata { type Output = BnString; - fn get_json_string(self) -> Result { - Metadata::get_json_string(self) + + fn get_json_string(self) -> Result { + Metadata::get_json_string(&self) } } impl IntoJson for Ref { type Output = BnString; - fn get_json_string(self) -> Result { + + fn get_json_string(self) -> Result { Metadata::get_json_string(&self) } } diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs index ad7a819a6..2d484f40b 100644 --- a/rust/src/mlil/function.rs +++ b/rust/src/mlil/function.rs @@ -1,5 +1,4 @@ use core::hash::{Hash, Hasher}; -use std::ffi::c_char; use binaryninjacore_sys::*; @@ -9,7 +8,7 @@ use crate::disassembly::DisassemblySettings; use crate::flowgraph::FlowGraph; use crate::function::{Function, Location}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use crate::types::{ Conf, MediumLevelILSSAVariable, PossibleValueSet, RegisterValue, SSAVariable, Type, UserVariableValues, Variable, @@ -119,21 +118,20 @@ impl MediumLevelILFunction { } } - pub fn create_user_stack_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_user_stack_var<'a, C: Into>>( self, offset: i64, var_type: C, - name: S, + name: impl AsCStr, ) { let var_type = var_type.into(); let mut raw_var_type: BNTypeWithConfidence = var_type.into(); - let name = name.into_bytes_with_nul(); unsafe { BNCreateUserStackVariable( self.get_function().handle, offset, &mut raw_var_type, - name.as_ref().as_ptr() as *const c_char, + name.as_cstr().as_ptr(), ) } } @@ -142,22 +140,21 @@ impl MediumLevelILFunction { unsafe { BNDeleteUserStackVariable(self.get_function().handle, offset) } } - pub fn create_user_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_user_var<'a, C: Into>>( &self, var: &Variable, var_type: C, - name: S, + name: impl AsCStr, ignore_disjoint_uses: bool, ) { let var_type = var_type.into(); let raw_var_type: BNTypeWithConfidence = var_type.into(); - let name = name.into_bytes_with_nul(); unsafe { BNCreateUserVariable( self.get_function().handle, &var.raw(), &raw_var_type as *const _ as *mut _, - name.as_ref().as_ptr() as *const _, + name.as_cstr().as_ptr(), ignore_disjoint_uses, ) } @@ -261,22 +258,20 @@ impl MediumLevelILFunction { Ok(()) } - pub fn create_auto_stack_var<'a, T: Into>, S: BnStrCompatible>( + pub fn create_auto_stack_var<'a, T: Into>>( &self, offset: i64, var_type: T, - name: S, + name: impl AsCStr, ) { let var_type: Conf<&Type> = var_type.into(); let mut var_type = var_type.into(); - let name = name.into_bytes_with_nul(); - let name_c_str = name.as_ref(); unsafe { BNCreateAutoStackVariable( self.get_function().handle, offset, &mut var_type, - name_c_str.as_ptr() as *const c_char, + name.as_cstr().as_ptr(), ) } } @@ -285,23 +280,21 @@ impl MediumLevelILFunction { unsafe { BNDeleteAutoStackVariable(self.get_function().handle, offset) } } - pub fn create_auto_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_auto_var<'a, C: Into>>( &self, var: &Variable, var_type: C, - name: S, + name: impl AsCStr, ignore_disjoint_uses: bool, ) { let var_type: Conf<&Type> = var_type.into(); let mut var_type = var_type.into(); - let name = name.into_bytes_with_nul(); - let name_c_str = name.as_ref(); unsafe { BNCreateAutoVariable( self.get_function().handle, &var.raw(), &mut var_type, - name_c_str.as_ptr() as *const c_char, + name.as_cstr().as_ptr(), ignore_disjoint_uses, ) } diff --git a/rust/src/platform.rs b/rust/src/platform.rs index b78ef4eb2..4b51a49c7 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -73,10 +73,9 @@ impl Platform { Ref::new(Self { handle }) } - pub fn by_name(name: S) -> Option> { - let raw_name = name.into_bytes_with_nul(); + pub fn by_name(name: impl AsCStr) -> Option> { unsafe { - let res = BNGetPlatformByName(raw_name.as_ref().as_ptr() as *mut _); + let res = BNGetPlatformByName(name.as_cstr().as_ptr()); if res.is_null() { None @@ -104,30 +103,20 @@ impl Platform { } } - pub fn list_by_os(name: S) -> Array { - let raw_name = name.into_bytes_with_nul(); - + pub fn list_by_os(name: impl AsCStr) -> Array { unsafe { let mut count = 0; - let handles = BNGetPlatformListByOS(raw_name.as_ref().as_ptr() as *mut _, &mut count); + let handles = BNGetPlatformListByOS(name.as_cstr().as_ptr(), &mut count); Array::new(handles, count, ()) } } - pub fn list_by_os_and_arch( - name: S, - arch: &CoreArchitecture, - ) -> Array { - let raw_name = name.into_bytes_with_nul(); - + pub fn list_by_os_and_arch(name: impl AsCStr, arch: &CoreArchitecture) -> Array { unsafe { let mut count = 0; - let handles = BNGetPlatformListByOSAndArchitecture( - raw_name.as_ref().as_ptr() as *mut _, - arch.0, - &mut count, - ); + let handles = + BNGetPlatformListByOSAndArchitecture(name.as_cstr().as_ptr(), arch.0, &mut count); Array::new(handles, count, ()) } @@ -142,10 +131,9 @@ impl Platform { } } - pub fn new(arch: &A, name: S) -> Ref { - let name = name.into_bytes_with_nul(); + pub fn new(arch: &A, name: impl AsCStr) -> Ref { unsafe { - let handle = BNCreatePlatform(arch.as_ref().0, name.as_ref().as_ptr() as *mut _); + let handle = BNCreatePlatform(arch.as_ref().0, name.as_cstr().as_ptr()); assert!(!handle.is_null()); @@ -173,11 +161,9 @@ impl Platform { unsafe { Array::new(result, count, ()) } } - pub fn register_os(&self, os: S) { - let os = os.into_bytes_with_nul(); - + pub fn register_os(&self, os: impl AsCStr) { unsafe { - BNRegisterPlatform(os.as_ref().as_ptr() as *mut _, self.handle); + BNRegisterPlatform(os.as_cstr().as_ptr(), self.handle); } } @@ -254,12 +240,12 @@ impl Platform { } pub trait TypeParser { - fn parse_types_from_source>( + fn parse_types_from_source>( &self, - _source: S, - _filename: S, + _source: impl AsCStr, + _filename: impl AsCStr, _include_directories: &[P], - _auto_type_source: S, + _auto_type_source: impl AsCStr, ) -> Result { Err(String::new()) } @@ -273,12 +259,12 @@ pub struct TypeParserResult { } impl TypeParser for Platform { - fn parse_types_from_source>( + fn parse_types_from_source>( &self, - source: S, - filename: S, + source: impl AsCStr, + filename: impl AsCStr, include_directories: &[P], - auto_type_source: S, + auto_type_source: impl AsCStr, ) -> Result { let mut result = BNTypeParserResult { functionCount: 0, @@ -293,31 +279,25 @@ impl TypeParser for Platform { let mut error_string: *mut raw::c_char = ptr::null_mut(); - let src = source.into_bytes_with_nul(); - let filename = filename.into_bytes_with_nul(); - let auto_type_source = auto_type_source.into_bytes_with_nul(); - - let mut include_dirs = vec![]; - - for dir in include_directories.iter() { - let d = dir - .as_ref() - .to_string_lossy() - .to_string() - .into_bytes_with_nul(); - include_dirs.push(d.as_ptr() as _); - } + let include_dirs = include_directories + .iter() + .map(|dir| BnString::new(dir.as_ref().to_string_lossy())) + .collect::>(); + let mut include_dirs = include_dirs + .iter() + .map(|dir| dir.as_raw() as *const _) + .collect::>(); unsafe { let success = BNParseTypesFromSource( self.handle, - src.as_ref().as_ptr() as _, - filename.as_ref().as_ptr() as _, + source.as_cstr().as_ptr(), + filename.as_cstr().as_ptr(), &mut result, &mut error_string, include_dirs.as_mut_ptr(), include_dirs.len(), - auto_type_source.as_ref().as_ptr() as _, + auto_type_source.as_cstr().as_ptr(), ); let error_msg = BnString::from_raw(error_string); diff --git a/rust/src/project.rs b/rust/src/project.rs index 79c750e32..8b387d328 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -1,3 +1,4 @@ +use std::path::Path; use std::ptr::{null_mut, NonNull}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::{ffi, mem}; @@ -6,7 +7,7 @@ use binaryninjacore_sys::*; use crate::metadata::Metadata; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct Project { @@ -34,24 +35,18 @@ impl Project { /// /// * `path` - Path to the project directory (.bnpr) /// * `name` - Name of the new project - pub fn create(path: P, name: S) -> Self { - 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, - ) - }; + pub fn create(path: impl AsRef, name: impl AsCStr) -> Self { + let path = path.as_ref().to_string_lossy(); + let handle = unsafe { BNCreateProject(path.as_cstr().as_ptr(), name.as_cstr().as_ptr()) }; unsafe { Self::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 { - let path_raw = path.into_bytes_with_nul(); - let handle = unsafe { BNOpenProject(path_raw.as_ref().as_ptr() as *const ffi::c_char) }; + pub fn open_project(path: impl AsRef) -> Self { + let path = path.as_ref().to_string_lossy(); + let handle = unsafe { BNOpenProject(path.as_cstr().as_ptr()) }; unsafe { Self::from_raw(NonNull::new(handle).unwrap()) } } @@ -94,9 +89,8 @@ impl Project { } /// 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) } + pub fn set_name(&self, value: impl AsCStr) { + unsafe { BNProjectSetName(self.as_raw(), value.as_cstr().as_ptr()) } } /// Get the description of the project @@ -105,19 +99,13 @@ impl Project { } /// 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) - } + pub fn set_description(&self, value: impl AsCStr) { + unsafe { BNProjectSetDescription(self.as_raw(), value.as_cstr().as_ptr()) } } /// Retrieves metadata stored under a key from the 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) - }; + pub fn query_metadata(&self, key: impl AsCStr) -> Ref { + let result = unsafe { BNProjectQueryMetadata(self.as_raw(), key.as_cstr().as_ptr()) }; unsafe { Metadata::ref_from_raw(result) } } @@ -125,26 +113,13 @@ impl Project { /// /// * `key` - Key under which to store the Metadata object /// * `value` - Object to store - pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { - let key_raw = key.into_bytes_with_nul(); - unsafe { - BNProjectStoreMetadata( - self.as_raw(), - key_raw.as_ref().as_ptr() as *const ffi::c_char, - value.handle, - ) - } + pub fn store_metadata(&self, key: impl AsCStr, value: &Metadata) -> bool { + unsafe { BNProjectStoreMetadata(self.as_raw(), key.as_cstr().as_ptr(), value.handle) } } /// Removes the metadata associated with this `key` from the project - pub fn remove_metadata(&self, key: S) { - let key_raw = key.into_bytes_with_nul(); - unsafe { - BNProjectRemoveMetadata( - self.as_raw(), - key_raw.as_ref().as_ptr() as *const ffi::c_char, - ) - } + pub fn remove_metadata(&self, key: impl AsCStr) { + unsafe { BNProjectRemoveMetadata(self.as_raw(), key.as_cstr().as_ptr()) } } pub fn push_folder(&self, file: &ProjectFolder) { @@ -156,18 +131,13 @@ 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 - pub fn create_folder_from_path( + pub fn create_folder_from_path( &self, - path: P, + path: impl AsRef, parent: Option<&ProjectFolder>, - description: D, - ) -> Result - where - P: BnStrCompatible, - D: BnStrCompatible, - { - let path_raw = path.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + description: impl AsCStr, + ) -> Result { + let path = path.as_ref().to_string_lossy(); let parent_ptr = parent .map(|p| unsafe { p.as_raw() as *mut _ }) .unwrap_or(null_mut()); @@ -175,9 +145,9 @@ impl Project { unsafe { let result = BNProjectCreateFolderFromPath( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), parent_ptr, - description_raw.as_ref().as_ptr() as *const ffi::c_char, + description.as_cstr().as_ptr(), null_mut(), Some(cb_progress_func_nop), ); @@ -191,20 +161,17 @@ impl Project { /// * `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( + pub fn create_folder_from_path_with_progress( &self, - path: P, + path: impl AsRef, parent: Option<&ProjectFolder>, - description: D, + description: impl AsCStr, mut progress_func: F, ) -> 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 path = path.as_ref().to_string_lossy(); let parent_ptr = parent .map(|p| unsafe { p.as_raw() as *mut _ }) .unwrap_or(null_mut()); @@ -213,9 +180,9 @@ impl Project { unsafe { let result = BNProjectCreateFolderFromPath( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), parent_ptr, - description_raw.as_ref().as_ptr() as *const ffi::c_char, + description.as_cstr().as_ptr(), progress_ctx, Some(cb_progress_func::), ); @@ -228,18 +195,12 @@ impl Project { /// * `parent` - Parent folder in the project that will contain the new folder /// * `name` - Name for the created folder /// * `description` - Description for created folder - pub fn create_folder( + pub fn create_folder( &self, parent: Option<&ProjectFolder>, - name: N, - description: D, - ) -> Result - where - N: BnStrCompatible, - D: BnStrCompatible, - { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + name: impl AsCStr, + description: impl AsCStr, + ) -> Result { let parent_ptr = parent .map(|p| unsafe { p.as_raw() as *mut _ }) .unwrap_or(null_mut()); @@ -247,8 +208,8 @@ impl Project { let result = BNProjectCreateFolder( self.as_raw(), 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.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), ); Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) } @@ -260,31 +221,23 @@ impl Project { /// * `name` - Name for the created folder /// * `description` - Description for created folder /// * `id` - id unique ID - pub unsafe fn create_folder_unsafe( + pub unsafe fn create_folder_unsafe( &self, parent: Option<&ProjectFolder>, - name: N, - description: D, - id: I, - ) -> Result - where - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, - { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + name: impl AsCStr, + description: impl AsCStr, + id: impl AsCStr, + ) -> Result { let parent_ptr = parent .map(|p| unsafe { p.as_raw() as *mut _ }) .unwrap_or(null_mut()); - let id_raw = id.into_bytes_with_nul(); unsafe { let result = BNProjectCreateFolderUnsafe( self.as_raw(), 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.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), + id.as_cstr().as_ptr(), ); Ok(ProjectFolder::from_raw(NonNull::new(result).ok_or(())?)) } @@ -302,11 +255,8 @@ impl Project { } /// Retrieve a folder in the project by unique folder `id` - 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) }; + pub fn folder_by_id(&self, id: impl AsCStr) -> Option { + let result = unsafe { BNProjectGetFolderById(self.as_raw(), id.as_cstr().as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFolder::from_raw(handle) }) } @@ -368,28 +318,21 @@ 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 - pub fn create_file_from_path( + pub fn create_file_from_path( &self, - path: P, + path: impl AsRef, folder: Option<&ProjectFolder>, - name: N, - description: D, - ) -> 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(); + name: impl AsCStr, + description: impl AsCStr, + ) -> Result { + let path = path.as_ref().to_string_lossy(); unsafe { let result = BNProjectCreateFileFromPath( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), null_mut(), Some(cb_progress_func_nop), ); @@ -404,31 +347,26 @@ impl Project { /// * `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( + pub fn create_file_from_path_with_progress( &self, - path: P, + path: impl AsRef, folder: Option<&ProjectFolder>, - name: N, - description: D, + name: impl AsCStr, + description: impl AsCStr, mut progress_func: F, ) -> 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 path = path.as_ref().to_string_lossy(); let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; unsafe { let result = BNProjectCreateFileFromPath( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), progress_ctx, Some(cb_progress_func::), ); @@ -444,33 +382,24 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - pub unsafe fn create_file_from_path_unsafe( + pub unsafe fn create_file_from_path_unsafe( &self, - path: P, + path: impl AsRef, folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: impl AsCStr, + description: impl AsCStr, + id: impl AsCStr, creation_time: SystemTime, - ) -> 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(); + ) -> Result { + let path = path.as_ref().to_string_lossy(); unsafe { let result = BNProjectCreateFileFromPathUnsafe( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), + id.as_cstr().as_ptr(), systime_to_bntime(creation_time).unwrap(), null_mut(), Some(cb_progress_func_nop), @@ -489,36 +418,29 @@ impl Project { /// * `creation_time` - Creation time of the file /// * `progress_func` - Progress function that will be called as the file is being added #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_from_path_with_progress_unsafe( + pub unsafe fn create_file_from_path_with_progress_unsafe( &self, - path: P, + path: impl AsRef, folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: impl AsCStr, + description: impl AsCStr, + id: impl AsCStr, creation_time: SystemTime, mut progress_func: F, ) -> 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 path = path.as_ref().to_string_lossy(); let progress_ctx = &mut progress_func as *mut F as *mut ffi::c_void; unsafe { let result = BNProjectCreateFileFromPathUnsafe( self.as_raw(), - path_raw.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), + id.as_cstr().as_ptr(), systime_to_bntime(creation_time).unwrap(), progress_ctx, Some(cb_progress_func::), @@ -533,27 +455,21 @@ 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 - pub fn create_file( + pub fn create_file( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - ) -> Result - where - N: BnStrCompatible, - D: BnStrCompatible, - { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + name: impl AsCStr, + description: impl AsCStr, + ) -> Result { 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), null_mut(), Some(cb_progress_func_nop), ); @@ -568,21 +484,17 @@ impl Project { /// * `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( + pub fn create_file_with_progress( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, + name: impl AsCStr, + description: impl AsCStr, mut progress_func: F, ) -> 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; unsafe { let result = BNProjectCreateFile( @@ -590,8 +502,8 @@ impl Project { 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), progress_ctx, Some(cb_progress_func::), ); @@ -607,32 +519,24 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - pub unsafe fn create_file_unsafe( + pub unsafe fn create_file_unsafe( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: impl AsCStr, + description: impl AsCStr, + id: impl AsCStr, creation_time: SystemTime, - ) -> 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(); + ) -> Result { 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), + id.as_cstr().as_ptr(), systime_to_bntime(creation_time).unwrap(), null_mut(), Some(cb_progress_func_nop), @@ -651,25 +555,19 @@ impl Project { /// * `creation_time` - Creation time of the file /// * `progress_func` - Progress function that will be called as the file is being added #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_with_progress_unsafe( + pub unsafe fn create_file_with_progress_unsafe( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: impl AsCStr, + description: impl AsCStr, + id: impl AsCStr, creation_time: SystemTime, mut progress_func: F, ) -> 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; unsafe { let result = BNProjectCreateFileUnsafe( @@ -677,9 +575,9 @@ impl Project { 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, + name.as_cstr().as_ptr(), + description.as_cstr().as_ptr(), + id.as_cstr().as_ptr(), systime_to_bntime(creation_time).unwrap(), progress_ctx, Some(cb_progress_func::), @@ -697,21 +595,16 @@ impl Project { } /// Retrieve a file in the project by unique `id` - 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 result = unsafe { BNProjectGetFileById(self.as_raw(), id_ptr) }; + pub fn file_by_id(&self, id: impl AsCStr) -> Option { + let result = unsafe { BNProjectGetFileById(self.as_raw(), id.as_cstr().as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFile::from_raw(handle) }) } /// Retrieve a file in the project by the `path` on disk - 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 result = unsafe { BNProjectGetFileByPathOnDisk(self.as_raw(), path_ptr) }; + pub fn file_by_path(&self, path: impl AsCStr) -> Option { + let result = + unsafe { BNProjectGetFileByPathOnDisk(self.as_raw(), path.as_cstr().as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFile::from_raw(handle) }) } @@ -841,14 +734,8 @@ impl ProjectFolder { } /// 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, - ) - } + pub fn set_name(&self, value: impl AsCStr) -> bool { + unsafe { BNProjectFolderSetName(self.as_raw(), value.as_cstr().as_ptr()) } } /// Get the description of this folder @@ -857,14 +744,8 @@ impl ProjectFolder { } /// 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, - ) - } + pub fn set_description(&self, value: impl AsCStr) -> bool { + unsafe { BNProjectFolderSetDescription(self.as_raw(), value.as_cstr().as_ptr()) } } /// Get the folder that contains this folder @@ -884,12 +765,11 @@ impl ProjectFolder { /// 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(); + pub fn export(&self, dest: impl AsCStr) -> bool { unsafe { BNProjectFolderExport( self.as_raw(), - dest_raw.as_ref().as_ptr() as *const ffi::c_char, + dest.as_cstr().as_ptr(), null_mut(), Some(cb_progress_func_nop), ) @@ -900,16 +780,14 @@ impl ProjectFolder { /// /// * `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 + pub fn export_with_progress(&self, dest: impl AsCStr, 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, + dest.as_cstr().as_ptr(), &mut progress as *mut _ as *mut ffi::c_void, Some(cb_progress_func::), ) @@ -988,14 +866,8 @@ impl ProjectFile { } /// 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, - ) - } + pub fn set_name(&self, value: impl AsCStr) -> bool { + unsafe { BNProjectFileSetName(self.as_raw(), value.as_cstr().as_ptr()) } } /// Get the description of this file @@ -1004,14 +876,8 @@ impl ProjectFile { } /// 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, - ) - } + pub fn set_description(&self, value: impl AsCStr) -> bool { + unsafe { BNProjectFileSetDescription(self.as_raw(), value.as_cstr().as_ptr()) } } /// Get the file creation time @@ -1036,14 +902,8 @@ impl ProjectFile { /// 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, - ) - } + pub fn export(&self, dest: impl AsCStr) -> bool { + unsafe { BNProjectFileExport(self.as_raw(), dest.as_cstr().as_ptr()) } } } diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index 9b00508ea..2688ae2ae 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -1,4 +1,4 @@ -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use crate::{ architecture::{Architecture, CoreArchitecture}, binaryview::BinaryView, @@ -399,9 +399,8 @@ unsafe impl RefCountable for CoreRelocationHandler { } } -pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: S, func: F) +pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: impl AsCStr, func: F) where - S: BnStrCompatible, R: 'static + RelocationHandler> + Send + Sync + Sized, F: FnOnce(CustomRelocationHandlerHandle, CoreRelocationHandler) -> R, { @@ -501,8 +500,6 @@ where .into() } - let name = name.into_bytes_with_nul(); - let raw = Box::leak(Box::new( MaybeUninit::>::zeroed(), )); @@ -527,7 +524,7 @@ where BNArchitectureRegisterRelocationHandler( arch.handle().as_ref().0, - name.as_ref().as_ptr() as *const _, + name.as_cstr().as_ptr(), handle.handle().as_ref().0, ); } diff --git a/rust/src/section.rs b/rust/src/section.rs index 8f8064290..115a7d258 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -79,7 +79,7 @@ impl Section { /// let bv = binaryninja::load("/bin/cat").unwrap(); /// bv.add_section(Section::builder("example", 0..1024).align(4).entry_size(4)) /// ``` - pub fn builder(name: S, range: Range) -> SectionBuilder { + pub fn builder(name: S, range: Range) -> SectionBuilder { SectionBuilder::new(name, range) } @@ -191,7 +191,7 @@ unsafe impl CoreArrayProviderInner for Section { } #[must_use] -pub struct SectionBuilder { +pub struct SectionBuilder { is_auto: bool, name: S, range: Range, @@ -204,7 +204,7 @@ pub struct SectionBuilder { info_data: u64, } -impl SectionBuilder { +impl SectionBuilder { pub fn new(name: S, range: Range) -> Self { Self { is_auto: false, @@ -261,51 +261,35 @@ impl SectionBuilder { } pub(crate) fn create(self, view: &BinaryView) { - let name = self.name.into_bytes_with_nul(); - let ty = self._ty.map(|s| s.into_bytes_with_nul()); - let linked_section = self.linked_section.map(|s| s.into_bytes_with_nul()); - let info_section = self.info_section.map(|s| s.into_bytes_with_nul()); + let ty = self._ty.as_ref().map(|s| s.as_cstr()); + let linked_section = self.linked_section.as_ref().map(|s| s.as_cstr()); + let info_section = self.info_section.as_ref().map(|s| s.as_cstr()); let start = self.range.start; let len = self.range.end.wrapping_sub(start); + let add_section = if self.is_auto { + BNAddAutoSection + } else { + BNAddUserSection + }; + + let nul_str = c"".as_ptr(); + unsafe { - let nul_str = std::ffi::CStr::from_bytes_with_nul_unchecked(b"\x00").as_ptr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - let ty_ptr = ty.map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); - let linked_section_ptr = - linked_section.map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); - let info_section_ptr = info_section.map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); - - if self.is_auto { - BNAddAutoSection( - view.handle, - name_ptr, - start, - len, - self.semantics.into(), - ty_ptr, - self.align, - self.entry_size, - linked_section_ptr, - info_section_ptr, - self.info_data, - ); - } else { - BNAddUserSection( - view.handle, - name_ptr, - start, - len, - self.semantics.into(), - ty_ptr, - self.align, - self.entry_size, - linked_section_ptr, - info_section_ptr, - self.info_data, - ); - } + add_section( + view.handle, + self.name.as_cstr().as_ptr(), + start, + len, + self.semantics.into(), + ty.map_or(nul_str, |s| s.as_ptr()), + self.align, + self.entry_size, + linked_section.map_or(nul_str, |s| s.as_ptr()), + info_section.map_or(nul_str, |s| s.as_ptr()), + self.info_data, + ) } } } diff --git a/rust/src/settings.rs b/rust/src/settings.rs index f37a5a348..f13543fda 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -16,11 +16,10 @@ pub use binaryninjacore_sys::BNSettingsScope as SettingsScope; use binaryninjacore_sys::*; -use std::os::raw::c_char; use crate::binaryview::BinaryView; use crate::rc::*; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use std::ptr; @@ -39,10 +38,9 @@ impl Settings { Ref::new(Self { handle }) } - pub fn new(instance_id: S) -> Ref { - let instance_id = instance_id.into_bytes_with_nul(); + pub fn new(instance_id: impl AsCStr) -> Ref { unsafe { - let handle = BNCreateSettings(instance_id.as_ref().as_ptr() as *mut _); + let handle = BNCreateSettings(instance_id.as_cstr().as_ptr()); debug_assert!(!handle.is_null()); @@ -50,483 +48,370 @@ impl Settings { } } - pub fn set_resource_id(&self, resource_id: S) { - let resource_id = resource_id.into_bytes_with_nul(); - unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ref().as_ptr() as *mut _) }; + pub fn set_resource_id(&self, resource_id: impl AsCStr) { + unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_cstr().as_ptr()) }; } pub fn serialize_schema(&self) -> BnString { unsafe { BnString::from_raw(BNSettingsSerializeSchema(self.handle)) } } - pub fn deserialize_schema(&self, schema: S) -> bool { - let schema = schema.into_bytes_with_nul(); + pub fn deserialize_schema(&self, schema: impl AsCStr) -> bool { unsafe { BNSettingsDeserializeSchema( self.handle, - schema.as_ref().as_ptr() as *mut _, + schema.as_cstr().as_ptr(), BNSettingsScope::SettingsAutoScope, true, ) } } - pub fn contains(&self, key: S) -> bool { - let key = key.into_bytes_with_nul(); - - unsafe { BNSettingsContains(self.handle, key.as_ref().as_ptr() as *mut _) } + pub fn contains(&self, key: impl AsCStr) -> bool { + unsafe { BNSettingsContains(self.handle, key.as_cstr().as_ptr()) } } // 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, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> bool { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); unsafe { BNSettingsGetBool( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope_ptr, ) } } - pub fn get_double( + pub fn get_double( &self, - key: S, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> f64 { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); unsafe { BNSettingsGetDouble( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope_ptr, ) } } - pub fn get_integer( + pub fn get_integer( &self, - key: S, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> u64 { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); unsafe { BNSettingsGetUInt64( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope_ptr, ) } } - pub fn get_string( + pub fn get_string( &self, - key: S, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> BnString { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); unsafe { BnString::from_raw(BNSettingsGetString( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope_ptr, )) } } - pub fn get_string_list( + pub fn get_string_list( &self, - key: S, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> Array { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); let mut size: usize = 0; unsafe { - Array::new( - BNSettingsGetStringList( - self.handle, - key.as_ref().as_ptr() as *mut _, - view_handle, - std::ptr::null_mut(), - scope_ptr, - &mut size, - ) as *mut *mut c_char, - size, - (), - ) + let string_list = BNSettingsGetStringList( + self.handle, + key.as_cstr().as_ptr(), + view_handle, + ptr::null_mut(), + scope_ptr, + &mut size, + ) as *mut *mut _; + Array::new(string_list, size, ()) } } - pub fn get_json( + pub fn get_json( &self, - key: S, + key: impl AsCStr, view: Option<&BinaryView>, scope: Option>, ) -> BnString { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope_ptr = match scope { - Some(mut scope) => scope.as_mut(), - _ => ptr::null_mut() as *mut _, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope_ptr = scope.map_or(ptr::null_mut(), |mut scope| scope.as_mut()); unsafe { BnString::from_raw(BNSettingsGetJson( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope_ptr, )) } } - pub fn set_bool( + pub fn set_bool( &self, - key: S, + key: impl AsCStr, value: bool, view: Option<&BinaryView>, scope: Option, ) { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); unsafe { BNSettingsSetBool( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), value, ); } } - pub fn set_double( + pub fn set_double( &self, - key: S, + key: impl AsCStr, value: f64, view: Option<&BinaryView>, scope: Option, ) { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); unsafe { BNSettingsSetDouble( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), value, ); } } - pub fn set_integer( + pub fn set_integer( &self, - key: S, + key: impl AsCStr, value: u64, view: Option<&BinaryView>, scope: Option, ) { - let key = key.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); unsafe { BNSettingsSetUInt64( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), value, ); } } - pub fn set_string( + pub fn set_string( &self, - key: S1, - value: S2, + key: impl AsCStr, + value: impl AsCStr, view: Option<&BinaryView>, scope: Option, ) { - let key = key.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); - let view_handle = match view { - Some(view) => view.handle, - _ => ptr::null_mut() as *mut _, - }; - let scope = match scope { - Some(scope) => scope, - _ => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); unsafe { BNSettingsSetString( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + value.as_cstr().as_ptr(), ); } } - pub fn set_string_list>( + pub fn set_string_list( &self, - key: S1, - value: I, + key: impl AsCStr, + value: impl IntoIterator, view: Option<&BinaryView>, scope: Option, ) -> 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) - .collect(); - - let view_handle = match view { - Some(view) => view.handle, - None => ptr::null_mut() as *mut _, - }; - - let scope = match scope { - Some(scope) => scope, - None => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); + let value = value.into_iter().map(BnString::new).collect::>(); + let mut value = value + .into_iter() + .map(|item| item.as_raw() as *const _) + .collect::>(); unsafe { BNSettingsSetStringList( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, - list.as_mut_ptr(), - list.len(), + key.as_cstr().as_ptr(), + value.as_mut_ptr(), + value.len(), ) } } - pub fn set_json( + pub fn set_json( &self, - key: S1, - value: S2, + key: impl AsCStr, + value: impl AsCStr, view: Option<&BinaryView>, scope: Option, ) -> bool { - let key = key.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); - - let view_handle = match view { - Some(view) => view.handle, - None => ptr::null_mut() as *mut _, - }; - - let scope = match scope { - Some(scope) => scope, - None => SettingsScope::SettingsAutoScope, - }; + let view_handle = view.map_or(ptr::null_mut(), |view| view.handle); + let scope = scope.unwrap_or(SettingsScope::SettingsAutoScope); unsafe { BNSettingsSetJson( self.handle, view_handle, - std::ptr::null_mut(), + ptr::null_mut(), scope, - key.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + value.as_cstr().as_ptr(), ) } } - 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(); + pub fn update_bool_property(&self, key: impl AsCStr, property: impl AsCStr, value: bool) { unsafe { BNSettingsUpdateBoolProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + property.as_cstr().as_ptr(), value, ); } } - pub fn update_integer_property(&self, key: S, property: S, value: u64) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn update_integer_property(&self, key: impl AsCStr, property: impl AsCStr, value: u64) { unsafe { BNSettingsUpdateUInt64Property( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + property.as_cstr().as_ptr(), value, ); } } - pub fn update_double_property(&self, key: S, property: S, value: f64) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn update_double_property(&self, key: impl AsCStr, property: impl AsCStr, value: f64) { unsafe { BNSettingsUpdateDoubleProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + property.as_cstr().as_ptr(), value, ); } } - pub fn update_string_property(&self, key: S, property: S, value: S) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); + pub fn update_string_property( + &self, + key: impl AsCStr, + property: impl AsCStr, + value: impl AsCStr, + ) { unsafe { BNSettingsUpdateStringProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_cstr().as_ptr(), + property.as_cstr().as_ptr(), + value.as_cstr().as_ptr(), ); } } - pub fn update_string_list_property>( + pub fn update_string_list_property( &self, - key: S, - property: S, - value: I, + key: impl AsCStr, + property: impl AsCStr, + value: impl IntoIterator, ) { - 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) - .collect(); + let value = value.into_iter().map(BnString::new).collect::>(); + let mut value = value + .iter() + .map(|s| s.as_raw() as *const _) + .collect::>(); unsafe { BNSettingsUpdateStringListProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - list.as_mut_ptr(), - list.len(), + key.as_cstr().as_ptr(), + property.as_cstr().as_ptr(), + value.as_mut_ptr(), + value.len(), ); } } - pub fn register_group( - &self, - group: S1, - title: S2, - ) -> bool { - let group = group.into_bytes_with_nul(); - let title = title.into_bytes_with_nul(); - + pub fn register_group(&self, group: impl AsCStr, title: impl AsCStr) -> bool { unsafe { BNSettingsRegisterGroup( self.handle, - group.as_ref().as_ptr() as *mut _, - title.as_ref().as_ptr() as *mut _, + group.as_cstr().as_ptr(), + title.as_cstr().as_ptr(), ) } } - pub fn register_setting_json( - &self, - group: S1, - properties: S2, - ) -> bool { - let group = group.into_bytes_with_nul(); - let properties = properties.into_bytes_with_nul(); - + pub fn register_setting_json(&self, group: impl AsCStr, properties: impl AsCStr) -> bool { unsafe { BNSettingsRegisterSetting( self.handle, - group.as_ref().as_ptr() as *mut _, - properties.as_ref().as_ptr() as *mut _, + group.as_cstr().as_ptr(), + properties.as_cstr().as_ptr(), ) } } diff --git a/rust/src/string.rs b/rust/src/string.rs index 7b672cccb..87a37f2b0 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -19,11 +19,9 @@ use std::ffi::{CStr, CString}; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; -use std::ops::Deref; use std::os::raw; use crate::rc::*; -use crate::types::QualifiedName; pub(crate) fn raw_to_string(ptr: *const raw::c_char) -> Option { if ptr.is_null() { @@ -33,33 +31,26 @@ pub(crate) fn raw_to_string(ptr: *const raw::c_char) -> Option { } } -/// Is the equivalent of [CString] but using the allocation and free -/// functions provided by binaryninja_sys. +/// A nul-terminated C string allocated by the core. +/// +/// Received from a variety of core function calls, and must be used when giving strings to the +/// core from many core-invoked callbacks. +/// +/// These are strings we're responsible for freeing, such as strings allocated by the core and +/// given to us through the API and then forgotten about by the core. #[repr(transparent)] pub struct BnString { raw: *mut raw::c_char, } -/// A nul-terminated C string allocated by the core. -/// -/// Received from a variety of core function calls, and -/// must be used when giving strings to the core from many -/// core-invoked callbacks. -/// -/// These are strings we're responsible for freeing, such as -/// strings allocated by the core and given to us through the API -/// and then forgotten about by the core. impl BnString { - pub fn new(s: S) -> Self { + pub fn new(s: impl AsCStr) -> Self { use binaryninjacore_sys::BNAllocString; - - let raw = s.into_bytes_with_nul(); + let raw = s.as_cstr(); unsafe { - let ptr = raw.as_ref().as_ptr() as *mut _; - Self { - raw: BNAllocString(ptr), + raw: BNAllocString(raw.as_ptr()), } } } @@ -83,24 +74,24 @@ impl BnString { unsafe { &*self.raw } } - pub fn as_str(&self) -> &str { - unsafe { CStr::from_ptr(self.raw).to_str().unwrap() } + pub fn as_c_str(&self) -> &CStr { + unsafe { CStr::from_ptr(self.raw) } } - pub fn as_bytes(&self) -> &[u8] { - self.as_str().as_bytes() + pub fn as_str(&self) -> &str { + self.as_c_str().to_str().unwrap() } - pub fn as_bytes_with_null(&self) -> &[u8] { - self.deref().to_bytes() + pub fn as_bytes(&self) -> &[u8] { + self.as_c_str().to_bytes() } pub fn len(&self) -> usize { - self.as_ref().len() + self.as_bytes().len() } pub fn is_empty(&self) -> bool { - self.as_ref().is_empty() + self.as_bytes().is_empty() } } @@ -125,29 +116,15 @@ impl Clone for BnString { } } -impl Deref for BnString { - type Target = CStr; - - fn deref(&self) -> &CStr { - unsafe { CStr::from_ptr(self.raw) } - } -} - -impl AsRef<[u8]> for BnString { - fn as_ref(&self) -> &[u8] { - self.to_bytes_with_nul() - } -} - impl Hash for BnString { fn hash(&self, state: &mut H) { - self.raw.hash(state) + self.as_cstr().hash(state) } } impl PartialEq for BnString { fn eq(&self, other: &Self) -> bool { - self.deref() == other.deref() + self.as_cstr() == other.as_cstr() } } @@ -155,13 +132,13 @@ impl Eq for BnString {} impl fmt::Display for BnString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string_lossy()) + write!(f, "{}", self.as_cstr().to_string_lossy()) } } impl fmt::Debug for BnString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string_lossy()) + write!(f, "{:?}", self.as_cstr()) } } @@ -184,83 +161,63 @@ unsafe impl CoreArrayProviderInner for BnString { } } -pub unsafe trait BnStrCompatible { - type Result: AsRef<[u8]>; - fn into_bytes_with_nul(self) -> Self::Result; +pub trait AsCStr { + fn as_cstr(&self) -> Cow<'_, CStr>; } -unsafe impl<'a> BnStrCompatible for &'a CStr { - type Result = &'a [u8]; - - fn into_bytes_with_nul(self) -> Self::Result { - self.to_bytes_with_nul() +impl AsCStr for CStr { + fn as_cstr(&self) -> Cow<'_, CStr> { + self.into() } } -unsafe impl BnStrCompatible for BnString { - type Result = Self; - - fn into_bytes_with_nul(self) -> Self::Result { - self +impl AsCStr for CString { + fn as_cstr(&self) -> Cow<'_, CStr> { + self.into() } } -unsafe impl BnStrCompatible for CString { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - self.into_bytes_with_nul() +impl AsCStr for BnString { + fn as_cstr(&self) -> Cow<'_, CStr> { + self.as_c_str().into() } } -unsafe impl<'a> BnStrCompatible for &'a str { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - let ret = CString::new(self).expect("can't pass strings with internal nul bytes to core!"); - ret.into_bytes_with_nul() +impl AsCStr for str { + fn as_cstr(&self) -> Cow<'_, CStr> { + CString::new(self) + .expect("can't pass strings with internal nul bytes to core!") + .into() } } -unsafe impl BnStrCompatible for String { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - self.as_str().into_bytes_with_nul() +impl AsCStr for String { + fn as_cstr(&self) -> Cow<'_, CStr> { + self.as_str().as_cstr() } } -unsafe impl<'a> BnStrCompatible for &'a String { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - self.as_str().into_bytes_with_nul() - } -} - -unsafe impl<'a> BnStrCompatible for &'a Cow<'a, str> { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - self.to_string().into_bytes_with_nul() +impl AsCStr for Cow<'_, str> { + fn as_cstr(&self) -> Cow<'_, CStr> { + self.as_ref().as_cstr() } } -unsafe impl BnStrCompatible for &QualifiedName { - type Result = Vec; - - fn into_bytes_with_nul(self) -> Self::Result { - self.string().into_bytes_with_nul() +impl AsCStr for &T { + fn as_cstr(&self) -> Cow<'_, CStr> { + (*self).as_cstr() } } pub trait IntoJson { - type Output: BnStrCompatible; + type Output: AsCStr; + fn get_json_string(self) -> Result; } -impl IntoJson for S { - type Output = S; +impl IntoJson for S { + type Output = Self; + fn get_json_string(self) -> Result { Ok(self) } diff --git a/rust/src/symbol.rs b/rust/src/symbol.rs index 8ff0b040a..a11de3569 100644 --- a/rust/src/symbol.rs +++ b/rust/src/symbol.rs @@ -152,64 +152,28 @@ impl SymbolBuilder { } pub fn create(self) -> Ref { - let raw_name = self.raw_name.into_bytes_with_nul(); - let short_name = self.short_name.map(|s| s.into_bytes_with_nul()); - let full_name = self.full_name.map(|s| s.into_bytes_with_nul()); + let raw_name = self.raw_name.as_cstr(); + let short_name = self + .short_name + .as_ref() + .map_or(raw_name.clone(), |s| s.as_cstr()); + let full_name = self + .full_name + .as_ref() + .map_or(raw_name.clone(), |s| s.as_cstr()); - // Lifetimes, man - let raw_name = raw_name.as_ptr() as _; unsafe { - if let Some(short_name) = short_name { - if let Some(full_name) = full_name { - let res = BNCreateSymbol( - self.ty.into(), - short_name.as_ptr() as _, - full_name.as_ptr() as _, - raw_name, - self.addr, - self.binding.into(), - ptr::null_mut(), - self.ordinal, - ); - Symbol::ref_from_raw(res) - } else { - let res = BNCreateSymbol( - self.ty.into(), - short_name.as_ptr() as _, - raw_name, - raw_name, - self.addr, - self.binding.into(), - ptr::null_mut(), - self.ordinal, - ); - Symbol::ref_from_raw(res) - } - } else if let Some(full_name) = full_name { - let res = BNCreateSymbol( - self.ty.into(), - raw_name, - full_name.as_ptr() as _, - raw_name, - self.addr, - self.binding.into(), - ptr::null_mut(), - self.ordinal, - ); - Symbol::ref_from_raw(res) - } else { - let res = BNCreateSymbol( - self.ty.into(), - raw_name, - raw_name, - raw_name, - self.addr, - self.binding.into(), - ptr::null_mut(), - self.ordinal, - ); - Symbol::ref_from_raw(res) - } + let res = BNCreateSymbol( + self.ty.into(), + short_name.as_ptr(), + full_name.as_ptr(), + raw_name.as_ptr(), + self.addr, + self.binding.into(), + ptr::null_mut(), + self.ordinal, + ); + Symbol::ref_from_raw(res) } } } diff --git a/rust/src/tags.rs b/rust/src/tags.rs index daa56d507..4fed2cd08 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -35,9 +35,8 @@ impl Tag { Ref::new(Self { handle }) } - pub fn new(t: &TagType, data: S) -> Ref { - let data = data.into_bytes_with_nul(); - unsafe { Self::from_raw(BNCreateTag(t.handle, data.as_ref().as_ptr() as *mut _)) } + pub fn new(t: &TagType, data: impl AsCStr) -> Ref { + unsafe { Self::from_raw(BNCreateTag(t.handle, data.as_cstr().as_ptr())) } } pub fn id(&self) -> BnString { @@ -52,11 +51,8 @@ impl Tag { unsafe { TagType::from_raw(BNTagGetType(self.handle)) } } - pub fn set_data(&self, data: S) { - let data = data.into_bytes_with_nul(); - unsafe { - BNTagSetData(self.handle, data.as_ref().as_ptr() as *mut _); - } + pub fn set_data(&self, data: impl AsCStr) { + unsafe { BNTagSetData(self.handle, data.as_cstr().as_ptr()) } } } @@ -114,11 +110,7 @@ impl TagType { Ref::new(Self { handle }) } - pub fn create( - view: &BinaryView, - name: N, - icon: I, - ) -> Ref { + pub fn create(view: &BinaryView, name: impl AsCStr, icon: impl AsCStr) -> Ref { let tag_type = unsafe { Self::from_raw(BNCreateTagType(view.handle)) }; tag_type.set_name(name); tag_type.set_icon(icon); @@ -133,22 +125,16 @@ impl TagType { unsafe { BnString::from_raw(BNTagTypeGetIcon(self.handle)) } } - pub fn set_icon(&self, icon: S) { - let icon = icon.into_bytes_with_nul(); - unsafe { - BNTagTypeSetIcon(self.handle, icon.as_ref().as_ptr() as *mut _); - } + pub fn set_icon(&self, icon: impl AsCStr) { + unsafe { BNTagTypeSetIcon(self.handle, icon.as_cstr().as_ptr()) } } pub fn name(&self) -> BnString { unsafe { BnString::from_raw(BNTagTypeGetName(self.handle)) } } - pub fn set_name(&self, name: S) { - let name = name.into_bytes_with_nul(); - unsafe { - BNTagTypeSetName(self.handle, name.as_ref().as_ptr() as *mut _); - } + pub fn set_name(&self, name: impl AsCStr) { + unsafe { BNTagTypeSetName(self.handle, name.as_cstr().as_ptr()) } } pub fn visible(&self) -> bool { @@ -163,11 +149,8 @@ impl TagType { unsafe { BNTagTypeGetType(self.handle) } } - pub fn set_type(&self, t: S) { - let t = t.into_bytes_with_nul(); - unsafe { - BNTagTypeSetName(self.handle, t.as_ref().as_ptr() as *mut _); - } + pub fn set_type(&self, t: impl AsCStr) { + unsafe { BNTagTypeSetName(self.handle, t.as_cstr().as_ptr()) } } pub fn view(&self) -> Ref { diff --git a/rust/src/templatesimplifier.rs b/rust/src/templatesimplifier.rs index 5959167da..7c39e1f8b 100644 --- a/rust/src/templatesimplifier.rs +++ b/rust/src/templatesimplifier.rs @@ -1,20 +1,13 @@ use crate::{ - string::{BnStrCompatible, BnString}, + string::{AsCStr, BnString}, types::QualifiedName, }; use binaryninjacore_sys::{BNRustSimplifyStrToFQN, BNRustSimplifyStrToStr}; -pub fn simplify_str_to_str(input: S) -> BnString { - let name = input.into_bytes_with_nul(); - unsafe { BnString::from_raw(BNRustSimplifyStrToStr(name.as_ref().as_ptr() as *mut _)) } +pub fn simplify_str_to_str(input: impl AsCStr) -> BnString { + unsafe { BnString::from_raw(BNRustSimplifyStrToStr(input.as_cstr().as_ptr())) } } -pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { - let name = input.into_bytes_with_nul(); - unsafe { - QualifiedName(BNRustSimplifyStrToFQN( - name.as_ref().as_ptr() as *mut _, - simplify, - )) - } +pub fn simplify_str_to_fqn(input: impl AsCStr, simplify: bool) -> QualifiedName { + unsafe { QualifiedName(BNRustSimplifyStrToFQN(input.as_cstr().as_ptr(), simplify)) } } diff --git a/rust/src/typearchive.rs b/rust/src/typearchive.rs index a00b446a9..ed688b5d2 100644 --- a/rust/src/typearchive.rs +++ b/rust/src/typearchive.rs @@ -1,4 +1,5 @@ use core::{ffi, mem, ptr}; +use std::path::Path; use binaryninjacore_sys::*; @@ -6,7 +7,7 @@ use crate::databuffer::DataBuffer; use crate::metadata::Metadata; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type}; /// Type Archives are a collection of types which can be shared between different analysis @@ -68,46 +69,39 @@ impl TypeArchive { } /// Open the Type Archive at the given path, if it exists. - pub fn open(path: S) -> Option { - let path = path.into_bytes_with_nul(); - let handle = unsafe { BNOpenTypeArchive(path.as_ref().as_ptr() as *const ffi::c_char) }; + pub fn open(path: impl AsRef) -> Option { + let path = path.as_ref().to_string_lossy(); + let handle = unsafe { BNOpenTypeArchive(path.as_cstr().as_ptr()) }; ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) } /// Create a Type Archive at the given path, returning None if it could not be created. - pub fn create(path: S, platform: &Platform) -> Option { - let path = path.into_bytes_with_nul(); - let handle = unsafe { - BNCreateTypeArchive( - path.as_ref().as_ptr() as *const ffi::c_char, - platform.handle, - ) - }; + pub fn create(path: impl AsRef, platform: &Platform) -> Option { + let path = path.as_ref().to_string_lossy(); + let handle = unsafe { BNCreateTypeArchive(path.as_cstr().as_ptr(), platform.handle) }; ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) } /// Create a Type Archive at the given path and id, returning None if it could not be created. - pub fn create_with_id( - path: P, - id: I, + pub fn create_with_id( + path: impl AsRef, + id: impl AsCStr, platform: &Platform, ) -> Option { - let path = path.into_bytes_with_nul(); - let id = id.into_bytes_with_nul(); + let path = path.as_ref().to_string_lossy(); let handle = unsafe { BNCreateTypeArchiveWithId( - path.as_ref().as_ptr() as *const ffi::c_char, + path.as_cstr().as_ptr(), platform.handle, - id.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), ) }; ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::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 { - let id = id.into_bytes_with_nul(); - let handle = unsafe { BNLookupTypeArchiveById(id.as_ref().as_ptr() as *const ffi::c_char) }; + pub fn lookup_by_id(id: impl AsCStr) -> Option { + let handle = unsafe { BNLookupTypeArchiveById(id.as_cstr().as_ptr()) }; ptr::NonNull::new(handle).map(|handle| unsafe { TypeArchive::from_raw(handle) }) } @@ -138,14 +132,8 @@ impl TypeArchive { } /// 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(); - unsafe { - BNSetTypeArchiveCurrentSnapshot( - self.as_raw(), - id.as_ref().as_ptr() as *const ffi::c_char, - ) - } + pub fn set_current_snapshot_id(&self, id: impl AsCStr) { + unsafe { BNSetTypeArchiveCurrentSnapshot(self.as_raw(), id.as_cstr().as_ptr()) } } /// Get a list of every snapshot's id @@ -157,16 +145,12 @@ impl TypeArchive { } /// Get the ids of the parents to the given snapshot - pub fn get_snapshot_parent_ids( - &self, - snapshot: S, - ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn get_snapshot_parent_ids(&self, snapshot: impl AsCStr) -> Option> { let mut count = 0; let result = unsafe { BNGetTypeArchiveSnapshotParentIds( self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, + snapshot.as_cstr().as_ptr(), &mut count, ) }; @@ -174,18 +158,10 @@ impl TypeArchive { } /// Get the ids of the children to the given snapshot - pub fn get_snapshot_child_ids( - &self, - snapshot: S, - ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn get_snapshot_child_ids(&self, snapshot: impl AsCStr) -> Option> { let mut count = 0; let result = unsafe { - BNGetTypeArchiveSnapshotChildIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, - &mut count, - ) + BNGetTypeArchiveSnapshotChildIds(self.as_raw(), snapshot.as_cstr().as_ptr(), &mut count) }; (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) }) } @@ -229,15 +205,9 @@ impl TypeArchive { /// /// * `id` - Old id of type in archive /// * `new_name` - New type name - pub fn rename_type_by_id(&self, id: S, new_name: &QualifiedName) { - let id = id.into_bytes_with_nul(); - let result = unsafe { - BNRenameTypeArchiveType( - self.as_raw(), - id.as_ref().as_ptr() as *const ffi::c_char, - &new_name.0, - ) - }; + pub fn rename_type_by_id(&self, id: impl AsCStr, new_name: &QualifiedName) { + let result = + unsafe { BNRenameTypeArchiveType(self.as_raw(), id.as_cstr().as_ptr(), &new_name.0) }; assert!(result); } @@ -251,11 +221,8 @@ impl TypeArchive { } /// Delete an existing type in the type archive. - pub fn delete_type_by_id(&self, id: S) { - let id = id.into_bytes_with_nul(); - let result = unsafe { - BNDeleteTypeArchiveType(self.as_raw(), id.as_ref().as_ptr() as *const ffi::c_char) - }; + pub fn delete_type_by_id(&self, id: impl AsCStr) { + let result = unsafe { BNDeleteTypeArchiveType(self.as_raw(), id.as_cstr().as_ptr()) }; assert!(result); } @@ -263,18 +230,13 @@ impl TypeArchive { /// /// * `name` - Type name /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_name( + pub fn get_type_by_name( &self, name: &QualifiedName, - snapshot: S, + snapshot: impl AsCStr, ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); let result = unsafe { - BNGetTypeArchiveTypeByName( - self.as_raw(), - &name.0, - snapshot.as_ref().as_ptr() as *const ffi::c_char, - ) + BNGetTypeArchiveTypeByName(self.as_raw(), &name.0, snapshot.as_cstr().as_ptr()) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -283,18 +245,12 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_id( - &self, - id: I, - snapshot: S, - ) -> Option> { - let snapshot = snapshot.into_bytes_with_nul(); - let id = id.into_bytes_with_nul(); + pub fn get_type_by_id(&self, id: impl AsCStr, snapshot: impl AsCStr) -> Option> { let result = unsafe { BNGetTypeArchiveTypeById( self.as_raw(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), ) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) @@ -304,18 +260,12 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_name_by_id( - &self, - id: I, - snapshot: S, - ) -> QualifiedName { - let snapshot = snapshot.into_bytes_with_nul(); - let id = id.into_bytes_with_nul(); + pub fn get_type_name_by_id(&self, id: impl AsCStr, snapshot: impl AsCStr) -> QualifiedName { let result = unsafe { BNGetTypeArchiveTypeName( self.as_raw(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), ) }; QualifiedName(result) @@ -325,37 +275,19 @@ impl TypeArchive { /// /// * `name` - Type name /// * `snapshot` - Snapshot id to search for types - pub fn get_type_id( - &self, - name: &QualifiedName, - snapshot: S, - ) -> Option { - let snapshot = snapshot.into_bytes_with_nul(); - let result = unsafe { - BNGetTypeArchiveTypeId( - self.as_raw(), - &name.0, - snapshot.as_ref().as_ptr() as *const ffi::c_char, - ) - }; + pub fn get_type_id(&self, name: &QualifiedName, snapshot: impl AsCStr) -> Option { + let result = + unsafe { BNGetTypeArchiveTypeId(self.as_raw(), &name.0, snapshot.as_cstr().as_ptr()) }; (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) } /// Retrieve all stored types in the archive at a snapshot /// /// * `snapshot` - Snapshot id to search for types - pub fn get_types_and_ids( - &self, - snapshot: S, - ) -> Array { - let snapshot = snapshot.into_bytes_with_nul(); + pub fn get_types_and_ids(&self, snapshot: impl AsCStr) -> Array { let mut count = 0; let result = unsafe { - BNGetTypeArchiveTypes( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, - &mut count, - ) + BNGetTypeArchiveTypes(self.as_raw(), snapshot.as_cstr().as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } @@ -364,15 +296,10 @@ impl TypeArchive { /// 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(&self, snapshot: impl AsCStr) -> Array { let mut count = 0; let result = unsafe { - BNGetTypeArchiveTypeIds( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, - &mut count, - ) + BNGetTypeArchiveTypeIds(self.as_raw(), snapshot.as_cstr().as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } @@ -381,15 +308,10 @@ impl TypeArchive { /// 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(&self, snapshot: impl AsCStr) -> Array { let mut count = 0; let result = unsafe { - BNGetTypeArchiveTypeNames( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, - &mut count, - ) + BNGetTypeArchiveTypeNames(self.as_raw(), snapshot.as_cstr().as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } @@ -398,18 +320,17 @@ impl TypeArchive { /// Get a list of all types' names and ids in the archive at a current snapshot /// * `snapshot` - Snapshot id to search for types - pub fn get_type_names_and_ids( + pub fn get_type_names_and_ids( &self, - snapshot: S, + snapshot: impl AsCStr, ) -> (Array, Array) { - let snapshot = snapshot.into_bytes_with_nul(); let mut count = 0; let mut names = ptr::null_mut(); let mut ids = ptr::null_mut(); let result = unsafe { BNGetTypeArchiveTypeNamesAndIds( self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, + snapshot.as_cstr().as_ptr(), &mut names, &mut ids, &mut count, @@ -425,19 +346,17 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_direct_references( + pub fn get_outgoing_direct_references( &self, - id: I, - snapshot: S, + id: impl AsCStr, + snapshot: impl AsCStr, ) -> 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(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), &mut count, ) }; @@ -449,19 +368,17 @@ impl TypeArchive { /// /// :param id: Source type id /// :param snapshot: Snapshot id to search for types - pub fn get_outgoing_recursive_references( + pub fn get_outgoing_recursive_references( &self, - id: I, - snapshot: S, + id: impl AsCStr, + snapshot: impl AsCStr, ) -> 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(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), &mut count, ) }; @@ -473,19 +390,17 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types - pub fn get_incoming_direct_references( + pub fn get_incoming_direct_references( &self, - id: I, - snapshot: S, + id: impl AsCStr, + snapshot: impl AsCStr, ) -> 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(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), &mut count, ) }; @@ -497,19 +412,17 @@ impl TypeArchive { /// /// * `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( &self, - id: I, - snapshot: S, + id: impl AsCStr, + snapshot: impl AsCStr, ) -> 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(), - id.as_ref().as_ptr() as *const ffi::c_char, - snapshot.as_ref().as_ptr() as *const ffi::c_char, + id.as_cstr().as_ptr(), + snapshot.as_cstr().as_ptr(), &mut count, ) }; @@ -518,11 +431,8 @@ impl TypeArchive { } /// Look up a metadata entry in the archive - 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 ffi::c_char) - }; + pub fn query_metadata(&self, key: impl AsCStr) -> Option> { + let result = unsafe { BNTypeArchiveQueryMetadata(self.as_raw(), key.as_cstr().as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) } @@ -530,35 +440,21 @@ impl TypeArchive { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { - let key = key.into_bytes_with_nul(); - let result = unsafe { - BNTypeArchiveStoreMetadata( - self.as_raw(), - key.as_ref().as_ptr() as *const ffi::c_char, - md.handle, - ) - }; + pub fn store_metadata(&self, key: impl AsCStr, md: &Metadata) { + let result = + unsafe { BNTypeArchiveStoreMetadata(self.as_raw(), key.as_cstr().as_ptr(), md.handle) }; assert!(result); } /// Delete a given metadata entry in the archive from the `key` - 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 ffi::c_char) - } + pub fn remove_metadata(&self, key: impl AsCStr) -> bool { + unsafe { BNTypeArchiveRemoveMetadata(self.as_raw(), key.as_cstr().as_ptr()) } } /// Turn a given `snapshot` id into a data stream - pub fn serialize_snapshot(&self, snapshot: S) -> DataBuffer { - let snapshot = snapshot.into_bytes_with_nul(); - let result = unsafe { - BNTypeArchiveSerializeSnapshot( - self.as_raw(), - snapshot.as_ref().as_ptr() as *const ffi::c_char, - ) - }; + pub fn serialize_snapshot(&self, snapshot: impl AsCStr) -> DataBuffer { + let result = + unsafe { BNTypeArchiveSerializeSnapshot(self.as_raw(), snapshot.as_cstr().as_ptr()) }; assert!(!result.is_null()); DataBuffer::from_raw(result) } @@ -623,9 +519,9 @@ impl TypeArchive { } /// 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 ffi::c_char) } + pub fn is_type_archive(file: impl AsRef) -> bool { + let path = file.as_ref().to_string_lossy(); + unsafe { BNIsTypeArchive(path.as_cstr().as_ptr()) } } // TODO implement TypeContainer @@ -643,9 +539,12 @@ 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: impl IntoIterator, + ) -> BnString where - P: BnStrCompatible, F: FnMut(&str) -> bool, { unsafe extern "C" fn cb_callback bool>( @@ -656,15 +555,21 @@ impl TypeArchive { fun(&ffi::CStr::from_ptr(id).to_string_lossy()) } - // SAFETY BnString and `*const ffi::c_char` are transparent - let parents_raw = parents.as_ptr() as *const *const ffi::c_char; + let parents = parents + .into_iter() + .map(|parent| BnString::new(parent)) + .collect::>(); + let parents = parents + .into_iter() + .map(|parent| parent.as_raw() as *const _) + .collect::>(); let result = unsafe { BNTypeArchiveNewSnapshotTransaction( self.as_raw(), Some(cb_callback::), &mut function as *mut F as *mut ffi::c_void, - parents_raw, + parents.as_ptr(), parents.len(), ) }; @@ -682,22 +587,18 @@ 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, + base_snapshot: impl AsCStr, + first_snapshot: impl AsCStr, + second_snapshot: impl AsCStr, + merge_conflicts: impl IntoIterator, mut progress: P, ) -> Result> where - B: BnStrCompatible, - F: BnStrCompatible, - S: BnStrCompatible, P: FnMut(usize, usize) -> bool, - M: IntoIterator, - MI: BnStrCompatible, - MK: BnStrCompatible, + K: AsCStr, + V: AsCStr, { unsafe extern "C" fn cb_callback bool>( ctxt: *mut ffi::c_void, @@ -708,16 +609,18 @@ impl TypeArchive { ctxt(progress, total) } - 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(); - let (merge_keys, merge_values): (Vec, Vec) = merge_conflicts + let (merge_keys, merge_values): (Vec<_>, Vec<_>) = merge_conflicts .into_iter() .map(|(k, v)| (BnString::new(k), BnString::new(v))) .unzip(); - // SAFETY BnString and `*const ffi::c_char` are transparent - let merge_keys_raw = merge_keys.as_ptr() as *const *const ffi::c_char; - let merge_values_raw = merge_values.as_ptr() as *const *const ffi::c_char; + let merge_keys = merge_keys + .iter() + .map(|k| k.as_raw() as *const _) + .collect::>(); + let merge_values = merge_values + .iter() + .map(|v| v.as_raw() as *const _) + .collect::>(); let mut conflicts_errors = ptr::null_mut(); let mut conflicts_errors_count = 0; @@ -727,11 +630,11 @@ impl TypeArchive { let success = unsafe { BNTypeArchiveMergeSnapshots( self.as_raw(), - base_snapshot.as_ref().as_ptr() as *const ffi::c_char, - first_snapshot.as_ref().as_ptr() as *const ffi::c_char, - second_snapshot.as_ref().as_ptr() as *const ffi::c_char, - merge_keys_raw, - merge_values_raw, + base_snapshot.as_cstr().as_ptr(), + first_snapshot.as_cstr().as_ptr(), + second_snapshot.as_cstr().as_ptr(), + merge_keys.as_ptr(), + merge_values.as_ptr(), merge_keys.len(), &mut conflicts_errors, &mut conflicts_errors_count, diff --git a/rust/src/typelibrary.rs b/rust/src/typelibrary.rs index 22ac9f9e9..d00897cca 100644 --- a/rust/src/typelibrary.rs +++ b/rust/src/typelibrary.rs @@ -1,13 +1,14 @@ use binaryninjacore_sys::*; -use core::{ffi, mem, ptr}; +use core::{mem, ptr}; +use std::path::Path; use crate::{ architecture::CoreArchitecture, metadata::Metadata, platform::Platform, rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}, - string::{BnStrCompatible, BnString}, + string::{AsCStr, BnString}, types::{QualifiedName, QualifiedNameAndType, Type}, }; @@ -42,10 +43,8 @@ impl TypeLibrary { } /// Creates an empty type library object with a random GUID and the provided name. - pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { - let name = name.into_bytes_with_nul(); - let new_lib = - unsafe { BNNewTypeLibrary(arch.0, name.as_ref().as_ptr() as *const ffi::c_char) }; + pub fn new(arch: CoreArchitecture, name: impl AsCStr) -> TypeLibrary { + let new_lib = unsafe { BNNewTypeLibrary(arch.0, name.as_cstr().as_ptr()) }; unsafe { TypeLibrary::from_raw(ptr::NonNull::new(new_lib).unwrap()) } } @@ -57,49 +56,33 @@ impl TypeLibrary { } /// Decompresses a type library file to a file on disk. - pub fn decompress_to_file(path: P, output: O) -> bool { - let path = path.into_bytes_with_nul(); - let output = output.into_bytes_with_nul(); - unsafe { - BNTypeLibraryDecompressToFile( - path.as_ref().as_ptr() as *const ffi::c_char, - output.as_ref().as_ptr() as *const ffi::c_char, - ) - } + pub fn decompress_to_file(path: impl AsRef, output: impl AsRef) -> bool { + let path = path.as_ref().to_string_lossy(); + let output = output.as_ref().to_string_lossy(); + unsafe { BNTypeLibraryDecompressToFile(path.as_cstr().as_ptr(), output.as_cstr().as_ptr()) } } /// Loads a finalized type library instance from file - pub fn load_from_file(path: S) -> Option { - let path = path.into_bytes_with_nul(); - let handle = - unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; + pub fn load_from_file(path: impl AsCStr) -> Option { + let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_cstr().as_ptr()) }; ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) } /// Saves a finalized type library instance to file - pub fn write_to_file(&self, path: S) -> bool { - let path = path.into_bytes_with_nul(); - unsafe { - BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) - } + pub fn write_to_file(&self, path: impl AsCStr) -> bool { + unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_cstr().as_ptr()) } } /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. - pub fn from_name(arch: CoreArchitecture, name: S) -> Option { - let name = name.into_bytes_with_nul(); - let handle = unsafe { - BNLookupTypeLibraryByName(arch.0, name.as_ref().as_ptr() as *const ffi::c_char) - }; + pub fn from_name(arch: CoreArchitecture, name: impl AsCStr) -> Option { + let handle = unsafe { BNLookupTypeLibraryByName(arch.0, name.as_cstr().as_ptr()) }; ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) } /// Attempts to grab a type library associated with the provided Architecture and GUID pair - pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { - let guid = guid.into_bytes_with_nul(); - let handle = unsafe { - BNLookupTypeLibraryByGuid(arch.0, guid.as_ref().as_ptr() as *const ffi::c_char) - }; + pub fn from_guid(arch: CoreArchitecture, guid: impl AsCStr) -> Option { + let handle = unsafe { BNLookupTypeLibraryByGuid(arch.0, guid.as_cstr().as_ptr()) }; ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) } @@ -117,11 +100,8 @@ impl TypeLibrary { } /// Sets the name of a type library instance that has not been finalized - pub fn set_name(&self, value: S) { - let value = value.into_bytes_with_nul(); - unsafe { - BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) - } + pub fn set_name(&self, value: impl AsCStr) { + unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_cstr().as_ptr()) } } /// The `dependency_name` of a library is the name used to record dependencies across @@ -135,14 +115,8 @@ impl TypeLibrary { } /// Sets the dependency name of a type library instance that has not been finalized - pub fn set_dependency_name(&self, value: S) { - let value = value.into_bytes_with_nul(); - unsafe { - BNSetTypeLibraryDependencyName( - self.as_raw(), - value.as_ref().as_ptr() as *const ffi::c_char, - ) - } + pub fn set_dependency_name(&self, value: impl AsCStr) { + unsafe { BNSetTypeLibraryDependencyName(self.as_raw(), value.as_cstr().as_ptr()) } } /// Returns the GUID associated with the type library @@ -152,11 +126,8 @@ impl TypeLibrary { } /// Sets the GUID of a type library instance that has not been finalized - pub fn set_guid(&self, value: S) { - let value = value.into_bytes_with_nul(); - unsafe { - BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) - } + pub fn set_guid(&self, value: impl AsCStr) { + unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_cstr().as_ptr()) } } /// A list of extra names that will be considered a match by [Platform::get_type_libraries_by_name] @@ -168,14 +139,8 @@ impl TypeLibrary { } /// Adds an extra name to this type library used during library lookups and dependency resolution - pub fn add_alternate_name(&self, value: S) { - let value = value.into_bytes_with_nul(); - unsafe { - BNAddTypeLibraryAlternateName( - self.as_raw(), - value.as_ref().as_ptr() as *const ffi::c_char, - ) - } + pub fn add_alternate_name(&self, value: impl AsCStr) { + unsafe { BNAddTypeLibraryAlternateName(self.as_raw(), value.as_cstr().as_ptr()) } } /// Returns a list of all platform names that this type library will register with during platform @@ -212,11 +177,8 @@ impl TypeLibrary { } /// Retrieves a metadata associated with the given key stored in the type library - pub fn query_metadata(&self, key: S) -> Option { - let key = key.into_bytes_with_nul(); - let result = unsafe { - BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) - }; + pub fn query_metadata(&self, key: impl AsCStr) -> Option { + let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_cstr().as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::from_raw(result) }) } @@ -231,23 +193,13 @@ impl TypeLibrary { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { - let key = key.into_bytes_with_nul(); - unsafe { - BNTypeLibraryStoreMetadata( - self.as_raw(), - key.as_ref().as_ptr() as *const ffi::c_char, - md.handle, - ) - } + pub fn store_metadata(&self, key: impl AsCStr, md: &Metadata) { + unsafe { BNTypeLibraryStoreMetadata(self.as_raw(), key.as_cstr().as_ptr(), md.handle) } } /// Removes the metadata associated with key from the current type library. - pub fn remove_metadata(&self, key: S) { - let key = key.into_bytes_with_nul(); - unsafe { - BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) - } + pub fn remove_metadata(&self, key: impl AsCStr) { + unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_cstr().as_ptr()) } } /// Retrieves the metadata associated with the current type library. @@ -299,13 +251,12 @@ impl TypeLibrary { /// Use this api with extreme caution. /// /// - pub fn add_type_source(&self, name: &QualifiedName, source: S) { - let source = source.into_bytes_with_nul(); + pub fn add_type_source(&self, name: &QualifiedName, source: impl AsCStr) { unsafe { BNAddTypeLibraryNamedTypeSource( self.as_raw(), &name.0 as *const _ as *mut _, - source.as_ref().as_ptr() as *const ffi::c_char, + source.as_cstr().as_ptr(), ) } } diff --git a/rust/src/types.rs b/rust/src/types.rs index 0587df0ac..23e6b3f94 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -27,7 +27,7 @@ use crate::{ hlil::HighLevelILFunction, mlil::MediumLevelILFunction, rc::*, - string::{raw_to_string, BnStrCompatible, BnString}, + string::{raw_to_string, AsCStr, BnString}, symbol::Symbol, }; @@ -39,7 +39,7 @@ use std::{ ffi::CStr, fmt::{self, Debug, Display, Formatter}, hash::{Hash, Hasher}, - iter::{zip, IntoIterator}, + iter::IntoIterator, mem::{self, ManuallyDrop}, ops::Range, os::raw::c_char, @@ -527,44 +527,29 @@ impl TypeBuilder { Self::from_raw(BNCreateIntegerTypeBuilder( width, &mut is_signed, - BnString::new("").as_ptr() as *mut _, + c"".as_ptr(), )) } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { + pub fn named_int(width: usize, is_signed: bool, alt_name: impl AsCStr) -> Self { let mut is_signed = Conf::new(is_signed, max_confidence()).into(); - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data unsafe { Self::from_raw(BNCreateIntegerTypeBuilder( width, &mut is_signed, - alt_name.as_ref().as_ptr() as _, + alt_name.as_cstr().as_ptr(), )) } } pub fn float(width: usize) -> Self { - unsafe { - Self::from_raw(BNCreateFloatTypeBuilder( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, c"".as_ptr())) } } - pub fn named_float(width: usize, alt_name: S) -> Self { - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // See same line in `named_int` above - - unsafe { - Self::from_raw(BNCreateFloatTypeBuilder( - width, - alt_name.as_ref().as_ptr() as _, - )) - } + pub fn named_float(width: usize, alt_name: impl AsCStr) -> Self { + unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, alt_name.as_cstr().as_ptr())) } } pub fn array<'a, T: Into>>(t: T, count: u64) -> Self { @@ -608,12 +593,12 @@ impl TypeBuilder { } } - pub fn named_type_from_type(name: S, t: &Type) -> Self { + pub fn named_type_from_type(name: impl AsCStr, t: &Type) -> Self { let mut name = QualifiedName::from(name); unsafe { Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId( - BnString::new("").as_ptr() as *mut _, + c"".as_ptr(), &mut name.0, t.handle, )) @@ -904,53 +889,32 @@ impl Type { } pub fn wide_char(width: usize) -> Ref { - unsafe { - Self::ref_from_raw(BNCreateWideCharType( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateWideCharType(width, c"".as_ptr())) } } pub fn int(width: usize, is_signed: bool) -> Ref { let mut is_signed = Conf::new(is_signed, max_confidence()).into(); - unsafe { - Self::ref_from_raw(BNCreateIntegerType( - width, - &mut is_signed, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateIntegerType(width, &mut is_signed, c"".as_ptr())) } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { + pub fn named_int(width: usize, is_signed: bool, alt_name: impl AsCStr) -> Ref { let mut is_signed = Conf::new(is_signed, max_confidence()).into(); - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data unsafe { Self::ref_from_raw(BNCreateIntegerType( width, &mut is_signed, - alt_name.as_ref().as_ptr() as _, + alt_name.as_cstr().as_ptr(), )) } } pub fn float(width: usize) -> Ref { - unsafe { - Self::ref_from_raw(BNCreateFloatType( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateFloatType(width, c"".as_ptr())) } } - pub fn named_float(width: usize, alt_name: S) -> Ref { - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // See same line in `named_int` above - - unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) } + pub fn named_float(width: usize, alt_name: impl AsCStr) -> Ref { + unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_cstr().as_ptr())) } } pub fn array<'a, T: Into>>(t: T, count: u64) -> Ref { @@ -995,12 +959,12 @@ impl Type { } } - pub fn named_type_from_type(name: S, t: &Type) -> Ref { + pub fn named_type_from_type(name: impl AsCStr, t: &Type) -> Ref { let mut name = QualifiedName::from(name); unsafe { Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId( - BnString::new("").as_ptr() as *mut _, + c"".as_ptr(), &mut name.0, t.handle, )) @@ -1024,24 +988,24 @@ impl Type { }; let mut stack_adjust = Conf::::new(0, min_confidence()).into(); - let mut raw_parameters = Vec::::with_capacity(parameters.len()); - let mut parameter_name_references = Vec::with_capacity(parameters.len()); - for parameter in parameters { - let raw_name = parameter.name.as_str().into_bytes_with_nul(); - let location = match ¶meter.location { - Some(location) => location.raw(), - None => unsafe { mem::zeroed() }, - }; + let parameter_names = parameters.iter().map(|parameter| parameter.name.as_cstr()); + let mut raw_parameters = parameters + .iter() + .zip(parameter_names) + .map(|(parameter, name)| { + let location = parameter + .location + .map_or(unsafe { mem::zeroed() }, |location| location.raw()); + BNFunctionParameter { + name: name.as_ptr() as *mut _, + type_: parameter.t.contents.handle, + typeConfidence: parameter.t.confidence, + defaultLocation: parameter.location.is_none(), + location, + } + }) + .collect::>(); - raw_parameters.push(BNFunctionParameter { - name: raw_name.as_slice().as_ptr() as *mut _, - type_: parameter.t.contents.handle, - typeConfidence: parameter.t.confidence, - defaultLocation: parameter.location.is_none(), - location, - }); - parameter_name_references.push(raw_name); - } let reg_stack_adjust_regs = ptr::null_mut(); let reg_stack_adjust_values = ptr::null_mut(); @@ -1090,29 +1054,23 @@ impl Type { calling_convention.into().into(); let mut stack_adjust = stack_adjust.into(); - let mut raw_parameters = Vec::::with_capacity(parameters.len()); - let mut parameter_name_references = Vec::with_capacity(parameters.len()); - let mut name_ptrs = vec![]; - for parameter in parameters { - name_ptrs.push(parameter.name.clone()); - } - - for (name, parameter) in zip(name_ptrs, parameters) { - let raw_name = name.as_str().into_bytes_with_nul(); - let location = match ¶meter.location { - Some(location) => location.raw(), - None => unsafe { mem::zeroed() }, - }; - - raw_parameters.push(BNFunctionParameter { - name: raw_name.as_slice().as_ptr() as *mut _, - type_: parameter.t.contents.handle, - typeConfidence: parameter.t.confidence, - defaultLocation: parameter.location.is_none(), - location, - }); - parameter_name_references.push(raw_name); - } + let parameter_names = parameters.iter().map(|parameter| parameter.name.as_cstr()); + let mut raw_parameters = parameters + .iter() + .zip(parameter_names) + .map(|(parameter, name)| { + let location = parameter + .location + .map_or(unsafe { mem::zeroed() }, |location| location.raw()); + BNFunctionParameter { + name: name.as_ptr() as *mut _, + type_: parameter.t.contents.handle, + typeConfidence: parameter.t.confidence, + defaultLocation: parameter.location.is_none(), + location, + } + }) + .collect::>(); // TODO: Update type signature and include these (will be a breaking change) let reg_stack_adjust_regs = ptr::null_mut(); @@ -1214,7 +1172,7 @@ impl Type { } } - pub fn generate_auto_demangled_type_id(name: S) -> BnString { + pub fn generate_auto_demangled_type_id(name: impl AsCStr) -> BnString { let mut name = QualifiedName::from(name); unsafe { BnString::from_raw(BNGenerateAutoDemangledTypeId(&mut name.0)) } } @@ -1647,26 +1605,21 @@ impl EnumerationBuilder { unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) } } - pub fn append(&self, name: S) -> &Self { - let name = name.into_bytes_with_nul(); - unsafe { - BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _); - } + pub fn append(&self, name: impl AsCStr) -> &Self { + unsafe { BNAddEnumerationBuilderMember(self.handle, name.as_cstr().as_ptr()) } self } - pub fn insert(&self, name: S, value: u64) -> &Self { - let name = name.into_bytes_with_nul(); + pub fn insert(&self, name: impl AsCStr, value: u64) -> &Self { unsafe { - BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value); + BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_cstr().as_ptr(), value) } self } - pub fn replace(&self, id: usize, name: S, value: u64) -> &Self { - let name = name.into_bytes_with_nul(); + pub fn replace(&self, id: usize, name: impl AsCStr, value: u64) -> &Self { unsafe { - BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value); + BNReplaceEnumerationBuilderMember(self.handle, id, name.as_cstr().as_ptr(), value) } self } @@ -1884,19 +1837,18 @@ impl StructureBuilder { self } - pub fn append<'a, S: BnStrCompatible, T: Into>>( + pub fn append<'a, T: Into>>( &self, t: T, - name: S, + name: impl AsCStr, access: MemberAccess, scope: MemberScope, ) -> &Self { - let name = name.into_bytes_with_nul(); unsafe { BNAddStructureBuilderMember( self.handle, &t.into().into(), - name.as_ref().as_ptr() as _, + name.as_cstr().as_ptr(), access, scope, ); @@ -1918,21 +1870,20 @@ impl StructureBuilder { self } - pub fn insert<'a, S: BnStrCompatible, T: Into>>( + pub fn insert<'a, T: Into>>( &self, t: T, - name: S, + name: impl AsCStr, offset: u64, overwrite_existing: bool, access: MemberAccess, scope: MemberScope, ) -> &Self { - let name = name.into_bytes_with_nul(); unsafe { BNAddStructureBuilderMemberAtOffset( self.handle, &t.into().into(), - name.as_ref().as_ptr() as _, + name.as_cstr().as_ptr(), offset, overwrite_existing, access, @@ -1943,7 +1894,7 @@ impl StructureBuilder { self } - pub fn with_members<'a, S: BnStrCompatible, T: Into>>( + pub fn with_members<'a, S: AsCStr, T: Into>>( &self, members: impl IntoIterator, ) -> &Self { @@ -2040,16 +1991,19 @@ impl StructureBuilder { unsafe { BNRemoveStructureBuilderMember(self.handle, index) } } - pub fn replace(&self, index: usize, type_: Conf<&Type>, name: &str, overwrite: bool) { - let name = name.into_bytes_with_nul(); - let name_ptr = name.as_ptr() as *const _; - + pub fn replace(&self, index: usize, type_: Conf<&Type>, name: impl AsCStr, overwrite: bool) { let raw_type_ = BNTypeWithConfidence { type_: type_.contents as *const Type as *mut _, confidence: type_.confidence, }; unsafe { - BNReplaceStructureBuilderMember(self.handle, index, &raw_type_, name_ptr, overwrite) + BNReplaceStructureBuilderMember( + self.handle, + index, + &raw_type_, + name.as_cstr().as_ptr(), + overwrite, + ) } } } @@ -2341,16 +2295,14 @@ impl NamedTypeReference { /// You should not assign type ids yourself: if you use this to reference a type you are going /// to create but have not yet created, you may run into problems when giving your types to /// a BinaryView. - pub fn new_with_id( + pub fn new_with_id( type_class: NamedTypeReferenceClass, - type_id: S, + type_id: impl AsCStr, mut name: QualifiedName, ) -> Ref { - let type_id = type_id.into_bytes_with_nul(); - unsafe { RefCountable::inc_ref(&Self { - handle: BNCreateNamedType(type_class, type_id.as_ref().as_ptr() as _, &mut name.0), + handle: BNCreateNamedType(type_class, type_id.as_cstr().as_ptr(), &mut name.0), }) } } @@ -2461,31 +2413,23 @@ impl QualifiedName { } } -impl From for QualifiedName { +impl From for QualifiedName { fn from(name: S) -> Self { let join = BnString::new("::"); - let name = name.into_bytes_with_nul(); - let mut list = vec![name.as_ref().as_ptr() as *const _]; QualifiedName(BNQualifiedName { - name: unsafe { BNAllocStringList(list.as_mut_ptr(), 1) }, + name: unsafe { BNAllocStringList(vec![name.as_cstr().as_ptr()].as_mut_ptr(), 1) }, join: join.into_raw(), nameCount: 1, }) } } -impl From> for QualifiedName { +impl From> for QualifiedName { fn from(names: Vec) -> Self { let join = BnString::new("::"); - let names = names - .into_iter() - .map(|n| n.into_bytes_with_nul()) - .collect::>(); - let mut list = names - .iter() - .map(|n| n.as_ref().as_ptr() as *const _) - .collect::>(); + let names = names.iter().map(|n| n.as_cstr()).collect::>(); + let mut list = names.iter().map(|n| n.as_ptr()).collect::>(); QualifiedName(BNQualifiedName { name: unsafe { BNAllocStringList(list.as_mut_ptr(), list.len()) }, @@ -2653,10 +2597,10 @@ impl NameAndType { } impl NameAndType { - pub fn new(name: S, t: &Type, confidence: u8) -> Ref { + pub fn new(name: impl AsCStr, t: &Type, confidence: u8) -> Ref { unsafe { Ref::new(Self(BNNameAndType { - name: BNAllocString(name.into_bytes_with_nul().as_ref().as_ptr() as *mut _), + name: BNAllocString(name.as_cstr().as_ptr()), type_: Ref::into_raw(t.to_owned()).handle, typeConfidence: confidence, })) @@ -2799,7 +2743,7 @@ unsafe impl CoreArrayProviderInner for DataVariable { ///////////////////////// // DataVariableAndName -pub struct DataVariableAndName { +pub struct DataVariableAndName { pub address: u64, pub t: Conf>, pub auto_discovered: bool, @@ -2817,7 +2761,7 @@ impl DataVariableAndName { } } -impl DataVariableAndName { +impl DataVariableAndName { pub fn new(address: u64, t: Conf>, auto_discovered: bool, name: S) -> Self { Self { address, @@ -2964,12 +2908,12 @@ impl ConstantData { } } -// unsafe impl CoreArrayProvider for DataVariableAndName { +// unsafe impl CoreArrayProvider for DataVariableAndName { // type Raw = BNDataVariableAndName; // type Context = (); // } -// unsafe impl CoreOwnedArrayProvider for DataVariableAndName { +// unsafe impl CoreOwnedArrayProvider for DataVariableAndName { // unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { // BNFreeDataVariablesAndName(raw, count); // } diff --git a/rust/src/update.rs b/rust/src/update.rs index 31e02cd81..dac0c47eb 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -4,7 +4,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; use binaryninjacore_sys::*; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::BnString; +use crate::string::{AsCStr, BnString}; pub type UpdateResult = BNUpdateResult; @@ -38,8 +38,9 @@ impl UpdateChannel { 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 result = unsafe { + BNGetUpdateChannelVersions(self.name.as_cstr().as_ptr(), &mut count, &mut errors) + }; if !errors.is_null() { Err(unsafe { BnString::from_raw(errors) }) } else { @@ -65,7 +66,7 @@ impl UpdateChannel { let mut errors = ptr::null_mut(); let result = unsafe { BNAreUpdatesAvailable( - self.name.as_ptr(), + self.name.as_cstr().as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut errors, @@ -82,7 +83,7 @@ impl UpdateChannel { let mut errors = ptr::null_mut(); let result = unsafe { BNUpdateToLatestVersion( - self.name.as_ptr(), + self.name.as_cstr().as_ptr(), &mut errors, Some(cb_progress_nop), ptr::null_mut(), @@ -105,7 +106,7 @@ impl UpdateChannel { let mut errors = ptr::null_mut(); let result = unsafe { BNUpdateToLatestVersion( - self.name.as_ptr(), + self.name.as_cstr().as_ptr(), &mut errors, Some(cb_progress::), &mut progress as *mut _ as *mut ffi::c_void, @@ -122,8 +123,8 @@ impl UpdateChannel { let mut errors = ptr::null_mut(); let result = unsafe { BNUpdateToVersion( - self.name.as_ptr(), - version.version.as_ptr(), + self.name.as_cstr().as_ptr(), + version.version.as_cstr().as_ptr(), &mut errors, Some(cb_progress_nop), ptr::null_mut(), @@ -147,8 +148,8 @@ impl UpdateChannel { let mut errors = ptr::null_mut(); let result = unsafe { BNUpdateToVersion( - self.name.as_ptr(), - version.version.as_ptr(), + self.name.as_cstr().as_ptr(), + version.version.as_cstr().as_ptr(), &mut errors, Some(cb_progress::), &mut progress as *mut _ as *mut ffi::c_void,