|
16 | 16 |
|
17 | 17 | use binaryninjacore_sys::*;
|
18 | 18 |
|
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}; |
21 | 26 |
|
22 | 27 | use crate::rc::*;
|
23 | 28 |
|
| 29 | +use core::ffi; |
24 | 30 | use std::convert::From;
|
25 | 31 | use std::ffi::CStr;
|
26 | 32 | use std::mem;
|
@@ -512,3 +518,298 @@ unsafe impl RefCountable for DisassemblySettings {
|
512 | 518 | BNFreeDisassemblySettings(handle.handle);
|
513 | 519 | }
|
514 | 520 | }
|
| 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 | +} |
0 commit comments