binaryninja/medium_level_il/
function.rs1use 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}