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 files analysis.
16
17use binaryninjacore_sys::*;
18
19// Used for documentation
20#[allow(unused)]
21pub use crate::workflow::AnalysisContext;
22
23use crate::architecture::{Architecture, CoreArchitecture};
24use crate::base_detection::BaseAddressDetection;
25use crate::basic_block::BasicBlock;
26use crate::binary_view::search::SearchQuery;
27use crate::component::Component;
28use crate::confidence::Conf;
29use crate::data_buffer::DataBuffer;
30use crate::debuginfo::DebugInfo;
31use crate::disassembly::DisassemblySettings;
32use crate::external_library::{ExternalLibrary, ExternalLocation};
33use crate::file_accessor::{Accessor, FileAccessor};
34use crate::file_metadata::FileMetadata;
35use crate::flowgraph::FlowGraph;
36use crate::function::{Function, FunctionViewType, Location, NativeBlock};
37use crate::linear_view::{LinearDisassemblyLine, LinearViewCursor};
38use crate::metadata::Metadata;
39use crate::platform::Platform;
40use crate::progress::{NoProgressCallback, ProgressCallback};
41use crate::project::file::ProjectFile;
42use crate::rc::*;
43use crate::references::{CodeReference, DataReference};
44use crate::relocation::Relocation;
45use crate::section::{Section, SectionBuilder};
46use crate::segment::{Segment, SegmentBuilder};
47use crate::settings::Settings;
48use crate::string::*;
49use crate::symbol::{Symbol, SymbolType};
50use crate::tags::{Tag, TagReference, TagType};
51use crate::types::{
52    NamedTypeReference, QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type,
53    TypeArchive, TypeArchiveId, TypeContainer, TypeLibrary,
54};
55use crate::variable::DataVariable;
56use crate::workflow::Workflow;
57use crate::{Endianness, BN_FULL_CONFIDENCE};
58use std::collections::{BTreeMap, HashMap};
59use std::ffi::{c_char, c_void, CString};
60use std::fmt::{Display, Formatter};
61use std::ops::Range;
62use std::path::{Path, PathBuf};
63use std::ptr::NonNull;
64use std::{result, slice};
65
66pub mod memory_map;
67pub mod reader;
68pub mod search;
69pub mod writer;
70
71pub use memory_map::{MemoryMap, MemoryRegionInfo, ResolvedRange};
72pub use reader::BinaryReader;
73pub use writer::BinaryWriter;
74
75pub type Result<R> = result::Result<R, ()>;
76pub type BinaryViewEventType = BNBinaryViewEventType;
77pub type AnalysisState = BNAnalysisState;
78pub type ModificationStatus = BNModificationStatus;
79pub type StringType = BNStringType;
80pub type FindFlag = BNFindFlag;
81
82#[allow(clippy::len_without_is_empty)]
83pub trait BinaryViewBase: AsRef<BinaryView> {
84    fn read(&self, _buf: &mut [u8], _offset: u64) -> usize {
85        0
86    }
87
88    fn write(&self, _offset: u64, _data: &[u8]) -> usize {
89        0
90    }
91
92    fn insert(&self, _offset: u64, _data: &[u8]) -> usize {
93        0
94    }
95
96    fn remove(&self, _offset: u64, _len: usize) -> usize {
97        0
98    }
99
100    /// Check if the offset is valid for the current view.
101    fn offset_valid(&self, offset: u64) -> bool {
102        let mut buf = [0u8; 1];
103
104        // don't use self.read so that if segments were used we
105        // check against those as well
106        self.as_ref().read(&mut buf[..], offset) == buf.len()
107    }
108
109    /// Check if the offset is readable for the current view.
110    fn offset_readable(&self, offset: u64) -> bool {
111        self.offset_valid(offset)
112    }
113
114    /// Check if the offset is writable for the current view.
115    fn offset_writable(&self, offset: u64) -> bool {
116        self.offset_valid(offset)
117    }
118
119    /// Check if the offset is executable for the current view.
120    fn offset_executable(&self, offset: u64) -> bool {
121        self.offset_valid(offset)
122    }
123
124    /// Check if the offset is backed by the original file and not added after the fact.
125    fn offset_backed_by_file(&self, offset: u64) -> bool {
126        self.offset_valid(offset)
127    }
128
129    /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all
130    /// readable offsets in the view.
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    /// Whether the data at the given `offset` been modified (patched).
142    fn modification_status(&self, _offset: u64) -> ModificationStatus {
143        ModificationStatus::Original
144    }
145
146    /// The lowest address in the view.
147    fn start(&self) -> u64 {
148        0
149    }
150
151    /// The length of the view.
152    fn len(&self) -> u64 {
153        0
154    }
155
156    fn executable(&self) -> bool {
157        true
158    }
159
160    fn relocatable(&self) -> bool {
161        true
162    }
163
164    fn entry_point(&self) -> u64;
165    fn default_endianness(&self) -> Endianness;
166    fn address_size(&self) -> usize;
167
168    fn save(&self) -> bool {
169        self.as_ref()
170            .parent_view()
171            .map(|view| view.save())
172            .unwrap_or(false)
173    }
174}
175
176#[derive(Debug, Clone)]
177pub struct ActiveAnalysisInfo {
178    pub func: Ref<Function>,
179    pub analysis_time: u64,
180    pub update_count: usize,
181    pub submit_count: usize,
182}
183
184#[derive(Debug, Clone)]
185pub struct AnalysisInfo {
186    pub state: AnalysisState,
187    pub analysis_time: u64,
188    pub active_info: Vec<ActiveAnalysisInfo>,
189}
190
191#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
192pub enum AnalysisProgress {
193    Initial,
194    Hold,
195    Idle,
196    Discovery,
197    Disassembling(usize, usize),
198    Analyzing(usize, usize),
199    ExtendedAnalysis,
200}
201
202impl Display for AnalysisProgress {
203    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
204        match self {
205            AnalysisProgress::Initial => {
206                write!(f, "Initial")
207            }
208            AnalysisProgress::Hold => {
209                write!(f, "Hold")
210            }
211            AnalysisProgress::Idle => {
212                write!(f, "Idle")
213            }
214            AnalysisProgress::Discovery => {
215                write!(f, "Discovery")
216            }
217            AnalysisProgress::Disassembling(count, total) => {
218                write!(f, "Disassembling ({count}/{total})")
219            }
220            AnalysisProgress::Analyzing(count, total) => {
221                write!(f, "Analyzing ({count}/{total})")
222            }
223            AnalysisProgress::ExtendedAnalysis => {
224                write!(f, "Extended Analysis")
225            }
226        }
227    }
228}
229
230impl From<BNAnalysisProgress> for AnalysisProgress {
231    fn from(value: BNAnalysisProgress) -> Self {
232        match value.state {
233            BNAnalysisState::InitialState => Self::Initial,
234            BNAnalysisState::HoldState => Self::Hold,
235            BNAnalysisState::IdleState => Self::Idle,
236            BNAnalysisState::DiscoveryState => Self::Discovery,
237            BNAnalysisState::DisassembleState => Self::Disassembling(value.count, value.total),
238            BNAnalysisState::AnalyzeState => Self::Analyzing(value.count, value.total),
239            BNAnalysisState::ExtendedAnalyzeState => Self::ExtendedAnalysis,
240        }
241    }
242}
243
244pub trait BinaryViewExt: BinaryViewBase {
245    fn file(&self) -> Ref<FileMetadata> {
246        unsafe {
247            let raw = BNGetFileForView(self.as_ref().handle);
248            FileMetadata::ref_from_raw(raw)
249        }
250    }
251
252    fn parent_view(&self) -> Option<Ref<BinaryView>> {
253        let raw_view_ptr = unsafe { BNGetParentView(self.as_ref().handle) };
254        match raw_view_ptr.is_null() {
255            false => Some(unsafe { BinaryView::ref_from_raw(raw_view_ptr) }),
256            true => None,
257        }
258    }
259
260    fn raw_view(&self) -> Option<Ref<BinaryView>> {
261        self.file().view_of_type("Raw")
262    }
263
264    fn view_type(&self) -> String {
265        let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) };
266        unsafe { BnString::into_string(ptr) }
267    }
268
269    /// Reads up to `len` bytes from address `offset`
270    fn read_vec(&self, offset: u64, len: usize) -> Vec<u8> {
271        let mut ret = vec![0; len];
272        let size = self.read(&mut ret, offset);
273        ret.truncate(size);
274        ret
275    }
276
277    /// Appends up to `len` bytes from address `offset` into `dest`
278    fn read_into_vec(&self, dest: &mut Vec<u8>, offset: u64, len: usize) -> usize {
279        let starting_len = dest.len();
280        dest.resize(starting_len + len, 0);
281        let read_size = self.read(&mut dest[starting_len..], offset);
282        dest.truncate(starting_len + read_size);
283        read_size
284    }
285
286    /// Reads up to `len` bytes from the address `offset` returning a `CString` if available.
287    fn read_c_string_at(&self, offset: u64, len: usize) -> Option<CString> {
288        let mut buf = vec![0; len];
289        let size = self.read(&mut buf, offset);
290        let string = CString::new(buf[..size].to_vec()).ok()?;
291        Some(string)
292    }
293
294    /// Reads up to `len` bytes from the address `offset` returning a `String` if available.
295    fn read_utf8_string_at(&self, offset: u64, len: usize) -> Option<String> {
296        let mut buf = vec![0; len];
297        let size = self.read(&mut buf, offset);
298        let string = String::from_utf8(buf[..size].to_vec()).ok()?;
299        Some(string)
300    }
301
302    /// Search the view using the query options.
303    ///
304    /// In the `on_match` callback return `false` to stop searching.
305    fn search<C: FnMut(u64, &DataBuffer) -> bool>(&self, query: &SearchQuery, on_match: C) -> bool {
306        self.search_with_progress(query, on_match, NoProgressCallback)
307    }
308
309    /// Search the view using the query options.
310    ///
311    /// In the `on_match` callback return `false` to stop searching.
312    fn search_with_progress<P: ProgressCallback, C: FnMut(u64, &DataBuffer) -> bool>(
313        &self,
314        query: &SearchQuery,
315        mut on_match: C,
316        mut progress: P,
317    ) -> bool {
318        unsafe extern "C" fn cb_on_match<C: FnMut(u64, &DataBuffer) -> bool>(
319            ctx: *mut c_void,
320            offset: u64,
321            data: *mut BNDataBuffer,
322        ) -> bool {
323            let f = ctx as *mut C;
324            let buffer = DataBuffer::from_raw(data);
325            (*f)(offset, &buffer)
326        }
327
328        let query = query.to_json().to_cstr();
329        unsafe {
330            BNSearch(
331                self.as_ref().handle,
332                query.as_ptr(),
333                &mut progress as *mut P as *mut c_void,
334                Some(P::cb_progress_callback),
335                &mut on_match as *const C as *mut c_void,
336                Some(cb_on_match::<C>),
337            )
338        }
339    }
340
341    fn find_next_data(&self, start: u64, end: u64, data: &DataBuffer) -> Option<u64> {
342        self.find_next_data_with_opts(
343            start,
344            end,
345            data,
346            FindFlag::FindCaseInsensitive,
347            NoProgressCallback,
348        )
349    }
350
351    /// # Warning
352    ///
353    /// This function is likely to be changed to take in a "query" structure. Or deprecated entirely.
354    fn find_next_data_with_opts<P: ProgressCallback>(
355        &self,
356        start: u64,
357        end: u64,
358        data: &DataBuffer,
359        flag: FindFlag,
360        mut progress: P,
361    ) -> Option<u64> {
362        let mut result: u64 = 0;
363        let found = unsafe {
364            BNFindNextDataWithProgress(
365                self.as_ref().handle,
366                start,
367                end,
368                data.as_raw(),
369                &mut result,
370                flag,
371                &mut progress as *mut P as *mut c_void,
372                Some(P::cb_progress_callback),
373            )
374        };
375
376        if found {
377            Some(result)
378        } else {
379            None
380        }
381    }
382
383    fn find_next_constant(
384        &self,
385        start: u64,
386        end: u64,
387        constant: u64,
388        view_type: FunctionViewType,
389    ) -> Option<u64> {
390        // TODO: What are the best "default" settings?
391        let settings = DisassemblySettings::new();
392        self.find_next_constant_with_opts(
393            start,
394            end,
395            constant,
396            &settings,
397            view_type,
398            NoProgressCallback,
399        )
400    }
401
402    /// # Warning
403    ///
404    /// This function is likely to be changed to take in a "query" structure.
405    fn find_next_constant_with_opts<P: ProgressCallback>(
406        &self,
407        start: u64,
408        end: u64,
409        constant: u64,
410        disasm_settings: &DisassemblySettings,
411        view_type: FunctionViewType,
412        mut progress: P,
413    ) -> Option<u64> {
414        let mut result: u64 = 0;
415        let raw_view_type = FunctionViewType::into_raw(view_type);
416        let found = unsafe {
417            BNFindNextConstantWithProgress(
418                self.as_ref().handle,
419                start,
420                end,
421                constant,
422                &mut result,
423                disasm_settings.handle,
424                raw_view_type,
425                &mut progress as *mut P as *mut c_void,
426                Some(P::cb_progress_callback),
427            )
428        };
429        FunctionViewType::free_raw(raw_view_type);
430
431        if found {
432            Some(result)
433        } else {
434            None
435        }
436    }
437
438    fn find_next_text(
439        &self,
440        start: u64,
441        end: u64,
442        text: &str,
443        view_type: FunctionViewType,
444    ) -> Option<u64> {
445        // TODO: What are the best "default" settings?
446        let settings = DisassemblySettings::new();
447        self.find_next_text_with_opts(
448            start,
449            end,
450            text,
451            &settings,
452            FindFlag::FindCaseInsensitive,
453            view_type,
454            NoProgressCallback,
455        )
456    }
457
458    /// # Warning
459    ///
460    /// This function is likely to be changed to take in a "query" structure.
461    fn find_next_text_with_opts<P: ProgressCallback>(
462        &self,
463        start: u64,
464        end: u64,
465        text: &str,
466        disasm_settings: &DisassemblySettings,
467        flag: FindFlag,
468        view_type: FunctionViewType,
469        mut progress: P,
470    ) -> Option<u64> {
471        let text = text.to_cstr();
472        let raw_view_type = FunctionViewType::into_raw(view_type);
473        let mut result: u64 = 0;
474        let found = unsafe {
475            BNFindNextTextWithProgress(
476                self.as_ref().handle,
477                start,
478                end,
479                text.as_ptr(),
480                &mut result,
481                disasm_settings.handle,
482                flag,
483                raw_view_type,
484                &mut progress as *mut P as *mut c_void,
485                Some(P::cb_progress_callback),
486            )
487        };
488        FunctionViewType::free_raw(raw_view_type);
489
490        if found {
491            Some(result)
492        } else {
493            None
494        }
495    }
496
497    fn notify_data_written(&self, offset: u64, len: usize) {
498        unsafe {
499            BNNotifyDataWritten(self.as_ref().handle, offset, len);
500        }
501    }
502
503    fn notify_data_inserted(&self, offset: u64, len: usize) {
504        unsafe {
505            BNNotifyDataInserted(self.as_ref().handle, offset, len);
506        }
507    }
508
509    fn notify_data_removed(&self, offset: u64, len: usize) {
510        unsafe {
511            BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64);
512        }
513    }
514
515    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
516    /// offset has code semantics.
517    fn offset_has_code_semantics(&self, offset: u64) -> bool {
518        unsafe { BNIsOffsetCodeSemantics(self.as_ref().handle, offset) }
519    }
520
521    /// Check if the offset is within a [`Section`] with [`crate::section::Semantics::External`].
522    fn offset_has_extern_semantics(&self, offset: u64) -> bool {
523        unsafe { BNIsOffsetExternSemantics(self.as_ref().handle, offset) }
524    }
525
526    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
527    /// offset has writable semantics.
528    fn offset_has_writable_semantics(&self, offset: u64) -> bool {
529        unsafe { BNIsOffsetWritableSemantics(self.as_ref().handle, offset) }
530    }
531
532    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
533    /// offset has read only semantics.
534    fn offset_has_read_only_semantics(&self, offset: u64) -> bool {
535        unsafe { BNIsOffsetReadOnlySemantics(self.as_ref().handle, offset) }
536    }
537
538    fn image_base(&self) -> u64 {
539        unsafe { BNGetImageBase(self.as_ref().handle) }
540    }
541
542    fn original_image_base(&self) -> u64 {
543        unsafe { BNGetOriginalImageBase(self.as_ref().handle) }
544    }
545
546    fn set_original_image_base(&self, image_base: u64) {
547        unsafe { BNSetOriginalImageBase(self.as_ref().handle, image_base) }
548    }
549
550    /// The highest address in the view.
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    fn type_libraries(&self) -> Array<TypeLibrary> {
2138        let mut count = 0;
2139        let result = unsafe { BNGetBinaryViewTypeLibraries(self.as_ref().handle, &mut count) };
2140        unsafe { Array::new(result, count, ()) }
2141    }
2142
2143    /// Make the contents of a type library available for type/import resolution
2144    fn add_type_library(&self, library: &TypeLibrary) {
2145        unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) }
2146    }
2147
2148    fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
2149        let name = name.to_cstr();
2150        let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) };
2151        NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
2152    }
2153
2154    /// Should be called by custom [`BinaryView`] implementations when they have successfully
2155    /// imported an object from a type library (eg a symbol's type). Values recorded with this
2156    /// function will then be queryable via [`BinaryViewExt::lookup_imported_object_library`].
2157    ///
2158    /// * `lib` - Type Library containing the imported type
2159    /// * `name` - Name of the object in the type library
2160    /// * `addr` - address of symbol at import site
2161    /// * `platform` - Platform of symbol at import site
2162    fn record_imported_object_library<T: Into<QualifiedName>>(
2163        &self,
2164        lib: &TypeLibrary,
2165        name: T,
2166        addr: u64,
2167        platform: &Platform,
2168    ) {
2169        let mut raw_name = QualifiedName::into_raw(name.into());
2170        unsafe {
2171            BNBinaryViewRecordImportedObjectLibrary(
2172                self.as_ref().handle,
2173                platform.handle,
2174                addr,
2175                lib.as_raw(),
2176                &mut raw_name,
2177            )
2178        }
2179        QualifiedName::free_raw(raw_name);
2180    }
2181
2182    /// Recursively imports a type from the specified type library, or, if no library was
2183    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2184    /// provides the name requested.
2185    ///
2186    /// This may have the impact of loading other type libraries as dependencies on other type
2187    /// libraries are lazily resolved when references to types provided by them are first encountered.
2188    ///
2189    /// Note that the name actually inserted into the view may not match the name as it exists in
2190    /// the type library in the event of a name conflict. To aid in this, the [`Type`] object
2191    /// returned is a `NamedTypeReference` to the deconflicted name used.
2192    fn import_type_library_type<T: Into<QualifiedName>>(
2193        &self,
2194        name: T,
2195        lib: Option<&TypeLibrary>,
2196    ) -> Option<Ref<Type>> {
2197        let mut lib_ref = lib
2198            .as_ref()
2199            .map(|l| unsafe { l.as_raw() } as *mut _)
2200            .unwrap_or(std::ptr::null_mut());
2201        let mut raw_name = QualifiedName::into_raw(name.into());
2202        let result = unsafe {
2203            BNBinaryViewImportTypeLibraryType(self.as_ref().handle, &mut lib_ref, &mut raw_name)
2204        };
2205        QualifiedName::free_raw(raw_name);
2206        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2207    }
2208
2209    /// Recursively imports an object (function) from the specified type library, or, if no library was
2210    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2211    /// provides the name requested.
2212    ///
2213    /// This may have the impact of loading other type libraries as dependencies on other type
2214    /// libraries are lazily resolved when references to types provided by them are first encountered.
2215    ///
2216    /// NOTE: If you are implementing a custom [`BinaryView`] and use this method to import object types,
2217    /// you should then call [BinaryViewExt::record_imported_object_library] with the details of
2218    /// where the object is located.
2219    fn import_type_library_object<T: Into<QualifiedName>>(
2220        &self,
2221        name: T,
2222        lib: Option<&TypeLibrary>,
2223    ) -> Option<Ref<Type>> {
2224        let mut lib_ref = lib
2225            .as_ref()
2226            .map(|l| unsafe { l.as_raw() } as *mut _)
2227            .unwrap_or(std::ptr::null_mut());
2228        let mut raw_name = QualifiedName::into_raw(name.into());
2229        let result = unsafe {
2230            BNBinaryViewImportTypeLibraryObject(self.as_ref().handle, &mut lib_ref, &mut raw_name)
2231        };
2232        QualifiedName::free_raw(raw_name);
2233        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2234    }
2235
2236    /// Recursively imports a [`Type`] given its GUID from available type libraries.
2237    fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> {
2238        let guid = guid.to_cstr();
2239        let result =
2240            unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) };
2241        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2242    }
2243
2244    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2245    ///
2246    /// As other referenced types are encountered, they are either copied into the destination type library or
2247    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2248    fn export_type_to_library<T: Into<QualifiedName>>(
2249        &self,
2250        lib: &TypeLibrary,
2251        name: T,
2252        type_obj: &Type,
2253    ) {
2254        let mut raw_name = QualifiedName::into_raw(name.into());
2255        unsafe {
2256            BNBinaryViewExportTypeToTypeLibrary(
2257                self.as_ref().handle,
2258                lib.as_raw(),
2259                &mut raw_name,
2260                type_obj.handle,
2261            )
2262        }
2263        QualifiedName::free_raw(raw_name);
2264    }
2265
2266    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2267    ///
2268    /// As other referenced types are encountered, they are either copied into the destination type library or
2269    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2270    fn export_object_to_library<T: Into<QualifiedName>>(
2271        &self,
2272        lib: &TypeLibrary,
2273        name: T,
2274        type_obj: &Type,
2275    ) {
2276        let mut raw_name = QualifiedName::into_raw(name.into());
2277        unsafe {
2278            BNBinaryViewExportObjectToTypeLibrary(
2279                self.as_ref().handle,
2280                lib.as_raw(),
2281                &mut raw_name,
2282                type_obj.handle,
2283            )
2284        }
2285        QualifiedName::free_raw(raw_name);
2286    }
2287
2288    /// Gives you details of which type library and name was used to determine
2289    /// the type of a symbol at a given address
2290    ///
2291    /// * `addr` - address of symbol at import site
2292    /// * `platform` - Platform of symbol at import site
2293    fn lookup_imported_object_library(
2294        &self,
2295        addr: u64,
2296        platform: &Platform,
2297    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2298        let mut result_lib = std::ptr::null_mut();
2299        let mut result_name = BNQualifiedName::default();
2300        let success = unsafe {
2301            BNBinaryViewLookupImportedObjectLibrary(
2302                self.as_ref().handle,
2303                platform.handle,
2304                addr,
2305                &mut result_lib,
2306                &mut result_name,
2307            )
2308        };
2309        if !success {
2310            return None;
2311        }
2312        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2313        let name = QualifiedName::from_owned_raw(result_name);
2314        Some((lib, name))
2315    }
2316
2317    /// Gives you details of from which type library and name a given type in the analysis was imported.
2318    ///
2319    /// * `name` - Name of type in analysis
2320    fn lookup_imported_type_library<T: Into<QualifiedName>>(
2321        &self,
2322        name: T,
2323    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2324        let raw_name = QualifiedName::into_raw(name.into());
2325        let mut result_lib = std::ptr::null_mut();
2326        let mut result_name = BNQualifiedName::default();
2327        let success = unsafe {
2328            BNBinaryViewLookupImportedTypeLibrary(
2329                self.as_ref().handle,
2330                &raw_name,
2331                &mut result_lib,
2332                &mut result_name,
2333            )
2334        };
2335        QualifiedName::free_raw(raw_name);
2336        if !success {
2337            return None;
2338        }
2339        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2340        let name = QualifiedName::from_owned_raw(result_name);
2341        Some((lib, name))
2342    }
2343
2344    /// Retrieve all known strings in the binary.
2345    ///
2346    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2347    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2348    /// data and convert it to a representable form.
2349    ///
2350    /// Some helpers for reading strings are available:
2351    ///
2352    /// - [`BinaryViewExt::read_c_string_at`]
2353    /// - [`BinaryViewExt::read_utf8_string_at`]
2354    ///
2355    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2356    /// and other settings.
2357    fn strings(&self) -> Array<StringReference> {
2358        unsafe {
2359            let mut count = 0;
2360            let strings = BNGetStrings(self.as_ref().handle, &mut count);
2361            Array::new(strings, count, ())
2362        }
2363    }
2364
2365    /// Retrieve the string that falls on a given virtual address.
2366    ///
2367    /// NOTE: This returns a [`StringReference`] and since strings may not be representable as a Rust
2368    /// [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2369    /// data and convert it to a representable form.
2370    ///
2371    /// Some helpers for reading strings are available:
2372    ///
2373    /// - [`BinaryViewExt::read_c_string_at`]
2374    /// - [`BinaryViewExt::read_utf8_string_at`]
2375    ///
2376    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2377    /// and other settings.
2378    fn string_at(&self, addr: u64) -> Option<StringReference> {
2379        let mut str_ref = BNStringReference::default();
2380        let success = unsafe { BNGetStringAtAddress(self.as_ref().handle, addr, &mut str_ref) };
2381        if success {
2382            Some(str_ref.into())
2383        } else {
2384            None
2385        }
2386    }
2387
2388    /// Retrieve all known strings within the provided `range`.
2389    ///
2390    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2391    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2392    /// data and convert it to a representable form.
2393    ///
2394    /// Some helpers for reading strings are available:
2395    ///
2396    /// - [`BinaryViewExt::read_c_string_at`]
2397    /// - [`BinaryViewExt::read_utf8_string_at`]
2398    ///
2399    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2400    /// and other settings.
2401    fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> {
2402        unsafe {
2403            let mut count = 0;
2404            let strings = BNGetStringsInRange(
2405                self.as_ref().handle,
2406                range.start,
2407                range.end - range.start,
2408                &mut count,
2409            );
2410            Array::new(strings, count, ())
2411        }
2412    }
2413
2414    /// Retrieve the attached type archives as their [`TypeArchiveId`].
2415    ///
2416    /// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryViewExt::type_archive_by_id`].
2417    fn attached_type_archives(&self) -> Vec<TypeArchiveId> {
2418        let mut ids: *mut *mut c_char = std::ptr::null_mut();
2419        let mut paths: *mut *mut c_char = std::ptr::null_mut();
2420        let count =
2421            unsafe { BNBinaryViewGetTypeArchives(self.as_ref().handle, &mut ids, &mut paths) };
2422        // We discard the path here, you can retrieve it later with [`BinaryViewExt::type_archive_path_by_id`],
2423        // this is so we can simplify the return type which will commonly just want to query through to the type
2424        // archive itself.
2425        let _path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
2426        let id_list = unsafe { Array::<BnString>::new(ids, count, ()) };
2427        id_list
2428            .into_iter()
2429            .map(|id| TypeArchiveId(id.to_string()))
2430            .collect()
2431    }
2432
2433    /// Look up a connected [`TypeArchive`] by its `id`.
2434    ///
2435    /// NOTE: A [`TypeArchive`] can be attached but not connected, returning `None`.
2436    fn type_archive_by_id(&self, id: &TypeArchiveId) -> Option<Ref<TypeArchive>> {
2437        let id = id.0.as_str().to_cstr();
2438        let result = unsafe { BNBinaryViewGetTypeArchive(self.as_ref().handle, id.as_ptr()) };
2439        let result_ptr = NonNull::new(result)?;
2440        Some(unsafe { TypeArchive::ref_from_raw(result_ptr) })
2441    }
2442
2443    /// Look up the path for an attached (but not necessarily connected) [`TypeArchive`] by its `id`.
2444    fn type_archive_path_by_id(&self, id: &TypeArchiveId) -> Option<PathBuf> {
2445        let id = id.0.as_str().to_cstr();
2446        let result = unsafe { BNBinaryViewGetTypeArchivePath(self.as_ref().handle, id.as_ptr()) };
2447        if result.is_null() {
2448            return None;
2449        }
2450        let path_str = unsafe { BnString::into_string(result) };
2451        Some(PathBuf::from(path_str))
2452    }
2453}
2454
2455impl<T: BinaryViewBase> BinaryViewExt for T {}
2456
2457/// Represents the "whole view" of the binary and its analysis.
2458///
2459/// Analysis information:
2460///
2461/// - [`BinaryViewExt::functions`]
2462/// - [`BinaryViewExt::data_variables`]
2463/// - [`BinaryViewExt::strings`]
2464///
2465/// Annotation information:
2466///
2467/// - [`BinaryViewExt::symbols`]
2468/// - [`BinaryViewExt::tags_all_scopes`]
2469/// - [`BinaryViewExt::comments`]
2470///
2471/// Data representation and binary information:
2472///
2473/// - [`BinaryViewExt::types`]
2474/// - [`BinaryViewExt::segments`]
2475/// - [`BinaryViewExt::sections`]
2476///
2477/// # Cleaning up
2478///
2479/// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong
2480/// reference to one another, so to properly clean up/free the [`BinaryView`], you must manually close the
2481/// file using [`FileMetadata::close`], this is not fixable in the general case, until [`FileMetadata`]
2482/// has only a weak reference to the [`BinaryView`].
2483#[derive(PartialEq, Eq, Hash)]
2484pub struct BinaryView {
2485    pub handle: *mut BNBinaryView,
2486}
2487
2488impl BinaryView {
2489    pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self {
2490        debug_assert!(!handle.is_null());
2491        Self { handle }
2492    }
2493
2494    pub(crate) unsafe fn ref_from_raw(handle: *mut BNBinaryView) -> Ref<Self> {
2495        debug_assert!(!handle.is_null());
2496        Ref::new(Self { handle })
2497    }
2498
2499    /// Construct the raw binary view from the given metadata.
2500    ///
2501    /// Before calling this, make sure you have a valid file path set for the [`FileMetadata`]. It is
2502    /// required that the [`FileMetadata::file_path`] exist in the local filesystem.
2503    pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>> {
2504        if !meta.file_path().exists() {
2505            return Err(());
2506        }
2507        let file = meta.file_path().to_cstr();
2508        let handle =
2509            unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) };
2510        if handle.is_null() {
2511            return Err(());
2512        }
2513        unsafe { Ok(Ref::new(Self { handle })) }
2514    }
2515
2516    /// Construct the raw binary view from the given `file_path` and metadata.
2517    ///
2518    /// This will implicitly set the metadata file path and then construct the view. If the metadata
2519    /// already has the desired file path, use [`BinaryView::from_metadata`] instead.
2520    pub fn from_path(meta: &FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>> {
2521        meta.set_file_path(file_path.as_ref());
2522        Self::from_metadata(meta)
2523    }
2524
2525    // TODO: Provide an API that manages the lifetime of the accessor and the view.
2526    /// Construct the raw binary view from the given `accessor` and metadata.
2527    ///
2528    /// It is the responsibility of the caller to keep the accessor alive for the lifetime of the view;
2529    /// because of this, we mark the function as unsafe.
2530    pub unsafe fn from_accessor<A: Accessor>(
2531        meta: &FileMetadata,
2532        accessor: &mut FileAccessor<A>,
2533    ) -> Result<Ref<Self>> {
2534        let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut accessor.raw) };
2535        if handle.is_null() {
2536            return Err(());
2537        }
2538        unsafe { Ok(Ref::new(Self { handle })) }
2539    }
2540
2541    /// Construct the raw binary view from the given `data` and metadata.
2542    ///
2543    /// The data will be copied into the view, so the caller does not need to keep the data alive.
2544    pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Ref<Self> {
2545        let handle = unsafe {
2546            BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len())
2547        };
2548        assert!(
2549            !handle.is_null(),
2550            "BNCreateBinaryDataViewFromData should always succeed"
2551        );
2552        unsafe { Ref::new(Self { handle }) }
2553    }
2554
2555    /// Save the original binary file to the provided `file_path` along with any modifications.
2556    ///
2557    /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action
2558    /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we
2559    /// are executing in this function.
2560    ///
2561    /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
2562    /// are no queued up main thread actions.
2563    pub fn save_to_path(&self, file_path: impl AsRef<Path>) -> bool {
2564        let file = file_path.as_ref().to_cstr();
2565        unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) }
2566    }
2567
2568    /// Save the original binary file to the provided [`FileAccessor`] along with any modifications.
2569    ///
2570    /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action
2571    /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we
2572    /// are executing in this function.
2573    ///
2574    /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
2575    /// are no queued up main thread actions.
2576    pub fn save_to_accessor<A: Accessor>(&self, file: &mut FileAccessor<A>) -> bool {
2577        unsafe { BNSaveToFile(self.handle, &mut file.raw) }
2578    }
2579}
2580
2581impl BinaryViewBase for BinaryView {
2582    fn read(&self, buf: &mut [u8], offset: u64) -> usize {
2583        unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) }
2584    }
2585
2586    fn write(&self, offset: u64, data: &[u8]) -> usize {
2587        unsafe { BNWriteViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
2588    }
2589
2590    fn insert(&self, offset: u64, data: &[u8]) -> usize {
2591        unsafe { BNInsertViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
2592    }
2593
2594    fn remove(&self, offset: u64, len: usize) -> usize {
2595        unsafe { BNRemoveViewData(self.handle, offset, len as u64) }
2596    }
2597
2598    fn offset_valid(&self, offset: u64) -> bool {
2599        unsafe { BNIsValidOffset(self.handle, offset) }
2600    }
2601
2602    fn offset_readable(&self, offset: u64) -> bool {
2603        unsafe { BNIsOffsetReadable(self.handle, offset) }
2604    }
2605
2606    fn offset_writable(&self, offset: u64) -> bool {
2607        unsafe { BNIsOffsetWritable(self.handle, offset) }
2608    }
2609
2610    fn offset_executable(&self, offset: u64) -> bool {
2611        unsafe { BNIsOffsetExecutable(self.handle, offset) }
2612    }
2613
2614    fn offset_backed_by_file(&self, offset: u64) -> bool {
2615        unsafe { BNIsOffsetBackedByFile(self.handle, offset) }
2616    }
2617
2618    fn next_valid_offset_after(&self, offset: u64) -> u64 {
2619        unsafe { BNGetNextValidOffset(self.handle, offset) }
2620    }
2621
2622    fn modification_status(&self, offset: u64) -> ModificationStatus {
2623        unsafe { BNGetModification(self.handle, offset) }
2624    }
2625
2626    fn start(&self) -> u64 {
2627        unsafe { BNGetStartOffset(self.handle) }
2628    }
2629
2630    fn len(&self) -> u64 {
2631        unsafe { BNGetViewLength(self.handle) }
2632    }
2633
2634    fn executable(&self) -> bool {
2635        unsafe { BNIsExecutableView(self.handle) }
2636    }
2637
2638    fn relocatable(&self) -> bool {
2639        unsafe { BNIsRelocatable(self.handle) }
2640    }
2641
2642    fn entry_point(&self) -> u64 {
2643        unsafe { BNGetEntryPoint(self.handle) }
2644    }
2645
2646    fn default_endianness(&self) -> Endianness {
2647        unsafe { BNGetDefaultEndianness(self.handle) }
2648    }
2649
2650    fn address_size(&self) -> usize {
2651        unsafe { BNGetViewAddressSize(self.handle) }
2652    }
2653}
2654
2655unsafe impl RefCountable for BinaryView {
2656    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
2657        Ref::new(Self {
2658            handle: BNNewViewReference(handle.handle),
2659        })
2660    }
2661
2662    unsafe fn dec_ref(handle: &Self) {
2663        BNFreeBinaryView(handle.handle);
2664    }
2665}
2666
2667impl AsRef<BinaryView> for BinaryView {
2668    fn as_ref(&self) -> &Self {
2669        self
2670    }
2671}
2672
2673impl ToOwned for BinaryView {
2674    type Owned = Ref<Self>;
2675
2676    fn to_owned(&self) -> Self::Owned {
2677        unsafe { RefCountable::inc_ref(self) }
2678    }
2679}
2680
2681unsafe impl Send for BinaryView {}
2682unsafe impl Sync for BinaryView {}
2683
2684impl std::fmt::Debug for BinaryView {
2685    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2686        f.debug_struct("BinaryView")
2687            .field("view_type", &self.view_type())
2688            .field("file", &self.file())
2689            .field("original_image_base", &self.original_image_base())
2690            .field("start", &self.start())
2691            .field("end", &self.end())
2692            .field("len", &self.len())
2693            .field("default_platform", &self.default_platform())
2694            .field("default_arch", &self.default_arch())
2695            .field("default_endianness", &self.default_endianness())
2696            .field("entry_point", &self.entry_point())
2697            .field(
2698                "entry_point_functions",
2699                &self.entry_point_functions().to_vec(),
2700            )
2701            .field("address_size", &self.address_size())
2702            .field("sections", &self.sections().to_vec())
2703            .field("segments", &self.segments().to_vec())
2704            .finish()
2705    }
2706}
2707
2708pub trait BinaryViewEventHandler: 'static + Sync {
2709    fn on_event(&self, binary_view: &BinaryView);
2710}
2711
2712/// Registers an event listener for binary view events.
2713///
2714/// # Example
2715///
2716/// ```no_run
2717/// use binaryninja::binary_view::{
2718///     register_binary_view_event, BinaryView, BinaryViewEventHandler, BinaryViewEventType,
2719/// };
2720///
2721/// struct EventHandlerContext {
2722///     // Context holding state available to event handler
2723/// }
2724///
2725/// impl BinaryViewEventHandler for EventHandlerContext {
2726///     fn on_event(&self, binary_view: &BinaryView) {
2727///         // handle event
2728///     }
2729/// }
2730///
2731/// #[no_mangle]
2732/// pub extern "C" fn CorePluginInit() {
2733///     let context = EventHandlerContext {};
2734///
2735///     register_binary_view_event(
2736///         BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent,
2737///         context,
2738///     );
2739/// }
2740/// ```
2741pub fn register_binary_view_event<Handler>(event_type: BinaryViewEventType, handler: Handler)
2742where
2743    Handler: BinaryViewEventHandler,
2744{
2745    unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
2746        ctx: *mut ::std::os::raw::c_void,
2747        view: *mut BNBinaryView,
2748    ) {
2749        ffi_wrap!("EventHandler::on_event", {
2750            let context = unsafe { &*(ctx as *const Handler) };
2751            context.on_event(&BinaryView::ref_from_raw(BNNewViewReference(view)));
2752        })
2753    }
2754
2755    let boxed = Box::new(handler);
2756    let raw = Box::into_raw(boxed);
2757
2758    unsafe {
2759        BNRegisterBinaryViewEvent(
2760            event_type,
2761            Some(on_event::<Handler>),
2762            raw as *mut ::std::os::raw::c_void,
2763        );
2764    }
2765}
2766
2767#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2768pub struct CommentReference {
2769    pub start: u64,
2770}
2771
2772impl From<u64> for CommentReference {
2773    fn from(start: u64) -> Self {
2774        Self { start }
2775    }
2776}
2777
2778impl CoreArrayProvider for CommentReference {
2779    type Raw = u64;
2780    type Context = ();
2781    type Wrapped<'a> = Self;
2782}
2783
2784unsafe impl CoreArrayProviderInner for CommentReference {
2785    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2786        BNFreeAddressList(raw)
2787    }
2788
2789    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2790        Self::from(*raw)
2791    }
2792}
2793
2794#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2795pub struct StringReference {
2796    pub ty: StringType,
2797    pub start: u64,
2798    pub length: usize,
2799}
2800
2801impl From<BNStringReference> for StringReference {
2802    fn from(raw: BNStringReference) -> Self {
2803        Self {
2804            ty: raw.type_,
2805            start: raw.start,
2806            length: raw.length,
2807        }
2808    }
2809}
2810
2811impl From<StringReference> for BNStringReference {
2812    fn from(raw: StringReference) -> Self {
2813        Self {
2814            type_: raw.ty,
2815            start: raw.start,
2816            length: raw.length,
2817        }
2818    }
2819}
2820
2821impl CoreArrayProvider for StringReference {
2822    type Raw = BNStringReference;
2823    type Context = ();
2824    type Wrapped<'a> = Self;
2825}
2826
2827unsafe impl CoreArrayProviderInner for StringReference {
2828    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2829        BNFreeStringReferenceList(raw)
2830    }
2831
2832    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2833        Self::from(*raw)
2834    }
2835}
2836
2837#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2838pub struct AddressRange {
2839    pub start: u64,
2840    pub end: u64,
2841}
2842
2843impl From<BNAddressRange> for AddressRange {
2844    fn from(raw: BNAddressRange) -> Self {
2845        Self {
2846            start: raw.start,
2847            end: raw.end,
2848        }
2849    }
2850}
2851
2852impl From<AddressRange> for BNAddressRange {
2853    fn from(raw: AddressRange) -> Self {
2854        Self {
2855            start: raw.start,
2856            end: raw.end,
2857        }
2858    }
2859}
2860
2861impl CoreArrayProvider for AddressRange {
2862    type Raw = BNAddressRange;
2863    type Context = ();
2864    type Wrapped<'a> = Self;
2865}
2866
2867unsafe impl CoreArrayProviderInner for AddressRange {
2868    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2869        BNFreeAddressRanges(raw);
2870    }
2871
2872    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2873        Self::from(*raw)
2874    }
2875}