Skip to content

Commit 0152aee

Browse files
committed
[Rust] Refactor binary view modules
- Improves discoverability - Added a few missing API's and a few misc fixes - Fixup `show_*_report` into `interaction` module where they belong
1 parent 7945efd commit 0152aee

File tree

21 files changed

+643
-547
lines changed

21 files changed

+643
-547
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ rust/examples/*/target/
8989
rust/examples/dwarf/*/target/
9090
# Allow the test binaries
9191
!/rust/fixtures/bin/**
92+
# Allow the types directory in rust, its actually code
93+
!/rust/src/types
9294

9395
# Debugger docs
9496
docs/img/debugger

arch/msp430/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ extern crate msp430_asm;
55
use binaryninja::{
66
add_optional_plugin_dependency,
77
architecture::ArchitectureExt,
8-
calling_convention,
9-
custom_binary_view::{BinaryViewType, BinaryViewTypeExt},
10-
Endianness,
8+
binary_view::types::{BinaryViewTypeExt, CoreBinaryViewType},
9+
calling_convention, Endianness,
1110
};
1211
use log::LevelFilter;
1312

@@ -50,7 +49,7 @@ pub extern "C" fn CorePluginInit() -> bool {
5049

5150
arch.set_default_calling_convention(&default);
5251

53-
if let Ok(bvt) = BinaryViewType::by_name("ELF") {
52+
if let Some(bvt) = CoreBinaryViewType::by_name("ELF") {
5453
bvt.register_arch(105, Endianness::LittleEndian, arch);
5554
}
5655

arch/riscv/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use binaryninja::{
1515
},
1616
binary_view::{BinaryView, BinaryViewExt},
1717
calling_convention::{register_calling_convention, CallingConvention, ConventionBuilder},
18-
custom_binary_view::{BinaryViewType, BinaryViewTypeExt},
1918
disassembly::{InstructionTextToken, InstructionTextTokenKind},
2019
function::Function,
2120
function_recognizer::FunctionRecognizer,
@@ -35,6 +34,7 @@ use std::hash::Hash;
3534
use std::marker::PhantomData;
3635

3736
use binaryninja::architecture::{BranchKind, IntrinsicId, RegisterId};
37+
use binaryninja::binary_view::types::{BinaryViewTypeExt, CoreBinaryViewType};
3838
use binaryninja::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
3939
use binaryninja::logger::Logger;
4040
use binaryninja::low_level_il::expression::{LowLevelILExpressionKind, ValueExpr};
@@ -3070,7 +3070,7 @@ pub extern "C" fn CorePluginInit() -> bool {
30703070
);
30713071
arch64.set_default_calling_convention(&cc64);
30723072

3073-
if let Ok(bvt) = BinaryViewType::by_name("ELF") {
3073+
if let Some(bvt) = CoreBinaryViewType::by_name("ELF") {
30743074
bvt.register_arch(
30753075
(1 << 16) | 243,
30763076
binaryninja::Endianness::LittleEndian,

plugins/dwarf/dwarf_export/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ fn export_functions(
409409
dwarf: &mut DwarfUnit,
410410
defined_types: &mut Vec<(Ref<Type>, UnitEntryId)>,
411411
) {
412-
let entry_point = bv.entry_point_function();
412+
let entry_point = bv.analysis_entry_point_function();
413413

414414
for function in &bv.functions() {
415415
// Create function DIE as child of the compilation unit DIE

plugins/dwarf/shared/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
144144
let ch_type_vec = view.read_vec(section.start(), 4);
145145
let ch_type = endian.read_u32(&ch_type_vec);
146146

147-
if let Ok(buffer) = view.read_buffer(offset, len) {
147+
if let Some(buffer) = view.read_buffer(offset, len) {
148148
match ch_type {
149149
1 => {
150150
return Ok(EndianRcSlice::new(

plugins/warp/src/plugin/create.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use binaryninja::background_task::BackgroundTask;
88
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
99
use binaryninja::command::Command;
1010
use binaryninja::interaction::form::{Form, FormInputField};
11-
use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon};
11+
use binaryninja::interaction::{show_plaintext_report, MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon};
1212
use binaryninja::rc::Ref;
1313
use std::path::PathBuf;
1414
use std::thread;
@@ -204,7 +204,7 @@ impl CreateFromCurrentView {
204204
view.show_markdown_report("Generated WARP File", report_string.as_str(), "");
205205
}
206206
ReportKindField::Json => {
207-
view.show_plaintext_report("Generated WARP File", report_string.as_str());
207+
show_plaintext_report("Generated WARP File", report_string.as_str());
208208
}
209209
}
210210
}

rust/src/binary_view.rs

Lines changed: 80 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ use crate::Endianness;
5858
use std::collections::HashMap;
5959
use std::ffi::{c_char, c_void};
6060
use std::ops::Range;
61-
use std::path::Path;
61+
use std::path::{Path, PathBuf};
6262
use std::ptr::NonNull;
6363
use std::{result, slice};
6464
// TODO : general reorg of modules related to bv
6565

66+
pub mod custom;
6667
pub mod memory_map;
6768
pub mod reader;
6869
pub mod search;
70+
pub mod types;
6971
pub mod writer;
7072

7173
use crate::binary_view::search::SearchQuery;
@@ -535,11 +537,9 @@ pub trait BinaryViewExt: BinaryViewBase {
535537
}
536538
}
537539

538-
fn analysis_info(&self) -> Result<AnalysisInfo> {
540+
fn analysis_info(&self) -> AnalysisInfo {
539541
let info_ref = unsafe { BNGetAnalysisInfo(self.as_ref().handle) };
540-
if info_ref.is_null() {
541-
return Err(());
542-
}
542+
assert!(!info_ref.is_null());
543543
let info = unsafe { *info_ref };
544544
let active_infos = unsafe { slice::from_raw_parts(info.activeInfo, info.count) };
545545

@@ -561,7 +561,7 @@ pub trait BinaryViewExt: BinaryViewBase {
561561
};
562562

563563
unsafe { BNFreeAnalysisInfo(info_ref) };
564-
Ok(result)
564+
result
565565
}
566566

567567
fn analysis_progress(&self) -> AnalysisProgress {
@@ -1182,17 +1182,22 @@ pub trait BinaryViewExt: BinaryViewBase {
11821182
address: u64,
11831183
platform: &Platform,
11841184
) -> Option<Ref<Function>> {
1185-
self.add_auto_function_ext(address, platform, None)
1185+
self.add_auto_function_ext(address, platform, None, true)
11861186
}
11871187

11881188
/// Add an auto function at the given `address` with the `platform` and function type.
11891189
///
1190+
/// If you set `auto_discovered` to `false`, the function will not be considered for unused function
1191+
/// deletion, nor will it allow the function to be "blacklisted", that is, the function will always
1192+
/// be created.
1193+
///
11901194
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
11911195
fn add_auto_function_ext(
11921196
&self,
11931197
address: u64,
11941198
platform: &Platform,
11951199
func_type: Option<&Type>,
1200+
auto_discovered: bool,
11961201
) -> Option<Ref<Function>> {
11971202
unsafe {
11981203
let func_type = match func_type {
@@ -1204,7 +1209,7 @@ pub trait BinaryViewExt: BinaryViewBase {
12041209
self.as_ref().handle,
12051210
platform.handle,
12061211
address,
1207-
true,
1212+
auto_discovered,
12081213
func_type,
12091214
);
12101215

@@ -1285,7 +1290,7 @@ pub trait BinaryViewExt: BinaryViewBase {
12851290
}
12861291
}
12871292

1288-
fn entry_point_function(&self) -> Option<Ref<Function>> {
1293+
fn analysis_entry_point_function(&self) -> Option<Ref<Function>> {
12891294
unsafe {
12901295
let raw_func_ptr = BNGetAnalysisEntryPoint(self.as_ref().handle);
12911296
match raw_func_ptr.is_null() {
@@ -1295,6 +1300,11 @@ pub trait BinaryViewExt: BinaryViewBase {
12951300
}
12961301
}
12971302

1303+
/// This list contains the analysis entry function, and functions like init_array, fini_array,
1304+
/// and TLS callbacks etc.
1305+
///
1306+
/// We see `entry_functions` as good starting points for analysis, these functions normally don't
1307+
/// have internal references. Exported functions in a dll/so file are not included.
12981308
fn entry_point_functions(&self) -> Array<Function> {
12991309
unsafe {
13001310
let mut count = 0;
@@ -1381,7 +1391,7 @@ pub trait BinaryViewExt: BinaryViewBase {
13811391

13821392
/// Checks if target analysis should be skipped.
13831393
///
1384-
/// NOTE: This function should **only** be used by within an [`Architecture`].
1394+
/// NOTE: This function should **only** be used by within [`Architecture::analyze_basic_blocks`].
13851395
fn should_skip_target_analysis<L: Into<Location>>(
13861396
&self,
13871397
source: L,
@@ -1403,12 +1413,12 @@ pub trait BinaryViewExt: BinaryViewBase {
14031413
}
14041414
}
14051415

1406-
fn read_buffer(&self, offset: u64, len: usize) -> Result<DataBuffer> {
1416+
fn read_buffer(&self, offset: u64, len: usize) -> Option<DataBuffer> {
14071417
let read_buffer = unsafe { BNReadViewBuffer(self.as_ref().handle, offset, len) };
14081418
if read_buffer.is_null() {
1409-
Err(())
1419+
None
14101420
} else {
1411-
Ok(DataBuffer::from_raw(read_buffer))
1421+
Some(DataBuffer::from_raw(read_buffer))
14121422
}
14131423
}
14141424

@@ -1424,51 +1434,19 @@ pub trait BinaryViewExt: BinaryViewBase {
14241434
unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) }
14251435
}
14261436

1427-
fn show_plaintext_report(&self, title: &str, plaintext: &str) {
1428-
let title = title.to_cstr();
1429-
let plaintext = plaintext.to_cstr();
1430-
unsafe {
1431-
BNShowPlainTextReport(
1432-
self.as_ref().handle,
1433-
title.as_ref().as_ptr() as *mut _,
1434-
plaintext.as_ref().as_ptr() as *mut _,
1435-
)
1436-
}
1437-
}
1438-
1437+
/// Wrapper for [`crate::interaction::show_markdown_report`].
14391438
fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) {
1440-
let title = title.to_cstr();
1441-
let contents = contents.to_cstr();
1442-
let plaintext = plaintext.to_cstr();
1443-
unsafe {
1444-
BNShowMarkdownReport(
1445-
self.as_ref().handle,
1446-
title.as_ref().as_ptr() as *mut _,
1447-
contents.as_ref().as_ptr() as *mut _,
1448-
plaintext.as_ref().as_ptr() as *mut _,
1449-
)
1450-
}
1439+
crate::interaction::show_markdown_report(Some(self.as_ref()), title, contents, plaintext);
14511440
}
14521441

1442+
/// Wrapper for [`crate::interaction::show_html_report`].
14531443
fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) {
1454-
let title = title.to_cstr();
1455-
let contents = contents.to_cstr();
1456-
let plaintext = plaintext.to_cstr();
1457-
unsafe {
1458-
BNShowHTMLReport(
1459-
self.as_ref().handle,
1460-
title.as_ref().as_ptr() as *mut _,
1461-
contents.as_ref().as_ptr() as *mut _,
1462-
plaintext.as_ref().as_ptr() as *mut _,
1463-
)
1464-
}
1444+
crate::interaction::show_html_report(Some(self.as_ref()), title, contents, plaintext);
14651445
}
14661446

1447+
/// Wrapper for [`crate::interaction::show_graph_report`].
14671448
fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) {
1468-
let raw_name = raw_name.to_cstr();
1469-
unsafe {
1470-
BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle);
1471-
}
1449+
crate::interaction::show_graph_report(Some(self.as_ref()), raw_name, graph);
14721450
}
14731451

14741452
fn load_settings(&self, view_type_name: &str) -> Result<Ref<Settings>> {
@@ -1608,6 +1586,7 @@ pub trait BinaryViewExt: BinaryViewBase {
16081586
result
16091587
}
16101588

1589+
// TODO: Why is this impl'd here?
16111590
/// Retrieves a list of the previous disassembly lines.
16121591
///
16131592
/// `get_previous_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
@@ -1643,6 +1622,9 @@ pub trait BinaryViewExt: BinaryViewBase {
16431622
}
16441623
}
16451624

1625+
/// Retrieve the metadata as the type `T`.
1626+
///
1627+
/// Fails if the metadata does not exist, or if the metadata failed to coerce to type `T`.
16461628
fn get_metadata<T>(&self, key: &str) -> Option<Result<T>>
16471629
where
16481630
T: for<'a> TryFrom<&'a Metadata>,
@@ -1672,7 +1654,7 @@ pub trait BinaryViewExt: BinaryViewBase {
16721654
unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) };
16731655
}
16741656

1675-
/// Retrieves a list of [CodeReference]s pointing to a given address.
1657+
/// Retrieves a list of [`CodeReference`]s pointing to a given address.
16761658
fn code_refs_to_addr(&self, addr: u64) -> Array<CodeReference> {
16771659
unsafe {
16781660
let mut count = 0;
@@ -1681,7 +1663,7 @@ pub trait BinaryViewExt: BinaryViewBase {
16811663
}
16821664
}
16831665

1684-
/// Retrieves a list of [CodeReference]s pointing into a given [Range].
1666+
/// Retrieves a list of [`CodeReference`]s pointing into a given [`Range`].
16851667
fn code_refs_into_range(&self, range: Range<u64>) -> Array<CodeReference> {
16861668
unsafe {
16871669
let mut count = 0;
@@ -2171,16 +2153,20 @@ pub trait BinaryViewExt: BinaryViewBase {
21712153
Array::new(strings, count, ())
21722154
}
21732155
}
2174-
fn string_at(&self, addr: u64) -> Option<BNStringReference> {
2156+
2157+
/// Retrieve the string that falls on a given virtual address.
2158+
///
2159+
/// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength` and other settings.
2160+
fn string_at(&self, addr: u64) -> Option<StringReference> {
21752161
let mut str_ref = BNStringReference::default();
21762162
let success = unsafe { BNGetStringAtAddress(self.as_ref().handle, addr, &mut str_ref) };
2177-
21782163
if success {
2179-
Some(str_ref)
2164+
Some(str_ref.into())
21802165
} else {
21812166
None
21822167
}
21832168
}
2169+
21842170
/// Retrieve all known strings within the provided `range`.
21852171
///
21862172
/// NOTE: This returns a list of [`StringReference`] as strings may not be representable
@@ -2199,23 +2185,43 @@ pub trait BinaryViewExt: BinaryViewBase {
21992185
}
22002186
}
22012187

2202-
//
2203-
// fn type_archives(&self) -> Array<TypeArchive> {
2204-
// let mut ids: *mut *mut c_char = std::ptr::null_mut();
2205-
// let mut paths: *mut *mut c_char = std::ptr::null_mut();
2206-
// let count = unsafe { BNBinaryViewGetTypeArchives(self.as_ref().handle, &mut ids, &mut paths) };
2207-
// let path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
2208-
// let ids_list = unsafe { std::slice::from_raw_parts(ids, count).to_vec() };
2209-
// let archives = ids_list.iter().filter_map(|id| {
2210-
// let archive_raw = unsafe { BNBinaryViewGetTypeArchive(self.as_ref().handle, *id) };
2211-
// match archive_raw.is_null() {
2212-
// true => None,
2213-
// false => Some(archive_raw)
2214-
// }
2215-
// }).collect();
2216-
// unsafe { BNFreeStringList(ids, count) };
2217-
// Array::new(archives)
2218-
// }
2188+
/// Retrieve the attached type archives as a tuple of id and path.
2189+
///
2190+
/// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryViewExt::type_archive_by_id`].
2191+
fn attached_type_archives(&self) -> Vec<(String, String)> {
2192+
let mut ids: *mut *mut c_char = std::ptr::null_mut();
2193+
let mut paths: *mut *mut c_char = std::ptr::null_mut();
2194+
let count =
2195+
unsafe { BNBinaryViewGetTypeArchives(self.as_ref().handle, &mut ids, &mut paths) };
2196+
let path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
2197+
let id_list = unsafe { Array::<BnString>::new(ids, count, ()) };
2198+
path_list
2199+
.iter()
2200+
.zip(id_list.iter())
2201+
.map(|(path, id)| (id.to_string(), path.to_string()))
2202+
.collect()
2203+
}
2204+
2205+
/// Look up a connected [`TypeArchive`] by its `id`.
2206+
///
2207+
/// NOTE: A [`TypeArchive`] can be attached but not connected, returning `None`.
2208+
fn type_archive_by_id(&self, id: &str) -> Option<Ref<TypeArchive>> {
2209+
let id = id.to_cstr();
2210+
let result = unsafe { BNBinaryViewGetTypeArchive(self.as_ref().handle, id.as_ptr()) };
2211+
let result_ptr = NonNull::new(result)?;
2212+
Some(unsafe { TypeArchive::ref_from_raw(result_ptr) })
2213+
}
2214+
2215+
/// Look up the path for an attached (but not necessarily connected) [`TypeArchive`] by its `id`.
2216+
fn type_archive_path_by_id(&self, id: &str) -> Option<PathBuf> {
2217+
let id = id.to_cstr();
2218+
let result = unsafe { BNBinaryViewGetTypeArchivePath(self.as_ref().handle, id.as_ptr()) };
2219+
if result.is_null() {
2220+
return None;
2221+
}
2222+
let path_str = unsafe { BnString::into_string(result) };
2223+
Some(PathBuf::from(path_str))
2224+
}
22192225
}
22202226

22212227
impl<T: BinaryViewBase> BinaryViewExt for T {}
@@ -2428,6 +2434,7 @@ impl std::fmt::Debug for BinaryView {
24282434
.field("address_size", &self.address_size())
24292435
.field("sections", &self.sections().to_vec())
24302436
.field("segments", &self.segments().to_vec())
2437+
.field("attached_type_archives", &self.attached_type_archives())
24312438
.finish()
24322439
}
24332440
}

0 commit comments

Comments
 (0)