From d3140edec185f47235b9e4642bdd56d6c585a341 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Thu, 21 Jan 2021 18:27:48 +0000 Subject: 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 --- rust/src/rc.rs | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 rust/src/rc.rs (limited to 'rust/src/rc.rs') diff --git a/rust/src/rc.rs b/rust/src/rc.rs new file mode 100644 index 00000000..3302fb3f --- /dev/null +++ b/rust/src/rc.rs @@ -0,0 +1,361 @@ +use std::marker::PhantomData; +use std::borrow::Borrow; +use std::ops::{Deref, DerefMut}; +use std::slice; +use std::mem; +use std::ptr; + +// RefCountable provides an abstraction over the various +// core-allocated refcounted resources. +// +// It is important that consumers don't acquire ownership +// of a `RefCountable` object directly -- they should only +// ever get their hands on a `Ref` or `&T`, otherwise it +// would be possible for the allocation in the core to +// be trivially leaked, as `T` does not have the `Drop` impl +// +// `T` does not have the `Drop` impl in order to allow more +// efficient handling of core owned objects we receive pointers +// to in callbacks +pub unsafe trait RefCountable: ToOwned> + Sized { + unsafe fn inc_ref(handle: &Self) -> Ref; + unsafe fn dec_ref(handle: &Self); +} + +// Represents an 'owned' reference tracked by the core +// that we are responsible for cleaning up once we're +// done with the encapsulated value. +pub struct Ref { + contents: T, +} + +impl Ref { + pub(crate) unsafe fn new(contents: T) -> Self { + Self { contents } + } + + pub(crate) unsafe fn into_raw(obj: Self) -> T { + let res = ptr::read(&obj.contents); + + mem::forget(obj); + + res + } +} + +impl AsRef for Ref { + fn as_ref(&self) -> &T { + &self.contents + } +} + +impl Deref for Ref { + type Target = T; + + fn deref(&self) -> &T { + &self.contents + } +} + +impl DerefMut for Ref { + fn deref_mut(&mut self) -> &mut T { + &mut self.contents + } +} + +impl Borrow for Ref { + fn borrow(&self) -> &T { + &self.contents + } +} + +impl Drop for Ref { + fn drop(&mut self) { + unsafe { RefCountable::dec_ref(&self.contents); } + } +} + +impl Clone for Ref { + fn clone(&self) -> Self { + unsafe { RefCountable::inc_ref(&self.contents) } + } +} + +// Guard provides access to a core-allocated resource whose +// reference is held indirectly (e.g. a core-allocated array +// of raw `*mut BNRawT`). +// +// This wrapper is necessary because `binja-rs` wrappers around +// core objects can be bigger than the raw pointer to the core +// object. This lets us create the full wrapper object and ensure +// that it does not outlive the core-allocated array (or similar) +// that our object came from. +pub struct Guard<'a, T> { + contents: T, + _guard: PhantomData<&'a ()>, +} + +impl<'a, T> Guard<'a, T> { + pub(crate) unsafe fn new(contents: T, _owner: &O) -> Self { + Self { + contents, + _guard: PhantomData + } + } +} + +impl<'a, T> AsRef for Guard<'a, T> { + fn as_ref(&self) -> &T { + &self.contents + } +} + +impl<'a, T> Deref for Guard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.contents + } +} + +impl<'a, T> DerefMut for Guard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.contents + } +} + +impl<'a, T> Borrow for Guard<'a, T> { + fn borrow(&self) -> &T { + &self.contents + } +} + +pub unsafe trait CoreOwnedArrayProvider { + type Raw; + type Context; + + unsafe fn free(raw: *mut Self::Raw, count: usize, context: &Self::Context); +} + +pub unsafe trait CoreOwnedArrayWrapper<'a>: CoreOwnedArrayProvider +where + Self::Raw: 'a, + Self::Context: 'a, +{ + type Wrapped: 'a; + + unsafe fn wrap_raw(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped; +} + +pub struct Array

+where + P: CoreOwnedArrayProvider +{ + contents: *mut P::Raw, + count: usize, + context: P::Context, +} + +unsafe impl

Sync for Array

where P: CoreOwnedArrayProvider, P::Context: Sync {} +unsafe impl

Send for Array

