diff options
| author | Fabian Freyer <fabian.freyer@physik.tu-berlin.de> | 2022-01-28 01:36:26 +0100 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2022-02-14 18:45:11 -0500 |
| commit | 6cd49edb317112acc73f7caeb285f4134a472d72 (patch) | |
| tree | 3fc1af20b46dcb33c1ba5490193a0226e112e839 /rust | |
| parent | 181ad567199e5685578ecf7ad400257098c2e175 (diff) | |
rust: add linearview and related APIs
This should include everything required to retrieve linear disassembly
for a function.
* add `highest_address` method to `Function`
* add `DisassemblySettings`
* add text getter for `InstructionTextToken`
* add `LinearViewObject`, `LinearViewCursor`
* add decompilation example
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/examples/decompile/Cargo.toml | 10 | ||||
| -rw-r--r-- | rust/examples/decompile/build.rs | 68 | ||||
| -rw-r--r-- | rust/examples/decompile/src/main.rs | 54 | ||||
| -rw-r--r-- | rust/src/binaryview.rs | 50 | ||||
| -rw-r--r-- | rust/src/disassembly.rs | 118 | ||||
| -rw-r--r-- | rust/src/function.rs | 4 | ||||
| -rw-r--r-- | rust/src/lib.rs | 1 | ||||
| -rw-r--r-- | rust/src/linearview.rs | 420 |
8 files changed, 723 insertions, 2 deletions
diff --git a/rust/examples/decompile/Cargo.toml b/rust/examples/decompile/Cargo.toml new file mode 100644 index 00000000..2a6ac3b1 --- /dev/null +++ b/rust/examples/decompile/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "decompile" +version = "0.1.0" +authors = ["Fabian Freyer <mail@fabianfreyer.de>"] +edition = "2018" + +[dependencies] +binaryninja = {path="../../"} +clap = { version = "3.0", features = ["derive"] } + diff --git a/rust/examples/decompile/build.rs b/rust/examples/decompile/build.rs new file mode 100644 index 00000000..5ba9bcde --- /dev/null +++ b/rust/examples/decompile/build.rs @@ -0,0 +1,68 @@ +use std::env; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +#[cfg(target_os = "macos")] +static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun"); + +#[cfg(target_os = "linux")] +static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun"); + +#[cfg(windows)] +static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun"); + +// Check last run location for path to BinaryNinja; Otherwise check the default install locations +fn link_path() -> PathBuf { + use std::io::prelude::*; + + let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap()); + let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1); + + File::open(lastrun) + .and_then(|f| { + let mut binja_path = String::new(); + let mut reader = BufReader::new(f); + + reader.read_line(&mut binja_path)?; + Ok(PathBuf::from(binja_path.trim())) + }) + .unwrap_or_else(|_| { + #[cfg(target_os = "macos")] + return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS"); + + #[cfg(target_os = "linux")] + return home.join("binaryninja"); + + #[cfg(windows)] + return PathBuf::from(env::var("PROGRAMFILES").unwrap()) + .join("Vector35\\BinaryNinja\\"); + }) +} + +fn main() { + // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults + let install_path = env::var("BINARYNINJADIR") + .map(PathBuf::from) + .unwrap_or_else(|_| link_path()); + + #[cfg(target_os = "linux")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "macos")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "windows")] + { + println!("cargo:rustc-link-lib=binaryninjacore"); + println!("cargo:rustc-link-search={}", install_path.to_str().unwrap()); + } +} diff --git a/rust/examples/decompile/src/main.rs b/rust/examples/decompile/src/main.rs new file mode 100644 index 00000000..accb7697 --- /dev/null +++ b/rust/examples/decompile/src/main.rs @@ -0,0 +1,54 @@ +use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings}; +use binaryninja::function::Function; +use binaryninja::linearview::{LinearViewCursor, LinearViewObject}; + +use clap::Parser; + +/// Use binaryninja to decompile to C. +#[derive(Parser, Debug)] +#[clap(version, long_about = None)] +struct Args { + /// Path to the file to decompile + filename: String, +} + +fn decompile_to_c(view: &BinaryView, func: &Function) { + let mut settings = DisassemblySettings::new(); + settings.set_option(DisassemblyOption::ShowAddress, false); + settings.set_option(DisassemblyOption::WaitForIL, true); + + let linearview = LinearViewObject::language_representation(view, &settings); + + let mut cursor = LinearViewCursor::new(&linearview); + cursor.seek_to_address(func.highest_address()); + + let last = view.get_next_linear_disassembly_lines(&mut cursor.duplicate()); + let first = view.get_previous_linear_disassembly_lines(&mut cursor); + + let lines = first.into_iter().chain(last.into_iter()); + + for line in lines { + println!("{}", line.as_ref()); + } +} + +fn main() { + let args = Args::parse(); + + eprintln!("Loading plugins..."); + binaryninja::headless::init(); + + eprintln!("Loading binary..."); + let bv = binaryninja::open_view(args.filename).expect("Couldn't open file"); + + eprintln!("Filename: `{}`", bv.metadata().filename()); + eprintln!("File size: `{:#x}`", bv.len()); + eprintln!("Function count: {}", bv.functions().len()); + + for func in &bv.functions() { + decompile_to_c(bv.as_ref(), func.as_ref()); + } + + binaryninja::headless::shutdown(); +} diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs index 00069c15..6d52fa88 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binaryview.rs @@ -29,6 +29,8 @@ use crate::fileaccessor::FileAccessor; use crate::filemetadata::FileMetadata; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; +use crate::linearview::LinearDisassemblyLine; +use crate::linearview::LinearViewCursor; use crate::platform::Platform; use crate::section::{Section, SectionBuilder}; use crate::segment::{Segment, SegmentBuilder}; @@ -774,6 +776,54 @@ pub trait BinaryViewExt: BinaryViewBase { fn remove_user_data_tag(&self, addr: u64, tag: &Tag) { unsafe { BNRemoveUserDataTag(self.as_ref().handle, addr, tag.handle) } } + + /// Retrieves a list of the next disassembly lines. + /// + /// `get_next_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the + /// next disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called + /// repeatedly to get more lines of linear disassembly. + /// + /// # Arguments + /// * `pos` - Position to start retrieving linear disassembly lines from + fn get_next_linear_disassembly_lines( + &self, + pos: &mut LinearViewCursor, + ) -> Array<LinearDisassemblyLine> { + let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) }; + + while result.len() == 0 { + result = pos.lines(); + if !pos.next() { + return result; + } + } + + result + } + + /// Retrieves a list of the next disassembly lines. + /// + /// `get_previous_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the + /// previous disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called + /// repeatedly to get more lines of linear disassembly. + /// + /// # Arguments + /// * `pos` - Position to start retrieving linear disassembly lines from + fn get_previous_linear_disassembly_lines( + &self, + pos: &mut LinearViewCursor, + ) -> Array<LinearDisassemblyLine> { + let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) }; + while result.len() == 0 { + if !pos.previous() { + return result; + } + + result = pos.lines(); + } + + result + } } impl<T: BinaryViewBase> BinaryViewExt for T {} diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 8edf3c4f..6266597c 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -16,9 +16,11 @@ use binaryninjacore_sys::*; -use crate::string::BnString; +use crate::string::{BnStr, BnString}; use crate::{BN_FULL_CONFIDENCE, BN_INVALID_EXPR}; +use crate::rc::*; + use std::convert::From; use std::mem; use std::ptr; @@ -31,6 +33,9 @@ pub struct InstructionTextToken(pub(crate) BNInstructionTextToken); // TODO : Consider remodeling this after types::EnumerationMember impl InstructionTextToken { // TODO : New vs new_with_value ? + pub(crate) unsafe fn from_raw(raw: &BNInstructionTextToken) -> Self { + Self(raw.clone()) + } pub fn new(type_: InstructionTextTokenType, text: &str, value: u64) -> Self { let raw_name = BnString::new(text); @@ -59,6 +64,10 @@ impl InstructionTextToken { pub fn set_context(&mut self, context: InstructionTextTokenContext) { self.0.context = context; } + + pub fn text(&self) -> &BnStr { + unsafe { BnStr::from_raw(self.0.text) } + } } impl Default for InstructionTextToken { @@ -79,21 +88,73 @@ impl Default for InstructionTextToken { } } +impl CoreArrayProvider for InstructionTextToken { + type Raw = BNInstructionTextToken; + type Context = (); +} + +unsafe impl CoreOwnedArrayProvider for InstructionTextToken { + unsafe fn free(raw: *mut BNInstructionTextToken, count: usize, _context: &()) { + BNFreeInstructionText(raw, count); + } +} + +unsafe impl<'a> CoreArrayWrapper<'a> for InstructionTextToken { + type Wrapped = Guard<'a, InstructionTextToken>; + + unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { + Guard::new(InstructionTextToken::from_raw(raw), _context) + } +} + pub struct DisassemblyTextLine(pub(crate) BNDisassemblyTextLine); impl DisassemblyTextLine { // TODO : this should probably be removed, though it doesn't actually hurt anything pub fn debug_print(&self) { + println!("{}", self); + } + + pub fn addr(&self) -> u64 { + self.0.addr + } + + pub fn instr_idx(&self) -> usize { + self.0.instrIndex + } + + pub fn count(&self) -> usize { + self.0.count + } + + pub fn tag_count(&self) -> usize { + self.0.tagCount + } + + pub fn tokens(&self) -> ArrayGuard<InstructionTextToken> { + unsafe { ArrayGuard::new(self.0.tokens, self.0.count, ()) } + } +} + +impl std::fmt::Display for DisassemblyTextLine { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let tokens: Vec<InstructionTextToken> = unsafe { Vec::from_raw_parts(self.0.tokens as *mut _, self.0.count, self.0.count) }; for token in &tokens { let token_string = unsafe { BnString::from_raw(token.0.text) }; - print!("{}", token_string); + let result = write!(f, "{}", token_string); token_string.into_raw(); + + if result.is_err() { + mem::forget(tokens); + return result; + } } mem::forget(tokens); + + Ok(()) } } @@ -210,3 +271,56 @@ impl Drop for DisassemblyTextLine { } } } + +pub type DisassemblyOption = BNDisassemblyOption; + +#[derive(PartialEq, Eq, Hash)] +pub struct DisassemblySettings { + pub(crate) handle: *mut BNDisassemblySettings, +} + +impl DisassemblySettings { + pub fn new() -> Ref<Self> { + unsafe { + let handle = BNCreateDisassemblySettings(); + + debug_assert!(!handle.is_null()); + + Ref::new(Self { handle }) + } + } + + pub fn set_option(&self, option: DisassemblyOption, state: bool) { + unsafe { BNSetDisassemblySettingsOption(self.handle, option, state) } + } + + pub fn is_option_set(&self, option: DisassemblyOption) -> bool { + unsafe { BNIsDisassemblySettingsOptionSet(self.handle, option) } + } +} + +impl AsRef<DisassemblySettings> for DisassemblySettings { + fn as_ref(&self) -> &Self { + self + } +} + +impl ToOwned for DisassemblySettings { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for DisassemblySettings { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewDisassemblySettingsReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeDisassemblySettings(handle.handle); + } +} diff --git a/rust/src/function.rs b/rust/src/function.rs index 865a22db..4ce90457 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -155,6 +155,10 @@ impl Function { unsafe { BNGetFunctionStart(self.handle) } } + pub fn highest_address(&self) -> u64 { + unsafe { BNGetFunctionHighestAddress(self.handle) } + } + pub fn comment(&self) -> BnString { unsafe { BnString::from_raw(BNGetFunctionComment(self.handle)) } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1208bb8c..9c18d91d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -55,6 +55,7 @@ pub mod flowgraph; pub mod function; pub mod headless; pub mod interaction; +pub mod linearview; pub mod llil; pub mod platform; pub mod rc; diff --git a/rust/src/linearview.rs b/rust/src/linearview.rs new file mode 100644 index 00000000..a4221443 --- /dev/null +++ b/rust/src/linearview.rs @@ -0,0 +1,420 @@ +use binaryninjacore_sys::*; + +use crate::binaryview::BinaryView; +use crate::disassembly::{DisassemblySettings, DisassemblyTextLine}; +use crate::function::Function; + +use crate::rc::*; +use std::ops::Deref; + +use std::mem; + +pub struct LinearViewObject { + pub(crate) handle: *mut BNLinearViewObject, +} + +impl LinearViewObject { + pub(crate) unsafe fn from_raw(handle: *mut BNLinearViewObject) -> Ref<Self> { + debug_assert!(!handle.is_null()); + + Ref::new(Self { handle }) + } + + pub fn data_only(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewDataOnly(view.handle, settings.handle); + + Self::from_raw(handle) + } + } + + pub fn disassembly(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewDisassembly(view.handle, settings.handle); + + Self::from_raw(handle) + } + } + + pub fn lifted_il(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewLiftedIL(view.handle, settings.handle); + + Self::from_raw(handle) + } + } + + pub fn mlil(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewMediumLevelIL(view.handle, settings.handle); + + Self::from_raw(handle) + } + } + + pub fn mlil_ssa(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewMediumLevelILSSAForm( + view.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn hlil(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewHighLevelIL(view.handle, settings.handle); + + Self::from_raw(handle) + } + } + + pub fn hlil_ssa(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewHighLevelILSSAForm( + view.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn language_representation(view: &BinaryView, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewLanguageRepresentation( + view.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_disassembly( + function: &Function, + settings: &DisassemblySettings, + ) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionDisassembly( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_lifted_il( + function: &Function, + settings: &DisassemblySettings, + ) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionLiftedIL( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_mlil(function: &Function, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionMediumLevelIL( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_mlil_ssa( + function: &Function, + settings: &DisassemblySettings, + ) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionMediumLevelILSSAForm( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_hlil(function: &Function, settings: &DisassemblySettings) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionHighLevelIL( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_hlil_ssa( + function: &Function, + settings: &DisassemblySettings, + ) -> Ref<Self> { + unsafe { + let handle = binaryninjacore_sys::BNCreateLinearViewSingleFunctionHighLevelILSSAForm( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } + + pub fn single_function_language_representation( + function: &Function, + settings: &DisassemblySettings, + ) -> Ref<Self> { + unsafe { + let handle = + binaryninjacore_sys::BNCreateLinearViewSingleFunctionLanguageRepresentation( + function.handle, + settings.handle, + ); + + Self::from_raw(handle) + } + } +} + +unsafe impl RefCountable for LinearViewObject { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewLinearViewObjectReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeLinearViewObject(handle.handle); + } +} + +impl ToOwned for LinearViewObject { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl Send for LinearViewObject {} +unsafe impl Sync for LinearViewObject {} + +#[derive(Eq)] +pub struct LinearViewCursor { + pub(crate) handle: *mut binaryninjacore_sys::BNLinearViewCursor, +} + +impl LinearViewCursor { + pub(crate) unsafe fn from_raw(handle: *mut BNLinearViewCursor) -> Ref<Self> { + debug_assert!(!handle.is_null()); + + Ref::new(Self { handle }) + } + + pub fn new(root: &LinearViewObject) -> Ref<Self> { + unsafe { + let handle = BNCreateLinearViewCursor(root.handle); + Self::from_raw(handle) + } + } + + /// Gets the current [LinearViewObject] associated with this cursor. + pub fn current_object(&self) -> Ref<LinearViewObject> { + unsafe { + let handle = BNGetLinearViewCursorCurrentObject(self.handle); + LinearViewObject::from_raw(handle) + } + } + + // FIXME: can we implement clone without shadowing ToOwned? + pub fn duplicate(&self) -> Ref<Self> { + unsafe { + let handle = BNDuplicateLinearViewCursor(self.handle); + Self::from_raw(handle) + } + } + + pub fn before_begin(&self) -> bool { + unsafe { BNIsLinearViewCursorBeforeBegin(self.handle) } + } + + pub fn after_end(&self) -> bool { + unsafe { BNIsLinearViewCursorAfterEnd(self.handle) } + } + + pub fn valid(&self) -> bool { + !(self.before_begin() || self.after_end()) + } + + pub fn seek_to_start(&self) { + unsafe { BNSeekLinearViewCursorToBegin(self.handle) } + } + + pub fn seek_to_end(&self) { + unsafe { BNSeekLinearViewCursorToEnd(self.handle) } + } + + pub fn seek_to_address(&self, address: u64) { + unsafe { BNSeekLinearViewCursorToAddress(self.handle, address) } + } + + pub fn ordering_index(&self) -> std::ops::Range<u64> { + unsafe { + let range = BNGetLinearViewCursorOrderingIndex(self.handle); + range.start..range.end + } + } + + pub fn ordering_index_total(&self) -> u64 { + unsafe { BNGetLinearViewCursorOrderingIndexTotal(self.handle) } + } + + pub fn seek_to_ordering_index(&self, idx: u64) { + unsafe { BNSeekLinearViewCursorToAddress(self.handle, idx) } + } + + pub fn previous(&self) -> bool { + unsafe { BNLinearViewCursorPrevious(self.handle) } + } + + pub fn next(&self) -> bool { + unsafe { BNLinearViewCursorNext(self.handle) } + } + + pub fn lines(&self) -> Array<LinearDisassemblyLine> { + let mut count: usize = 0; + unsafe { + let handles = BNGetLinearViewCursorLines(self.handle, &mut count); + Array::new(handles, count, ()) + } + } +} + +impl PartialEq for LinearViewCursor { + fn eq(&self, other: &Self) -> bool { + unsafe { BNCompareLinearViewCursors(self.handle, other.handle) == 0 } + } +} + +impl PartialOrd for LinearViewCursor { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + match unsafe { BNCompareLinearViewCursors(self.handle, other.handle) } { + i if i < 0 => Some(std::cmp::Ordering::Less), + i if i > 0 => Some(std::cmp::Ordering::Greater), + _ => Some(std::cmp::Ordering::Equal), + } + } +} + +impl Ord for LinearViewCursor { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match unsafe { BNCompareLinearViewCursors(self.handle, other.handle) } { + i if i < 0 => std::cmp::Ordering::Less, + i if i > 0 => std::cmp::Ordering::Greater, + _ => std::cmp::Ordering::Equal, + } + } +} + +unsafe impl RefCountable for LinearViewCursor { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewLinearViewCursorReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeLinearViewCursor(handle.handle); + } +} + +impl ToOwned for LinearViewCursor { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl Send for LinearViewCursor {} +unsafe impl Sync for LinearViewCursor {} + +pub type LinearDisassemblyLineType = BNLinearDisassemblyLineType; + +pub struct LinearDisassemblyLine { + t: LinearDisassemblyLineType, + + // These will be cleaned up by BNFreeLinearDisassemblyLines, so we + // don't drop them in the relevant deconstructors. + function: mem::ManuallyDrop<Ref<Function>>, + contents: mem::ManuallyDrop<DisassemblyTextLine>, +} + +impl LinearDisassemblyLine { + pub(crate) unsafe fn from_raw(raw: &BNLinearDisassemblyLine) -> Self { + let linetype = raw.type_; + let function = mem::ManuallyDrop::new(Function::from_raw(raw.function)); + let contents = mem::ManuallyDrop::new(DisassemblyTextLine(raw.contents)); + Self { + t: linetype, + function, + contents, + } + } + + pub fn function(&self) -> &Function { + self.function.as_ref() + } + + pub fn line_type(&self) -> LinearDisassemblyLineType { + self.t + } +} + +impl Deref for LinearDisassemblyLine { + type Target = DisassemblyTextLine; + fn deref(&self) -> &Self::Target { + self.contents.deref() + } +} + +impl std::fmt::Display for LinearDisassemblyLine { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.deref()) + } +} + +impl CoreArrayProvider for LinearDisassemblyLine { + type Raw = BNLinearDisassemblyLine; + type Context = (); +} + +unsafe impl CoreOwnedArrayProvider for LinearDisassemblyLine { + unsafe fn free(raw: *mut BNLinearDisassemblyLine, count: usize, _context: &()) { + BNFreeLinearDisassemblyLines(raw, count); + } +} + +unsafe impl<'a> CoreArrayWrapper<'a> for LinearDisassemblyLine { + type Wrapped = Guard<'a, LinearDisassemblyLine>; + + unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { + Guard::new(LinearDisassemblyLine::from_raw(raw), _context) + } +} |
