Skip to content

Commit 16abca3

Browse files
committed
impl rust DisassemblyTextRenderer
1 parent 4ef7a93 commit 16abca3

File tree

2 files changed

+313
-4
lines changed

2 files changed

+313
-4
lines changed

rust/src/disassembly.rs

+303-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@
1616

1717
use binaryninjacore_sys::*;
1818

19-
use crate::string::BnString;
20-
use crate::{BN_FULL_CONFIDENCE, BN_INVALID_EXPR};
19+
use crate::architecture::{Architecture, CoreArchitecture};
20+
use crate::basicblock::BasicBlock;
21+
use crate::function::{Function, NativeBlock};
22+
use crate::llil::{FunctionForm, FunctionMutability};
23+
use crate::string::{BnStrCompatible, BnString};
24+
use crate::types::StackVariableReference;
25+
use crate::{hlil, llil, mlil, BN_FULL_CONFIDENCE, BN_INVALID_EXPR};
2126

2227
use crate::rc::*;
2328

29+
use core::ffi;
2430
use std::convert::From;
2531
use std::ffi::CStr;
2632
use std::mem;
@@ -512,3 +518,298 @@ unsafe impl RefCountable for DisassemblySettings {
512518
BNFreeDisassemblySettings(handle.handle);
513519
}
514520
}
521+
522+
#[repr(transparent)]
523+
pub struct DisassemblyTextRenderer {
524+
handle: ptr::NonNull<BNDisassemblyTextRenderer>,
525+
}
526+
527+
impl DisassemblyTextRenderer {
528+
pub unsafe fn from_raw(handle: ptr::NonNull<BNDisassemblyTextRenderer>) -> Self {
529+
Self { handle }
530+
}
531+
532+
#[allow(clippy::mut_from_ref)]
533+
pub unsafe fn as_raw(&self) -> &mut BNDisassemblyTextRenderer {
534+
unsafe { &mut *self.handle.as_ptr() }
535+
}
536+
537+
pub fn from_function(func: &Function, settings: Option<&DisassemblySettings>) -> Self {
538+
let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
539+
let result = unsafe { BNCreateDisassemblyTextRenderer(func.handle, settings_ptr) };
540+
unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) }
541+
}
542+
543+
pub fn from_llil_function<A: Architecture, M: FunctionMutability, F: FunctionForm>(
544+
func: &llil::Function<A, M, F>,
545+
settings: Option<&DisassemblySettings>,
546+
) -> Self {
547+
let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
548+
let result =
549+
unsafe { BNCreateLowLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
550+
unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) }
551+
}
552+
553+
pub fn from_mlil_function(
554+
func: &mlil::MediumLevelILFunction,
555+
settings: Option<&DisassemblySettings>,
556+
) -> Self {
557+
let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
558+
let result =
559+
unsafe { BNCreateMediumLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
560+
unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) }
561+
}
562+
563+
pub fn from_hlil_function(
564+
func: &hlil::HighLevelILFunction,
565+
settings: Option<&DisassemblySettings>,
566+
) -> Self {
567+
let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
568+
let result =
569+
unsafe { BNCreateHighLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
570+
unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) }
571+
}
572+
573+
pub fn function(&self) -> Ref<Function> {
574+
let result = unsafe { BNGetDisassemblyTextRendererFunction(self.as_raw()) };
575+
assert!(!result.is_null());
576+
unsafe { Function::from_raw(result) }
577+
}
578+
579+
pub fn llil_function<M: FunctionMutability, F: FunctionForm>(
580+
&self,
581+
) -> Ref<llil::Function<CoreArchitecture, M, F>> {
582+
let arch = self.arch();
583+
let result = unsafe { BNGetDisassemblyTextRendererLowLevelILFunction(self.as_raw()) };
584+
assert!(!result.is_null());
585+
unsafe { llil::Function::from_raw(arch.handle(), result) }
586+
}
587+
588+
pub fn mlil_function(&self) -> Ref<mlil::MediumLevelILFunction> {
589+
let result = unsafe { BNGetDisassemblyTextRendererMediumLevelILFunction(self.as_raw()) };
590+
assert!(!result.is_null());
591+
unsafe { mlil::MediumLevelILFunction::ref_from_raw(result) }
592+
}
593+
594+
pub fn hlil_function(&self) -> Ref<hlil::HighLevelILFunction> {
595+
let result = unsafe { BNGetDisassemblyTextRendererHighLevelILFunction(self.as_raw()) };
596+
assert!(!result.is_null());
597+
unsafe { hlil::HighLevelILFunction::ref_from_raw(result, true) }
598+
}
599+
600+
pub fn basic_block(&self) -> Option<Ref<BasicBlock<NativeBlock>>> {
601+
let result = unsafe { BNGetDisassemblyTextRendererBasicBlock(self.as_raw()) };
602+
if result.is_null() {
603+
return None;
604+
}
605+
Some(unsafe { Ref::new(BasicBlock::from_raw(result, NativeBlock::new())) })
606+
}
607+
608+
pub fn set_basic_block(&self, value: Option<&BasicBlock<NativeBlock>>) {
609+
let block_ptr = value.map(|b| b.handle).unwrap_or(ptr::null_mut());
610+
unsafe { BNSetDisassemblyTextRendererBasicBlock(self.as_raw(), block_ptr) }
611+
}
612+
613+
pub fn arch(&self) -> CoreArchitecture {
614+
let result = unsafe { BNGetDisassemblyTextRendererArchitecture(self.as_raw()) };
615+
assert!(!result.is_null());
616+
CoreArchitecture(result)
617+
}
618+
619+
pub fn set_arch(&self, value: CoreArchitecture) {
620+
unsafe { BNSetDisassemblyTextRendererArchitecture(self.as_raw(), value.0) }
621+
}
622+
623+
pub fn settings(&self) -> DisassemblySettings {
624+
DisassemblySettings {
625+
handle: unsafe { BNGetDisassemblyTextRendererSettings(self.as_raw()) },
626+
}
627+
}
628+
629+
pub fn set_settings(&self, settings: Option<&DisassemblySettings>) {
630+
let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
631+
unsafe { BNSetDisassemblyTextRendererSettings(self.as_raw(), settings_ptr) }
632+
}
633+
634+
pub fn is_il(&self) -> bool {
635+
unsafe { BNIsILDisassemblyTextRenderer(self.as_raw()) }
636+
}
637+
638+
pub fn has_data_flow(&self) -> bool {
639+
unsafe { BNDisassemblyTextRendererHasDataFlow(self.as_raw()) }
640+
}
641+
642+
pub fn instruction_annotations(&self, addr: u64) -> Array<InstructionTextToken> {
643+
let mut count = 0;
644+
let result = unsafe {
645+
BNGetDisassemblyTextRendererInstructionAnnotations(self.as_raw(), addr, &mut count)
646+
};
647+
assert!(!result.is_null());
648+
unsafe { Array::new(result, count, ()) }
649+
}
650+
651+
pub fn instruction_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> {
652+
let mut count = 0;
653+
let mut length = 0;
654+
let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut();
655+
let result = unsafe {
656+
BNGetDisassemblyTextRendererInstructionText(
657+
self.as_raw(),
658+
addr,
659+
&mut length,
660+
&mut lines,
661+
&mut count,
662+
)
663+
};
664+
result.then(|| (unsafe { Array::new(lines, count, ()) }, length))
665+
}
666+
667+
pub fn disassembly_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> {
668+
let mut count = 0;
669+
let mut length = 0;
670+
let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut();
671+
let result = unsafe {
672+
BNGetDisassemblyTextRendererLines(
673+
self.as_raw(),
674+
addr,
675+
&mut length,
676+
&mut lines,
677+
&mut count,
678+
)
679+
};
680+
result.then(|| (unsafe { Array::new(lines, count, ()) }, length))
681+
}
682+
683+
// TODO post_process_lines BNPostProcessDisassemblyTextRendererLines
684+
685+
pub fn is_integer_token(token_type: InstructionTextTokenType) -> bool {
686+
unsafe { BNIsIntegerToken(token_type) }
687+
}
688+
689+
pub fn reset_deduplicated_comments(&self) {
690+
unsafe { BNResetDisassemblyTextRendererDeduplicatedComments(self.as_raw()) }
691+
}
692+
693+
pub fn symbol_tokens(
694+
&self,
695+
addr: u64,
696+
size: usize,
697+
operand: Option<usize>,
698+
) -> Option<Array<InstructionTextToken>> {
699+
let operand = operand.unwrap_or(0xffffffff);
700+
let mut count = 0;
701+
let mut tokens: *mut BNInstructionTextToken = ptr::null_mut();
702+
let result = unsafe {
703+
BNGetDisassemblyTextRendererSymbolTokens(
704+
self.as_raw(),
705+
addr,
706+
size,
707+
operand,
708+
&mut tokens,
709+
&mut count,
710+
)
711+
};
712+
result.then(|| unsafe { Array::new(tokens, count, ()) })
713+
}
714+
715+
pub fn stack_var_reference_tokens(
716+
&self,
717+
ref_: &StackVariableReference,
718+
) -> Array<InstructionTextToken> {
719+
let name = ref_.name().into_bytes_with_nul();
720+
let mut stack_ref = BNStackVariableReference {
721+
sourceOperand: ref_.source_operand().unwrap_or(0xffffffff),
722+
typeConfidence: ref_.variable_type().confidence,
723+
type_: ref_.variable_type().contents.handle,
724+
name: name.as_ptr() as *mut ffi::c_char,
725+
varIdentifier: ref_.variable().identifier(),
726+
referencedOffset: ref_.offset(),
727+
size: ref_.size(),
728+
};
729+
let mut count = 0;
730+
let tokens = unsafe {
731+
BNGetDisassemblyTextRendererStackVariableReferenceTokens(
732+
self.as_raw(),
733+
&mut stack_ref,
734+
&mut count,
735+
)
736+
};
737+
assert!(!tokens.is_null());
738+
unsafe { Array::new(tokens, count, ()) }
739+
}
740+
741+
pub fn integer_token(
742+
&self,
743+
int_token: &InstructionTextToken,
744+
addr: u64,
745+
arch: Option<CoreArchitecture>,
746+
) -> Array<InstructionTextToken> {
747+
let arch = arch.map(|a| a.0).unwrap_or(ptr::null_mut());
748+
let mut count = 0;
749+
let tokens = unsafe {
750+
BNGetDisassemblyTextRendererIntegerTokens(
751+
self.as_raw(),
752+
&int_token.0 as *const BNInstructionTextToken as *mut _,
753+
arch,
754+
addr,
755+
&mut count,
756+
)
757+
};
758+
assert!(!tokens.is_null());
759+
unsafe { Array::new(tokens, count, ()) }
760+
}
761+
762+
pub fn wrap_comment<S1: BnStrCompatible, S2: BnStrCompatible, S3: BnStrCompatible>(
763+
&self,
764+
cur_line: &DisassemblyTextLine,
765+
comment: S1,
766+
has_auto_annotations: bool,
767+
leading_spaces: S2,
768+
indent_spaces: S3,
769+
) -> Array<DisassemblyTextLine> {
770+
//// //leading_spaces: str = " ", indent_spaces: str = ""
771+
let tokens = cur_line.tokens();
772+
let mut tokens_raw: Vec<_> = tokens.iter().map(|x| x.0).collect();
773+
let mut cur_line_obj = BNDisassemblyTextLine {
774+
addr: cur_line.addr(),
775+
instrIndex: cur_line.instr_idx(),
776+
tokens: tokens_raw.as_mut_ptr(),
777+
count: tokens.len(),
778+
highlight: cur_line.0.highlight,
779+
..Default::default()
780+
};
781+
let mut count = 0;
782+
let comment_raw = comment.into_bytes_with_nul();
783+
let leading_spaces_raw = leading_spaces.into_bytes_with_nul();
784+
let indent_spaces_raw = indent_spaces.into_bytes_with_nul();
785+
let lines = unsafe {
786+
BNDisassemblyTextRendererWrapComment(
787+
self.as_raw(),
788+
&mut cur_line_obj,
789+
&mut count,
790+
comment_raw.as_ref().as_ptr() as *const ffi::c_char,
791+
has_auto_annotations,
792+
leading_spaces_raw.as_ref().as_ptr() as *const ffi::c_char,
793+
indent_spaces_raw.as_ref().as_ptr() as *const ffi::c_char,
794+
)
795+
};
796+
assert!(!lines.is_null());
797+
unsafe { Array::new(lines, count, ()) }
798+
}
799+
}
800+
801+
impl Clone for DisassemblyTextRenderer {
802+
fn clone(&self) -> Self {
803+
unsafe {
804+
Self::from_raw(
805+
ptr::NonNull::new(BNNewDisassemblyTextRendererReference(self.as_raw())).unwrap(),
806+
)
807+
}
808+
}
809+
}
810+
811+
impl Drop for DisassemblyTextRenderer {
812+
fn drop(&mut self) {
813+
unsafe { BNFreeDisassemblyTextRenderer(self.as_raw()) }
814+
}
815+
}

