Skip to content

Commit f371cb9

Browse files
committed
[Rust] More architecture module documentation and misc cleanup
1 parent 38eb602 commit f371cb9

File tree

1 file changed

+72
-26
lines changed

1 file changed

+72
-26
lines changed

rust/src/architecture.rs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
//! Architectures provide disassembly, lifting, and associated metadata about a CPU to inform analysis and decompilation.
15+
//! Architectures provide disassembly, lifting, and associated metadata about a CPU to inform
16+
//! analysis and decompilation.
17+
//!
18+
//! For more information see the [`Architecture`] trait and the [`CoreArchitecture`] structure for
19+
//! querying already registered architectures.
1620
17-
// container abstraction to avoid Vec<> (want CoreArchFlagList, CoreArchRegList)
1821
// RegisterInfo purge
1922
use binaryninjacore_sys::*;
2023
use std::fmt::{Debug, Formatter};
@@ -91,6 +94,16 @@ macro_rules! new_id_type {
9194
};
9295
}
9396

97+
/// The [`Architecture`] trait is the backbone of Binary Ninja's analysis capabilities. It tells the
98+
/// core how to interpret the machine code into LLIL, a generic intermediate representation for
99+
/// program analysis.
100+
///
101+
/// To add support for a new Instruction Set Architecture (ISA), you must implement this trait and
102+
/// register it. The core analysis loop relies on your implementation for three critical stages:
103+
///
104+
/// 1. **Disassembly ([`Architecture::instruction_text`])**: Machine code into human-readable text (e.g., `55` -> `push rbp`).
105+
/// 2. **Control Flow Analysis ([`Architecture::instruction_info`])**: Identifying where execution goes next (e.g., "This is a `call` instruction, it targets address `0x401000`").
106+
/// 3. **Lifting ([`Architecture::instruction_llil`])**: Translating machine code into **Low Level Intermediate Language (LLIL)**, which enables decompilation and automated analysis.
94107
pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
95108
type Handle: Borrow<Self> + Clone;
96109

@@ -316,6 +329,12 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
316329
Vec::new()
317330
}
318331

332+
fn stack_pointer_reg(&self) -> Option<Self::Register>;
333+
334+
fn link_reg(&self) -> Option<Self::Register> {
335+
None
336+
}
337+
319338
/// List of concrete register stacks for this architecture.
320339
///
321340
/// You **must** override the following functions as well:
@@ -450,12 +469,6 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
450469
None
451470
}
452471

453-
fn stack_pointer_reg(&self) -> Option<Self::Register>;
454-
455-
fn link_reg(&self) -> Option<Self::Register> {
456-
None
457-
}
458-
459472
/// List of concrete intrinsics for this architecture.
460473
///
461474
/// You **must** override the following functions as well:
@@ -478,30 +491,51 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
478491
None
479492
}
480493

494+
/// Let the UI display this patch option.
495+
///
496+
/// If set to true, you must override [`Architecture::assemble`].
481497
fn can_assemble(&self) -> bool {
482498
false
483499
}
484500

501+
/// Assemble the code at the specified address and return the machine code in bytes.
502+
///
503+
/// If overridden, you must set [`Architecture::can_assemble`] to `true`.
485504
fn assemble(&self, _code: &str, _addr: u64) -> Result<Vec<u8>, String> {
486505
Err("Assemble unsupported".into())
487506
}
488507

489-
fn is_never_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
490-
false
508+
/// Let the UI display this patch option.
509+
///
510+
/// If set to true, you must override [`Architecture::invert_branch`].
511+
fn is_never_branch_patch_available(&self, data: &[u8], addr: u64) -> bool {
512+
self.is_invert_branch_patch_available(data, addr)
491513
}
492514

515+
/// Let the UI display this patch option.
516+
///
517+
/// If set to true, you must override [`Architecture::always_branch`].
493518
fn is_always_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
494519
false
495520
}
496521

