binaryninja/
binary_view.rs

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