rust/src/types.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,11 @@ impl Variable {
13911391
storage: self.storage,
13921392
}
13931393
}
1394+
1395+
/// A UID for a variable within a function.
1396+
pub fn identifier(&self) -> u64 {
1397+
unsafe { BNToVariableIdentifier(&self.raw()) }
1398+
}
13941399
}
13951400

13961401
impl CoreArrayProvider for Variable {
@@ -3540,7 +3545,7 @@ pub type IntegerDisplayType = binaryninjacore_sys::BNIntegerDisplayType;
35403545

35413546
#[derive(Debug, Clone)]
35423547
pub struct StackVariableReference {
3543-
_source_operand: u32,
3548+
source_operand: u32,
35443549
var_type: Conf<Ref<Type>>,
35453550
name: BnString,
35463551
var: Variable,
@@ -3559,7 +3564,7 @@ impl StackVariableReference {
35593564
let offset = value.referencedOffset;
35603565
let size = value.size;
35613566
Self {
3562-
_source_operand: value.sourceOperand,
3567+
source_operand: value.sourceOperand,
35633568
var_type,
35643569
name,
35653570
var,
@@ -3582,6 +3587,9 @@ impl StackVariableReference {
35823587
pub fn size(&self) -> usize {
35833588
self.size
35843589
}
3590+
pub fn source_operand(&self) -> Option<u32> {
3591+
(self.source_operand != 0xffffffff).then_some(self.source_operand)
3592+
}
35853593
}
35863594

35873595
impl CoreArrayProvider for StackVariableReference {

0 commit comments

Comments
 (0)