where P: CoreOwnedArrayProvider, P::Context: Send {} + +impl Array

{ + pub(crate) unsafe fn new(raw: *mut P::Raw, count: usize, context: P::Context) -> Self { + Self { + contents: raw, + count: count, + context: context, + } + } + + #[inline] + pub fn len(&self) -> usize { + self.count + } +} + +impl<'a, P: 'a + CoreOwnedArrayWrapper<'a>> Array

{ + #[inline] + pub fn get(&'a self, index: usize) -> P::Wrapped { + unsafe { + let backing = slice::from_raw_parts(self.contents, self.count); + P::wrap_raw(&backing[index], &self.context) + } + } + + pub fn iter(&'a self) -> ArrayIter<'a, P> { + ArrayIter { + it: unsafe { slice::from_raw_parts(self.contents, self.count).iter() }, + context: &self.context + } + } +} + + +impl<'a, P: 'a + CoreOwnedArrayWrapper<'a>> IntoIterator for &'a Array

{ + type Item = P::Wrapped; + type IntoIter = ArrayIter<'a, P>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + + +impl Drop for Array

{ + fn drop(&mut self) { + unsafe { P::free(self.contents, self.count, &self.context); } + } +} + +pub struct ArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a> +{ + it: slice::Iter<'a, P::Raw>, + context: &'a P::Context, +} + +unsafe impl<'a, P> Send for ArrayIter<'a, P> where P: CoreOwnedArrayWrapper<'a>, P::Context: Sync {} + +impl<'a, P> Iterator for ArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a> +{ + type Item = P::Wrapped; + + #[inline] + fn next(&mut self) -> Option { + self.it.next().map(|r| unsafe { P::wrap_raw(r, &self.context) }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, P> ExactSizeIterator for ArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a> +{ + #[inline] + fn len(&self) -> usize { + self.it.len() + } +} + +impl<'a, P> DoubleEndedIterator for ArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a> +{ + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back().map(|r| unsafe { P::wrap_raw(r, &self.context) }) + } +} + +#[cfg(feature = "rayon")] +use rayon::prelude::*; + +#[cfg(feature = "rayon")] +use rayon::iter::plumbing::*; + +#[cfg(feature = "rayon")] +impl<'a, P> Array

+where + P: 'a + CoreOwnedArrayWrapper<'a>, + P::Context: Sync, + P::Wrapped: Send, +{ + pub fn par_iter(&'a self) -> ParArrayIter<'a, P> { + ParArrayIter { + it: self.iter(), + } + } +} +#[cfg(feature = "rayon")] +pub struct ParArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a>, + ArrayIter<'a, P>: Send, +{ + it: ArrayIter<'a, P>, +} + +#[cfg(feature = "rayon")] +impl<'a, P> ParallelIterator for ParArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a>, + P::Wrapped: Send, + ArrayIter<'a, P>: Send, +{ + type Item = P::Wrapped; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.it.len()) + } +} + +#[cfg(feature = "rayon")] +impl<'a, P> IndexedParallelIterator for ParArrayIter<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a>, + P::Wrapped: Send, + ArrayIter<'a, P>: Send, +{ + fn drive(self, consumer: C) -> C::Result + where + C: Consumer + { + bridge(self, consumer) + } + + fn len(&self) -> usize { + self.it.len() + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback + { + callback.callback(ArrayIterProducer { it: self.it }) + } +} + +#[cfg(feature = "rayon")] +struct ArrayIterProducer<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a>, + ArrayIter<'a, P>: Send, +{ + it: ArrayIter<'a, P>, +} + +#[cfg(feature = "rayon")] +impl<'a, P> Producer for ArrayIterProducer<'a, P> +where + P: 'a + CoreOwnedArrayWrapper<'a>, + ArrayIter<'a, P>: Send, +{ + type Item = P::Wrapped; + type IntoIter = ArrayIter<'a, P>; + + fn into_iter(self) -> ArrayIter<'a, P> { + self.it + } + + fn split_at(self, index: usize) -> (Self, Self) { + let (l, r) = self.it.it.as_slice().split_at(index); + + (Self { it: ArrayIter { it: l.iter(), context: self.it.context } }, + Self { it: ArrayIter { it: r.iter(), context: self.it.context } }) + } +} -- cgit v1.3.1