binaryninja/medium_level_il/
function.rs

1use binaryninjacore_sys::*;
2use std::fmt::{Debug, Formatter};
3use std::hash::{Hash, Hasher};
4
5use super::{
6    MediumLevelExpressionIndex, MediumLevelILBlock, MediumLevelILInstruction,
7    MediumLevelInstructionIndex,
8};
9use crate::architecture::CoreArchitecture;
10use crate::basic_block::BasicBlock;
11use crate::confidence::Conf;
12use crate::disassembly::DisassemblySettings;
13use crate::flowgraph::FlowGraph;
14use crate::function::{Function, Location};
15use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
16use crate::types::Type;
17use crate::variable::{PossibleValueSet, RegisterValue, SSAVariable, UserVariableValue, Variable};
18
19// TODO: Does this belong here?
20pub use binaryninjacore_sys::BNFunctionGraphType as FunctionGraphType;
21
22pub struct MediumLevelILFunction {
23    pub(crate) handle: *mut BNMediumLevelILFunction,
24}
25
26impl MediumLevelILFunction {
27    pub(crate) unsafe fn from_raw(handle: *mut BNMediumLevelILFunction) -> Self {
28        debug_assert!(!handle.is_null());
29        Self { handle }
30    }
31
32    pub(crate) unsafe fn ref_from_raw(handle: *mut BNMediumLevelILFunction) -> Ref<Self> {
33        debug_assert!(!handle.is_null());
34        Ref::new(Self::from_raw(handle))
35    }
36
37    pub fn instruction_at<L: Into<Location>>(&self, loc: L) -> Option<MediumLevelILInstruction> {
38        Some(MediumLevelILInstruction::from_instr_index(
39            self.to_owned(),
40            self.instruction_index_at(loc)?,
41        ))
42    }
43
44    pub fn instruction_index_at<L: Into<Location>>(
45        &self,
46        loc: L,
47    ) -> Option<MediumLevelInstructionIndex> {
48        let loc: Location = loc.into();
49        // If the location does not specify an architecture, use the function's architecture.
50        let arch = loc.arch.unwrap_or_else(|| self.function().arch());
51        let instr_idx =
52            unsafe { BNMediumLevelILGetInstructionStart(self.handle, arch.handle, loc.addr) };
53        // `instr_idx` will equal self.instruction_count() if the instruction is not valid.
54        if instr_idx >= self.instruction_count() {
55            None
56        } else {
57            Some(MediumLevelInstructionIndex(instr_idx))
58        }
59    }
60
61    pub fn instruction_from_index(
62        &self,
63        index: MediumLevelInstructionIndex,
64    ) -> Option<MediumLevelILInstruction> {
65        if index.0 >= self.instruction_count() {
66            None
67        } else {
68            Some(MediumLevelILInstruction::from_instr_index(
69                self.to_owned(),
70                index,
71            ))
72        }
73    }
74
75    pub fn instruction_from_expr_index(
76        &self,
77        expr_index: MediumLevelExpressionIndex,
78    ) -> Option<MediumLevelILInstruction> {
79        if expr_index.0 >= self.expression_count() {
80            None
81        } else {
82            Some(MediumLevelILInstruction::from_expr_index(
83                self.to_owned(),
84                expr_index,
85            ))
86        }
87    }
88
89    pub fn instruction_count(&self) -> usize {
90        unsafe { BNGetMediumLevelILInstructionCount(self.handle) }
91    }
92
93    pub fn expression_count(&self) -> usize {
94        unsafe { BNGetMediumLevelILExprCount(self.handle) }
95    }
96
97    pub fn ssa_form(&self) -> Ref<MediumLevelILFunction> {
98        let ssa = unsafe { BNGetMediumLevelILSSAForm(self.handle) };
99        assert!(!ssa.is_null());
100        unsafe { MediumLevelILFunction::ref_from_raw(ssa) }
101    }
102
103    pub fn function(&self) -> Ref<Function> {
104        unsafe {
105            let func = BNGetMediumLevelILOwnerFunction(self.handle);
106            Function::ref_from_raw(func)
107        }
108    }
109
110    pub fn basic_blocks(&self) -> Array<BasicBlock<MediumLevelILBlock>> {
111        let mut count = 0;
112        let blocks = unsafe { BNGetMediumLevelILBasicBlockList(self.handle, &mut count) };
113        let context = MediumLevelILBlock {
114            function: self.to_owned(),
115        };
116        unsafe { Array::new(blocks, count, context) }
117    }
118
119    #[deprecated = "Use `Function::create_user_stack_var` instead"]
120    pub fn create_user_stack_var<'a, C: Into<Conf<&'a Type>>>(
121        &self,
122        offset: i64,
123        var_type: C,
124        name: &str,
125    ) {
126        self.function()
127            .create_user_stack_var(offset, var_type, name)
128    }
129
130    #[deprecated = "Use `Function::delete_user_stack_var` instead"]
131    pub fn delete_user_stack_var(&self, offset: i64) {
132        self.function().delete_user_stack_var(offset)
133    }
134
135    #[deprecated = "Use `Function::create_user_var` instead"]
136    pub fn create_user_var<'a, C: Into<Conf<&'a Type>>>(
137        &self,
138        var: &Variable,
139        var_type: C,
140        name: &str,
141        ignore_disjoint_uses: bool,
142    ) {
143        self.function()
144            .create_user_var(var, var_type, name, ignore_disjoint_uses)
145    }
146
147    #[deprecated = "Use `Function::delete_user_var` instead"]
148    pub fn delete_user_var(&self, var: &Variable) {
149        self.function().delete_user_var(var)
150    }
151
152    #[deprecated = "Use `Function::is_var_user_defined` instead"]
153    pub fn is_var_user_defined(&self, var: &Variable) -> bool {
154        self.function().is_var_user_defined(var)
155    }
156
157    /// Allows the user to specify a PossibleValueSet value for an MLIL
158    /// variable at its definition site.
159    ///
160    /// WARNING: Setting the variable value, triggers a reanalysis of the
161    /// function and allows the dataflow to compute and propagate values which
162    /// depend on the current variable. This implies that branch conditions
163    /// whose values can be determined statically will be computed, leading to
164    /// potential branch elimination at the HLIL layer.
165    ///
166    /// * `var` - Variable for which the value is to be set
167    /// * `addr` - Address of the definition site of the variable
168    /// * `value` - Informed value of the variable
169    ///
170    /// # Example
171    /// ```no_run
172    /// # use binaryninja::medium_level_il::MediumLevelILFunction;
173    /// # use binaryninja::variable::PossibleValueSet;
174    /// # let mlil_fun: MediumLevelILFunction = todo!();
175    /// let user_var_val = mlil_fun.user_var_values().iter().next().unwrap();
176    /// let def_address = user_var_val.def_site.addr;
177    /// let var_value = PossibleValueSet::ConstantValue { value: 5 };
178    /// mlil_fun
179    ///     .set_user_var_value(&user_var_val.variable, def_address, var_value, false)
180    ///     .unwrap();
181    /// ```
182    pub fn set_user_var_value(
183        &self,
184        var: &Variable,
185        addr: u64,
186        value: PossibleValueSet,
187        after: bool,
188    ) -> Result<(), ()> {
189        let function = self.function();
190        let def_site = BNArchitectureAndAddress {
191            arch: function.arch().handle,
192            address: addr,
193        };
194        let raw_var = BNVariable::from(var);
195        let raw_value = PossibleValueSet::into_rust_raw(value);
196        unsafe { BNSetUserVariableValue(function.handle, &raw_var, &def_site, after, &raw_value) }
197        PossibleValueSet::free_rust_raw(raw_value);
198        Ok(())
199    }
200
201    /// Clears a previously defined user variable value.
202    ///
203    /// * `var` - Variable for which the value was informed
204    /// * `def_addr` - Address of the definition site of the variable
205    pub fn clear_user_var_value(&self, var: &Variable, addr: u64, after: bool) -> Result<(), ()> {
206        let Some(_var_def) = self
207            .variable_definitions(var)
208            .iter()
209            .find(|site| site.address == addr)
210        else {
211            //error "Could not get definition for Variable"
212            return Err(());
213        };
214
215        let function = self.function();
216        let raw_var = BNVariable::from(var);
217        let def_site = BNArchitectureAndAddress {
218            arch: function.arch().handle,
219            address: addr,
220        };
221
222        unsafe { BNClearUserVariableValue(function.handle, &raw_var, &def_site, after) };
223        Ok(())
224    }
225
226    /// Returns a map of current defined user variable values.
227    /// Returns a Map of user current defined user variable values and their definition sites.
228    pub fn user_var_values(&self) -> Array<UserVariableValue> {
229        let mut count = 0;
230        let function = self.function();
231        let var_values = unsafe { BNGetAllUserVariableValues(function.handle, &mut count) };
232        assert!(!var_values.is_null());
233        unsafe { Array::new(var_values, count, ()) }
234    }
235
236    /// Clear all user defined variable values.
237    pub fn clear_user_var_values(&self) -> Result<(), ()> {
238        for user_var_val in &self.user_var_values() {
239            self.clear_user_var_value(
240                &user_var_val.variable,
241                user_var_val.def_site.addr,
242                user_var_val.after,
243            )?;
244        }
245        Ok(())
246    }
247
248    #[deprecated = "Use `Function::create_auto_stack_var` instead"]
249    pub fn create_auto_stack_var<'a, T: Into<Conf<&'a Type>>>(
250        &self,
251        offset: i64,
252        var_type: T,
253        name: &str,
254    ) {
255        self.function()
256            .create_auto_stack_var(offset, var_type, name)
257    }
258
259    #[deprecated = "Use `Function::delete_auto_stack_var` instead"]
260    pub fn delete_auto_stack_var(&self, offset: i64) {
261        self.function().delete_auto_stack_var(offset)
262    }
263
264    #[deprecated = "Use `Function::create_auto_var` instead"]
265    pub fn create_auto_var<'a, C: Into<Conf<&'a Type>>>(
266        &self,
267        var: &Variable,
268        var_type: C,
269        name: &str,
270        ignore_disjoint_uses: bool,
271    ) {
272        self.function()
273            .create_auto_var(var, var_type, name, ignore_disjoint_uses)
274    }
275
276    /// Returns a list of ILReferenceSource objects (IL xrefs or cross-references)
277    /// that reference the given variable. The variable is a local variable that can be either on the stack,
278    /// in a register, or in a flag.
279    /// This function is related to get_hlil_var_refs(), which returns variable references collected
280    /// from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged
281    /// into a single variable in HLIL.
282    ///
283    /// * `var` - Variable for which to query the xref
284    ///
285    /// # Example
286    /// ```no_run
287    /// # use binaryninja::medium_level_il::MediumLevelILFunction;
288    /// # use binaryninja::variable::Variable;
289    /// # let mlil_fun: MediumLevelILFunction = todo!();
290    /// # let mlil_var: Variable = todo!();
291    /// let instr_idx = mlil_fun.var_refs(&mlil_var).get(0).expr_idx;
292    /// ```
293    pub fn var_refs(&self, var: &Variable) -> Array<ILReferenceSource> {
294        let mut count = 0;
295        let mut raw_var = BNVariable::from(var);
296        let refs = unsafe {
297            BNGetMediumLevelILVariableReferences(self.function().handle, &mut raw_var, &mut count)
298        };
299        assert!(!refs.is_null());
300        unsafe { Array::new(refs, count, ()) }
301    }
302
303    /// Retrieves variable references from a specified location or range within a medium-level IL function.
304    ///
305    /// Passing in a `length` will query a range for variable references, instead of just the address
306    /// specified in `location`.
307    pub fn var_refs_from(
308        &self,
309        location: impl Into<Location>,
310        length: Option<u64>,
311    ) -> Array<VariableReferenceSource> {
312        let location = location.into();
313        let raw_arch = location
314            .arch
315            .map(|a| a.handle)
316            .unwrap_or(std::ptr::null_mut());
317        let function = self.function();
318        let mut count = 0;
319
320        let refs = if let Some(length) = length {
321            unsafe {
322                BNGetMediumLevelILVariableReferencesInRange(
323                    function.handle,
324                    raw_arch,
325                    location.addr,
326                    length,
327                    &mut count,
328                )
329            }
330        } else {
331            unsafe {
332                BNGetMediumLevelILVariableReferencesFrom(
333                    function.handle,
334                    raw_arch,
335                    location.addr,
336                    &mut count,
337                )
338            }
339        };
340        assert!(!refs.is_null());
341        unsafe { Array::new(refs, count, ()) }
342    }
343
344    // TODO: Rename to `current_location`?
345    /// Current IL Address
346    pub fn current_address(&self) -> Location {
347        let addr = unsafe { BNMediumLevelILGetCurrentAddress(self.handle) };
348        Location::from(addr)
349    }
350
351    // TODO: Rename to `set_current_location`?
352    /// Set the current IL Address
353    pub fn set_current_address(&self, location: impl Into<Location>) {
354        let location = location.into();
355        let arch = location
356            .arch
357            .map(|a| a.handle)
358            .unwrap_or(std::ptr::null_mut());
359        unsafe { BNMediumLevelILSetCurrentAddress(self.handle, arch, location.addr) }
360    }
361
362    /// Returns the [`BasicBlock`] at the given instruction `index`. Function must be finalized.
363    ///
364    /// You can also retrieve this using [`MediumLevelILInstruction::basic_block`].
365    pub fn basic_block_containing_index(
366        &self,
367        index: MediumLevelInstructionIndex,
368    ) -> Option<Ref<BasicBlock<MediumLevelILBlock>>> {
369        let context = MediumLevelILBlock {
370            function: self.to_owned(),
371        };
372        // TODO: If we can guarantee self.index is valid we can omit the wrapped Option.
373        let basic_block_ptr =
374            unsafe { BNGetMediumLevelILBasicBlockForInstruction(self.handle, index.0) };
375        match basic_block_ptr.is_null() {
376            false => Some(unsafe { BasicBlock::ref_from_raw(basic_block_ptr, context) }),
377            true => None,
378        }
379    }
380
381    /// Ends the function and computes the list of basic blocks.
382    ///
383    /// NOTE: This should be called after updating MLIL.
384    pub fn finalize(&self) {
385        unsafe { BNFinalizeMediumLevelILFunction(self.handle) }
386    }
387
388    /// Generate SSA form given the current MLIL.
389    ///
390    /// NOTE: This should be called after updating MLIL.
391    ///
392    /// * `analyze_conditionals` - whether to analyze conditionals
393    /// * `handle_aliases` - whether to handle aliases
394    /// * `non_aliased_vars` - optional list of variables known to be not aliased
395    /// * `aliased_vars` - optional list of variables known to be aliased
396    pub fn generate_ssa_form(
397        &self,
398        analyze_conditionals: bool,
399        handle_aliases: bool,
400        non_aliased_vars: impl IntoIterator<Item = Variable>,
401        aliased_vars: impl IntoIterator<Item = Variable>,
402    ) {
403        let raw_non_aliased_vars: Vec<BNVariable> =
404            non_aliased_vars.into_iter().map(Into::into).collect();
405        let raw_aliased_vars: Vec<BNVariable> = aliased_vars.into_iter().map(Into::into).collect();
406        unsafe {
407            BNGenerateMediumLevelILSSAForm(
408                self.handle,
409                analyze_conditionals,
410                handle_aliases,
411                raw_non_aliased_vars.as_ptr() as *mut _,
412                raw_non_aliased_vars.len(),
413                raw_aliased_vars.as_ptr() as *mut _,
414                raw_aliased_vars.len(),
415            )
416        }
417    }
418
419    /// Gets the instruction that contains the given SSA variable's definition.
420    ///
421    /// Since SSA variables can only be defined once, this will return the single instruction where that occurs.
422    /// For SSA variable version 0s, which don't have definitions, this will return `None` instead.
423    pub fn ssa_variable_definition(
424        &self,
425        ssa_variable: &SSAVariable,
426    ) -> Option<MediumLevelILInstruction> {
427        let raw_var = BNVariable::from(ssa_variable.variable);
428        let result = unsafe {
429            BNGetMediumLevelILSSAVarDefinition(self.handle, &raw_var, ssa_variable.version)
430        };
431        // TODO: Does this return the expression or instruction index? Also we dont diff and this prob doesnt work.
432        self.instruction_from_index(MediumLevelInstructionIndex(result))
433    }
434
435    pub fn ssa_memory_definition(&self, version: usize) -> Option<MediumLevelILInstruction> {
436        let result = unsafe { BNGetMediumLevelILSSAMemoryDefinition(self.handle, version) };
437        // TODO: Does this return the expression or instruction index? Also we dont diff and this prob doesnt work.
438        self.instruction_from_index(MediumLevelInstructionIndex(result))
439    }
440
441    /// Gets all the instructions that use the given SSA variable.
442    pub fn ssa_variable_uses(&self, ssa_variable: &SSAVariable) -> Array<MediumLevelILInstruction> {
443        let mut count = 0;
444        let raw_var = BNVariable::from(ssa_variable.variable);
445        let uses = unsafe {
446            BNGetMediumLevelILSSAVarUses(self.handle, &raw_var, ssa_variable.version, &mut count)
447        };
448        assert!(!uses.is_null());
449        unsafe { Array::new(uses, count, self.to_owned()) }
450    }
451
452    pub fn ssa_memory_uses(&self, version: usize) -> Array<MediumLevelILInstruction> {
453        let mut count = 0;
454        let uses = unsafe { BNGetMediumLevelILSSAMemoryUses(self.handle, version, &mut count) };
455        assert!(!uses.is_null());
456        unsafe { Array::new(uses, count, self.to_owned()) }
457    }
458
459    /// Determines if `variable` is live at any point in the function
460    pub fn is_ssa_variable_live(&self, ssa_variable: &SSAVariable) -> bool {
461        let raw_var = BNVariable::from(ssa_variable.variable);
462        unsafe { BNIsMediumLevelILSSAVarLive(self.handle, &raw_var, ssa_variable.version) }
463    }
464
465    pub fn variable_definitions(&self, variable: &Variable) -> Array<MediumLevelILInstruction> {
466        let mut count = 0;
467        let raw_var = BNVariable::from(variable);
468        let defs =
469            unsafe { BNGetMediumLevelILVariableDefinitions(self.handle, &raw_var, &mut count) };
470        assert!(!defs.is_null());
471        unsafe { Array::new(defs, count, self.to_owned()) }
472    }
473
474    pub fn variable_uses(&self, variable: &Variable) -> Array<MediumLevelILInstruction> {
475        let mut count = 0;
476        let raw_var = BNVariable::from(variable);
477        let uses = unsafe { BNGetMediumLevelILVariableUses(self.handle, &raw_var, &mut count) };
478        unsafe { Array::new(uses, count, self.to_owned()) }
479    }
480
481    /// Computes the list of instructions for which `var` is live.
482    /// If `include_last_use` is false, the last use of the variable will not be included in the
483    /// list (this allows for easier computation of overlaps in liveness between two variables).
484    /// If the variable is never used, this function will return an empty list.
485    ///
486    /// `var` - the variable to query
487    /// `include_last_use` - whether to include the last use of the variable in the list of instructions
488    pub fn live_instruction_for_variable(
489        &self,
490        variable: &Variable,
491        include_last_use: bool,
492    ) -> Array<MediumLevelILInstruction> {
493        let mut count = 0;
494        let raw_var = BNVariable::from(variable);
495        let uses = unsafe {
496            BNGetMediumLevelILLiveInstructionsForVariable(
497                self.handle,
498                &raw_var,
499                include_last_use,
500                &mut count,
501            )
502        };
503        unsafe { Array::new(uses, count, self.to_owned()) }
504    }
505
506    pub fn ssa_variable_value(&self, ssa_variable: &SSAVariable) -> RegisterValue {
507        let raw_var = BNVariable::from(ssa_variable.variable);
508        unsafe { BNGetMediumLevelILSSAVarValue(self.handle, &raw_var, ssa_variable.version) }.into()
509    }
510
511    pub fn create_graph(&self, settings: Option<DisassemblySettings>) -> Ref<FlowGraph> {
512        let settings = settings.map(|x| x.handle).unwrap_or(std::ptr::null_mut());
513        let graph = unsafe { BNCreateMediumLevelILFunctionGraph(self.handle, settings) };
514        unsafe { FlowGraph::ref_from_raw(graph) }
515    }
516
517    /// This gets just the MLIL variables - you may be interested in the union
518    /// of [`MediumLevelILFunction::aliased_variables`] and [`Function::parameter_variables`] for
519    /// all the variables used in the function
520    pub fn variables(&self) -> Array<Variable> {
521        let mut count = 0;
522        let uses = unsafe { BNGetMediumLevelILVariables(self.handle, &mut count) };
523        unsafe { Array::new(uses, count, ()) }
524    }
525
526    /// This returns a list of Variables that are taken reference to and used
527    /// elsewhere. You may also wish to consider [`MediumLevelILFunction::variables`]
528    /// and [`Function::parameter_variables`]
529    pub fn aliased_variables(&self) -> Array<Variable> {
530        let mut count = 0;
531        let uses = unsafe { BNGetMediumLevelILAliasedVariables(self.handle, &mut count) };
532        unsafe { Array::new(uses, count, ()) }
533    }
534
535    /// This gets the MLIL SSA variables for a given [`Variable`].
536    pub fn ssa_variables(&self, variable: &Variable) -> Array<SSAVariable> {
537        let mut count = 0;
538        let raw_variable = BNVariable::from(variable);
539        let versions = unsafe {
540            BNGetMediumLevelILVariableSSAVersions(self.handle, &raw_variable, &mut count)
541        };
542        unsafe { Array::new(versions, count, *variable) }
543    }
544}
545
546impl ToOwned for MediumLevelILFunction {
547    type Owned = Ref<Self>;
548
549    fn to_owned(&self) -> Self::Owned {
550        unsafe { RefCountable::inc_ref(self) }
551    }
552}
553
554unsafe impl RefCountable for MediumLevelILFunction {
555    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
556        Ref::new(Self {
557            handle: BNNewMediumLevelILFunctionReference(handle.handle),
558        })
559    }
560
561    unsafe fn dec_ref(handle: &Self) {
562        BNFreeMediumLevelILFunction(handle.handle);
563    }
564}
565
566impl Debug for MediumLevelILFunction {
567    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
568        f.debug_struct("MediumLevelILFunction")
569            .field("arch", &self.function().arch())
570            .field("instruction_count", &self.instruction_count())
571            .finish()
572    }
573}
574
575unsafe impl Send for MediumLevelILFunction {}
576unsafe impl Sync for MediumLevelILFunction {}
577
578impl Eq for MediumLevelILFunction {}
579impl PartialEq for MediumLevelILFunction {
580    fn eq(&self, rhs: &Self) -> bool {
581        self.function().eq(&rhs.function())
582    }
583}
584
585impl Hash for MediumLevelILFunction {
586    fn hash<H: Hasher>(&self, state: &mut H) {
587        self.function().hash(state)
588    }
589}
590
591pub struct ILReferenceSource {
592    pub function: Ref<Function>,
593    pub arch: CoreArchitecture,
594    pub addr: u64,
595    pub graph_type: FunctionGraphType,
596    pub expr_idx: usize,
597}
598
599impl From<BNILReferenceSource> for ILReferenceSource {
600    fn from(value: BNILReferenceSource) -> Self {
601        Self {
602            function: unsafe { Function::ref_from_raw(value.func) },
603            arch: unsafe { CoreArchitecture::from_raw(value.arch) },
604            addr: value.addr,
605            graph_type: value.type_,
606            expr_idx: value.exprId,
607        }
608    }
609}
610
611impl From<&BNILReferenceSource> for ILReferenceSource {
612    fn from(value: &BNILReferenceSource) -> Self {
613        Self {
614            function: unsafe { Function::from_raw(value.func).to_owned() },
615            arch: unsafe { CoreArchitecture::from_raw(value.arch) },
616            addr: value.addr,
617            graph_type: value.type_,
618            expr_idx: value.exprId,
619        }
620    }
621}
622
623impl CoreArrayProvider for ILReferenceSource {
624    type Raw = BNILReferenceSource;
625    type Context = ();
626    type Wrapped<'a> = Self;
627}
628
629unsafe impl CoreArrayProviderInner for ILReferenceSource {
630    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
631        BNFreeILReferences(raw, count)
632    }
633
634    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
635        raw.into()
636    }
637}
638
639pub struct VariableReferenceSource {
640    pub variable: Variable,
641    pub source: ILReferenceSource,
642}
643
644impl From<BNVariableReferenceSource> for VariableReferenceSource {
645    fn from(value: BNVariableReferenceSource) -> Self {
646        Self {
647            variable: Variable::from(value.var),
648            source: value.source.into(),
649        }
650    }
651}
652
653impl From<&BNVariableReferenceSource> for VariableReferenceSource {
654    fn from(value: &BNVariableReferenceSource) -> Self {
655        Self {
656            variable: Variable::from(value.var),
657            // TODO: We really need to document this better, or have some other facility for this.
658            // NOTE: We take this as a ref to increment the function ref.
659            source: ILReferenceSource::from(&value.source),
660        }
661    }
662}
663
664impl CoreArrayProvider for VariableReferenceSource {
665    type Raw = BNVariableReferenceSource;
666    type Context = ();
667    type Wrapped<'a> = Self;
668}
669
670unsafe impl CoreArrayProviderInner for VariableReferenceSource {
671    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
672        BNFreeVariableReferenceSourceList(raw, count)
673    }
674
675    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
676        raw.into()
677    }
678}