Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement rust ExternalLibrary #5683

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions rust/src/externallibrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
use core::{ffi, mem, ptr};

use binaryninjacore_sys::*;

use crate::project::ProjectFile;
use crate::rc::{CoreArrayProvider, CoreArrayProviderInner};
use crate::string::{BnStrCompatible, BnString};
use crate::symbol::Symbol;

/// An ExternalLibrary is an abstraction for a library that is optionally backed
/// by a [ProjectFile].
#[repr(transparent)]
pub struct ExternalLibrary {
handle: ptr::NonNull<BNExternalLibrary>,
}

impl Drop for ExternalLibrary {
fn drop(&mut self) {
unsafe { BNFreeExternalLibrary(self.as_raw()) }
}
}

impl Clone for ExternalLibrary {
fn clone(&self) -> Self {
unsafe {
Self::from_raw(ptr::NonNull::new(BNNewExternalLibraryReference(self.as_raw())).unwrap())
}
}
}

impl ExternalLibrary {
pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNExternalLibrary>) -> Self {
Self { handle }
}

pub(crate) unsafe fn ref_from_raw(handle: &*mut BNExternalLibrary) -> &Self {
assert!(!handle.is_null());
mem::transmute(handle)
}

#[allow(clippy::mut_from_ref)]
pub(crate) unsafe fn as_raw(&self) -> &mut BNExternalLibrary {
&mut *self.handle.as_ptr()
}

/// Get the name of this external library
pub fn name(&self) -> BnString {
let result = unsafe { BNExternalLibraryGetName(self.as_raw()) };
assert!(!result.is_null());
unsafe { BnString::from_raw(result) }
}

/// Get the file backing this external library
pub fn backing_file(&self) -> ProjectFile {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return Option<ProjectFile>

let result = unsafe { BNExternalLibraryGetBackingFile(self.as_raw()) };
unsafe { ProjectFile::from_raw(ptr::NonNull::new(result).unwrap()) }
}

/// Set the file backing this external library
pub fn set_backing_file(&self, file: &ProjectFile) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file should be Option<&ProjectFile>

unsafe { BNExternalLibrarySetBackingFile(self.as_raw(), file.as_raw()) }
}
}

impl CoreArrayProvider for ExternalLibrary {
type Raw = *mut BNExternalLibrary;
type Context = ();
type Wrapped<'a> = &'a Self;
}

unsafe impl CoreArrayProviderInner for ExternalLibrary {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeExternalLibraryList(raw, count)
}

unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
Self::ref_from_raw(raw)
}
}

/// An ExternalLocation is an association from a source symbol in a binary view
/// to a target symbol and/or address in an [ExternalLibrary].
#[repr(transparent)]
pub struct ExternalLocation {
handle: ptr::NonNull<BNExternalLocation>,
}

impl Drop for ExternalLocation {
fn drop(&mut self) {
unsafe { BNFreeExternalLocation(self.as_raw()) }
}
}

impl Clone for ExternalLocation {
fn clone(&self) -> Self {
unsafe {
Self::from_raw(
ptr::NonNull::new(BNNewExternalLocationReference(self.as_raw())).unwrap(),
)
}
}
}

impl ExternalLocation {
pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNExternalLocation>) -> Self {
Self { handle }
}

pub(crate) unsafe fn ref_from_raw(handle: &*mut BNExternalLocation) -> &Self {
assert!(!handle.is_null());
mem::transmute(handle)
}

#[allow(clippy::mut_from_ref)]
pub(crate) unsafe fn as_raw(&self) -> &mut BNExternalLocation {
&mut *self.handle.as_ptr()
}

/// Get the source symbol for this ExternalLocation
pub fn source_symbol(&self) -> Symbol {
let result = unsafe { BNExternalLocationGetSourceSymbol(self.as_raw()) };
assert!(!result.is_null());
unsafe { Symbol::from_raw(result) }
}

/// Get the ExternalLibrary that this ExternalLocation targets
pub fn library(&self) -> ExternalLibrary {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return Option<ExternalLibrary>

let result = unsafe { BNExternalLocationGetExternalLibrary(self.as_raw()) };
unsafe { ExternalLibrary::from_raw(ptr::NonNull::new(result).unwrap()) }
}

/// Set the ExternalLibrary that this ExternalLocation targets
pub fn set_external_library(&self, lib: &ExternalLibrary) {
unsafe { BNExternalLocationSetExternalLibrary(self.as_raw(), lib.as_raw()) }
}

/// Check if this ExternalLocation has a target address
pub fn has_target_address(&self) -> bool {
unsafe { BNExternalLocationHasTargetAddress(self.as_raw()) }
}

/// Check if this ExternalLocation has a target symbol
pub fn has_target_symbol(&self) -> bool {
unsafe { BNExternalLocationHasTargetSymbol(self.as_raw()) }
}

/// Get the address pointed to by this ExternalLocation, if any
pub fn target_address(&self) -> Option<u64> {
self.has_target_address()
.then(|| unsafe { BNExternalLocationGetTargetAddress(self.as_raw()) })
}

/// Set the address pointed to by this ExternalLocation.
/// ExternalLocations must have a valid target address and/or symbol set.
pub fn set_target_address(&self, mut address: Option<u64>) -> bool {
let address_ptr = address
.as_mut()
.map(|x| x as *mut u64)
.unwrap_or(ptr::null_mut());
unsafe { BNExternalLocationSetTargetAddress(self.as_raw(), address_ptr) }
}

/// Get the symbol pointed to by this ExternalLocation, if any
pub fn target_symbol(&self) -> Option<BnString> {
self.has_target_symbol().then(|| unsafe {
let result = BNExternalLocationGetTargetSymbol(self.as_raw());
assert!(!result.is_null());
BnString::from_raw(result)
})
}

/// Remove the symbol pointed to by this ExternalLocation.
pub fn remove_target_symbol(&self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed and set_target_symbol should take an Option<S>

unsafe { BNExternalLocationSetTargetSymbol(self.as_raw(), ptr::null_mut()) }
}

/// Set the symbol pointed to by this ExternalLocation.
/// ExternalLocations must have a valid target address and/or symbol set.
pub fn set_target_symbol<S: BnStrCompatible>(&self, symbol: S) -> bool {
let symbol = symbol.into_bytes_with_nul();
unsafe {
BNExternalLocationSetTargetSymbol(
self.as_raw(),
symbol.as_ref().as_ptr() as *const ffi::c_char,
)
}
}
}

impl CoreArrayProvider for ExternalLocation {
type Raw = *mut BNExternalLocation;
type Context = ();
type Wrapped<'a> = &'a Self;
}

unsafe impl CoreArrayProviderInner for ExternalLocation {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeExternalLocationList(raw, count)
}

unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
Self::ref_from_raw(raw)
}
}
1 change: 1 addition & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ pub mod demangle;
pub mod disassembly;
pub mod component;
pub mod downloadprovider;
pub mod externallibrary;
pub mod fileaccessor;
pub mod filemetadata;
pub mod flowgraph;
Expand Down
Loading