summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorFabian Freyer <fabian.freyer@physik.tu-berlin.de>2022-01-28 01:36:26 +0100
committerKyleMiles <krm504@nyu.edu>2022-02-14 18:45:11 -0500
commit6cd49edb317112acc73f7caeb285f4134a472d72 (patch)
tree3fc1af20b46dcb33c1ba5490193a0226e112e839 /rust
parent181ad567199e5685578ecf7ad400257098c2e175 (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.toml10
-rw-r--r--rust/examples/decompile/build.rs68
-rw-r--r--rust/examples/decompile/src/main.rs54
-rw-r--r--rust/src/binaryview.rs50
-rw-r--r--rust/src/disassembly.rs118
-rw-r--r--rust/src/function.rs4
-rw-r--r--rust/src/lib.rs1
-rw-r--r--rust/src/linearview.rs420
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)
+ }
+}