diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-01-21 18:27:48 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:06:55 +0000 |
| commit | d3140edec185f47235b9e4642bdd56d6c585a341 (patch) | |
| tree | a61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/string.rs | |
| parent | c0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff) | |
This is a combination of 23 commits, the work of Ryan Snyder:
Initial fresh repo
Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one.
Add support for auto function analysis suppression
Finish moving binaryninjacore-sys back into this crate
Update for Symbol/Segment core API changes
Update for Symbol API cleanup
api: advance submodule reference, support Token changes
arch/lifting: support for flags in custom architectures
arch/lifting: support default flag write behaviors, handle more ops
build: enable headless binary support on MacOS via evil hack
bv: add BinaryView wrapper support, remove wrong comment
api: update to latest binja dev branch support
deps: bump dep versions
rust: bump to 2018 edition
api: bump to avoid cargo submodule brokenness
build: improve binaryninja path detection; enable linux linkhack
bv: stub for bv load settings
arch: fix flag related crash, minor llil update
api: update for recent changes
macos: disable linkhack briefly
Diffstat (limited to 'rust/src/string.rs')
| -rw-r--r-- | rust/src/string.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/rust/src/string.rs b/rust/src/string.rs new file mode 100644 index 00000000..1b2e0913 --- /dev/null +++ b/rust/src/string.rs @@ -0,0 +1,201 @@ +use std::fmt; +use std::borrow::Borrow; +use std::ops::Deref; +use std::ffi::{CStr, CString}; +use std::os::raw; +use std::mem; + +use crate::rc::*; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[repr(C)] +pub struct BnStr { + raw: [u8] +} + +impl BnStr { + pub(crate) unsafe fn from_raw<'a>(ptr: *const raw::c_char) -> &'a Self { + mem::transmute(CStr::from_ptr(ptr).to_bytes_with_nul()) + } + + pub fn as_str(&self) -> &str { + self.as_cstr().to_str().unwrap() + } + + pub fn as_cstr(&self) -> &CStr { + unsafe { CStr::from_bytes_with_nul_unchecked(&self.raw) } + } +} + +impl Deref for BnStr { + type Target = str; + + fn deref(&self) -> &str { + self.as_str() + } +} + +impl AsRef<[u8]> for BnStr { + fn as_ref(&self) -> &[u8] { + &self.raw + } +} + +impl AsRef<str> for BnStr { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl Borrow<str> for BnStr { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl fmt::Display for BnStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_cstr().to_string_lossy()) + } +} + +#[repr(C)] +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. +impl BnString { + pub fn new<S: BnStrCompatible>(s: S) -> Self { + use binaryninjacore_sys::BNAllocString; + + let raw = s.as_bytes_with_nul(); + + unsafe { + let ptr = raw.as_ref().as_ptr() as *mut _; + + Self { raw: BNAllocString(ptr) } + } + } + + pub(crate) unsafe fn from_raw(raw: *mut raw::c_char) -> Self { + Self { raw } + } + + pub(crate) fn into_raw(self) -> *mut raw::c_char { + let res = self.raw; + + // we're surrendering ownership over the *mut c_char to + // the core, so ensure we don't free it + mem::forget(self); + + res + } +} + +impl Drop for BnString { + fn drop(&mut self) { + use binaryninjacore_sys::BNFreeString; + + unsafe { + BNFreeString(self.raw); + } + } +} + +impl Deref for BnString { + type Target = BnStr; + + fn deref(&self) -> &BnStr { + unsafe { BnStr::from_raw(self.raw) } + } +} + +impl AsRef<[u8]> for BnString { + fn as_ref(&self) -> &[u8] { + self.as_cstr().to_bytes_with_nul() + } +} + +impl fmt::Display for BnString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_cstr().to_string_lossy()) + } +} + +unsafe impl CoreOwnedArrayProvider for BnString { + type Raw = *mut raw::c_char; + type Context = (); + + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + use binaryninjacore_sys::BNFreeStringList; + BNFreeStringList(raw, count); + } +} + +unsafe impl<'a> CoreOwnedArrayWrapper<'a> for BnString { + type Wrapped = &'a BnStr; + + unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { + BnStr::from_raw(*raw) + } +} + +pub unsafe trait BnStrCompatible { + type Result: AsRef<[u8]>; + fn as_bytes_with_nul(self) -> Self::Result; +} + +unsafe impl<'a> BnStrCompatible for &'a BnStr { + type Result = &'a [u8]; + + fn as_bytes_with_nul(self) -> Self::Result { + self.as_cstr().to_bytes_with_nul() + } +} + +unsafe impl BnStrCompatible for BnString { + type Result = Self; + + fn as_bytes_with_nul(self) -> Self::Result { + self + } +} + +unsafe impl<'a> BnStrCompatible for &'a CStr { + type Result = &'a [u8]; + + fn as_bytes_with_nul(self) -> Self::Result { + self.to_bytes_with_nul() + } +} + +unsafe impl BnStrCompatible for CString { + type Result = Vec<u8>; + + fn as_bytes_with_nul(self) -> Self::Result { + self.into_bytes_with_nul() + } +} + +unsafe impl<'a> BnStrCompatible for &'a str { + type Result = Vec<u8>; + + fn as_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() + } +} + +unsafe impl BnStrCompatible for String { + type Result = Vec<u8>; + + fn as_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() + } +} |
