summaryrefslogtreecommitdiff
path: root/rust/src/rc.rs
diff options
context:
space:
mode:
authorRyan Snyder <ryan@vector35.com>2021-01-21 18:27:48 +0000
committerKyleMiles <krm504@nyu.edu>2021-01-21 19:06:55 +0000
commitd3140edec185f47235b9e4642bdd56d6c585a341 (patch)
treea61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/rc.rs
parentc0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (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/rc.rs')
-rw-r--r--rust/src/rc.rs361
1 files changed, 361 insertions, 0 deletions
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<T>` 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<Owned=Ref<Self>> + Sized {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self>;
+ 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<T: RefCountable> {
+ contents: T,
+}
+
+impl<T: RefCountable> Ref<T> {
+ 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<T: RefCountable> AsRef<T> for Ref<T> {
+ fn as_ref(&self) -> &T {
+ &self.contents
+ }
+}
+
+impl<T: RefCountable> Deref for Ref<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.contents
+ }
+}
+
+impl<T: RefCountable> DerefMut for Ref<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.contents
+ }
+}
+
+impl<T: RefCountable> Borrow<T> for Ref<T> {
+ fn borrow(&self) -> &T {
+ &self.contents
+ }
+}
+
+impl<T: RefCountable> Drop for Ref<T> {
+ fn drop(&mut self) {
+ unsafe { RefCountable::dec_ref(&self.contents); }
+ }
+}
+
+impl <T: RefCountable> Clone for Ref<T> {
+ 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<O: 'a>(contents: T, _owner: &O) -> Self {
+ Self {
+ contents,
+ _guard: PhantomData
+ }
+ }
+}
+
+impl<'a, T> AsRef<T> 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<T> 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<P>
+where
+ P: CoreOwnedArrayProvider
+{
+ contents: *mut P::Raw,
+ count: usize,
+ context: P::Context,
+}
+
+unsafe impl<P> Sync for Array<P> where P: CoreOwnedArrayProvider, P::Context: Sync {}
+unsafe impl<P> Send for Array<P> where P: CoreOwnedArrayProvider, P::Context: Send {}
+
+impl<P: CoreOwnedArrayProvider> Array<P> {
+ 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<P> {
+ #[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<P> {
+ type Item = P::Wrapped;
+ type IntoIter = ArrayIter<'a, P>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+
+impl<P: CoreOwnedArrayProvider> Drop for Array<P> {
+ 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<P::Wrapped> {
+ self.it.next().map(|r| unsafe { P::wrap_raw(r, &self.context) })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<P::Wrapped> {
+ 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<P>
+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<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ 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<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>
+ {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.it.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>
+ {
+ 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 } })
+ }
+}