522+
/// Let the UI display this patch option.
523+
///
524+
/// If set to true, you must override [`Architecture::invert_branch`].
497525
fn is_invert_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
498526
false
499527
}
500528

501-
fn is_skip_and_return_zero_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
502-
false
529+
/// Let the UI display this patch option.
530+
///
531+
/// If set to true, you must override [`Architecture::skip_and_return_value`].
532+
fn is_skip_and_return_zero_patch_available(&self, data: &[u8], addr: u64) -> bool {
533+
self.is_skip_and_return_value_patch_available(data, addr)
503534
}
504535

536+
/// Let the UI display this patch option.
537+
///
538+
/// If set to true, you must override [`Architecture::skip_and_return_value`].
505539
fn is_skip_and_return_value_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
506540
false
507541
}
@@ -510,14 +544,23 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
510544
false
511545
}
512546

547+
/// Patch the instruction to always branch.
548+
///
549+
/// If overridden, you must also override [`Architecture::is_always_branch_patch_available`].
513550
fn always_branch(&self, _data: &mut [u8], _addr: u64) -> bool {
514551
false
515552
}
516553

554+
/// Patch the instruction to invert the branch condition.
555+
///
556+
/// If overridden, you must also override [`Architecture::is_invert_branch_patch_available`].
517557
fn invert_branch(&self, _data: &mut [u8], _addr: u64) -> bool {
518558
false
519559
}
520560

561+
/// Patch the instruction to skip and return value.
562+
///
563+
/// If overridden, you must also override [`Architecture::is_skip_and_return_value_patch_available`].
521564
fn skip_and_return_value(&self, _data: &mut [u8], _addr: u64, _value: u64) -> bool {
522565
false
523566
}
@@ -835,6 +878,20 @@ impl Architecture for CoreArchitecture {
835878
}
836879
}
837880

881+
fn stack_pointer_reg(&self) -> Option<CoreRegister> {
882+
match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } {
883+
0xffff_ffff => None,
884+
reg => Some(CoreRegister::new(*self, reg.into())?),
885+
}
886+
}
887+
888+
fn link_reg(&self) -> Option<CoreRegister> {
889+
match unsafe { BNGetArchitectureLinkRegister(self.handle) } {
890+
0xffff_ffff => None,
891+
reg => Some(CoreRegister::new(*self, reg.into())?),
892+
}
893+
}
894+
838895
fn register_stacks(&self) -> Vec<CoreRegisterStack> {
839896
unsafe {
840897
let mut count: usize = 0;
@@ -940,20 +997,6 @@ impl Architecture for CoreArchitecture {
940997
CoreFlagGroup::new(*self, id)
941998
}
942999

943-
fn stack_pointer_reg(&self) -> Option<CoreRegister> {
944-
match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } {
945-
0xffff_ffff => None,
946-
reg => Some(CoreRegister::new(*self, reg.into())?),
947-
}
948-
}
949-
950-
fn link_reg(&self) -> Option<CoreRegister> {
951-
match unsafe { BNGetArchitectureLinkRegister(self.handle) } {
952-
0xffff_ffff => None,
953-
reg => Some(CoreRegister::new(*self, reg.into())?),
954-
}
955-
}
956-
9571000
fn intrinsics(&self) -> Vec<CoreIntrinsic> {
9581001
unsafe {
9591002
let mut count: usize = 0;
@@ -1221,6 +1264,9 @@ pub trait ArchitectureExt: Architecture {
12211264

12221265
impl<T: Architecture> ArchitectureExt for T {}
12231266

1267+
/// Registers a new architecture with the given name.
1268+
///
1269+
/// NOTE: This function should only be called within `CorePluginInit`.
12241270
pub fn register_architecture<A, F>(name: &str, func: F) -> &'static A
12251271
where
12261272
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync + Sized,

0 commit comments

Comments
 (0)