binaryninja/
binary_view.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A view on binary data and queryable interface of a binary file.
16//!
17//! One key job of BinaryView is file format parsing which allows Binary Ninja to read, write,
18//! insert, remove portions of the file given a virtual address.
19//!
20//! For the purposes of this documentation we define a virtual address as the memory address that
21//! the various pieces of the physical file will be loaded at.
22//! TODO : Mirror the Python docs for this
23
24use binaryninjacore_sys::*;
25
26// Used for documentation
27#[allow(unused)]
28pub use crate::workflow::AnalysisContext;
29
30use crate::architecture::{Architecture, CoreArchitecture};
31use crate::base_detection::BaseAddressDetection;
32use crate::basic_block::BasicBlock;
33use crate::component::Component;
34use crate::confidence::Conf;
35use crate::data_buffer::DataBuffer;
36use crate::debuginfo::DebugInfo;
37use crate::external_library::{ExternalLibrary, ExternalLocation};
38use crate::file_accessor::{Accessor, FileAccessor};
39use crate::file_metadata::FileMetadata;
40use crate::flowgraph::FlowGraph;
41use crate::function::{ArchAndAddr, Function, FunctionViewType, NativeBlock};
42use crate::linear_view::{LinearDisassemblyLine, LinearViewCursor};
43use crate::metadata::Metadata;
44use crate::platform::Platform;
45use crate::progress::{NoProgressCallback, ProgressCallback};
46use crate::project::file::ProjectFile;
47use crate::rc::*;
48use crate::references::{CodeReference, DataReference};
49use crate::relocation::Relocation;
50use crate::section::{Section, SectionBuilder};
51use crate::segment::{Segment, SegmentBuilder};
52use crate::settings::Settings;
53use crate::string::*;
54use crate::symbol::{Symbol, SymbolType};
55use crate::tags::{Tag, TagType};
56use crate::type_container::TypeContainer;
57use crate::type_library::TypeLibrary;
58use crate::types::{
59    NamedTypeReference, QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type,
60};
61use crate::variable::DataVariable;
62use crate::Endianness;
63use std::collections::HashMap;
64use std::ffi::{c_char, c_void};
65use std::ops::Range;
66use std::path::Path;
67use std::ptr::NonNull;
68use std::{result, slice};
69// TODO : general reorg of modules related to bv
70
71pub mod memory_map;
72pub mod reader;
73pub mod search;
74pub mod writer;
75
76use crate::binary_view::search::SearchQuery;
77use crate::disassembly::DisassemblySettings;
78use crate::workflow::Workflow;
79pub use memory_map::MemoryMap;
80pub use reader::BinaryReader;
81pub use writer::BinaryWriter;
82
83pub type Result<R> = result::Result<R, ()>;
84pub type BinaryViewEventType = BNBinaryViewEventType;
85pub type AnalysisState = BNAnalysisState;
86pub type ModificationStatus = BNModificationStatus;
87pub type StringType = BNStringType;
88pub type FindFlag = BNFindFlag;
89
90#[allow(clippy::len_without_is_empty)]
91pub trait BinaryViewBase: AsRef<BinaryView> {
92    fn read(&self, _buf: &mut [u8], _offset: u64) -> usize {
93        0
94    }
95
96    fn write(&self, _offset: u64, _data: &[u8]) -> usize {
97        0
98    }
99
100    fn insert(&self, _offset: u64, _data: &[u8]) -> usize {
101        0
102    }
103
104    fn remove(&self, _offset: u64, _len: usize) -> usize {
105        0
106    }
107
108    fn offset_valid(&self, offset: u64) -> bool {
109        let mut buf = [0u8; 1];
110
111        // don't use self.read so that if segments were used we
112        // check against those as well
113        self.as_ref().read(&mut buf[..], offset) == buf.len()
114    }
115
116    fn offset_readable(&self, offset: u64) -> bool {
117        self.offset_valid(offset)
118    }
119
120    fn offset_writable(&self, offset: u64) -> bool {
121        self.offset_valid(offset)
122    }
123
124    fn offset_executable(&self, offset: u64) -> bool {
125        self.offset_valid(offset)
126    }
127
128    fn offset_backed_by_file(&self, offset: u64) -> bool {
129        self.offset_valid(offset)
130    }
131
132    fn next_valid_offset_after(&self, offset: u64) -> u64 {
133        let start = self.as_ref().start();
134
135        if offset < start {
136            start
137        } else {
138            offset
139        }
140    }
141
142    #[allow(unused)]
143    fn modification_status(&self, offset: u64) -> ModificationStatus {
144        ModificationStatus::Original
145    }
146
147    fn start(&self) -> u64 {
148        0
149    }
150
151    fn len(&self) -> u64 {
152        0
153    }
154
155    fn executable(&self) -> bool {
156        true
157    }
158
159    fn relocatable(&self) -> bool {
160        true
161    }
162
163    fn entry_point(&self) -> u64;
164    fn default_endianness(&self) -> Endianness;
165    fn address_size(&self) -> usize;
166
167    fn save(&self) -> bool {
168        self.as_ref()
169            .parent_view()
170            .map(|view| view.save())
171            .unwrap_or(false)
172    }
173}
174
175#[derive(Debug, Clone)]
176pub struct ActiveAnalysisInfo {
177    pub func: Ref<Function>,
178    pub analysis_time: u64,
179    pub update_count: usize,
180    pub submit_count: usize,
181}
182
183#[derive(Debug, Clone)]
184pub struct AnalysisInfo {
185    pub state: AnalysisState,
186    pub analysis_time: u64,
187    pub active_info: Vec<ActiveAnalysisInfo>,
188}
189
190#[derive(Debug, Clone)]
191pub struct AnalysisProgress {
192    pub state: AnalysisState,
193    pub count: usize,
194    pub total: usize,
195}
196
197pub trait BinaryViewExt: BinaryViewBase {
198    fn file(&self) -> Ref<FileMetadata> {
199        unsafe {
200            let raw = BNGetFileForView(self.as_ref().handle);
201            FileMetadata::ref_from_raw(raw)
202        }
203    }
204
205    fn parent_view(&self) -> Option<Ref<BinaryView>> {
206        let raw_view_ptr = unsafe { BNGetParentView(self.as_ref().handle) };
207        match raw_view_ptr.is_null() {
208            false => Some(unsafe { BinaryView::ref_from_raw(raw_view_ptr) }),
209            true => None,
210        }
211    }
212
213    fn raw_view(&self) -> Option<Ref<BinaryView>> {
214        self.file().view_of_type("Raw")
215    }
216
217    fn view_type(&self) -> String {
218        let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) };
219        unsafe { BnString::into_string(ptr) }
220    }
221
222    /// Reads up to `len` bytes from address `offset`
223    fn read_vec(&self, offset: u64, len: usize) -> Vec<u8> {
224        let mut ret = vec![0; len];
225
226        let size = self.read(&mut ret, offset);
227        ret.truncate(size);
228
229        ret
230    }
231
232    /// Appends up to `len` bytes from address `offset` into `dest`
233    fn read_into_vec(&self, dest: &mut Vec<u8>, offset: u64, len: usize) -> usize {
234        let starting_len = dest.len();
235        dest.resize(starting_len + len, 0);
236        let read_size = self.read(&mut dest[starting_len..], offset);
237        dest.truncate(starting_len + read_size);
238        read_size
239    }
240
241    /// Search the view using the query options.
242    ///
243    /// In the `on_match` callback return `false` to stop searching.
244    fn search<C: FnMut(u64, &DataBuffer) -> bool>(&self, query: &SearchQuery, on_match: C) -> bool {
245        self.search_with_progress(query, on_match, NoProgressCallback)
246    }
247
248    /// Search the view using the query options.
249    ///
250    /// In the `on_match` callback return `false` to stop searching.
251    fn search_with_progress<P: ProgressCallback, C: FnMut(u64, &DataBuffer) -> bool>(
252        &self,
253        query: &SearchQuery,
254        mut on_match: C,
255        mut progress: P,
256    ) -> bool {
257        unsafe extern "C" fn cb_on_match<C: FnMut(u64, &DataBuffer) -> bool>(
258            ctx: *mut c_void,
259            offset: u64,
260            data: *mut BNDataBuffer,
261        ) -> bool {
262            let f = ctx as *mut C;
263            let buffer = DataBuffer::from_raw(data);
264            (*f)(offset, &buffer)
265        }
266
267        let query = query.to_json().to_cstr();
268        unsafe {
269            BNSearch(
270                self.as_ref().handle,
271                query.as_ptr(),
272                &mut progress as *mut P as *mut c_void,
273                Some(P::cb_progress_callback),
274                &mut on_match as *const C as *mut c_void,
275                Some(cb_on_match::<C>),
276            )
277        }
278    }
279
280    fn find_next_data(&self, start: u64, end: u64, data: &DataBuffer) -> Option<u64> {
281        self.find_next_data_with_opts(
282            start,
283            end,
284            data,
285            FindFlag::FindCaseInsensitive,
286            NoProgressCallback,
287        )
288    }
289
290    /// # Warning
291    ///
292    /// This function is likely to be changed to take in a "query" structure. Or deprecated entirely.
293    fn find_next_data_with_opts<P: ProgressCallback>(
294        &self,
295        start: u64,
296        end: u64,
297        data: &DataBuffer,
298        flag: FindFlag,
299        mut progress: P,
300    ) -> Option<u64> {
301        let mut result: u64 = 0;
302        let found = unsafe {
303            BNFindNextDataWithProgress(
304                self.as_ref().handle,
305                start,
306                end,
307                data.as_raw(),
308                &mut result,
309                flag,
310                &mut progress as *mut P as *mut c_void,
311                Some(P::cb_progress_callback),
312            )
313        };
314
315        if found {
316            Some(result)
317        } else {
318            None
319        }
320    }
321
322    fn find_next_constant(
323        &self,
324        start: u64,
325        end: u64,
326        constant: u64,
327        view_type: FunctionViewType,
328    ) -> Option<u64> {
329        // TODO: What are the best "default" settings?
330        let settings = DisassemblySettings::new();
331        self.find_next_constant_with_opts(
332            start,
333            end,
334            constant,
335            &settings,
336            view_type,
337            NoProgressCallback,
338        )
339    }
340
341    /// # Warning
342    ///
343    /// This function is likely to be changed to take in a "query" structure.
344    fn find_next_constant_with_opts<P: ProgressCallback>(
345        &self,
346        start: u64,
347        end: u64,
348        constant: u64,
349        disasm_settings: &DisassemblySettings,
350        view_type: FunctionViewType,
351        mut progress: P,
352    ) -> Option<u64> {
353        let mut result: u64 = 0;
354        let raw_view_type = FunctionViewType::into_raw(view_type);
355        let found = unsafe {
356            BNFindNextConstantWithProgress(
357                self.as_ref().handle,
358                start,
359                end,
360                constant,
361                &mut result,
362                disasm_settings.handle,
363                raw_view_type,
364                &mut progress as *mut P as *mut c_void,
365                Some(P::cb_progress_callback),
366            )
367        };
368        FunctionViewType::free_raw(raw_view_type);
369
370        if found {
371            Some(result)
372        } else {
373            None
374        }
375    }
376
377    fn find_next_text(
378        &self,
379        start: u64,
380        end: u64,
381        text: &str,
382        view_type: FunctionViewType,
383    ) -> Option<u64> {
384        // TODO: What are the best "default" settings?
385        let settings = DisassemblySettings::new();
386        self.find_next_text_with_opts(
387            start,
388            end,
389            text,
390            &settings,
391            FindFlag::FindCaseInsensitive,
392            view_type,
393            NoProgressCallback,
394        )
395    }
396
397    /// # Warning
398    ///
399    /// This function is likely to be changed to take in a "query" structure.
400    fn find_next_text_with_opts<P: ProgressCallback>(
401        &self,
402        start: u64,
403        end: u64,
404        text: &str,
405        disasm_settings: &DisassemblySettings,
406        flag: FindFlag,
407        view_type: FunctionViewType,
408        mut progress: P,
409    ) -> Option<u64> {
410        let text = text.to_cstr();
411        let raw_view_type = FunctionViewType::into_raw(view_type);
412        let mut result: u64 = 0;
413        let found = unsafe {
414            BNFindNextTextWithProgress(
415                self.as_ref().handle,
416                start,
417                end,
418                text.as_ptr(),
419                &mut result,
420                disasm_settings.handle,
421                flag,
422                raw_view_type,
423                &mut progress as *mut P as *mut c_void,
424                Some(P::cb_progress_callback),
425            )
426        };
427        FunctionViewType::free_raw(raw_view_type);
428
429        if found {
430            Some(result)
431        } else {
432            None
433        }
434    }
435
436    fn notify_data_written(&self, offset: u64, len: usize) {
437        unsafe {
438            BNNotifyDataWritten(self.as_ref().handle, offset, len);
439        }
440    }
441
442    fn notify_data_inserted(&self, offset: u64, len: usize) {
443        unsafe {
444            BNNotifyDataInserted(self.as_ref().handle, offset, len);
445        }
446    }
447
448    fn notify_data_removed(&self, offset: u64, len: usize) {
449        unsafe {
450            BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64);
451        }
452    }
453
454    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
455    /// offset has code semantics.
456    fn offset_has_code_semantics(&self, offset: u64) -> bool {
457        unsafe { BNIsOffsetCodeSemantics(self.as_ref().handle, offset) }
458    }
459
460    /// Check if the offset is within a [`Section`] with [`crate::section::Semantics::External`].
461    fn offset_has_extern_semantics(&self, offset: u64) -> bool {
462        unsafe { BNIsOffsetExternSemantics(self.as_ref().handle, offset) }
463    }
464
465    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
466    /// offset has writable semantics.
467    fn offset_has_writable_semantics(&self, offset: u64) -> bool {
468        unsafe { BNIsOffsetWritableSemantics(self.as_ref().handle, offset) }
469    }
470
471    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
472    /// offset has read only semantics.
473    fn offset_has_read_only_semantics(&self, offset: u64) -> bool {
474        unsafe { BNIsOffsetReadOnlySemantics(self.as_ref().handle, offset) }
475    }
476
477    fn image_base(&self) -> u64 {
478        unsafe { BNGetImageBase(self.as_ref().handle) }
479    }
480
481    fn original_image_base(&self) -> u64 {
482        unsafe { BNGetOriginalImageBase(self.as_ref().handle) }
483    }
484
485    fn set_original_image_base(&self, image_base: u64) {
486        unsafe { BNSetOriginalImageBase(self.as_ref().handle, image_base) }
487    }
488
489    /// The highest address in the view.
490    ///
491    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::end`].
492    fn end(&self) -> u64 {
493        unsafe { BNGetEndOffset(self.as_ref().handle) }
494    }
495
496    fn add_analysis_option(&self, name: &str) {
497        let name = name.to_cstr();
498        unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_ptr()) }
499    }
500
501    fn has_initial_analysis(&self) -> bool {
502        unsafe { BNHasInitialAnalysis(self.as_ref().handle) }
503    }
504
505    fn set_analysis_hold(&self, enable: bool) {
506        unsafe { BNSetAnalysisHold(self.as_ref().handle, enable) }
507    }
508
509    /// Runs the analysis pipeline, analyzing any data that has been marked for updates.
510    ///
511    /// You can explicitly mark a function to be updated with:
512    /// - [`Function::mark_updates_required`]
513    /// - [`Function::mark_caller_updates_required`]
514    ///
515    /// NOTE: This is a **non-blocking** call, use [`BinaryViewExt::update_analysis_and_wait`] if you
516    /// require analysis to have completed before moving on.
517    fn update_analysis(&self) {
518        unsafe {
519            BNUpdateAnalysis(self.as_ref().handle);
520        }
521    }
522
523    /// Runs the analysis pipeline, analyzing any data that has been marked for updates.
524    ///
525    /// You can explicitly mark a function to be updated with:
526    /// - [`Function::mark_updates_required`]
527    /// - [`Function::mark_caller_updates_required`]
528    ///
529    /// NOTE: This is a **blocking** call, use [`BinaryViewExt::update_analysis`] if you do not
530    /// need to wait for the analysis update to finish.
531    fn update_analysis_and_wait(&self) {
532        unsafe {
533            BNUpdateAnalysisAndWait(self.as_ref().handle);
534        }
535    }
536
537    /// Causes **all** functions to be reanalyzed.
538    ///
539    /// Use [`BinaryViewExt::update_analysis`] or [`BinaryViewExt::update_analysis_and_wait`] instead
540    /// if you want to incrementally update analysis.
541    ///
542    /// NOTE: This function does not wait for the analysis to finish.
543    fn reanalyze(&self) {
544        unsafe {
545            BNReanalyzeAllFunctions(self.as_ref().handle);
546        }
547    }
548
549    fn abort_analysis(&self) {
550        unsafe { BNAbortAnalysis(self.as_ref().handle) }
551    }
552
553    fn analysis_is_aborted(&self) -> bool {
554        unsafe { BNAnalysisIsAborted(self.as_ref().handle) }
555    }
556
557    fn workflow(&self) -> Ref<Workflow> {
558        unsafe {
559            let raw_ptr = BNGetWorkflowForBinaryView(self.as_ref().handle);
560            let nonnull = NonNull::new(raw_ptr).expect("All views must have a workflow");
561            Workflow::ref_from_raw(nonnull)
562        }
563    }
564
565    fn analysis_info(&self) -> Result<AnalysisInfo> {
566        let info_ref = unsafe { BNGetAnalysisInfo(self.as_ref().handle) };
567        if info_ref.is_null() {
568            return Err(());
569        }
570        let info = unsafe { *info_ref };
571        let active_infos = unsafe { slice::from_raw_parts(info.activeInfo, info.count) };
572
573        let mut active_info_list = vec![];
574        for active_info in active_infos {
575            let func = unsafe { Function::ref_from_raw(active_info.func) };
576            active_info_list.push(ActiveAnalysisInfo {
577                func,
578                analysis_time: active_info.analysisTime,
579                update_count: active_info.updateCount,
580                submit_count: active_info.submitCount,
581            });
582        }
583
584        let result = AnalysisInfo {
585            state: info.state,
586            analysis_time: info.analysisTime,
587            active_info: vec![],
588        };
589
590        unsafe { BNFreeAnalysisInfo(info_ref) };
591        Ok(result)
592    }
593
594    fn analysis_progress(&self) -> AnalysisProgress {
595        let progress = unsafe { BNGetAnalysisProgress(self.as_ref().handle) };
596        AnalysisProgress {
597            state: progress.state,
598            count: progress.count,
599            total: progress.total,
600        }
601    }
602
603    fn default_arch(&self) -> Option<CoreArchitecture> {
604        unsafe {
605            let raw = BNGetDefaultArchitecture(self.as_ref().handle);
606
607            if raw.is_null() {
608                return None;
609            }
610
611            Some(CoreArchitecture::from_raw(raw))
612        }
613    }
614
615    fn set_default_arch<A: Architecture>(&self, arch: &A) {
616        unsafe {
617            BNSetDefaultArchitecture(self.as_ref().handle, arch.as_ref().handle);
618        }
619    }
620
621    fn default_platform(&self) -> Option<Ref<Platform>> {
622        unsafe {
623            let raw = BNGetDefaultPlatform(self.as_ref().handle);
624
625            if raw.is_null() {
626                return None;
627            }
628
629            Some(Platform::ref_from_raw(raw))
630        }
631    }
632
633    fn set_default_platform(&self, plat: &Platform) {
634        unsafe {
635            BNSetDefaultPlatform(self.as_ref().handle, plat.handle);
636        }
637    }
638
639    fn base_address_detection(&self) -> Option<BaseAddressDetection> {
640        unsafe {
641            let handle = BNCreateBaseAddressDetection(self.as_ref().handle);
642            NonNull::new(handle).map(|base| BaseAddressDetection::from_raw(base))
643        }
644    }
645
646    fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> {
647        unsafe {
648            let size = BNGetInstructionLength(self.as_ref().handle, arch.as_ref().handle, addr);
649
650            if size > 0 {
651                Some(size)
652            } else {
653                None
654            }
655        }
656    }
657
658    fn symbol_by_address(&self, addr: u64) -> Option<Ref<Symbol>> {
659        unsafe {
660            let raw_sym_ptr =
661                BNGetSymbolByAddress(self.as_ref().handle, addr, std::ptr::null_mut());
662            match raw_sym_ptr.is_null() {
663                false => Some(Symbol::ref_from_raw(raw_sym_ptr)),
664                true => None,
665            }
666        }
667    }
668
669    fn symbol_by_raw_name(&self, raw_name: impl IntoCStr) -> Option<Ref<Symbol>> {
670        let raw_name = raw_name.to_cstr();
671
672        unsafe {
673            let raw_sym_ptr = BNGetSymbolByRawName(
674                self.as_ref().handle,
675                raw_name.as_ptr(),
676                std::ptr::null_mut(),
677            );
678            match raw_sym_ptr.is_null() {
679                false => Some(Symbol::ref_from_raw(raw_sym_ptr)),
680                true => None,
681            }
682        }
683    }
684
685    fn symbols(&self) -> Array<Symbol> {
686        unsafe {
687            let mut count = 0;
688            let handles = BNGetSymbols(self.as_ref().handle, &mut count, std::ptr::null_mut());
689
690            Array::new(handles, count, ())
691        }
692    }
693
694    fn symbols_by_name(&self, name: impl IntoCStr) -> Array<Symbol> {
695        let raw_name = name.to_cstr();
696
697        unsafe {
698            let mut count = 0;
699            let handles = BNGetSymbolsByName(
700                self.as_ref().handle,
701                raw_name.as_ptr(),
702                &mut count,
703                std::ptr::null_mut(),
704            );
705
706            Array::new(handles, count, ())
707        }
708    }
709
710    fn symbols_in_range(&self, range: Range<u64>) -> Array<Symbol> {
711        unsafe {
712            let mut count = 0;
713            let len = range.end.wrapping_sub(range.start);
714            let handles = BNGetSymbolsInRange(
715                self.as_ref().handle,
716                range.start,
717                len,
718                &mut count,
719                std::ptr::null_mut(),
720            );
721
722            Array::new(handles, count, ())
723        }
724    }
725
726    fn symbols_of_type(&self, ty: SymbolType) -> Array<Symbol> {
727        unsafe {
728            let mut count = 0;
729            let handles = BNGetSymbolsOfType(
730                self.as_ref().handle,
731                ty.into(),
732                &mut count,
733                std::ptr::null_mut(),
734            );
735
736            Array::new(handles, count, ())
737        }
738    }
739
740    fn symbols_of_type_in_range(&self, ty: SymbolType, range: Range<u64>) -> Array<Symbol> {
741        unsafe {
742            let mut count = 0;
743            let len = range.end.wrapping_sub(range.start);
744            let handles = BNGetSymbolsOfTypeInRange(
745                self.as_ref().handle,
746                ty.into(),
747                range.start,
748                len,
749                &mut count,
750                std::ptr::null_mut(),
751            );
752
753            Array::new(handles, count, ())
754        }
755    }
756
757    fn define_auto_symbol(&self, sym: &Symbol) {
758        unsafe {
759            BNDefineAutoSymbol(self.as_ref().handle, sym.handle);
760        }
761    }
762
763    fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>(
764        &self,
765        sym: &Symbol,
766        plat: &Platform,
767        ty: T,
768    ) -> Result<Ref<Symbol>> {
769        let mut type_with_conf = BNTypeWithConfidence {
770            type_: if let Some(t) = ty.into() {
771                t.handle
772            } else {
773                std::ptr::null_mut()
774            },
775            confidence: 255, // BN_FULL_CONFIDENCE
776        };
777
778        unsafe {
779            let raw_sym = BNDefineAutoSymbolAndVariableOrFunction(
780                self.as_ref().handle,
781                plat.handle,
782                sym.handle,
783                &mut type_with_conf,
784            );
785
786            if raw_sym.is_null() {
787                return Err(());
788            }
789
790            Ok(Symbol::ref_from_raw(raw_sym))
791        }
792    }
793
794    fn undefine_auto_symbol(&self, sym: &Symbol) {
795        unsafe {
796            BNUndefineAutoSymbol(self.as_ref().handle, sym.handle);
797        }
798    }
799
800    fn define_user_symbol(&self, sym: &Symbol) {
801        unsafe {
802            BNDefineUserSymbol(self.as_ref().handle, sym.handle);
803        }
804    }
805
806    fn undefine_user_symbol(&self, sym: &Symbol) {
807        unsafe {
808            BNUndefineUserSymbol(self.as_ref().handle, sym.handle);
809        }
810    }
811
812    fn data_variables(&self) -> Array<DataVariable> {
813        unsafe {
814            let mut count = 0;
815            let vars = BNGetDataVariables(self.as_ref().handle, &mut count);
816            Array::new(vars, count, ())
817        }
818    }
819
820    fn data_variable_at_address(&self, addr: u64) -> Option<DataVariable> {
821        let mut dv = BNDataVariable::default();
822        unsafe {
823            if BNGetDataVariableAtAddress(self.as_ref().handle, addr, &mut dv) {
824                Some(DataVariable::from_owned_raw(dv))
825            } else {
826                None
827            }
828        }
829    }
830
831    fn define_auto_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) {
832        let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
833        unsafe {
834            BNDefineDataVariable(self.as_ref().handle, addr, &mut owned_raw_ty);
835        }
836    }
837
838    /// You likely would also like to call [`BinaryViewExt::define_user_symbol`] to bind this data variable with a name
839    fn define_user_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) {
840        let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
841        unsafe {
842            BNDefineUserDataVariable(self.as_ref().handle, addr, &mut owned_raw_ty);
843        }
844    }
845
846    fn undefine_auto_data_var(&self, addr: u64, blacklist: Option<bool>) {
847        unsafe {
848            BNUndefineDataVariable(self.as_ref().handle, addr, blacklist.unwrap_or(true));
849        }
850    }
851
852    fn undefine_user_data_var(&self, addr: u64) {
853        unsafe {
854            BNUndefineUserDataVariable(self.as_ref().handle, addr);
855        }
856    }
857
858    fn define_auto_type<T: Into<QualifiedName>>(
859        &self,
860        name: T,
861        source: &str,
862        type_obj: &Type,
863    ) -> QualifiedName {
864        let mut raw_name = QualifiedName::into_raw(name.into());
865        let source_str = source.to_cstr();
866        let name_handle = unsafe {
867            let id_str =
868                BNGenerateAutoTypeId(source_str.as_ref().as_ptr() as *const _, &mut raw_name);
869            BNDefineAnalysisType(self.as_ref().handle, id_str, &mut raw_name, type_obj.handle)
870        };
871        QualifiedName::free_raw(raw_name);
872        QualifiedName::from_owned_raw(name_handle)
873    }
874
875    fn define_auto_type_with_id<T: Into<QualifiedName>>(
876        &self,
877        name: T,
878        id: &str,
879        type_obj: &Type,
880    ) -> QualifiedName {
881        let mut raw_name = QualifiedName::into_raw(name.into());
882        let id_str = id.to_cstr();
883        let result_raw_name = unsafe {
884            BNDefineAnalysisType(
885                self.as_ref().handle,
886                id_str.as_ref().as_ptr() as *const _,
887                &mut raw_name,
888                type_obj.handle,
889            )
890        };
891        QualifiedName::free_raw(raw_name);
892        QualifiedName::from_owned_raw(result_raw_name)
893    }
894
895    fn define_user_type<T: Into<QualifiedName>>(&self, name: T, type_obj: &Type) {
896        let mut raw_name = QualifiedName::into_raw(name.into());
897        unsafe { BNDefineUserAnalysisType(self.as_ref().handle, &mut raw_name, type_obj.handle) }
898        QualifiedName::free_raw(raw_name);
899    }
900
901    fn define_auto_types<T, I>(&self, names_sources_and_types: T) -> HashMap<String, QualifiedName>
902    where
903        T: Iterator<Item = I>,
904        I: Into<QualifiedNameTypeAndId>,
905    {
906        self.define_auto_types_with_progress(names_sources_and_types, NoProgressCallback)
907    }
908
909    fn define_auto_types_with_progress<T, I, P>(
910        &self,
911        names_sources_and_types: T,
912        mut progress: P,
913    ) -> HashMap<String, QualifiedName>
914    where
915        T: Iterator<Item = I>,
916        I: Into<QualifiedNameTypeAndId>,
917        P: ProgressCallback,
918    {
919        let mut types: Vec<BNQualifiedNameTypeAndId> = names_sources_and_types
920            .map(Into::into)
921            .map(QualifiedNameTypeAndId::into_raw)
922            .collect();
923        let mut result_ids: *mut *mut c_char = std::ptr::null_mut();
924        let mut result_names: *mut BNQualifiedName = std::ptr::null_mut();
925
926        let result_count = unsafe {
927            BNDefineAnalysisTypes(
928                self.as_ref().handle,
929                types.as_mut_ptr(),
930                types.len(),
931                Some(P::cb_progress_callback),
932                &mut progress as *mut P as *mut c_void,
933                &mut result_ids as *mut _,
934                &mut result_names as *mut _,
935            )
936        };
937
938        for ty in types {
939            QualifiedNameTypeAndId::free_raw(ty);
940        }
941
942        let id_array = unsafe { Array::<BnString>::new(result_ids, result_count, ()) };
943        let name_array = unsafe { Array::<QualifiedName>::new(result_names, result_count, ()) };
944        id_array
945            .into_iter()
946            .zip(&name_array)
947            .map(|(id, name)| (id.to_owned(), name))
948            .collect()
949    }
950
951    fn define_user_types<T, I>(&self, names_and_types: T)
952    where
953        T: Iterator<Item = I>,
954        I: Into<QualifiedNameAndType>,
955    {
956        self.define_user_types_with_progress(names_and_types, NoProgressCallback);
957    }
958
959    fn define_user_types_with_progress<T, I, P>(&self, names_and_types: T, mut progress: P)
960    where
961        T: Iterator<Item = I>,
962        I: Into<QualifiedNameAndType>,
963        P: ProgressCallback,
964    {
965        let mut types: Vec<BNQualifiedNameAndType> = names_and_types
966            .map(Into::into)
967            .map(QualifiedNameAndType::into_raw)
968            .collect();
969
970        unsafe {
971            BNDefineUserAnalysisTypes(
972                self.as_ref().handle,
973                types.as_mut_ptr(),
974                types.len(),
975                Some(P::cb_progress_callback),
976                &mut progress as *mut P as *mut c_void,
977            )
978        };
979
980        for ty in types {
981            QualifiedNameAndType::free_raw(ty);
982        }
983    }
984
985    fn undefine_auto_type(&self, id: &str) {
986        let id_str = id.to_cstr();
987        unsafe {
988            BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _);
989        }
990    }
991
992    fn undefine_user_type<T: Into<QualifiedName>>(&self, name: T) {
993        let mut raw_name = QualifiedName::into_raw(name.into());
994        unsafe { BNUndefineUserAnalysisType(self.as_ref().handle, &mut raw_name) }
995        QualifiedName::free_raw(raw_name);
996    }
997
998    fn types(&self) -> Array<QualifiedNameAndType> {
999        unsafe {
1000            let mut count = 0usize;
1001            let types = BNGetAnalysisTypeList(self.as_ref().handle, &mut count);
1002            Array::new(types, count, ())
1003        }
1004    }
1005
1006    fn dependency_sorted_types(&self) -> Array<QualifiedNameAndType> {
1007        unsafe {
1008            let mut count = 0usize;
1009            let types = BNGetAnalysisDependencySortedTypeList(self.as_ref().handle, &mut count);
1010            Array::new(types, count, ())
1011        }
1012    }
1013
1014    fn type_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<Ref<Type>> {
1015        let mut raw_name = QualifiedName::into_raw(name.into());
1016        unsafe {
1017            let type_handle = BNGetAnalysisTypeByName(self.as_ref().handle, &mut raw_name);
1018            QualifiedName::free_raw(raw_name);
1019            if type_handle.is_null() {
1020                return None;
1021            }
1022            Some(Type::ref_from_raw(type_handle))
1023        }
1024    }
1025
1026    fn type_by_ref(&self, ref_: &NamedTypeReference) -> Option<Ref<Type>> {
1027        unsafe {
1028            let type_handle = BNGetAnalysisTypeByRef(self.as_ref().handle, ref_.handle);
1029            if type_handle.is_null() {
1030                return None;
1031            }
1032            Some(Type::ref_from_raw(type_handle))
1033        }
1034    }
1035
1036    fn type_by_id(&self, id: &str) -> Option<Ref<Type>> {
1037        let id_str = id.to_cstr();
1038        unsafe {
1039            let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ptr());
1040            if type_handle.is_null() {
1041                return None;
1042            }
1043            Some(Type::ref_from_raw(type_handle))
1044        }
1045    }
1046
1047    fn type_name_by_id(&self, id: &str) -> Option<QualifiedName> {
1048        let id_str = id.to_cstr();
1049        unsafe {
1050            let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ptr());
1051            let name = QualifiedName::from_owned_raw(name_handle);
1052            // The core will return an empty qualified name if no type name was found.
1053            match name.items.is_empty() {
1054                true => None,
1055                false => Some(name),
1056            }
1057        }
1058    }
1059
1060    fn type_id_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<String> {
1061        let mut raw_name = QualifiedName::into_raw(name.into());
1062        unsafe {
1063            let id_cstr = BNGetAnalysisTypeId(self.as_ref().handle, &mut raw_name);
1064            QualifiedName::free_raw(raw_name);
1065            let id = BnString::into_string(id_cstr);
1066            match id.is_empty() {
1067                true => None,
1068                false => Some(id),
1069            }
1070        }
1071    }
1072
1073    fn is_type_auto_defined<T: Into<QualifiedName>>(&self, name: T) -> bool {
1074        let mut raw_name = QualifiedName::into_raw(name.into());
1075        let result = unsafe { BNIsAnalysisTypeAutoDefined(self.as_ref().handle, &mut raw_name) };
1076        QualifiedName::free_raw(raw_name);
1077        result
1078    }
1079
1080    fn segments(&self) -> Array<Segment> {
1081        unsafe {
1082            let mut count = 0;
1083            let raw_segments = BNGetSegments(self.as_ref().handle, &mut count);
1084            Array::new(raw_segments, count, ())
1085        }
1086    }
1087
1088    fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> {
1089        unsafe {
1090            let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr);
1091            match raw_seg.is_null() {
1092                false => Some(Segment::ref_from_raw(raw_seg)),
1093                true => None,
1094            }
1095        }
1096    }
1097
1098    /// Adds a segment to the view.
1099    ///
1100    /// NOTE: Consider using [BinaryViewExt::begin_bulk_add_segments] and [BinaryViewExt::end_bulk_add_segments]
1101    /// if you plan on adding a number of segments all at once, to avoid unnecessary MemoryMap updates.
1102    fn add_segment(&self, segment: SegmentBuilder) {
1103        segment.create(self.as_ref());
1104    }
1105
1106    // TODO: Replace with BulkModify guard.
1107    /// Start adding segments in bulk. Useful for adding large numbers of segments.
1108    ///
1109    /// After calling this any call to [BinaryViewExt::add_segment] will be uncommitted until a call to
1110    /// [BinaryViewExt::end_bulk_add_segments]
1111    ///
1112    /// If you wish to discard the uncommitted segments you can call [BinaryViewExt::cancel_bulk_add_segments].
1113    ///
1114    /// NOTE: This **must** be paired with a later call to [BinaryViewExt::end_bulk_add_segments] or
1115    /// [BinaryViewExt::cancel_bulk_add_segments], otherwise segments added after this call will stay uncommitted.
1116    fn begin_bulk_add_segments(&self) {
1117        unsafe { BNBeginBulkAddSegments(self.as_ref().handle) }
1118    }
1119
1120    // TODO: Replace with BulkModify guard.
1121    /// Commit all auto and user segments that have been added since the call to [Self::begin_bulk_add_segments].
1122    ///
1123    /// NOTE: This **must** be paired with a prior call to [Self::begin_bulk_add_segments], otherwise this
1124    /// does nothing and segments are added individually.
1125    fn end_bulk_add_segments(&self) {
1126        unsafe { BNEndBulkAddSegments(self.as_ref().handle) }
1127    }
1128
1129    // TODO: Replace with BulkModify guard.
1130    /// Flushes the auto and user segments that have yet to be committed.
1131    ///
1132    /// This is to be used in conjunction with [Self::begin_bulk_add_segments]
1133    /// and [Self::end_bulk_add_segments], where the latter will commit the segments
1134    /// which have been added since [Self::begin_bulk_add_segments], this function
1135    /// will discard them so that they do not get added to the view.
1136    fn cancel_bulk_add_segments(&self) {
1137        unsafe { BNCancelBulkAddSegments(self.as_ref().handle) }
1138    }
1139
1140    fn add_section(&self, section: SectionBuilder) {
1141        section.create(self.as_ref());
1142    }
1143
1144    fn remove_auto_section(&self, name: impl IntoCStr) {
1145        let raw_name = name.to_cstr();
1146        let raw_name_ptr = raw_name.as_ptr();
1147        unsafe {
1148            BNRemoveAutoSection(self.as_ref().handle, raw_name_ptr);
1149        }
1150    }
1151
1152    fn remove_user_section(&self, name: impl IntoCStr) {
1153        let raw_name = name.to_cstr();
1154        let raw_name_ptr = raw_name.as_ptr();
1155        unsafe {
1156            BNRemoveUserSection(self.as_ref().handle, raw_name_ptr);
1157        }
1158    }
1159
1160    fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> {
1161        unsafe {
1162            let raw_name = name.to_cstr();
1163            let name_ptr = raw_name.as_ptr();
1164            let raw_section_ptr = BNGetSectionByName(self.as_ref().handle, name_ptr);
1165            match raw_section_ptr.is_null() {
1166                false => Some(Section::ref_from_raw(raw_section_ptr)),
1167                true => None,
1168            }
1169        }
1170    }
1171
1172    fn sections(&self) -> Array<Section> {
1173        unsafe {
1174            let mut count = 0;
1175            let sections = BNGetSections(self.as_ref().handle, &mut count);
1176            Array::new(sections, count, ())
1177        }
1178    }
1179
1180    fn sections_at(&self, addr: u64) -> Array<Section> {
1181        unsafe {
1182            let mut count = 0;
1183            let sections = BNGetSectionsAt(self.as_ref().handle, addr, &mut count);
1184            Array::new(sections, count, ())
1185        }
1186    }
1187
1188    fn memory_map(&self) -> MemoryMap {
1189        MemoryMap::new(self.as_ref().to_owned())
1190    }
1191
1192    /// Add an auto function at the given `address` with the views default platform.
1193    ///
1194    /// Use [`BinaryViewExt::add_auto_function_with_platform`] if you wish to specify a platform.
1195    ///
1196    /// NOTE: The default platform **must** be set for this view!
1197    fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> {
1198        let platform = self.default_platform()?;
1199        self.add_auto_function_with_platform(address, &platform)
1200    }
1201
1202    /// Add an auto function at the given `address` with the `platform`.
1203    ///
1204    /// Use [`BinaryViewExt::add_auto_function_ext`] if you wish to specify a function type.
1205    ///
1206    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1207    fn add_auto_function_with_platform(
1208        &self,
1209        address: u64,
1210        platform: &Platform,
1211    ) -> Option<Ref<Function>> {
1212        self.add_auto_function_ext(address, platform, None)
1213    }
1214
1215    /// Add an auto function at the given `address` with the `platform` and function type.
1216    ///
1217    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1218    fn add_auto_function_ext(
1219        &self,
1220        address: u64,
1221        platform: &Platform,
1222        func_type: Option<&Type>,
1223    ) -> Option<Ref<Function>> {
1224        unsafe {
1225            let func_type = match func_type {
1226                Some(func_type) => func_type.handle,
1227                None => std::ptr::null_mut(),
1228            };
1229
1230            let handle = BNAddFunctionForAnalysis(
1231                self.as_ref().handle,
1232                platform.handle,
1233                address,
1234                true,
1235                func_type,
1236            );
1237
1238            if handle.is_null() {
1239                return None;
1240            }
1241
1242            Some(Function::ref_from_raw(handle))
1243        }
1244    }
1245
1246    /// Remove an auto function from the view.
1247    ///
1248    /// Pass `true` for `update_refs` to update all references of the function.
1249    ///
1250    /// NOTE: Unlike [`BinaryViewExt::remove_user_function`], this will NOT prohibit the function from
1251    /// being re-added in the future, use [`BinaryViewExt::remove_user_function`] to blacklist the
1252    /// function from being automatically created.
1253    fn remove_auto_function(&self, func: &Function, update_refs: bool) {
1254        unsafe {
1255            BNRemoveAnalysisFunction(self.as_ref().handle, func.handle, update_refs);
1256        }
1257    }
1258
1259    /// Add a user function at the given `address` with the views default platform.
1260    ///
1261    /// Use [`BinaryViewExt::add_user_function_with_platform`] if you wish to specify a platform.
1262    ///
1263    /// NOTE: The default platform **must** be set for this view!
1264    fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> {
1265        let platform = self.default_platform()?;
1266        self.add_user_function_with_platform(addr, &platform)
1267    }
1268
1269    /// Add an auto function at the given `address` with the `platform`.
1270    ///
1271    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1272    fn add_user_function_with_platform(
1273        &self,
1274        addr: u64,
1275        platform: &Platform,
1276    ) -> Option<Ref<Function>> {
1277        unsafe {
1278            let func = BNCreateUserFunction(self.as_ref().handle, platform.handle, addr);
1279            if func.is_null() {
1280                return None;
1281            }
1282            Some(Function::ref_from_raw(func))
1283        }
1284    }
1285
1286    /// Removes the function from the view and blacklists it from being created automatically.
1287    ///
1288    /// NOTE: If you call [`BinaryViewExt::add_user_function`], it will override the blacklist.
1289    fn remove_user_function(&self, func: &Function) {
1290        unsafe { BNRemoveUserFunction(self.as_ref().handle, func.handle) }
1291    }
1292
1293    fn has_functions(&self) -> bool {
1294        unsafe { BNHasFunctions(self.as_ref().handle) }
1295    }
1296
1297    /// Add an entry point at the given `address` with the view's default platform.
1298    ///
1299    /// NOTE: The default platform **must** be set for this view!
1300    fn add_entry_point(&self, addr: u64) {
1301        if let Some(platform) = self.default_platform() {
1302            self.add_entry_point_with_platform(addr, &platform);
1303        }
1304    }
1305
1306    /// Add an entry point at the given `address` with the `platform`.
1307    ///
1308    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1309    fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) {
1310        unsafe {
1311            BNAddEntryPointForAnalysis(self.as_ref().handle, platform.handle, addr);
1312        }
1313    }
1314
1315    fn entry_point_function(&self) -> Option<Ref<Function>> {
1316        unsafe {
1317            let raw_func_ptr = BNGetAnalysisEntryPoint(self.as_ref().handle);
1318            match raw_func_ptr.is_null() {
1319                false => Some(Function::ref_from_raw(raw_func_ptr)),
1320                true => None,
1321            }
1322        }
1323    }
1324
1325    fn entry_point_functions(&self) -> Array<Function> {
1326        unsafe {
1327            let mut count = 0;
1328            let functions = BNGetAllEntryFunctions(self.as_ref().handle, &mut count);
1329
1330            Array::new(functions, count, ())
1331        }
1332    }
1333
1334    fn functions(&self) -> Array<Function> {
1335        unsafe {
1336            let mut count = 0;
1337            let functions = BNGetAnalysisFunctionList(self.as_ref().handle, &mut count);
1338
1339            Array::new(functions, count, ())
1340        }
1341    }
1342
1343    /// List of functions *starting* at `addr`
1344    fn functions_at(&self, addr: u64) -> Array<Function> {
1345        unsafe {
1346            let mut count = 0;
1347            let functions =
1348                BNGetAnalysisFunctionsForAddress(self.as_ref().handle, addr, &mut count);
1349
1350            Array::new(functions, count, ())
1351        }
1352    }
1353
1354    // List of functions containing `addr`
1355    fn functions_containing(&self, addr: u64) -> Array<Function> {
1356        unsafe {
1357            let mut count = 0;
1358            let functions =
1359                BNGetAnalysisFunctionsContainingAddress(self.as_ref().handle, addr, &mut count);
1360
1361            Array::new(functions, count, ())
1362        }
1363    }
1364
1365    /// List of functions with the given name.
1366    ///
1367    /// There is one special case where if you pass a string of the form `sub_[0-9a-f]+` then it will lookup all
1368    /// functions defined at the address matched by the regular expression if that symbol is not defined in the
1369    /// database.
1370    ///
1371    /// # Params
1372    /// - `name`: Name that the function should have
1373    /// - `plat`: Optional platform that the function should be defined for. Defaults to all platforms if `None` passed.
1374    fn functions_by_name(
1375        &self,
1376        name: impl IntoCStr,
1377        plat: Option<&Platform>,
1378    ) -> Vec<Ref<Function>> {
1379        let name = name.to_cstr();
1380        let symbols = self.symbols_by_name(&*name);
1381        let mut addresses: Vec<u64> = symbols.into_iter().map(|s| s.address()).collect();
1382        if addresses.is_empty() && name.to_bytes().starts_with(b"sub_") {
1383            if let Ok(str) = name.to_str() {
1384                if let Ok(address) = u64::from_str_radix(&str[4..], 16) {
1385                    addresses.push(address);
1386                }
1387            }
1388        }
1389
1390        let mut functions = Vec::new();
1391
1392        for address in addresses {
1393            let funcs = self.functions_at(address);
1394            for func in funcs.into_iter() {
1395                if func.start() == address && plat.map_or(true, |p| p == func.platform().as_ref()) {
1396                    functions.push(func.clone());
1397                }
1398            }
1399        }
1400
1401        functions
1402    }
1403
1404    fn function_at(&self, platform: &Platform, addr: u64) -> Option<Ref<Function>> {
1405        unsafe {
1406            let raw_func_ptr = BNGetAnalysisFunction(self.as_ref().handle, platform.handle, addr);
1407            match raw_func_ptr.is_null() {
1408                false => Some(Function::ref_from_raw(raw_func_ptr)),
1409                true => None,
1410            }
1411        }
1412    }
1413
1414    fn function_start_before(&self, addr: u64) -> u64 {
1415        unsafe { BNGetPreviousFunctionStartBeforeAddress(self.as_ref().handle, addr) }
1416    }
1417
1418    fn function_start_after(&self, addr: u64) -> u64 {
1419        unsafe { BNGetNextFunctionStartAfterAddress(self.as_ref().handle, addr) }
1420    }
1421
1422    fn basic_blocks_containing(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> {
1423        unsafe {
1424            let mut count = 0;
1425            let blocks = BNGetBasicBlocksForAddress(self.as_ref().handle, addr, &mut count);
1426            Array::new(blocks, count, NativeBlock::new())
1427        }
1428    }
1429
1430    fn basic_blocks_starting_at(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> {
1431        unsafe {
1432            let mut count = 0;
1433            let blocks = BNGetBasicBlocksStartingAtAddress(self.as_ref().handle, addr, &mut count);
1434            Array::new(blocks, count, NativeBlock::new())
1435        }
1436    }
1437
1438    fn is_new_auto_function_analysis_suppressed(&self) -> bool {
1439        unsafe { BNGetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle) }
1440    }
1441
1442    fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) {
1443        unsafe {
1444            BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress);
1445        }
1446    }
1447
1448    fn should_skip_target_analysis(
1449        &self,
1450        source: &ArchAndAddr,
1451        srcfunc: &Function,
1452        srcend: u64,
1453        target: &ArchAndAddr,
1454    ) -> bool {
1455        let mut srccopy = BNArchitectureAndAddress {
1456            arch: source.arch.handle,
1457            address: source.addr,
1458        };
1459        let mut targetcopy = BNArchitectureAndAddress {
1460            arch: target.arch.handle,
1461            address: target.addr,
1462        };
1463
1464        unsafe {
1465            BNShouldSkipTargetAnalysis(
1466                self.as_ref().handle,
1467                &mut srccopy,
1468                srcfunc.handle,
1469                srcend,
1470                &mut targetcopy,
1471            )
1472        }
1473    }
1474
1475    fn read_buffer(&self, offset: u64, len: usize) -> Result<DataBuffer> {
1476        let read_buffer = unsafe { BNReadViewBuffer(self.as_ref().handle, offset, len) };
1477        if read_buffer.is_null() {
1478            Err(())
1479        } else {
1480            Ok(DataBuffer::from_raw(read_buffer))
1481        }
1482    }
1483
1484    fn debug_info(&self) -> Ref<DebugInfo> {
1485        unsafe { DebugInfo::ref_from_raw(BNGetDebugInfo(self.as_ref().handle)) }
1486    }
1487
1488    fn set_debug_info(&self, debug_info: &DebugInfo) {
1489        unsafe { BNSetDebugInfo(self.as_ref().handle, debug_info.handle) }
1490    }
1491
1492    fn apply_debug_info(&self, debug_info: &DebugInfo) {
1493        unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) }
1494    }
1495
1496    fn show_plaintext_report(&self, title: &str, plaintext: &str) {
1497        let title = title.to_cstr();
1498        let plaintext = plaintext.to_cstr();
1499        unsafe {
1500            BNShowPlainTextReport(
1501                self.as_ref().handle,
1502                title.as_ref().as_ptr() as *mut _,
1503                plaintext.as_ref().as_ptr() as *mut _,
1504            )
1505        }
1506    }
1507
1508    fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) {
1509        let title = title.to_cstr();
1510        let contents = contents.to_cstr();
1511        let plaintext = plaintext.to_cstr();
1512        unsafe {
1513            BNShowMarkdownReport(
1514                self.as_ref().handle,
1515                title.as_ref().as_ptr() as *mut _,
1516                contents.as_ref().as_ptr() as *mut _,
1517                plaintext.as_ref().as_ptr() as *mut _,
1518            )
1519        }
1520    }
1521
1522    fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) {
1523        let title = title.to_cstr();
1524        let contents = contents.to_cstr();
1525        let plaintext = plaintext.to_cstr();
1526        unsafe {
1527            BNShowHTMLReport(
1528                self.as_ref().handle,
1529                title.as_ref().as_ptr() as *mut _,
1530                contents.as_ref().as_ptr() as *mut _,
1531                plaintext.as_ref().as_ptr() as *mut _,
1532            )
1533        }
1534    }
1535
1536    fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) {
1537        let raw_name = raw_name.to_cstr();
1538        unsafe {
1539            BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle);
1540        }
1541    }
1542
1543    fn load_settings(&self, view_type_name: &str) -> Result<Ref<Settings>> {
1544        let view_type_name = view_type_name.to_cstr();
1545        let settings_handle =
1546            unsafe { BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_ptr()) };
1547
1548        if settings_handle.is_null() {
1549            Err(())
1550        } else {
1551            Ok(unsafe { Settings::ref_from_raw(settings_handle) })
1552        }
1553    }
1554
1555    fn set_load_settings(&self, view_type_name: &str, settings: &Settings) {
1556        let view_type_name = view_type_name.to_cstr();
1557
1558        unsafe {
1559            BNBinaryViewSetLoadSettings(
1560                self.as_ref().handle,
1561                view_type_name.as_ptr(),
1562                settings.handle,
1563            )
1564        };
1565    }
1566
1567    /// Creates a new [TagType] and adds it to the view.
1568    ///
1569    /// # Arguments
1570    /// * `name` - the name for the tag
1571    /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag
1572    fn create_tag_type(&self, name: &str, icon: &str) -> Ref<TagType> {
1573        let tag_type = TagType::create(self.as_ref(), name, icon);
1574        unsafe {
1575            BNAddTagType(self.as_ref().handle, tag_type.handle);
1576        }
1577        tag_type
1578    }
1579
1580    /// Removes a [TagType] and all tags that use it
1581    fn remove_tag_type(&self, tag_type: &TagType) {
1582        unsafe { BNRemoveTagType(self.as_ref().handle, tag_type.handle) }
1583    }
1584
1585    /// Get a tag type by its name.
1586    fn tag_type_by_name(&self, name: &str) -> Option<Ref<TagType>> {
1587        let name = name.to_cstr();
1588        unsafe {
1589            let handle = BNGetTagType(self.as_ref().handle, name.as_ptr());
1590            if handle.is_null() {
1591                return None;
1592            }
1593            Some(TagType::ref_from_raw(handle))
1594        }
1595    }
1596
1597    /// Get a tag by its id.
1598    ///
1599    /// Note this does not tell you anything about where it is used.
1600    fn tag_by_id(&self, id: &str) -> Option<Ref<Tag>> {
1601        let id = id.to_cstr();
1602        unsafe {
1603            let handle = BNGetTag(self.as_ref().handle, id.as_ptr());
1604            if handle.is_null() {
1605                return None;
1606            }
1607            Some(Tag::ref_from_raw(handle))
1608        }
1609    }
1610
1611    /// Creates and adds a tag to an address
1612    ///
1613    /// User tag creations will be added to the undo buffer
1614    fn add_tag(&self, addr: u64, t: &TagType, data: &str, user: bool) {
1615        let tag = Tag::new(t, data);
1616
1617        unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) }
1618
1619        if user {
1620            unsafe { BNAddUserDataTag(self.as_ref().handle, addr, tag.handle) }
1621        } else {
1622            unsafe { BNAddAutoDataTag(self.as_ref().handle, addr, tag.handle) }
1623        }
1624    }
1625
1626    /// removes a Tag object at a data address.
1627    fn remove_auto_data_tag(&self, addr: u64, tag: &Tag) {
1628        unsafe { BNRemoveAutoDataTag(self.as_ref().handle, addr, tag.handle) }
1629    }
1630
1631    /// removes a Tag object at a data address.
1632    /// Since this removes a user tag, it will be added to the current undo buffer.
1633    fn remove_user_data_tag(&self, addr: u64, tag: &Tag) {
1634        unsafe { BNRemoveUserDataTag(self.as_ref().handle, addr, tag.handle) }
1635    }
1636
1637    fn comment_at(&self, addr: u64) -> Option<String> {
1638        unsafe {
1639            let comment_raw = BNGetGlobalCommentForAddress(self.as_ref().handle, addr);
1640            match comment_raw.is_null() {
1641                false => Some(BnString::into_string(comment_raw)),
1642                true => None,
1643            }
1644        }
1645    }
1646
1647    /// Sets a comment for the [`BinaryView`] at the address specified.
1648    ///
1649    /// NOTE: This is different from setting a comment at the function-level. To set a comment in a
1650    /// function use [`Function::set_comment_at`]
1651    fn set_comment_at(&self, addr: u64, comment: &str) {
1652        let comment_raw = comment.to_cstr();
1653        unsafe { BNSetGlobalCommentForAddress(self.as_ref().handle, addr, comment_raw.as_ptr()) }
1654    }
1655
1656    /// Retrieves a list of the next disassembly lines.
1657    ///
1658    /// Retrieves an [`Array`] over [`LinearDisassemblyLine`] objects for the
1659    /// next disassembly lines, and updates the [`LinearViewCursor`] passed in. This function can be called
1660    /// repeatedly to get more lines of linear disassembly.
1661    ///
1662    /// # Arguments
1663    /// * `pos` - Position to retrieve linear disassembly lines from
1664    fn get_next_linear_disassembly_lines(
1665        &self,
1666        pos: &mut LinearViewCursor,
1667    ) -> Array<LinearDisassemblyLine> {
1668        let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
1669
1670        while result.is_empty() {
1671            result = pos.lines();
1672            if !pos.next() {
1673                return result;
1674            }
1675        }
1676
1677        result
1678    }
1679
1680    /// Retrieves a list of the previous disassembly lines.
1681    ///
1682    /// `get_previous_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
1683    /// previous disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called
1684    /// repeatedly to get more lines of linear disassembly.
1685    ///
1686    /// # Arguments
1687    /// * `pos` - Position to retrieve linear disassembly lines relative to
1688    fn get_previous_linear_disassembly_lines(
1689        &self,
1690        pos: &mut LinearViewCursor,
1691    ) -> Array<LinearDisassemblyLine> {
1692        let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
1693        while result.is_empty() {
1694            if !pos.previous() {
1695                return result;
1696            }
1697
1698            result = pos.lines();
1699        }
1700
1701        result
1702    }
1703
1704    fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
1705        let key = key.to_cstr();
1706        let value: *mut BNMetadata =
1707            unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_ptr()) };
1708        if value.is_null() {
1709            None
1710        } else {
1711            Some(unsafe { Metadata::ref_from_raw(value) })
1712        }
1713    }
1714
1715    fn get_metadata<T>(&self, key: &str) -> Option<Result<T>>
1716    where
1717        T: for<'a> TryFrom<&'a Metadata>,
1718    {
1719        self.query_metadata(key)
1720            .map(|md| T::try_from(md.as_ref()).map_err(|_| ()))
1721    }
1722
1723    fn store_metadata<V>(&self, key: &str, value: V, is_auto: bool)
1724    where
1725        V: Into<Ref<Metadata>>,
1726    {
1727        let md = value.into();
1728        let key = key.to_cstr();
1729        unsafe {
1730            BNBinaryViewStoreMetadata(
1731                self.as_ref().handle,
1732                key.as_ptr(),
1733                md.as_ref().handle,
1734                is_auto,
1735            )
1736        };
1737    }
1738
1739    fn remove_metadata(&self, key: &str) {
1740        let key = key.to_cstr();
1741        unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) };
1742    }
1743
1744    /// Retrieves a list of [CodeReference]s pointing to a given address.
1745    fn code_refs_to_addr(&self, addr: u64) -> Array<CodeReference> {
1746        unsafe {
1747            let mut count = 0;
1748            let handle = BNGetCodeReferences(self.as_ref().handle, addr, &mut count, false, 0);
1749            Array::new(handle, count, ())
1750        }
1751    }
1752
1753    /// Retrieves a list of [CodeReference]s pointing into a given [Range].
1754    fn code_refs_into_range(&self, range: Range<u64>) -> Array<CodeReference> {
1755        unsafe {
1756            let mut count = 0;
1757            let handle = BNGetCodeReferencesInRange(
1758                self.as_ref().handle,
1759                range.start,
1760                range.end - range.start,
1761                &mut count,
1762                false,
1763                0,
1764            );
1765            Array::new(handle, count, ())
1766        }
1767    }
1768
1769    /// Retrieves a list of addresses pointed to by a given address.
1770    fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec<u64> {
1771        unsafe {
1772            let mut count = 0;
1773            let code_ref =
1774                CodeReference::new(addr, func.map(|f| f.to_owned()), func.map(|f| f.arch()));
1775            let mut raw_code_ref = CodeReference::into_owned_raw(&code_ref);
1776            let addresses =
1777                BNGetCodeReferencesFrom(self.as_ref().handle, &mut raw_code_ref, &mut count);
1778            let res = std::slice::from_raw_parts(addresses, count).to_vec();
1779            BNFreeAddressList(addresses);
1780            res
1781        }
1782    }
1783
1784    /// Retrieves a list of [DataReference]s pointing to a given address.
1785    fn data_refs_to_addr(&self, addr: u64) -> Array<DataReference> {
1786        unsafe {
1787            let mut count = 0;
1788            let handle = BNGetDataReferences(self.as_ref().handle, addr, &mut count, false, 0);
1789            Array::new(handle, count, ())
1790        }
1791    }
1792
1793    /// Retrieves a list of [DataReference]s pointing into a given [Range].
1794    fn data_refs_into_range(&self, range: Range<u64>) -> Array<DataReference> {
1795        unsafe {
1796            let mut count = 0;
1797            let handle = BNGetDataReferencesInRange(
1798                self.as_ref().handle,
1799                range.start,
1800                range.end - range.start,
1801                &mut count,
1802                false,
1803                0,
1804            );
1805            Array::new(handle, count, ())
1806        }
1807    }
1808
1809    /// Retrieves a list of [DataReference]s originating from a given address.
1810    fn data_refs_from_addr(&self, addr: u64) -> Array<DataReference> {
1811        unsafe {
1812            let mut count = 0;
1813            let handle = BNGetDataReferencesFrom(self.as_ref().handle, addr, &mut count);
1814            Array::new(handle, count, ())
1815        }
1816    }
1817
1818    /// Retrieves a list of [CodeReference]s for locations in code that use a given named type.
1819    fn code_refs_using_type_name<T: Into<QualifiedName>>(&self, name: T) -> Array<CodeReference> {
1820        let mut raw_name = QualifiedName::into_raw(name.into());
1821        unsafe {
1822            let mut count = 0;
1823            let handle = BNGetCodeReferencesForType(
1824                self.as_ref().handle,
1825                &mut raw_name,
1826                &mut count,
1827                false,
1828                0,
1829            );
1830            QualifiedName::free_raw(raw_name);
1831            Array::new(handle, count, ())
1832        }
1833    }
1834
1835    /// Retrieves a list of [DataReference]s for locations in data that use a given named type.
1836    fn data_refs_using_type_name<T: Into<QualifiedName>>(&self, name: T) -> Array<DataReference> {
1837        let mut raw_name = QualifiedName::into_raw(name.into());
1838        unsafe {
1839            let mut count = 0;
1840            let handle = BNGetDataReferencesForType(
1841                self.as_ref().handle,
1842                &mut raw_name,
1843                &mut count,
1844                false,
1845                0,
1846            );
1847            QualifiedName::free_raw(raw_name);
1848            Array::new(handle, count, ())
1849        }
1850    }
1851
1852    fn relocations_at(&self, addr: u64) -> Array<Relocation> {
1853        unsafe {
1854            let mut count = 0;
1855            let handle = BNGetRelocationsAt(self.as_ref().handle, addr, &mut count);
1856            Array::new(handle, count, ())
1857        }
1858    }
1859
1860    fn relocation_ranges(&self) -> Vec<Range<u64>> {
1861        let ranges = unsafe {
1862            let mut count = 0;
1863            let reloc_ranges_ptr = BNGetRelocationRanges(self.as_ref().handle, &mut count);
1864            let ranges = std::slice::from_raw_parts(reloc_ranges_ptr, count).to_vec();
1865            BNFreeRelocationRanges(reloc_ranges_ptr);
1866            ranges
1867        };
1868
1869        // TODO: impl From BNRange for Range?
1870        ranges
1871            .iter()
1872            .map(|range| Range {
1873                start: range.start,
1874                end: range.end,
1875            })
1876            .collect()
1877    }
1878
1879    fn component_by_guid(&self, guid: &str) -> Option<Ref<Component>> {
1880        let name = guid.to_cstr();
1881        let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, name.as_ptr()) };
1882        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
1883    }
1884
1885    fn root_component(&self) -> Option<Ref<Component>> {
1886        let result = unsafe { BNGetRootComponent(self.as_ref().handle) };
1887        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
1888    }
1889
1890    fn component_by_path(&self, path: &str) -> Option<Ref<Component>> {
1891        let path = path.to_cstr();
1892        let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_ptr()) };
1893        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
1894    }
1895
1896    fn remove_component(&self, component: &Component) -> bool {
1897        unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) }
1898    }
1899
1900    fn remove_component_by_guid(&self, guid: &str) -> bool {
1901        let path = guid.to_cstr();
1902        unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) }
1903    }
1904
1905    fn data_variable_parent_components(&self, data_variable: &DataVariable) -> Array<Component> {
1906        let mut count = 0;
1907        let result = unsafe {
1908            BNGetDataVariableParentComponents(
1909                self.as_ref().handle,
1910                data_variable.address,
1911                &mut count,
1912            )
1913        };
1914        unsafe { Array::new(result, count, ()) }
1915    }
1916
1917    fn external_libraries(&self) -> Array<ExternalLibrary> {
1918        let mut count = 0;
1919        let result = unsafe { BNBinaryViewGetExternalLibraries(self.as_ref().handle, &mut count) };
1920        unsafe { Array::new(result, count, ()) }
1921    }
1922
1923    fn external_library(&self, name: &str) -> Option<Ref<ExternalLibrary>> {
1924        let name_ptr = name.to_cstr();
1925        let result =
1926            unsafe { BNBinaryViewGetExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) };
1927        let result_ptr = NonNull::new(result)?;
1928        Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) })
1929    }
1930
1931    fn remove_external_library(&self, name: &str) {
1932        let name_ptr = name.to_cstr();
1933        unsafe { BNBinaryViewRemoveExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) };
1934    }
1935
1936    fn add_external_library(
1937        &self,
1938        name: &str,
1939        backing_file: Option<&ProjectFile>,
1940        auto: bool,
1941    ) -> Option<Ref<ExternalLibrary>> {
1942        let name_ptr = name.to_cstr();
1943        let result = unsafe {
1944            BNBinaryViewAddExternalLibrary(
1945                self.as_ref().handle,
1946                name_ptr.as_ptr(),
1947                backing_file
1948                    .map(|b| b.handle.as_ptr())
1949                    .unwrap_or(std::ptr::null_mut()),
1950                auto,
1951            )
1952        };
1953        NonNull::new(result).map(|h| unsafe { ExternalLibrary::ref_from_raw(h) })
1954    }
1955
1956    fn external_locations(&self) -> Array<ExternalLocation> {
1957        let mut count = 0;
1958        let result = unsafe { BNBinaryViewGetExternalLocations(self.as_ref().handle, &mut count) };
1959        unsafe { Array::new(result, count, ()) }
1960    }
1961
1962    fn external_location_from_symbol(&self, symbol: &Symbol) -> Option<Ref<ExternalLocation>> {
1963        let result =
1964            unsafe { BNBinaryViewGetExternalLocation(self.as_ref().handle, symbol.handle) };
1965        let result_ptr = NonNull::new(result)?;
1966        Some(unsafe { ExternalLocation::ref_from_raw(result_ptr) })
1967    }
1968
1969    fn remove_external_location(&self, location: &ExternalLocation) {
1970        self.remove_external_location_from_symbol(&location.source_symbol())
1971    }
1972
1973    fn remove_external_location_from_symbol(&self, symbol: &Symbol) {
1974        unsafe { BNBinaryViewRemoveExternalLocation(self.as_ref().handle, symbol.handle) };
1975    }
1976
1977    // TODO: This is awful, rewrite this.
1978    fn add_external_location(
1979        &self,
1980        symbol: &Symbol,
1981        library: &ExternalLibrary,
1982        target_symbol_name: &str,
1983        target_address: Option<u64>,
1984        target_is_auto: bool,
1985    ) -> Option<Ref<ExternalLocation>> {
1986        let target_symbol_name = target_symbol_name.to_cstr();
1987        let target_address_ptr = target_address
1988            .map(|a| a as *mut u64)
1989            .unwrap_or(std::ptr::null_mut());
1990        let result = unsafe {
1991            BNBinaryViewAddExternalLocation(
1992                self.as_ref().handle,
1993                symbol.handle,
1994                library.handle.as_ptr(),
1995                target_symbol_name.as_ptr(),
1996                target_address_ptr,
1997                target_is_auto,
1998            )
1999        };
2000        NonNull::new(result).map(|h| unsafe { ExternalLocation::ref_from_raw(h) })
2001    }
2002
2003    /// Type container for all types (user and auto) in the Binary View.
2004    ///
2005    /// NOTE: Modifying an auto type will promote it to a user type.
2006    fn type_container(&self) -> TypeContainer {
2007        let type_container_ptr =
2008            NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.as_ref().handle) });
2009        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2010        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2011    }
2012
2013    /// Type container for user types in the Binary View.
2014    fn user_type_container(&self) -> TypeContainer {
2015        let type_container_ptr =
2016            NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.as_ref().handle) });
2017        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2018        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }.clone()
2019    }
2020
2021    /// Type container for auto types in the Binary View.
2022    ///
2023    /// NOTE: Unlike [`Self::type_container`] modification of auto types will **NOT** promote it to a user type.
2024    fn auto_type_container(&self) -> TypeContainer {
2025        let type_container_ptr =
2026            NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.as_ref().handle) });
2027        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2028        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2029    }
2030
2031    /// Make the contents of a type library available for type/import resolution
2032    fn add_type_library(&self, library: &TypeLibrary) {
2033        unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) }
2034    }
2035
2036    fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
2037        let name = name.to_cstr();
2038        let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) };
2039        NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
2040    }
2041
2042    /// Should be called by custom py:py:class:`BinaryView` implementations
2043    /// when they have successfully imported an object from a type library (eg a symbol's type).
2044    /// Values recorded with this function will then be queryable via [BinaryViewExt::lookup_imported_object_library].
2045    ///
2046    /// * `lib` - Type Library containing the imported type
2047    /// * `name` - Name of the object in the type library
2048    /// * `addr` - address of symbol at import site
2049    /// * `platform` - Platform of symbol at import site
2050    fn record_imported_object_library<T: Into<QualifiedName>>(
2051        &self,
2052        lib: &TypeLibrary,
2053        name: T,
2054        addr: u64,
2055        platform: &Platform,
2056    ) {
2057        let mut raw_name = QualifiedName::into_raw(name.into());
2058        unsafe {
2059            BNBinaryViewRecordImportedObjectLibrary(
2060                self.as_ref().handle,
2061                platform.handle,
2062                addr,
2063                lib.as_raw(),
2064                &mut raw_name,
2065            )
2066        }
2067        QualifiedName::free_raw(raw_name);
2068    }
2069
2070    /// Recursively imports a type from the specified type library, or, if
2071    /// no library was explicitly provided, the first type library associated with the current [BinaryView]
2072    /// that provides the name requested.
2073    ///
2074    /// This may have the impact of loading other type libraries as dependencies on other type libraries are lazily resolved
2075    /// when references to types provided by them are first encountered.
2076    ///
2077    /// Note that the name actually inserted into the view may not match the name as it exists in the type library in
2078    /// the event of a name conflict. To aid in this, the [Type] object returned is a `NamedTypeReference` to
2079    /// the deconflicted name used.
2080    fn import_type_library<T: Into<QualifiedName>>(
2081        &self,
2082        name: T,
2083        mut lib: Option<TypeLibrary>,
2084    ) -> Option<Ref<Type>> {
2085        let mut lib_ref = lib
2086            .as_mut()
2087            .map(|l| unsafe { l.as_raw() } as *mut _)
2088            .unwrap_or(std::ptr::null_mut());
2089        let mut raw_name = QualifiedName::into_raw(name.into());
2090        let result = unsafe {
2091            BNBinaryViewImportTypeLibraryType(self.as_ref().handle, &mut lib_ref, &mut raw_name)
2092        };
2093        QualifiedName::free_raw(raw_name);
2094        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2095    }
2096
2097    /// Recursively imports an object from the specified type library, or, if
2098    /// no library was explicitly provided, the first type library associated with the current [BinaryView]
2099    /// that provides the name requested.
2100    ///
2101    /// This may have the impact of loading other type libraries as dependencies on other type libraries are lazily resolved
2102    /// when references to types provided by them are first encountered.
2103    ///
2104    /// .. note:: If you are implementing a custom BinaryView and use this method to import object types,
2105    /// you should then call [BinaryViewExt::record_imported_object_library] with the details of where the object is located.
2106    fn import_type_object<T: Into<QualifiedName>>(
2107        &self,
2108        name: T,
2109        mut lib: Option<TypeLibrary>,
2110    ) -> Option<Ref<Type>> {
2111        let mut lib_ref = lib
2112            .as_mut()
2113            .map(|l| unsafe { l.as_raw() } as *mut _)
2114            .unwrap_or(std::ptr::null_mut());
2115        let mut raw_name = QualifiedName::into_raw(name.into());
2116        let result = unsafe {
2117            BNBinaryViewImportTypeLibraryObject(self.as_ref().handle, &mut lib_ref, &mut raw_name)
2118        };
2119        QualifiedName::free_raw(raw_name);
2120        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2121    }
2122
2123    /// Recursively imports a type interface given its GUID.
2124    fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> {
2125        let guid = guid.to_cstr();
2126        let result =
2127            unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) };
2128        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2129    }
2130
2131    /// Recursively exports `type_obj` into `lib` as a type with name `name`
2132    ///
2133    /// As other referenced types are encountered, they are either copied into the destination type library or
2134    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2135    fn export_type_to_library<T: Into<QualifiedName>>(
2136        &self,
2137        lib: &TypeLibrary,
2138        name: T,
2139        type_obj: &Type,
2140    ) {
2141        let mut raw_name = QualifiedName::into_raw(name.into());
2142        unsafe {
2143            BNBinaryViewExportTypeToTypeLibrary(
2144                self.as_ref().handle,
2145                lib.as_raw(),
2146                &mut raw_name,
2147                type_obj.handle,
2148            )
2149        }
2150        QualifiedName::free_raw(raw_name);
2151    }
2152
2153    /// Recursively exports `type_obj` into `lib` as a type with name `name`
2154    ///
2155    /// As other referenced types are encountered, they are either copied into the destination type library or
2156    ///     else the type library that provided the referenced type is added as a dependency for the destination library.
2157    fn export_object_to_library<T: Into<QualifiedName>>(
2158        &self,
2159        lib: &TypeLibrary,
2160        name: T,
2161        type_obj: &Type,
2162    ) {
2163        let mut raw_name = QualifiedName::into_raw(name.into());
2164        unsafe {
2165            BNBinaryViewExportObjectToTypeLibrary(
2166                self.as_ref().handle,
2167                lib.as_raw(),
2168                &mut raw_name,
2169                type_obj.handle,
2170            )
2171        }
2172        QualifiedName::free_raw(raw_name);
2173    }
2174
2175    /// Gives you details of which type library and name was used to determine
2176    /// the type of a symbol at a given address
2177    ///
2178    /// * `addr` - address of symbol at import site
2179    /// * `platform` - Platform of symbol at import site
2180    fn lookup_imported_object_library(
2181        &self,
2182        addr: u64,
2183        platform: &Platform,
2184    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2185        let mut result_lib = std::ptr::null_mut();
2186        let mut result_name = BNQualifiedName::default();
2187        let success = unsafe {
2188            BNBinaryViewLookupImportedObjectLibrary(
2189                self.as_ref().handle,
2190                platform.handle,
2191                addr,
2192                &mut result_lib,
2193                &mut result_name,
2194            )
2195        };
2196        if !success {
2197            return None;
2198        }
2199        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2200        let name = QualifiedName::from_owned_raw(result_name);
2201        Some((lib, name))
2202    }
2203
2204    /// Gives you details of from which type library and name a given type in the analysis was imported.
2205    ///
2206    /// * `name` - Name of type in analysis
2207    fn lookup_imported_type_library<T: Into<QualifiedName>>(
2208        &self,
2209        name: T,
2210    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2211        let raw_name = QualifiedName::into_raw(name.into());
2212        let mut result_lib = std::ptr::null_mut();
2213        let mut result_name = BNQualifiedName::default();
2214        let success = unsafe {
2215            BNBinaryViewLookupImportedTypeLibrary(
2216                self.as_ref().handle,
2217                &raw_name,
2218                &mut result_lib,
2219                &mut result_name,
2220            )
2221        };
2222        QualifiedName::free_raw(raw_name);
2223        if !success {
2224            return None;
2225        }
2226        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2227        let name = QualifiedName::from_owned_raw(result_name);
2228        Some((lib, name))
2229    }
2230
2231    /// Retrieve all known strings in the binary.
2232    ///
2233    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2234    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2235    /// data and convert it to a representable form.
2236    fn strings(&self) -> Array<StringReference> {
2237        unsafe {
2238            let mut count = 0;
2239            let strings = BNGetStrings(self.as_ref().handle, &mut count);
2240            Array::new(strings, count, ())
2241        }
2242    }
2243
2244    fn string_at(&self, addr: u64) -> Option<BNStringReference> {
2245        let mut str_ref = BNStringReference::default();
2246        let success = unsafe { BNGetStringAtAddress(self.as_ref().handle, addr, &mut str_ref) };
2247
2248        if success {
2249            Some(str_ref)
2250        } else {
2251            None
2252        }
2253    }
2254
2255    /// Retrieve all known strings within the provided `range`.
2256    ///
2257    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2258    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2259    /// data and convert it to a representable form.
2260    fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> {
2261        unsafe {
2262            let mut count = 0;
2263            let strings = BNGetStringsInRange(
2264                self.as_ref().handle,
2265                range.start,
2266                range.end - range.start,
2267                &mut count,
2268            );
2269            Array::new(strings, count, ())
2270        }
2271    }
2272
2273    //
2274    // fn type_archives(&self) -> Array<TypeArchive> {
2275    //     let mut ids: *mut *mut c_char = std::ptr::null_mut();
2276    //     let mut paths: *mut *mut c_char = std::ptr::null_mut();
2277    //     let count = unsafe { BNBinaryViewGetTypeArchives(self.as_ref().handle, &mut ids, &mut paths) };
2278    //     let path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
2279    //     let ids_list = unsafe { std::slice::from_raw_parts(ids, count).to_vec() };
2280    //     let archives = ids_list.iter().filter_map(|id| {
2281    //         let archive_raw = unsafe { BNBinaryViewGetTypeArchive(self.as_ref().handle, *id) };
2282    //         match archive_raw.is_null() {
2283    //             true => None,
2284    //             false => Some(archive_raw)
2285    //         }
2286    //     }).collect();
2287    //     unsafe { BNFreeStringList(ids, count) };
2288    //     Array::new(archives)
2289    // }
2290}
2291
2292impl<T: BinaryViewBase> BinaryViewExt for T {}
2293
2294/// # Cleaning up
2295///
2296/// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong
2297/// reference to one another, so to properly clean up/free the [`BinaryView`], you must manually close the
2298/// file using [`FileMetadata::close`], this is not fixable in the general case, until [`FileMetadata`]
2299/// has only a weak reference to the [`BinaryView`].
2300#[derive(PartialEq, Eq, Hash)]
2301pub struct BinaryView {
2302    pub handle: *mut BNBinaryView,
2303}
2304
2305impl BinaryView {
2306    pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self {
2307        debug_assert!(!handle.is_null());
2308        Self { handle }
2309    }
2310
2311    pub(crate) unsafe fn ref_from_raw(handle: *mut BNBinaryView) -> Ref<Self> {
2312        debug_assert!(!handle.is_null());
2313        Ref::new(Self { handle })
2314    }
2315
2316    pub fn from_path(meta: &mut FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>> {
2317        let file = file_path.as_ref().to_cstr();
2318        let handle =
2319            unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) };
2320
2321        if handle.is_null() {
2322            return Err(());
2323        }
2324
2325        unsafe { Ok(Ref::new(Self { handle })) }
2326    }
2327
2328    pub fn from_accessor<A: Accessor>(
2329        meta: &FileMetadata,
2330        file: &mut FileAccessor<A>,
2331    ) -> Result<Ref<Self>> {
2332        let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.raw) };
2333
2334        if handle.is_null() {
2335            return Err(());
2336        }
2337
2338        unsafe { Ok(Ref::new(Self { handle })) }
2339    }
2340
2341    pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Result<Ref<Self>> {
2342        let handle = unsafe {
2343            BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len())
2344        };
2345
2346        if handle.is_null() {
2347            return Err(());
2348        }
2349
2350        unsafe { Ok(Ref::new(Self { handle })) }
2351    }
2352
2353    /// Save the original binary file to the provided `file_path` along with any modifications.
2354    ///
2355    /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action
2356    /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we
2357    /// are executing in this function.
2358    ///
2359    /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
2360    /// are no queued up main thread actions.
2361    pub fn save_to_path(&self, file_path: impl AsRef<Path>) -> bool {
2362        let file = file_path.as_ref().to_cstr();
2363        unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) }
2364    }
2365
2366    /// Save the original binary file to the provided [`FileAccessor`] along with any modifications.
2367    ///
2368    /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action
2369    /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we
2370    /// are executing in this function.
2371    ///
2372    /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
2373    /// are no queued up main thread actions.
2374    pub fn save_to_accessor<A: Accessor>(&self, file: &mut FileAccessor<A>) -> bool {
2375        unsafe { BNSaveToFile(self.handle, &mut file.raw) }
2376    }
2377}
2378
2379impl BinaryViewBase for BinaryView {
2380    fn read(&self, buf: &mut [u8], offset: u64) -> usize {
2381        unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) }
2382    }
2383
2384    fn write(&self, offset: u64, data: &[u8]) -> usize {
2385        unsafe { BNWriteViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
2386    }
2387
2388    fn insert(&self, offset: u64, data: &[u8]) -> usize {
2389        unsafe { BNInsertViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
2390    }
2391
2392    fn remove(&self, offset: u64, len: usize) -> usize {
2393        unsafe { BNRemoveViewData(self.handle, offset, len as u64) }
2394    }
2395
2396    /// Check if the offset is valid for the current view.
2397    ///
2398    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_valid`].
2399    fn offset_valid(&self, offset: u64) -> bool {
2400        unsafe { BNIsValidOffset(self.handle, offset) }
2401    }
2402
2403    /// Check if the offset is readable for the current view.
2404    ///
2405    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_valid`].
2406    fn offset_readable(&self, offset: u64) -> bool {
2407        unsafe { BNIsOffsetReadable(self.handle, offset) }
2408    }
2409
2410    /// Check if the offset is writable for the current view.
2411    ///
2412    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_writable`].
2413    fn offset_writable(&self, offset: u64) -> bool {
2414        unsafe { BNIsOffsetWritable(self.handle, offset) }
2415    }
2416
2417    /// Check if the offset is executable for the current view.
2418    ///
2419    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_executable`].
2420    fn offset_executable(&self, offset: u64) -> bool {
2421        unsafe { BNIsOffsetExecutable(self.handle, offset) }
2422    }
2423
2424    /// Check if the offset is backed by the original file and not added after the fact.
2425    ///
2426    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_backed_by_file`].
2427    fn offset_backed_by_file(&self, offset: u64) -> bool {
2428        unsafe { BNIsOffsetBackedByFile(self.handle, offset) }
2429    }
2430
2431    /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all
2432    /// readable offsets in the view.
2433    ///
2434    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::next_valid_offset`].
2435    fn next_valid_offset_after(&self, offset: u64) -> u64 {
2436        unsafe { BNGetNextValidOffset(self.handle, offset) }
2437    }
2438
2439    fn modification_status(&self, offset: u64) -> ModificationStatus {
2440        unsafe { BNGetModification(self.handle, offset) }
2441    }
2442
2443    /// The lowest address in the view.
2444    ///
2445    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::start`].
2446    fn start(&self) -> u64 {
2447        unsafe { BNGetStartOffset(self.handle) }
2448    }
2449
2450    /// The length of the view, lowest to highest address.
2451    ///
2452    /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::length`].
2453    fn len(&self) -> u64 {
2454        unsafe { BNGetViewLength(self.handle) }
2455    }
2456
2457    fn executable(&self) -> bool {
2458        unsafe { BNIsExecutableView(self.handle) }
2459    }
2460
2461    fn relocatable(&self) -> bool {
2462        unsafe { BNIsRelocatable(self.handle) }
2463    }
2464
2465    fn entry_point(&self) -> u64 {
2466        unsafe { BNGetEntryPoint(self.handle) }
2467    }
2468
2469    fn default_endianness(&self) -> Endianness {
2470        unsafe { BNGetDefaultEndianness(self.handle) }
2471    }
2472
2473    fn address_size(&self) -> usize {
2474        unsafe { BNGetViewAddressSize(self.handle) }
2475    }
2476}
2477
2478unsafe impl RefCountable for BinaryView {
2479    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
2480        Ref::new(Self {
2481            handle: BNNewViewReference(handle.handle),
2482        })
2483    }
2484
2485    unsafe fn dec_ref(handle: &Self) {
2486        BNFreeBinaryView(handle.handle);
2487    }
2488}
2489
2490impl AsRef<BinaryView> for BinaryView {
2491    fn as_ref(&self) -> &Self {
2492        self
2493    }
2494}
2495
2496impl ToOwned for BinaryView {
2497    type Owned = Ref<Self>;
2498
2499    fn to_owned(&self) -> Self::Owned {
2500        unsafe { RefCountable::inc_ref(self) }
2501    }
2502}
2503
2504unsafe impl Send for BinaryView {}
2505unsafe impl Sync for BinaryView {}
2506
2507impl std::fmt::Debug for BinaryView {
2508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2509        f.debug_struct("BinaryView")
2510            .field("view_type", &self.view_type())
2511            .field("file", &self.file())
2512            .field("original_image_base", &self.original_image_base())
2513            .field("start", &self.start())
2514            .field("end", &self.end())
2515            .field("len", &self.len())
2516            .field("default_platform", &self.default_platform())
2517            .field("default_arch", &self.default_arch())
2518            .field("default_endianness", &self.default_endianness())
2519            .field("entry_point", &self.entry_point())
2520            .field(
2521                "entry_point_functions",
2522                &self.entry_point_functions().to_vec(),
2523            )
2524            .field("address_size", &self.address_size())
2525            .field("sections", &self.sections().to_vec())
2526            .field("segments", &self.segments().to_vec())
2527            .finish()
2528    }
2529}
2530
2531pub trait BinaryViewEventHandler: 'static + Sync {
2532    fn on_event(&self, binary_view: &BinaryView);
2533}
2534
2535/// Registers an event listener for binary view events.
2536///
2537/// # Example
2538///
2539/// ```no_run
2540/// use binaryninja::binary_view::{
2541///     register_binary_view_event, BinaryView, BinaryViewEventHandler, BinaryViewEventType,
2542/// };
2543///
2544/// struct EventHandlerContext {
2545///     // Context holding state available to event handler
2546/// }
2547///
2548/// impl BinaryViewEventHandler for EventHandlerContext {
2549///     fn on_event(&self, binary_view: &BinaryView) {
2550///         // handle event
2551///     }
2552/// }
2553///
2554/// #[no_mangle]
2555/// pub extern "C" fn CorePluginInit() {
2556///     let context = EventHandlerContext {};
2557///
2558///     register_binary_view_event(
2559///         BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent,
2560///         context,
2561///     );
2562/// }
2563/// ```
2564pub fn register_binary_view_event<Handler>(event_type: BinaryViewEventType, handler: Handler)
2565where
2566    Handler: BinaryViewEventHandler,
2567{
2568    unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
2569        ctx: *mut ::std::os::raw::c_void,
2570        view: *mut BNBinaryView,
2571    ) {
2572        ffi_wrap!("EventHandler::on_event", {
2573            let context = unsafe { &*(ctx as *const Handler) };
2574            context.on_event(&BinaryView::ref_from_raw(BNNewViewReference(view)));
2575        })
2576    }
2577
2578    let boxed = Box::new(handler);
2579    let raw = Box::into_raw(boxed);
2580
2581    unsafe {
2582        BNRegisterBinaryViewEvent(
2583            event_type,
2584            Some(on_event::<Handler>),
2585            raw as *mut ::std::os::raw::c_void,
2586        );
2587    }
2588}
2589
2590#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2591pub struct StringReference {
2592    pub ty: StringType,
2593    pub start: u64,
2594    pub length: usize,
2595}
2596
2597impl From<BNStringReference> for StringReference {
2598    fn from(raw: BNStringReference) -> Self {
2599        Self {
2600            ty: raw.type_,
2601            start: raw.start,
2602            length: raw.length,
2603        }
2604    }
2605}
2606
2607impl From<StringReference> for BNStringReference {
2608    fn from(raw: StringReference) -> Self {
2609        Self {
2610            type_: raw.ty,
2611            start: raw.start,
2612            length: raw.length,
2613        }
2614    }
2615}
2616
2617impl CoreArrayProvider for StringReference {
2618    type Raw = BNStringReference;
2619    type Context = ();
2620    type Wrapped<'a> = Self;
2621}
2622
2623unsafe impl CoreArrayProviderInner for StringReference {
2624    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2625        BNFreeStringReferenceList(raw)
2626    }
2627
2628    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2629        Self::from(*raw)
2630    }
2631}
2632
2633#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2634pub struct AddressRange {
2635    pub start: u64,
2636    pub end: u64,
2637}
2638
2639impl From<BNAddressRange> for AddressRange {
2640    fn from(raw: BNAddressRange) -> Self {
2641        Self {
2642            start: raw.start,
2643            end: raw.end,
2644        }
2645    }
2646}
2647
2648impl From<AddressRange> for BNAddressRange {
2649    fn from(raw: AddressRange) -> Self {
2650        Self {
2651            start: raw.start,
2652            end: raw.end,
2653        }
2654    }
2655}
2656
2657impl CoreArrayProvider for AddressRange {
2658    type Raw = BNAddressRange;
2659    type Context = ();
2660    type Wrapped<'a> = Self;
2661}
2662
2663unsafe impl CoreArrayProviderInner for AddressRange {
2664    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2665        BNFreeAddressRanges(raw);
2666    }
2667
2668    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2669        Self::from(*raw)
2670    }
2671}