binaryninja/
calling_convention.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//! Contains and provides information about different systems' calling conventions to analysis.
16
17use binaryninjacore_sys::*;
18use std::borrow::Borrow;
19use std::collections::BTreeMap;
20use std::ffi::c_void;
21use std::fmt::{Debug, Formatter};
22use std::hash::{Hash, Hasher};
23use std::marker::PhantomData;
24use std::mem::MaybeUninit;
25use std::ptr;
26
27use crate::architecture::{
28    Architecture, ArchitectureExt, CoreArchitecture, FlagId, Register, RegisterId, RegisterStack,
29    RegisterStackInfo,
30};
31use crate::binary_view::BinaryView;
32use crate::ffi::{slice_from_raw_parts, INVALID_REGISTER};
33use crate::function::Function;
34use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
35use crate::string::*;
36use crate::types::{FunctionParameter, ReturnValue, Type, ValueLocation};
37use crate::variable::{RegisterValue, RegisterValueType, Variable};
38
39// TODO
40// force valid registers once Arch has _from_id methods
41
42/// Describes how parameters, return values, and the stack are handled when a function is called.
43///
44/// Implementors only need to provide the methods that describe their convention; every method that
45/// computes a layout (parameter locations, return value location, and stack adjustments) has a
46/// default implementation that delegates to the core's default behavior via the implementor's
47/// associated [`CoreCallingConvention`]. A [`CallingConvention`] implementation must expose its
48/// core handle through [`AsRef<CoreCallingConvention>`]; see [`register_calling_convention`] for
49/// how the handle is provided to implementors.
50pub trait CallingConvention: 'static + Sync + Sized + AsRef<CoreCallingConvention> {
51    /// Gets the list of registers that are not preserved across a call
52    /// (caller-saved / volatile registers).
53    fn caller_saved_registers(&self) -> Vec<RegisterId>;
54
55    /// Gets the list of registers that a callee must preserve across a call
56    /// (callee-saved / non-volatile registers).
57    fn callee_saved_registers(&self) -> Vec<RegisterId>;
58
59    /// Gets the registers used to pass integer and pointer arguments, in the order they are used.
60    fn int_arg_registers(&self) -> Vec<RegisterId>;
61
62    /// Gets the registers used to pass floating point arguments, in the order they are used.
63    fn float_arg_registers(&self) -> Vec<RegisterId>;
64
65    /// Gets the set of registers that must be arguments for heuristic calling convention
66    /// detection to consider this calling convention as a valid option.
67    fn required_argument_registers(&self) -> Vec<RegisterId> {
68        Vec::new()
69    }
70
71    /// Gets the set of registers that must be clobbered for heuristic calling convention
72    /// detection to consider this calling convention as a valid option.
73    fn required_clobbered_registers(&self) -> Vec<RegisterId> {
74        Vec::new()
75    }
76
77    /// Whether the integer and floating point argument registers share a single argument index.
78    ///
79    /// When true, the Nth argument consumes the Nth slot of both the integer and float register
80    /// lists regardless of its type. When false, integer and float arguments are assigned from
81    /// their respective register lists independently.
82    fn arg_registers_shared_index(&self) -> bool;
83
84    /// Whether stack space is reserved by the caller for the register arguments (for example,
85    /// the shadow/home space used by the Windows x64 calling convention).
86    fn reserved_stack_space_for_arg_registers(&self) -> bool;
87
88    /// Whether the callee adjusts the stack to remove the arguments before returning (as in
89    /// stdcall), rather than leaving the caller to clean up the stack (as in cdecl).
90    fn stack_adjusted_on_return(&self) -> bool;
91
92    /// Whether this calling convention may be selected by heuristic calling convention detection.
93    fn is_eligible_for_heuristics(&self) -> bool;
94
95    /// Gets the register that holds the integer return value.
96    fn return_int_reg(&self) -> Option<RegisterId>;
97
98    /// Gets the register that holds the high part of an integer return value that is too large
99    /// to fit in a single register.
100    fn return_hi_int_reg(&self) -> Option<RegisterId>;
101
102    /// Gets the register that holds the floating point return value.
103    fn return_float_reg(&self) -> Option<RegisterId>;
104
105    /// Deprecated. Use [`CallingConvention::global_pointer_regs`] instead.
106    ///
107    /// Gets the register that holds the global pointer, if the calling convention defines one.
108    fn global_pointer_reg(&self) -> Option<RegisterId>;
109    fn global_pointer_regs(&self) -> Vec<RegisterId> {
110        self.global_pointer_reg().into_iter().collect()
111    }
112
113    /// Gets the registers that are implicitly given a known value on function entry by this
114    /// calling convention.
115    fn implicitly_defined_registers(&self) -> Vec<RegisterId>;
116
117    /// Whether argument registers are used to pass variadic arguments.
118    fn are_argument_registers_used_for_var_args(&self) -> bool;
119
120    /// The known value of a register on entry to a function. The default implementation models the
121    /// top of a register stack (such as the x87 floating point stack) as the constant zero and
122    /// leaves all other registers undetermined.
123    fn incoming_register_value(&self, reg: RegisterId, _func: Option<&Function>) -> RegisterValue {
124        let arch = self.as_ref().arch_handle;
125        if let Some(reg) = arch.register_from_id(reg) {
126            if let Some(reg_stack) = arch.register_stack_for_register(reg) {
127                if reg == reg_stack.info().stack_top_reg() {
128                    return RegisterValue::new(RegisterValueType::ConstantValue, 0, 0, 0);
129                }
130            }
131        }
132        RegisterValue::new(RegisterValueType::UndeterminedValue, 0, 0, 0)
133    }
134
135    /// The known value of a flag on entry to a function. The default implementation leaves all
136    /// flags undetermined.
137    fn incoming_flag_value(&self, _flag: FlagId, _func: Option<&Function>) -> RegisterValue {
138        RegisterValue::new(RegisterValueType::UndeterminedValue, 0, 0, 0)
139    }
140
141    /// The incoming variable used to pass the given parameter variable.
142    fn incoming_variable_for_parameter_variable(
143        &self,
144        var: &Variable,
145        _func: Option<&Function>,
146    ) -> Variable {
147        self.as_ref()
148            .default_incoming_variable_for_parameter_variable(var)
149    }
150
151    /// The parameter variable corresponding to the given incoming variable.
152    fn parameter_variable_for_incoming_variable(
153        &self,
154        var: &Variable,
155        _func: Option<&Function>,
156    ) -> Variable {
157        self.as_ref()
158            .default_parameter_variable_for_incoming_variable(var)
159    }
160
161    /// Whether a value of the given type can be returned in registers, as opposed to being
162    /// returned indirectly through memory. The default implementation allows register returns
163    /// for types that fit in a single register, have a size equal to two registers when
164    /// [`CallingConvention::return_hi_int_reg`] is a valid register, or are a floating point
165    /// type when [`CallingConvention::return_float_reg`] is a valid register.
166    fn is_return_type_register_compatible(&self, _view: Option<&BinaryView>, ty: &Type) -> bool {
167        self.as_ref().default_is_return_type_register_compatible(ty)
168    }
169
170    /// The location used to pass the hidden pointer argument for return values that are returned
171    /// indirectly through memory. The default location is the first integer argument register,
172    /// or the first stack slot if there are no integer argument registers.
173    fn indirect_return_value_location(&self) -> Variable {
174        self.as_ref().default_indirect_return_value_location()
175    }
176
177    /// The location in which the hidden indirect return value pointer is returned to the caller,
178    /// for calling conventions that return it.
179    fn returned_indirect_return_value_pointer(&self) -> Option<Variable> {
180        None
181    }
182
183    /// Whether a value of the given type can be passed as an argument in registers. The default
184    /// implementation allows register arguments for types that fit in a single register, or are
185    /// a floating point type when [`CallingConvention::float_arg_registers`] has valid registers.
186    fn is_argument_type_register_compatible(&self, _view: Option<&BinaryView>, ty: &Type) -> bool {
187        self.as_ref()
188            .default_is_argument_type_register_compatible(ty)
189    }
190
191    /// Whether an argument that cannot be passed in registers is passed indirectly by pointer, as
192    /// opposed to being passed directly on the stack.
193    fn is_non_register_argument_indirect(&self, _view: Option<&BinaryView>, _ty: &Type) -> bool {
194        false
195    }
196
197    /// Whether arguments passed on the stack are aligned to their natural alignment. If false,
198    /// arguments are aligned to the address size.
199    fn are_stack_arguments_naturally_aligned(&self) -> bool {
200        false
201    }
202
203    /// Whether arguments passed on the stack are pushed left-to-right, as opposed to the more
204    /// common right-to-left order.
205    fn are_stack_arguments_pushed_left_to_right(&self) -> bool {
206        false
207    }
208
209    /// Computes the complete call layout (parameter locations, return value location, and stack
210    /// adjustments) for a call with the given return value and parameters. The default
211    /// implementation uses [`CallingConvention::return_value_location`],
212    /// [`CallingConvention::parameter_locations`], [`CallingConvention::stack_adjustment_for_locations`],
213    /// and [`CallingConvention::stack_adjustment_for_locations`] to compute the layout.
214    ///
215    /// It is recommended to only override this method if the calling convention behavior cannot be
216    /// modeled with [`CallingConvention::return_value_location`] and/or
217    /// [`CallingConvention::parameter_locations`].
218    ///
219    /// When calling this function to query the layout of a function, the return value and
220    /// parameters should have their named type references dereferenced before passing them to
221    /// this function. Calling the functions [`BinaryView::deref_return_value_named_type_references`]
222    /// and [`BinaryView::deref_parameter_named_type_references`] will perform this dereferencing.
223    fn call_layout(
224        &self,
225        view: Option<&BinaryView>,
226        return_value: &ReturnValue,
227        params: &[FunctionParameter],
228        permitted_registers: Option<&[RegisterId]>,
229    ) -> CallLayout {
230        self.as_ref()
231            .default_call_layout(view, return_value, params, permitted_registers)
232    }
233
234    /// Computes the location of the return value for the given return value type. The default
235    /// implementation checks [`CallingConvention::is_return_type_register_compatible`] and places
236    /// the return value in registers if it can, or uses an indirect return by pointer if not. If
237    /// an indirect return is required, then [`CallingConvention::indirect_return_value_location`]
238    /// and [`CallingConvention::returned_indirect_return_value_pointer`] are used to provide the
239    /// location of the indirect return value.
240    fn return_value_location(
241        &self,
242        view: Option<&BinaryView>,
243        return_value: &ReturnValue,
244    ) -> ValueLocation {
245        self.as_ref()
246            .default_return_value_location(view, return_value)
247    }
248
249    /// Computes the locations of the parameters for a call with the given return value and
250    /// parameters. The default implementation uses [`CallingConvention::int_arg_registers`],
251    /// [`CallingConvention::float_arg_registers`], [`CallingConvention::arg_registers_shared_index`],
252    /// [`CallingConvention::reserved_stack_space_for_arg_registers`],
253    /// [`CallingConvention::is_argument_type_register_compatible`],
254    /// [`CallingConvention::is_non_register_argument_indirect`],
255    /// [`CallingConvention::are_stack_arguments_naturally_aligned`], and
256    /// [`CallingConvention::are_stack_arguments_pushed_left_to_right`] to compute the parameter
257    /// layout.
258    ///
259    /// This function is usually sufficient unless the calling convention has unusual parameter
260    /// passing behavior. Most calling conventions can be defined per-argument using the methods
261    /// listed above.
262    fn parameter_locations(
263        &self,
264        view: Option<&BinaryView>,
265        return_value: Option<&ValueLocation>,
266        params: &[FunctionParameter],
267        permitted_registers: Option<&[RegisterId]>,
268    ) -> Vec<ValueLocation> {
269        self.as_ref()
270            .default_parameter_locations(view, return_value, params, permitted_registers)
271    }
272
273    /// Computes the order in which the given parameter variables are passed. The default
274    /// implementation first checks [`CallingConvention::arg_registers_shared_index`] to see if the
275    /// parameter ordering is well defined. If the arguments do not share an index, it places all
276    /// integer arguments before the floating point arguments. Arguments that are not passed in a
277    /// normal location are placed last.
278    fn parameter_ordering_for_variables(
279        &self,
280        _view: Option<&BinaryView>,
281        params: &[(Variable, Ref<Type>)],
282    ) -> Vec<Variable> {
283        self.as_ref()
284            .default_parameter_ordering_for_variables(params)
285    }
286
287    /// Computes the stack adjustment applied on return for a call with the given return value and
288    /// parameter locations. The default implementation first checks
289    /// [`CallingConvention::stack_adjusted_on_return`], and returns zero if that returns false.
290    /// Otherwise, it checks the stack parameter locations and
291    /// [`CallingConvention::are_stack_arguments_naturally_aligned`] to compute the stack
292    /// adjustment necessary to cover all parameters.
293    fn stack_adjustment_for_locations(
294        &self,
295        _view: Option<&BinaryView>,
296        return_value: Option<&ValueLocation>,
297        params: &[(ValueLocation, Ref<Type>)],
298    ) -> i64 {
299        self.as_ref()
300            .default_stack_adjustment_for_locations(return_value, params)
301    }
302
303    /// Computes the per-register-stack adjustments (for architectures with register stacks, such
304    /// as the x87 floating point stack) for a call with the given return value and parameter
305    /// locations. The default implementation compares the register stack slots used by the
306    /// parameters and the return value to compute the adjustments.
307    fn register_stack_adjustments(
308        &self,
309        _view: Option<&BinaryView>,
310        return_value: Option<&ValueLocation>,
311        params: &[ValueLocation],
312    ) -> BTreeMap<RegisterId, i32> {
313        self.as_ref()
314            .default_register_stack_adjustments(return_value, params)
315    }
316}
317
318/// Registers a new calling convention with the given architecture.
319///
320/// The convention object is constructed by `func`, which is given the [`CoreCallingConvention`]
321/// handle of the newly created convention. Implementors must store this handle and return it from
322/// their [`AsRef<CoreCallingConvention>`] implementation so that the trait's layout methods can
323/// delegate to the core's default behavior.
324///
325/// NOTE: This function should only be called within `CorePluginInit`.
326pub fn register_calling_convention<A, C, F>(
327    arch: &A,
328    name: &str,
329    func: F,
330) -> Ref<CoreCallingConvention>
331where
332    A: Architecture,
333    C: 'static + CallingConvention,
334    F: FnOnce(CoreCallingConvention) -> C,
335{
336    #[repr(C)]
337    struct CustomCallingConventionContext<C>
338    where
339        C: CallingConvention,
340    {
341        cc: MaybeUninit<C>,
342    }
343
344    unsafe fn from_ctxt<'a, C: CallingConvention>(ctxt: *mut c_void) -> &'a C {
345        (*(ctxt as *mut CustomCallingConventionContext<C>))
346            .cc
347            .assume_init_ref()
348    }
349
350    unsafe fn register_list(regs: Vec<RegisterId>, count: *mut usize) -> *mut u32 {
351        let regs: Box<[u32]> = regs.iter().map(|r| r.0).collect();
352        *count = regs.len();
353        Box::leak(regs).as_mut_ptr()
354    }
355
356    unsafe fn permitted_registers(
357        has_permitted: bool,
358        regs: *mut u32,
359        count: usize,
360    ) -> Option<Vec<RegisterId>> {
361        if has_permitted {
362            let regs = unsafe { slice_from_raw_parts(regs, count) };
363            Some(regs.iter().copied().map(RegisterId::from).collect())
364        } else {
365            None
366        }
367    }
368
369    extern "C" fn cb_free<C>(ctxt: *mut c_void)
370    where
371        C: CallingConvention,
372    {
373        ffi_wrap!("CallingConvention::free", unsafe {
374            let mut ctxt = Box::from_raw(ctxt as *mut CustomCallingConventionContext<C>);
375            ctxt.cc.assume_init_drop();
376        })
377    }
378
379    extern "C" fn cb_free_register_list(_ctxt: *mut c_void, regs: *mut u32, count: usize) {
380        ffi_wrap!("CallingConvention::free_register_list", unsafe {
381            if regs.is_null() {
382                return;
383            }
384
385            let regs_ptr = ptr::slice_from_raw_parts_mut(regs, count);
386            let _regs = Box::from_raw(regs_ptr);
387        })
388    }
389
390    extern "C" fn cb_caller_saved<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
391    where
392        C: CallingConvention,
393    {
394        ffi_wrap!("CallingConvention::caller_saved_registers", unsafe {
395            register_list(from_ctxt::<C>(ctxt).caller_saved_registers(), count)
396        })
397    }
398
399    extern "C" fn cb_callee_saved<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
400    where
401        C: CallingConvention,
402    {
403        ffi_wrap!("CallingConvention::callee_saved_registers", unsafe {
404            register_list(from_ctxt::<C>(ctxt).callee_saved_registers(), count)
405        })
406    }
407
408    extern "C" fn cb_int_args<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
409    where
410        C: CallingConvention,
411    {
412        ffi_wrap!("CallingConvention::int_arg_registers", unsafe {
413            register_list(from_ctxt::<C>(ctxt).int_arg_registers(), count)
414        })
415    }
416
417    extern "C" fn cb_float_args<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
418    where
419        C: CallingConvention,
420    {
421        ffi_wrap!("CallingConvention::float_arg_registers", unsafe {
422            register_list(from_ctxt::<C>(ctxt).float_arg_registers(), count)
423        })
424    }
425
426    extern "C" fn cb_required_argument_registers<C>(
427        ctxt: *mut c_void,
428        count: *mut usize,
429    ) -> *mut u32
430    where
431        C: CallingConvention,
432    {
433        ffi_wrap!("CallingConvention::required_argument_registers", unsafe {
434            register_list(from_ctxt::<C>(ctxt).required_argument_registers(), count)
435        })
436    }
437
438    extern "C" fn cb_required_clobbered_registers<C>(
439        ctxt: *mut c_void,
440        count: *mut usize,
441    ) -> *mut u32
442    where
443        C: CallingConvention,
444    {
445        ffi_wrap!("CallingConvention::required_clobbered_registers", unsafe {
446            register_list(from_ctxt::<C>(ctxt).required_clobbered_registers(), count)
447        })
448    }
449
450    extern "C" fn cb_arg_shared_index<C>(ctxt: *mut c_void) -> bool
451    where
452        C: CallingConvention,
453    {
454        ffi_wrap!("CallingConvention::arg_registers_shared_index", unsafe {
455            from_ctxt::<C>(ctxt).arg_registers_shared_index()
456        })
457    }
458
459    extern "C" fn cb_stack_reserved_arg_regs<C>(ctxt: *mut c_void) -> bool
460    where
461        C: CallingConvention,
462    {
463        ffi_wrap!(
464            "CallingConvention::reserved_stack_space_for_arg_registers",
465            unsafe { from_ctxt::<C>(ctxt).reserved_stack_space_for_arg_registers() }
466        )
467    }
468
469    extern "C" fn cb_stack_adjusted_on_return<C>(ctxt: *mut c_void) -> bool
470    where
471        C: CallingConvention,
472    {
473        ffi_wrap!("CallingConvention::stack_adjusted_on_return", unsafe {
474            from_ctxt::<C>(ctxt).stack_adjusted_on_return()
475        })
476    }
477
478    extern "C" fn cb_is_eligible_for_heuristics<C>(ctxt: *mut c_void) -> bool
479    where
480        C: CallingConvention,
481    {
482        ffi_wrap!("CallingConvention::is_eligible_for_heuristics", unsafe {
483            from_ctxt::<C>(ctxt).is_eligible_for_heuristics()
484        })
485    }
486
487    extern "C" fn cb_return_int_reg<C>(ctxt: *mut c_void) -> u32
488    where
489        C: CallingConvention,
490    {
491        ffi_wrap!("CallingConvention::return_int_reg", unsafe {
492            from_ctxt::<C>(ctxt)
493                .return_int_reg()
494                .map(|r| r.0)
495                .unwrap_or(INVALID_REGISTER)
496        })
497    }
498
499    extern "C" fn cb_return_hi_int_reg<C>(ctxt: *mut c_void) -> u32
500    where
501        C: CallingConvention,
502    {
503        ffi_wrap!("CallingConvention::return_hi_int_reg", unsafe {
504            from_ctxt::<C>(ctxt)
505                .return_hi_int_reg()
506                .map(|r| r.0)
507                .unwrap_or(INVALID_REGISTER)
508        })
509    }
510
511    extern "C" fn cb_return_float_reg<C>(ctxt: *mut c_void) -> u32
512    where
513        C: CallingConvention,
514    {
515        ffi_wrap!("CallingConvention::return_float_reg", unsafe {
516            from_ctxt::<C>(ctxt)
517                .return_float_reg()
518                .map(|r| r.0)
519                .unwrap_or(INVALID_REGISTER)
520        })
521    }
522
523    extern "C" fn cb_global_pointer_regs<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
524    where
525        C: CallingConvention,
526    {
527        ffi_wrap!("CallingConvention::global_pointer_regs", unsafe {
528            register_list(from_ctxt::<C>(ctxt).global_pointer_regs(), count)
529        })
530    }
531
532    extern "C" fn cb_implicitly_defined_registers<C>(
533        ctxt: *mut c_void,
534        count: *mut usize,
535    ) -> *mut u32
536    where
537        C: CallingConvention,
538    {
539        ffi_wrap!("CallingConvention::implicitly_defined_registers", unsafe {
540            register_list(from_ctxt::<C>(ctxt).implicitly_defined_registers(), count)
541        })
542    }
543
544    extern "C" fn cb_incoming_reg_value<C>(
545        ctxt: *mut c_void,
546        reg: u32,
547        func: *mut BNFunction,
548        val: *mut BNRegisterValue,
549    ) where
550        C: CallingConvention,
551    {
552        ffi_wrap!("CallingConvention::incoming_reg_value", unsafe {
553            let func = (!func.is_null()).then(|| Function::from_raw(func));
554            let value =
555                from_ctxt::<C>(ctxt).incoming_register_value(RegisterId(reg), func.as_ref());
556            ptr::write(val, value.into());
557        })
558    }
559
560    extern "C" fn cb_incoming_flag_value<C>(
561        ctxt: *mut c_void,
562        flag: u32,
563        func: *mut BNFunction,
564        val: *mut BNRegisterValue,
565    ) where
566        C: CallingConvention,
567    {
568        ffi_wrap!("CallingConvention::incoming_flag_value", unsafe {
569            let func = (!func.is_null()).then(|| Function::from_raw(func));
570            let value = from_ctxt::<C>(ctxt).incoming_flag_value(FlagId(flag), func.as_ref());
571            ptr::write(val, value.into());
572        })
573    }
574
575    extern "C" fn cb_incoming_var_for_param<C>(
576        ctxt: *mut c_void,
577        var: *const BNVariable,
578        func: *mut BNFunction,
579        param: *mut BNVariable,
580    ) where
581        C: CallingConvention,
582    {
583        ffi_wrap!("CallingConvention::incoming_var_for_param", unsafe {
584            let func = (!func.is_null()).then(|| Function::from_raw(func));
585            let var = Variable::from(&*var);
586            let result =
587                from_ctxt::<C>(ctxt).incoming_variable_for_parameter_variable(&var, func.as_ref());
588            ptr::write(param, result.into());
589        })
590    }
591
592    extern "C" fn cb_incoming_param_for_var<C>(
593        ctxt: *mut c_void,
594        var: *const BNVariable,
595        func: *mut BNFunction,
596        param: *mut BNVariable,
597    ) where
598        C: CallingConvention,
599    {
600        ffi_wrap!("CallingConvention::incoming_param_for_var", unsafe {
601            let func = (!func.is_null()).then(|| Function::from_raw(func));
602            let var = Variable::from(&*var);
603            let result =
604                from_ctxt::<C>(ctxt).parameter_variable_for_incoming_variable(&var, func.as_ref());
605            ptr::write(param, result.into());
606        })
607    }
608
609    extern "C" fn cb_are_argument_registers_used_for_var_args<C>(ctxt: *mut c_void) -> bool
610    where
611        C: CallingConvention,
612    {
613        ffi_wrap!(
614            "CallingConvention::are_argument_registers_used_for_var_args",
615            unsafe { from_ctxt::<C>(ctxt).are_argument_registers_used_for_var_args() }
616        )
617    }
618
619    extern "C" fn cb_is_return_type_register_compatible<C>(
620        ctxt: *mut c_void,
621        view: *mut BNBinaryView,
622        ty: *mut BNType,
623    ) -> bool
624    where
625        C: CallingConvention,
626    {
627        ffi_wrap!(
628            "CallingConvention::is_return_type_register_compatible",
629            unsafe {
630                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
631                let ty = (!ty.is_null()).then(|| Type::from_raw(ty));
632                match ty.as_ref() {
633                    Some(ty) => {
634                        from_ctxt::<C>(ctxt).is_return_type_register_compatible(view.as_ref(), ty)
635                    }
636                    _ => false,
637                }
638            }
639        )
640    }
641
642    extern "C" fn cb_indirect_return_value_location<C>(ctxt: *mut c_void, out_var: *mut BNVariable)
643    where
644        C: CallingConvention,
645    {
646        ffi_wrap!(
647            "CallingConvention::indirect_return_value_location",
648            unsafe {
649                ptr::write(
650                    out_var,
651                    from_ctxt::<C>(ctxt).indirect_return_value_location().into(),
652                );
653            }
654        )
655    }
656
657    extern "C" fn cb_returned_indirect_return_value_pointer<C>(
658        ctxt: *mut c_void,
659        out_var: *mut BNVariable,
660    ) -> bool
661    where
662        C: CallingConvention,
663    {
664        ffi_wrap!(
665            "CallingConvention::returned_indirect_return_value_pointer",
666            unsafe {
667                match from_ctxt::<C>(ctxt).returned_indirect_return_value_pointer() {
668                    Some(var) => {
669                        ptr::write(out_var, var.into());
670                        true
671                    }
672                    None => false,
673                }
674            }
675        )
676    }
677
678    extern "C" fn cb_is_argument_type_register_compatible<C>(
679        ctxt: *mut c_void,
680        view: *mut BNBinaryView,
681        ty: *mut BNType,
682    ) -> bool
683    where
684        C: CallingConvention,
685    {
686        ffi_wrap!(
687            "CallingConvention::is_argument_type_register_compatible",
688            unsafe {
689                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
690                let ty = (!ty.is_null()).then(|| Type::from_raw(ty));
691                match ty.as_ref() {
692                    Some(ty) => {
693                        from_ctxt::<C>(ctxt).is_argument_type_register_compatible(view.as_ref(), ty)
694                    }
695                    _ => false,
696                }
697            }
698        )
699    }
700
701    extern "C" fn cb_is_non_register_argument_indirect<C>(
702        ctxt: *mut c_void,
703        view: *mut BNBinaryView,
704        ty: *mut BNType,
705    ) -> bool
706    where
707        C: CallingConvention,
708    {
709        ffi_wrap!(
710            "CallingConvention::is_non_register_argument_indirect",
711            unsafe {
712                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
713                let ty = (!ty.is_null()).then(|| Type::from_raw(ty));
714                match ty.as_ref() {
715                    Some(ty) => {
716                        from_ctxt::<C>(ctxt).is_non_register_argument_indirect(view.as_ref(), ty)
717                    }
718                    _ => false,
719                }
720            }
721        )
722    }
723
724    extern "C" fn cb_are_stack_arguments_naturally_aligned<C>(ctxt: *mut c_void) -> bool
725    where
726        C: CallingConvention,
727    {
728        ffi_wrap!(
729            "CallingConvention::are_stack_arguments_naturally_aligned",
730            unsafe { from_ctxt::<C>(ctxt).are_stack_arguments_naturally_aligned() }
731        )
732    }
733
734    extern "C" fn cb_are_stack_arguments_pushed_left_to_right<C>(ctxt: *mut c_void) -> bool
735    where
736        C: CallingConvention,
737    {
738        ffi_wrap!(
739            "CallingConvention::are_stack_arguments_pushed_left_to_right",
740            unsafe { from_ctxt::<C>(ctxt).are_stack_arguments_pushed_left_to_right() }
741        )
742    }
743
744    #[allow(clippy::too_many_arguments)]
745    extern "C" fn cb_get_call_layout<C>(
746        ctxt: *mut c_void,
747        view: *mut BNBinaryView,
748        return_value: *mut BNReturnValue,
749        params: *mut BNFunctionParameter,
750        param_count: usize,
751        has_permitted_regs: bool,
752        permitted_regs: *mut u32,
753        permitted_reg_count: usize,
754        result: *mut BNCallLayout,
755    ) where
756        C: CallingConvention,
757    {
758        ffi_wrap!("CallingConvention::get_call_layout", unsafe {
759            let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
760            let return_value = ReturnValue::from_raw(&*return_value);
761            let params: Vec<FunctionParameter> = slice_from_raw_parts(params, param_count)
762                .iter()
763                .map(FunctionParameter::from_raw)
764                .collect();
765            let permitted =
766                permitted_registers(has_permitted_regs, permitted_regs, permitted_reg_count);
767            let layout = from_ctxt::<C>(ctxt).call_layout(
768                view.as_ref(),
769                &return_value,
770                &params,
771                permitted.as_deref(),
772            );
773            ptr::write(result, CallLayout::into_rust_raw(&layout));
774        })
775    }
776
777    extern "C" fn cb_free_call_layout(_ctxt: *mut c_void, layout: *mut BNCallLayout) {
778        ffi_wrap!("CallingConvention::free_call_layout", unsafe {
779            CallLayout::free_rust_raw(&mut *layout);
780        })
781    }
782
783    extern "C" fn cb_get_return_value_location<C>(
784        ctxt: *mut c_void,
785        view: *mut BNBinaryView,
786        return_value: *mut BNReturnValue,
787        out_location: *mut BNValueLocation,
788    ) where
789        C: CallingConvention,
790    {
791        ffi_wrap!("CallingConvention::get_return_value_location", unsafe {
792            let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
793            let return_value = ReturnValue::from_raw(&*return_value);
794            let location = from_ctxt::<C>(ctxt).return_value_location(view.as_ref(), &return_value);
795            ptr::write(out_location, ValueLocation::into_rust_raw(&location));
796        })
797    }
798
799    extern "C" fn cb_free_value_location(_ctxt: *mut c_void, location: *mut BNValueLocation) {
800        ffi_wrap!("CallingConvention::free_value_location", unsafe {
801            ValueLocation::free_rust_raw(ptr::read(location));
802        })
803    }
804
805    #[allow(clippy::too_many_arguments)]
806    extern "C" fn cb_get_parameter_locations<C>(
807        ctxt: *mut c_void,
808        view: *mut BNBinaryView,
809        return_value: *mut BNValueLocation,
810        params: *mut BNFunctionParameter,
811        param_count: usize,
812        has_permitted_regs: bool,
813        permitted_regs: *mut u32,
814        permitted_reg_count: usize,
815        out_count: *mut usize,
816    ) -> *mut BNValueLocation
817    where
818        C: CallingConvention,
819    {
820        ffi_wrap!("CallingConvention::get_parameter_locations", unsafe {
821            let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
822            let return_value =
823                (!return_value.is_null()).then(|| ValueLocation::from_raw(&*return_value));
824            let params: Vec<FunctionParameter> = slice_from_raw_parts(params, param_count)
825                .iter()
826                .map(FunctionParameter::from_raw)
827                .collect();
828            let permitted =
829                permitted_registers(has_permitted_regs, permitted_regs, permitted_reg_count);
830            let locations = from_ctxt::<C>(ctxt).parameter_locations(
831                view.as_ref(),
832                return_value.as_ref(),
833                &params,
834                permitted.as_deref(),
835            );
836            let raw: Box<[BNValueLocation]> =
837                locations.iter().map(ValueLocation::into_rust_raw).collect();
838            *out_count = raw.len();
839            Box::leak(raw).as_mut_ptr()
840        })
841    }
842
843    extern "C" fn cb_free_parameter_locations(
844        _ctxt: *mut c_void,
845        locations: *mut BNValueLocation,
846        count: usize,
847    ) {
848        ffi_wrap!("CallingConvention::free_parameter_locations", unsafe {
849            if locations.is_null() {
850                return;
851            }
852            let raw = Box::from_raw(ptr::slice_from_raw_parts_mut(locations, count));
853            for loc in raw.into_vec() {
854                ValueLocation::free_rust_raw(loc);
855            }
856        })
857    }
858
859    extern "C" fn cb_get_parameter_ordering_for_variables<C>(
860        ctxt: *mut c_void,
861        view: *mut BNBinaryView,
862        vars: *mut BNVariable,
863        types: *mut *mut BNType,
864        param_count: usize,
865        out_count: *mut usize,
866    ) -> *mut BNVariable
867    where
868        C: CallingConvention,
869    {
870        ffi_wrap!(
871            "CallingConvention::get_parameter_ordering_for_variables",
872            unsafe {
873                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
874                let vars = slice_from_raw_parts(vars, param_count);
875                let types = slice_from_raw_parts(types, param_count);
876                let params: Option<Vec<(Variable, Ref<Type>)>> = vars
877                    .iter()
878                    .zip(types.iter())
879                    .map(|(v, &ty)| {
880                        (!ty.is_null()).then(|| {
881                            (
882                                Variable::from(v),
883                                Type::ref_from_raw(BNNewTypeReference(ty)),
884                            )
885                        })
886                    })
887                    .collect();
888                let ordering = if let Some(params) = params.as_deref() {
889                    from_ctxt::<C>(ctxt).parameter_ordering_for_variables(view.as_ref(), params)
890                } else {
891                    Vec::new()
892                };
893                let raw: Box<[BNVariable]> =
894                    ordering.iter().map(|v| BNVariable::from(*v)).collect();
895                *out_count = raw.len();
896                Box::leak(raw).as_mut_ptr()
897            }
898        )
899    }
900
901    extern "C" fn cb_free_variable_list(_ctxt: *mut c_void, vars: *mut BNVariable, count: usize) {
902        ffi_wrap!("CallingConvention::free_variable_list", unsafe {
903            if vars.is_null() {
904                return;
905            }
906            let _vars = Box::from_raw(ptr::slice_from_raw_parts_mut(vars, count));
907        })
908    }
909
910    extern "C" fn cb_get_stack_adjustment_for_locations<C>(
911        ctxt: *mut c_void,
912        view: *mut BNBinaryView,
913        return_value: *mut BNValueLocation,
914        locations: *mut BNValueLocation,
915        types: *mut *mut BNType,
916        param_count: usize,
917    ) -> i64
918    where
919        C: CallingConvention,
920    {
921        ffi_wrap!(
922            "CallingConvention::get_stack_adjustment_for_locations",
923            unsafe {
924                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
925                let return_value =
926                    (!return_value.is_null()).then(|| ValueLocation::from_raw(&*return_value));
927                let locations = slice_from_raw_parts(locations, param_count);
928                let types = slice_from_raw_parts(types, param_count);
929                let params: Option<Vec<(ValueLocation, Ref<Type>)>> = locations
930                    .iter()
931                    .zip(types.iter())
932                    .map(|(loc, &ty)| {
933                        (!ty.is_null()).then(|| {
934                            (
935                                ValueLocation::from_raw(loc),
936                                Type::ref_from_raw(BNNewTypeReference(ty)),
937                            )
938                        })
939                    })
940                    .collect();
941                if let Some(params) = params.as_deref() {
942                    from_ctxt::<C>(ctxt).stack_adjustment_for_locations(
943                        view.as_ref(),
944                        return_value.as_ref(),
945                        params,
946                    )
947                } else {
948                    0
949                }
950            }
951        )
952    }
953
954    extern "C" fn cb_get_register_stack_adjustments<C>(
955        ctxt: *mut c_void,
956        view: *mut BNBinaryView,
957        return_value: *mut BNValueLocation,
958        params: *mut BNValueLocation,
959        param_count: usize,
960        out_regs: *mut *mut u32,
961        out_adjust: *mut *mut i32,
962    ) -> usize
963    where
964        C: CallingConvention,
965    {
966        ffi_wrap!(
967            "CallingConvention::get_register_stack_adjustments",
968            unsafe {
969                let view = (!view.is_null()).then(|| BinaryView::from_raw(view));
970                let return_value =
971                    (!return_value.is_null()).then(|| ValueLocation::from_raw(&*return_value));
972                let param_objs: Vec<ValueLocation> = slice_from_raw_parts(params, param_count)
973                    .iter()
974                    .map(ValueLocation::from_raw)
975                    .collect();
976                let adjustments = from_ctxt::<C>(ctxt).register_stack_adjustments(
977                    view.as_ref(),
978                    return_value.as_ref(),
979                    &param_objs,
980                );
981                let regs: Box<[u32]> = adjustments.keys().map(|r| r.0).collect();
982                let adjust: Box<[i32]> = adjustments.values().copied().collect();
983                let count = regs.len();
984                ptr::write(out_regs, Box::leak(regs).as_mut_ptr());
985                ptr::write(out_adjust, Box::leak(adjust).as_mut_ptr());
986                count
987            }
988        )
989    }
990
991    extern "C" fn cb_free_register_stack_adjustments(
992        _ctxt: *mut c_void,
993        regs: *mut u32,
994        adjust: *mut i32,
995        count: usize,
996    ) {
997        ffi_wrap!(
998            "CallingConvention::free_register_stack_adjustments",
999            unsafe {
1000                if !regs.is_null() {
1001                    let _ = Box::from_raw(ptr::slice_from_raw_parts_mut(regs, count));
1002                }
1003                if !adjust.is_null() {
1004                    let _ = Box::from_raw(ptr::slice_from_raw_parts_mut(adjust, count));
1005                }
1006            }
1007        )
1008    }
1009
1010    let name = name.to_cstr();
1011    let raw = Box::into_raw(Box::new(CustomCallingConventionContext::<C> {
1012        cc: MaybeUninit::uninit(),
1013    }));
1014    let mut cc = BNCustomCallingConvention {
1015        context: raw as *mut _,
1016
1017        freeObject: Some(cb_free::<C>),
1018
1019        getCallerSavedRegisters: Some(cb_caller_saved::<C>),
1020        getCalleeSavedRegisters: Some(cb_callee_saved::<C>),
1021        getIntegerArgumentRegisters: Some(cb_int_args::<C>),
1022        getFloatArgumentRegisters: Some(cb_float_args::<C>),
1023        getRequiredArgumentRegisters: Some(cb_required_argument_registers::<C>),
1024        getRequiredClobberedRegisters: Some(cb_required_clobbered_registers::<C>),
1025        freeRegisterList: Some(cb_free_register_list),
1026
1027        areArgumentRegistersSharedIndex: Some(cb_arg_shared_index::<C>),
1028        isStackReservedForArgumentRegisters: Some(cb_stack_reserved_arg_regs::<C>),
1029        isStackAdjustedOnReturn: Some(cb_stack_adjusted_on_return::<C>),
1030        isEligibleForHeuristics: Some(cb_is_eligible_for_heuristics::<C>),
1031
1032        getIntegerReturnValueRegister: Some(cb_return_int_reg::<C>),
1033        getHighIntegerReturnValueRegister: Some(cb_return_hi_int_reg::<C>),
1034        getFloatReturnValueRegister: Some(cb_return_float_reg::<C>),
1035        getGlobalPointerRegisters: Some(cb_global_pointer_regs::<C>),
1036
1037        getImplicitlyDefinedRegisters: Some(cb_implicitly_defined_registers::<C>),
1038        getIncomingRegisterValue: Some(cb_incoming_reg_value::<C>),
1039        getIncomingFlagValue: Some(cb_incoming_flag_value::<C>),
1040        getIncomingVariableForParameterVariable: Some(cb_incoming_var_for_param::<C>),
1041        getParameterVariableForIncomingVariable: Some(cb_incoming_param_for_var::<C>),
1042
1043        areArgumentRegistersUsedForVarArgs: Some(cb_are_argument_registers_used_for_var_args::<C>),
1044
1045        isReturnTypeRegisterCompatible: Some(cb_is_return_type_register_compatible::<C>),
1046        getIndirectReturnValueLocation: Some(cb_indirect_return_value_location::<C>),
1047        getReturnedIndirectReturnValuePointer: Some(cb_returned_indirect_return_value_pointer::<C>),
1048        isArgumentTypeRegisterCompatible: Some(cb_is_argument_type_register_compatible::<C>),
1049        isNonRegisterArgumentIndirect: Some(cb_is_non_register_argument_indirect::<C>),
1050        areStackArgumentsNaturallyAligned: Some(cb_are_stack_arguments_naturally_aligned::<C>),
1051        areStackArgumentsPushedLeftToRight: Some(cb_are_stack_arguments_pushed_left_to_right::<C>),
1052
1053        getCallLayout: Some(cb_get_call_layout::<C>),
1054        freeCallLayout: Some(cb_free_call_layout),
1055        getReturnValueLocation: Some(cb_get_return_value_location::<C>),
1056        freeValueLocation: Some(cb_free_value_location),
1057        getParameterLocations: Some(cb_get_parameter_locations::<C>),
1058        freeParameterLocations: Some(cb_free_parameter_locations),
1059        getParameterOrderingForVariables: Some(cb_get_parameter_ordering_for_variables::<C>),
1060        freeVariableList: Some(cb_free_variable_list),
1061        getStackAdjustmentForLocations: Some(cb_get_stack_adjustment_for_locations::<C>),
1062        getRegisterStackAdjustments: Some(cb_get_register_stack_adjustments::<C>),
1063        freeRegisterStackAdjustments: Some(cb_free_register_stack_adjustments),
1064    };
1065
1066    unsafe {
1067        let cc_name = name.as_ptr();
1068        let result = BNCreateCallingConvention(arch.as_ref().handle, cc_name, &mut cc);
1069
1070        assert!(!result.is_null());
1071
1072        let core = CoreCallingConvention::from_raw(result, arch.as_ref().handle());
1073        (*raw).cc.write(func(core));
1074
1075        BNRegisterCallingConvention(arch.as_ref().handle, result);
1076
1077        Ref::new(CoreCallingConvention {
1078            handle: result,
1079            arch_handle: arch.as_ref().handle(),
1080        })
1081    }
1082}
1083
1084pub struct CoreCallingConvention {
1085    pub(crate) handle: *mut BNCallingConvention,
1086    pub(crate) arch_handle: CoreArchitecture,
1087}
1088
1089impl CoreCallingConvention {
1090    pub(crate) unsafe fn from_raw(
1091        handle: *mut BNCallingConvention,
1092        arch: CoreArchitecture,
1093    ) -> Self {
1094        CoreCallingConvention {
1095            handle,
1096            arch_handle: arch,
1097        }
1098    }
1099
1100    pub(crate) unsafe fn ref_from_raw(
1101        handle: *mut BNCallingConvention,
1102        arch: CoreArchitecture,
1103    ) -> Ref<Self> {
1104        Ref::new(CoreCallingConvention {
1105            handle,
1106            arch_handle: arch,
1107        })
1108    }
1109
1110    pub fn name(&self) -> String {
1111        unsafe { BnString::into_string(BNGetCallingConventionName(self.handle)) }
1112    }
1113
1114    pub fn arch(&self) -> CoreArchitecture {
1115        self.arch_handle
1116    }
1117
1118    fn raw_permitted_args(permitted_registers: Option<&[RegisterId]>) -> Option<Vec<u32>> {
1119        permitted_registers.map(|regs| regs.iter().map(|r| r.0).collect())
1120    }
1121
1122    pub fn default_incoming_variable_for_parameter_variable(&self, var: &Variable) -> Variable {
1123        let raw = BNVariable::from(var);
1124        Variable::from(unsafe {
1125            BNGetDefaultIncomingVariableForParameterVariable(self.handle, &raw)
1126        })
1127    }
1128
1129    pub fn default_parameter_variable_for_incoming_variable(&self, var: &Variable) -> Variable {
1130        let raw = BNVariable::from(var);
1131        Variable::from(unsafe {
1132            BNGetDefaultParameterVariableForIncomingVariable(self.handle, &raw)
1133        })
1134    }
1135
1136    pub fn default_is_return_type_register_compatible(&self, ty: &Type) -> bool {
1137        unsafe { BNDefaultIsReturnTypeRegisterCompatible(self.handle, ty.handle) }
1138    }
1139
1140    pub fn default_indirect_return_value_location(&self) -> Variable {
1141        Variable::from(unsafe { BNGetDefaultIndirectReturnValueLocation(self.handle) })
1142    }
1143
1144    pub fn default_is_argument_type_register_compatible(&self, ty: &Type) -> bool {
1145        unsafe { BNDefaultIsArgumentTypeRegisterCompatible(self.handle, ty.handle) }
1146    }
1147
1148    pub fn default_call_layout(
1149        &self,
1150        view: Option<&BinaryView>,
1151        return_value: &ReturnValue,
1152        params: &[FunctionParameter],
1153        permitted_registers: Option<&[RegisterId]>,
1154    ) -> CallLayout {
1155        let raw_return_value = ReturnValue::into_rust_raw(return_value);
1156        let raw_params: Vec<BNFunctionParameter> = params
1157            .iter()
1158            .cloned()
1159            .map(FunctionParameter::into_raw)
1160            .collect();
1161        let raw_layout: BNCallLayout = match Self::raw_permitted_args(permitted_registers) {
1162            Some(permitted) => unsafe {
1163                BNGetDefaultCallLayout(
1164                    self.handle,
1165                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1166                    &raw_return_value,
1167                    raw_params.as_ptr(),
1168                    raw_params.len(),
1169                    permitted.as_ptr(),
1170                    permitted.len(),
1171                )
1172            },
1173            None => unsafe {
1174                BNGetDefaultCallLayoutDefaultPermittedArgs(
1175                    self.handle,
1176                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1177                    &raw_return_value,
1178                    raw_params.as_ptr(),
1179                    raw_params.len(),
1180                )
1181            },
1182        };
1183
1184        ReturnValue::free_rust_raw(raw_return_value);
1185        for param in raw_params {
1186            FunctionParameter::free_raw(param);
1187        }
1188        CallLayout::from_owned_core_raw(raw_layout)
1189    }
1190
1191    pub fn default_return_value_location(
1192        &self,
1193        view: Option<&BinaryView>,
1194        return_value: &ReturnValue,
1195    ) -> ValueLocation {
1196        let mut raw_return_value = ReturnValue::into_rust_raw(return_value);
1197        let mut raw_location = unsafe {
1198            BNGetDefaultReturnValueLocation(
1199                self.handle,
1200                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1201                &mut raw_return_value,
1202            )
1203        };
1204        ReturnValue::free_rust_raw(raw_return_value);
1205        let result = ValueLocation::from_raw(&raw_location);
1206        unsafe {
1207            BNFreeValueLocation(&mut raw_location);
1208        }
1209        result
1210    }
1211
1212    pub fn default_parameter_locations(
1213        &self,
1214        view: Option<&BinaryView>,
1215        return_value: Option<&ValueLocation>,
1216        params: &[FunctionParameter],
1217        permitted_registers: Option<&[RegisterId]>,
1218    ) -> Vec<ValueLocation> {
1219        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1220        let return_value_ptr = raw_return_value
1221            .as_mut()
1222            .map(|r| r as *mut _)
1223            .unwrap_or(ptr::null_mut());
1224        let mut raw_params: Vec<BNFunctionParameter> = params
1225            .iter()
1226            .cloned()
1227            .map(FunctionParameter::into_raw)
1228            .collect();
1229        let mut count = 0;
1230        let locations_ptr = unsafe {
1231            match Self::raw_permitted_args(permitted_registers) {
1232                Some(permitted) => BNGetDefaultParameterLocations(
1233                    self.handle,
1234                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1235                    return_value_ptr,
1236                    raw_params.as_mut_ptr(),
1237                    raw_params.len(),
1238                    permitted.as_ptr(),
1239                    permitted.len(),
1240                    &mut count,
1241                ),
1242                None => BNGetDefaultParameterLocationsDefaultPermittedArgs(
1243                    self.handle,
1244                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1245                    return_value_ptr,
1246                    raw_params.as_mut_ptr(),
1247                    raw_params.len(),
1248                    &mut count,
1249                ),
1250            }
1251        };
1252
1253        if let Some(raw_return_value) = raw_return_value {
1254            ValueLocation::free_rust_raw(raw_return_value);
1255        }
1256        for param in raw_params.drain(..) {
1257            FunctionParameter::free_raw(param);
1258        }
1259
1260        let result = unsafe {
1261            slice_from_raw_parts(locations_ptr, count)
1262                .iter()
1263                .map(ValueLocation::from_raw)
1264                .collect()
1265        };
1266        unsafe {
1267            BNFreeValueLocationList(locations_ptr, count);
1268        }
1269        result
1270    }
1271
1272    pub fn default_parameter_ordering_for_variables(
1273        &self,
1274        params: &[(Variable, Ref<Type>)],
1275    ) -> Vec<Variable> {
1276        let raw_vars: Vec<BNVariable> = params.iter().map(|(v, _)| BNVariable::from(*v)).collect();
1277        let mut raw_types: Vec<*const BNType> = params
1278            .iter()
1279            .map(|(_, t)| t.handle as *const BNType)
1280            .collect();
1281        let mut count = 0;
1282        let vars_ptr = unsafe {
1283            BNGetDefaultParameterOrderingForVariables(
1284                self.handle,
1285                raw_vars.as_ptr(),
1286                raw_types.as_mut_ptr(),
1287                params.len(),
1288                &mut count,
1289            )
1290        };
1291        let result = unsafe {
1292            slice_from_raw_parts(vars_ptr, count)
1293                .iter()
1294                .map(Variable::from)
1295                .collect()
1296        };
1297        unsafe {
1298            BNFreeVariableList(vars_ptr);
1299        }
1300        result
1301    }
1302
1303    pub fn default_stack_adjustment_for_locations(
1304        &self,
1305        return_value: Option<&ValueLocation>,
1306        params: &[(ValueLocation, Ref<Type>)],
1307    ) -> i64 {
1308        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1309        let return_value_ptr = raw_return_value
1310            .as_mut()
1311            .map(|r| r as *mut _)
1312            .unwrap_or(ptr::null_mut());
1313        let raw_locations: Vec<BNValueLocation> = params
1314            .iter()
1315            .map(|(loc, _)| ValueLocation::into_rust_raw(loc))
1316            .collect();
1317        let mut raw_types: Vec<*const BNType> = params
1318            .iter()
1319            .map(|(_, t)| t.handle as *const BNType)
1320            .collect();
1321        let result = unsafe {
1322            BNGetDefaultStackAdjustmentForLocations(
1323                self.handle,
1324                return_value_ptr,
1325                raw_locations.as_ptr(),
1326                raw_types.as_mut_ptr(),
1327                params.len(),
1328            )
1329        };
1330        if let Some(raw_return_value) = raw_return_value {
1331            ValueLocation::free_rust_raw(raw_return_value);
1332        }
1333        for loc in raw_locations {
1334            ValueLocation::free_rust_raw(loc);
1335        }
1336        result
1337    }
1338
1339    pub fn default_register_stack_adjustments(
1340        &self,
1341        return_value: Option<&ValueLocation>,
1342        params: &[ValueLocation],
1343    ) -> BTreeMap<RegisterId, i32> {
1344        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1345        let return_value_ptr = raw_return_value
1346            .as_mut()
1347            .map(|r| r as *mut _)
1348            .unwrap_or(ptr::null_mut());
1349        let mut raw_params: Vec<BNValueLocation> =
1350            params.iter().map(ValueLocation::into_rust_raw).collect();
1351        let mut regs: *mut u32 = ptr::null_mut();
1352        let mut adjust: *mut i32 = ptr::null_mut();
1353        let count = unsafe {
1354            BNGetCallingConventionDefaultRegisterStackAdjustments(
1355                self.handle,
1356                return_value_ptr,
1357                raw_params.as_mut_ptr(),
1358                raw_params.len(),
1359                &mut regs,
1360                &mut adjust,
1361            )
1362        };
1363        let regs_slice = unsafe { slice_from_raw_parts(regs, count) };
1364        let adjust_slice = unsafe { slice_from_raw_parts(adjust, count) };
1365        let result = regs_slice
1366            .iter()
1367            .zip(adjust_slice.iter())
1368            .map(|(r, a)| (RegisterId(*r), *a))
1369            .collect();
1370        if let Some(raw_return_value) = raw_return_value {
1371            ValueLocation::free_rust_raw(raw_return_value);
1372        }
1373        for param in raw_params {
1374            ValueLocation::free_rust_raw(param);
1375        }
1376        unsafe {
1377            BNFreeCallingConventionRegisterStackAdjustments(regs, adjust);
1378        }
1379        result
1380    }
1381}
1382
1383unsafe impl Send for CoreCallingConvention {}
1384unsafe impl Sync for CoreCallingConvention {}
1385
1386impl Eq for CoreCallingConvention {}
1387impl PartialEq for CoreCallingConvention {
1388    fn eq(&self, rhs: &Self) -> bool {
1389        self.handle == rhs.handle
1390    }
1391}
1392
1393impl AsRef<CoreCallingConvention> for CoreCallingConvention {
1394    fn as_ref(&self) -> &CoreCallingConvention {
1395        self
1396    }
1397}
1398
1399impl Debug for CoreCallingConvention {
1400    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1401        f.debug_struct("CoreCallingConvention")
1402            .field("name", &self.name())
1403            .field("caller_saved_registers", &self.caller_saved_registers())
1404            .field("callee_saved_registers", &self.callee_saved_registers())
1405            .field("int_arg_registers", &self.int_arg_registers())
1406            .field("float_arg_registers", &self.float_arg_registers())
1407            .field(
1408                "required_argument_registers",
1409                &self.required_argument_registers(),
1410            )
1411            .field(
1412                "required_clobbered_registers",
1413                &self.required_clobbered_registers(),
1414            )
1415            .field(
1416                "arg_registers_shared_index",
1417                &self.arg_registers_shared_index(),
1418            )
1419            .field(
1420                "reserved_stack_space_for_arg_registers",
1421                &self.reserved_stack_space_for_arg_registers(),
1422            )
1423            .field("stack_adjusted_on_return", &self.stack_adjusted_on_return())
1424            .field(
1425                "is_eligible_for_heuristics",
1426                &self.is_eligible_for_heuristics(),
1427            )
1428            .field("return_int_reg", &self.return_int_reg())
1429            .field("return_hi_int_reg", &self.return_hi_int_reg())
1430            .field("return_float_reg", &self.return_float_reg())
1431            .field("global_pointer_reg", &self.global_pointer_reg())
1432            .field("global_pointer_regs", &self.global_pointer_regs())
1433            .field(
1434                "implicitly_defined_registers",
1435                &self.implicitly_defined_registers(),
1436            )
1437            .field(
1438                "are_argument_registers_used_for_var_args",
1439                &self.are_argument_registers_used_for_var_args(),
1440            )
1441            .finish()
1442    }
1443}
1444
1445impl Hash for CoreCallingConvention {
1446    fn hash<H: Hasher>(&self, state: &mut H) {
1447        self.handle.hash(state);
1448    }
1449}
1450
1451impl CallingConvention for CoreCallingConvention {
1452    fn caller_saved_registers(&self) -> Vec<RegisterId> {
1453        unsafe {
1454            let mut count = 0;
1455            let regs_ptr = BNGetCallerSavedRegisters(self.handle, &mut count);
1456            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1457                .iter()
1458                .copied()
1459                .map(RegisterId::from)
1460                .collect();
1461            BNFreeRegisterList(regs_ptr);
1462            regs
1463        }
1464    }
1465
1466    fn callee_saved_registers(&self) -> Vec<RegisterId> {
1467        unsafe {
1468            let mut count = 0;
1469            let regs_ptr = BNGetCalleeSavedRegisters(self.handle, &mut count);
1470            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1471                .iter()
1472                .copied()
1473                .map(RegisterId::from)
1474                .collect();
1475            BNFreeRegisterList(regs_ptr);
1476            regs
1477        }
1478    }
1479
1480    fn int_arg_registers(&self) -> Vec<RegisterId> {
1481        unsafe {
1482            let mut count = 0;
1483            let regs_ptr = BNGetIntegerArgumentRegisters(self.handle, &mut count);
1484            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1485                .iter()
1486                .copied()
1487                .map(RegisterId::from)
1488                .collect();
1489            BNFreeRegisterList(regs_ptr);
1490            regs
1491        }
1492    }
1493
1494    fn float_arg_registers(&self) -> Vec<RegisterId> {
1495        unsafe {
1496            let mut count = 0;
1497            let regs_ptr = BNGetFloatArgumentRegisters(self.handle, &mut count);
1498            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1499                .iter()
1500                .copied()
1501                .map(RegisterId::from)
1502                .collect();
1503            BNFreeRegisterList(regs_ptr);
1504            regs
1505        }
1506    }
1507
1508    fn required_argument_registers(&self) -> Vec<RegisterId> {
1509        unsafe {
1510            let mut count = 0;
1511            let regs_ptr = BNGetRequiredArgumentRegisters(self.handle, &mut count);
1512            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1513                .iter()
1514                .copied()
1515                .map(RegisterId::from)
1516                .collect();
1517            BNFreeRegisterList(regs_ptr);
1518            regs
1519        }
1520    }
1521
1522    fn required_clobbered_registers(&self) -> Vec<RegisterId> {
1523        unsafe {
1524            let mut count = 0;
1525            let regs_ptr = BNGetRequiredClobberedRegisters(self.handle, &mut count);
1526            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1527                .iter()
1528                .copied()
1529                .map(RegisterId::from)
1530                .collect();
1531            BNFreeRegisterList(regs_ptr);
1532            regs
1533        }
1534    }
1535
1536    fn arg_registers_shared_index(&self) -> bool {
1537        unsafe { BNAreArgumentRegistersSharedIndex(self.handle) }
1538    }
1539
1540    fn reserved_stack_space_for_arg_registers(&self) -> bool {
1541        unsafe { BNIsStackReservedForArgumentRegisters(self.handle) }
1542    }
1543
1544    fn stack_adjusted_on_return(&self) -> bool {
1545        unsafe { BNIsStackAdjustedOnReturn(self.handle) }
1546    }
1547
1548    fn is_eligible_for_heuristics(&self) -> bool {
1549        unsafe { BNIsEligibleForHeuristics(self.handle) }
1550    }
1551
1552    fn return_int_reg(&self) -> Option<RegisterId> {
1553        match unsafe { BNGetIntegerReturnValueRegister(self.handle) } {
1554            id if id < 0x8000_0000 => self
1555                .arch_handle
1556                .borrow()
1557                .register_from_id(RegisterId(id))
1558                .map(|r| r.id()),
1559            _ => None,
1560        }
1561    }
1562
1563    fn return_hi_int_reg(&self) -> Option<RegisterId> {
1564        match unsafe { BNGetHighIntegerReturnValueRegister(self.handle) } {
1565            id if id < 0x8000_0000 => self
1566                .arch_handle
1567                .borrow()
1568                .register_from_id(RegisterId(id))
1569                .map(|r| r.id()),
1570            _ => None,
1571        }
1572    }
1573
1574    fn return_float_reg(&self) -> Option<RegisterId> {
1575        match unsafe { BNGetFloatReturnValueRegister(self.handle) } {
1576            id if id < 0x8000_0000 => self
1577                .arch_handle
1578                .borrow()
1579                .register_from_id(RegisterId(id))
1580                .map(|r| r.id()),
1581            _ => None,
1582        }
1583    }
1584
1585    /// Deprecated. Use [`CallingConvention::global_pointer_regs`] instead.
1586    fn global_pointer_reg(&self) -> Option<RegisterId> {
1587        self.global_pointer_regs().first().copied()
1588    }
1589
1590    fn global_pointer_regs(&self) -> Vec<RegisterId> {
1591        unsafe {
1592            let mut count = 0;
1593            let regs_ptr = BNGetGlobalPointerRegisters(self.handle, &mut count);
1594            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1595                .iter()
1596                .copied()
1597                .map(RegisterId::from)
1598                .collect();
1599            BNFreeRegisterList(regs_ptr);
1600            regs
1601        }
1602    }
1603
1604    fn implicitly_defined_registers(&self) -> Vec<RegisterId> {
1605        unsafe {
1606            let mut count = 0;
1607            let regs_ptr = BNGetImplicitlyDefinedRegisters(self.handle, &mut count);
1608            let regs: Vec<RegisterId> = std::slice::from_raw_parts(regs_ptr, count)
1609                .iter()
1610                .copied()
1611                .map(RegisterId::from)
1612                .collect();
1613            BNFreeRegisterList(regs_ptr);
1614            regs
1615        }
1616    }
1617
1618    fn are_argument_registers_used_for_var_args(&self) -> bool {
1619        unsafe { BNAreArgumentRegistersUsedForVarArgs(self.handle) }
1620    }
1621
1622    fn incoming_register_value(&self, reg: RegisterId, func: Option<&Function>) -> RegisterValue {
1623        let func = func.map(|f| f.handle).unwrap_or(ptr::null_mut());
1624        RegisterValue::from(unsafe { BNGetIncomingRegisterValue(self.handle, reg.0, func) })
1625    }
1626
1627    fn incoming_flag_value(&self, flag: FlagId, func: Option<&Function>) -> RegisterValue {
1628        let func = func.map(|f| f.handle).unwrap_or(ptr::null_mut());
1629        RegisterValue::from(unsafe { BNGetIncomingFlagValue(self.handle, flag.0, func) })
1630    }
1631
1632    fn incoming_variable_for_parameter_variable(
1633        &self,
1634        var: &Variable,
1635        func: Option<&Function>,
1636    ) -> Variable {
1637        let raw = BNVariable::from(var);
1638        let func = func.map(|f| f.handle).unwrap_or(ptr::null_mut());
1639        Variable::from(unsafe {
1640            BNGetIncomingVariableForParameterVariable(self.handle, &raw, func)
1641        })
1642    }
1643
1644    fn parameter_variable_for_incoming_variable(
1645        &self,
1646        var: &Variable,
1647        func: Option<&Function>,
1648    ) -> Variable {
1649        let raw = BNVariable::from(var);
1650        let func = func.map(|f| f.handle).unwrap_or(ptr::null_mut());
1651        Variable::from(unsafe {
1652            BNGetParameterVariableForIncomingVariable(self.handle, &raw, func)
1653        })
1654    }
1655
1656    fn is_return_type_register_compatible(&self, view: Option<&BinaryView>, ty: &Type) -> bool {
1657        unsafe {
1658            BNIsReturnTypeRegisterCompatible(
1659                self.handle,
1660                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1661                ty.handle,
1662            )
1663        }
1664    }
1665
1666    fn indirect_return_value_location(&self) -> Variable {
1667        Variable::from(unsafe { BNGetIndirectReturnValueLocation(self.handle) })
1668    }
1669
1670    fn returned_indirect_return_value_pointer(&self) -> Option<Variable> {
1671        let mut var = BNVariable::default();
1672        unsafe {
1673            BNGetReturnedIndirectReturnValuePointer(self.handle, &mut var)
1674                .then(|| Variable::from(var))
1675        }
1676    }
1677
1678    fn is_argument_type_register_compatible(&self, view: Option<&BinaryView>, ty: &Type) -> bool {
1679        unsafe {
1680            BNIsArgumentTypeRegisterCompatible(
1681                self.handle,
1682                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1683                ty.handle,
1684            )
1685        }
1686    }
1687
1688    fn is_non_register_argument_indirect(&self, view: Option<&BinaryView>, ty: &Type) -> bool {
1689        unsafe {
1690            BNIsNonRegisterArgumentIndirect(
1691                self.handle,
1692                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1693                ty.handle,
1694            )
1695        }
1696    }
1697
1698    fn are_stack_arguments_naturally_aligned(&self) -> bool {
1699        unsafe { BNAreStackArgumentsNaturallyAligned(self.handle) }
1700    }
1701
1702    fn are_stack_arguments_pushed_left_to_right(&self) -> bool {
1703        unsafe { BNAreStackArgumentsPushedLeftToRight(self.handle) }
1704    }
1705
1706    fn call_layout(
1707        &self,
1708        view: Option<&BinaryView>,
1709        return_value: &ReturnValue,
1710        params: &[FunctionParameter],
1711        permitted_registers: Option<&[RegisterId]>,
1712    ) -> CallLayout {
1713        let raw_return_value = ReturnValue::into_rust_raw(return_value);
1714        let raw_params: Vec<BNFunctionParameter> = params
1715            .iter()
1716            .cloned()
1717            .map(FunctionParameter::into_raw)
1718            .collect();
1719        let raw_layout: BNCallLayout = if let Some(permitted_args) = permitted_registers {
1720            let permitted_regs = permitted_args.iter().map(|r| r.0).collect::<Vec<_>>();
1721
1722            unsafe {
1723                BNGetCallLayout(
1724                    self.handle,
1725                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1726                    &raw_return_value,
1727                    raw_params.as_ptr(),
1728                    raw_params.len(),
1729                    permitted_regs.as_ptr(),
1730                    permitted_regs.len(),
1731                )
1732            }
1733        } else {
1734            unsafe {
1735                BNGetCallLayoutDefaultPermittedArgs(
1736                    self.handle,
1737                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1738                    &raw_return_value,
1739                    raw_params.as_ptr(),
1740                    raw_params.len(),
1741                )
1742            }
1743        };
1744
1745        ReturnValue::free_rust_raw(raw_return_value);
1746        for param in raw_params {
1747            FunctionParameter::free_raw(param);
1748        }
1749        CallLayout::from_owned_core_raw(raw_layout)
1750    }
1751
1752    fn return_value_location(
1753        &self,
1754        view: Option<&BinaryView>,
1755        return_value: &ReturnValue,
1756    ) -> ValueLocation {
1757        let mut raw_return_value = ReturnValue::into_rust_raw(return_value);
1758        let mut raw_location = unsafe {
1759            BNGetReturnValueLocation(
1760                self.handle,
1761                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1762                &mut raw_return_value,
1763            )
1764        };
1765        ReturnValue::free_rust_raw(raw_return_value);
1766        let result = ValueLocation::from_raw(&raw_location);
1767        unsafe {
1768            BNFreeValueLocation(&mut raw_location);
1769        }
1770        result
1771    }
1772
1773    fn parameter_locations(
1774        &self,
1775        view: Option<&BinaryView>,
1776        return_value: Option<&ValueLocation>,
1777        params: &[FunctionParameter],
1778        permitted_registers: Option<&[RegisterId]>,
1779    ) -> Vec<ValueLocation> {
1780        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1781        let return_value_ptr = raw_return_value
1782            .as_mut()
1783            .map(|r| r as *mut _)
1784            .unwrap_or(ptr::null_mut());
1785        let mut raw_params: Vec<BNFunctionParameter> = params
1786            .iter()
1787            .cloned()
1788            .map(FunctionParameter::into_raw)
1789            .collect();
1790        let mut count = 0;
1791        let locations_ptr = unsafe {
1792            match Self::raw_permitted_args(permitted_registers) {
1793                Some(permitted) => BNGetParameterLocations(
1794                    self.handle,
1795                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1796                    return_value_ptr,
1797                    raw_params.as_mut_ptr(),
1798                    raw_params.len(),
1799                    permitted.as_ptr(),
1800                    permitted.len(),
1801                    &mut count,
1802                ),
1803                None => BNGetParameterLocationsDefaultPermittedArgs(
1804                    self.handle,
1805                    view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1806                    return_value_ptr,
1807                    raw_params.as_mut_ptr(),
1808                    raw_params.len(),
1809                    &mut count,
1810                ),
1811            }
1812        };
1813
1814        if let Some(raw_return_value) = raw_return_value {
1815            ValueLocation::free_rust_raw(raw_return_value);
1816        }
1817        for param in raw_params {
1818            FunctionParameter::free_raw(param);
1819        }
1820
1821        let result = unsafe {
1822            slice_from_raw_parts(locations_ptr, count)
1823                .iter()
1824                .map(ValueLocation::from_raw)
1825                .collect()
1826        };
1827        unsafe {
1828            BNFreeValueLocationList(locations_ptr, count);
1829        }
1830        result
1831    }
1832
1833    fn parameter_ordering_for_variables(
1834        &self,
1835        view: Option<&BinaryView>,
1836        params: &[(Variable, Ref<Type>)],
1837    ) -> Vec<Variable> {
1838        let raw_vars: Vec<BNVariable> = params.iter().map(|(v, _)| BNVariable::from(*v)).collect();
1839        let mut raw_types: Vec<*const BNType> = params
1840            .iter()
1841            .map(|(_, t)| t.handle as *const BNType)
1842            .collect();
1843        let mut count = 0;
1844        let vars_ptr = unsafe {
1845            BNGetParameterOrderingForVariables(
1846                self.handle,
1847                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1848                raw_vars.as_ptr(),
1849                raw_types.as_mut_ptr(),
1850                params.len(),
1851                &mut count,
1852            )
1853        };
1854        let result = unsafe {
1855            slice_from_raw_parts(vars_ptr, count)
1856                .iter()
1857                .map(Variable::from)
1858                .collect()
1859        };
1860        unsafe {
1861            BNFreeVariableList(vars_ptr);
1862        }
1863        result
1864    }
1865
1866    fn stack_adjustment_for_locations(
1867        &self,
1868        view: Option<&BinaryView>,
1869        return_value: Option<&ValueLocation>,
1870        params: &[(ValueLocation, Ref<Type>)],
1871    ) -> i64 {
1872        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1873        let return_value_ptr = raw_return_value
1874            .as_mut()
1875            .map(|r| r as *mut _)
1876            .unwrap_or(ptr::null_mut());
1877        let raw_locations: Vec<BNValueLocation> = params
1878            .iter()
1879            .map(|(loc, _)| ValueLocation::into_rust_raw(loc))
1880            .collect();
1881        let mut raw_types: Vec<*const BNType> = params
1882            .iter()
1883            .map(|(_, t)| t.handle as *const BNType)
1884            .collect();
1885        let result = unsafe {
1886            BNGetStackAdjustmentForLocations(
1887                self.handle,
1888                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1889                return_value_ptr,
1890                raw_locations.as_ptr(),
1891                raw_types.as_mut_ptr(),
1892                params.len(),
1893            )
1894        };
1895        if let Some(raw_return_value) = raw_return_value {
1896            ValueLocation::free_rust_raw(raw_return_value);
1897        }
1898        for loc in raw_locations {
1899            ValueLocation::free_rust_raw(loc);
1900        }
1901        result
1902    }
1903
1904    fn register_stack_adjustments(
1905        &self,
1906        view: Option<&BinaryView>,
1907        return_value: Option<&ValueLocation>,
1908        params: &[ValueLocation],
1909    ) -> BTreeMap<RegisterId, i32> {
1910        let mut raw_return_value = return_value.map(ValueLocation::into_rust_raw);
1911        let return_value_ptr = raw_return_value
1912            .as_mut()
1913            .map(|r| r as *mut _)
1914            .unwrap_or(ptr::null_mut());
1915        let mut raw_params: Vec<BNValueLocation> =
1916            params.iter().map(ValueLocation::into_rust_raw).collect();
1917        let mut regs: *mut u32 = ptr::null_mut();
1918        let mut adjust: *mut i32 = ptr::null_mut();
1919        let count = unsafe {
1920            BNGetCallingConventionRegisterStackAdjustments(
1921                self.handle,
1922                view.map(|view| view.handle).unwrap_or(ptr::null_mut()),
1923                return_value_ptr,
1924                raw_params.as_mut_ptr(),
1925                raw_params.len(),
1926                &mut regs,
1927                &mut adjust,
1928            )
1929        };
1930        let regs_slice = unsafe { slice_from_raw_parts(regs, count) };
1931        let adjust_slice = unsafe { slice_from_raw_parts(adjust, count) };
1932        let result = regs_slice
1933            .iter()
1934            .zip(adjust_slice.iter())
1935            .map(|(r, a)| (RegisterId(*r), *a))
1936            .collect();
1937        if let Some(raw_return_value) = raw_return_value {
1938            ValueLocation::free_rust_raw(raw_return_value);
1939        }
1940        for param in raw_params {
1941            ValueLocation::free_rust_raw(param);
1942        }
1943        unsafe {
1944            BNFreeCallingConventionRegisterStackAdjustments(regs, adjust);
1945        }
1946        result
1947    }
1948}
1949
1950impl ToOwned for CoreCallingConvention {
1951    type Owned = Ref<Self>;
1952
1953    fn to_owned(&self) -> Self::Owned {
1954        unsafe { RefCountable::inc_ref(self) }
1955    }
1956}
1957
1958unsafe impl RefCountable for CoreCallingConvention {
1959    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1960        Ref::new(Self {
1961            handle: BNNewCallingConventionReference(handle.handle),
1962            arch_handle: handle.arch_handle,
1963        })
1964    }
1965
1966    unsafe fn dec_ref(handle: &Self) {
1967        BNFreeCallingConvention(handle.handle);
1968    }
1969}
1970
1971impl CoreArrayProvider for CoreCallingConvention {
1972    type Raw = *mut BNCallingConvention;
1973    type Context = CoreArchitecture;
1974    type Wrapped<'a> = Guard<'a, CoreCallingConvention>;
1975}
1976
1977unsafe impl CoreArrayProviderInner for CoreCallingConvention {
1978    unsafe fn free(raw: *mut *mut BNCallingConvention, count: usize, _content: &Self::Context) {
1979        BNFreeCallingConventionList(raw, count);
1980    }
1981
1982    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
1983        Guard::new(
1984            CoreCallingConvention {
1985                handle: *raw,
1986                arch_handle: *context,
1987            },
1988            context,
1989        )
1990    }
1991}
1992
1993/// A builder for a calling convention defined entirely by its register sets and flags.
1994///
1995/// Conventions built this way use the core's default behavior for parameter and return value
1996/// placement. Override the [`CallingConvention`] trait directly if you need custom layout logic.
1997pub struct ConventionBuilder<A: Architecture> {
1998    config: ConventionConfig,
1999    arch_handle: A::Handle,
2000    _arch: PhantomData<*const A>,
2001}
2002
2003/// The plain-data portion of a [`ConventionBuilder`]. Moved to a [`RegisteredConvention`] when
2004/// registered.
2005struct ConventionConfig {
2006    caller_saved_registers: Vec<RegisterId>,
2007    callee_saved_registers: Vec<RegisterId>,
2008    int_arg_registers: Vec<RegisterId>,
2009    float_arg_registers: Vec<RegisterId>,
2010    required_argument_registers: Vec<RegisterId>,
2011    required_clobbered_registers: Vec<RegisterId>,
2012
2013    arg_registers_shared_index: bool,
2014    reserved_stack_space_for_arg_registers: bool,
2015    stack_adjusted_on_return: bool,
2016    is_eligible_for_heuristics: bool,
2017
2018    return_int_reg: Option<RegisterId>,
2019    return_hi_int_reg: Option<RegisterId>,
2020    return_float_reg: Option<RegisterId>,
2021
2022    global_pointer_reg: Option<RegisterId>,
2023    global_pointer_regs: Vec<RegisterId>,
2024
2025    implicitly_defined_registers: Vec<RegisterId>,
2026
2027    are_argument_registers_used_for_var_args: bool,
2028    are_stack_arguments_naturally_aligned: bool,
2029    are_stack_arguments_pushed_left_to_right: bool,
2030
2031    is_non_register_argument_indirect: bool,
2032
2033    indirect_return_value_location: Option<Variable>,
2034    returned_indirect_return_value_pointer: Option<Variable>,
2035}
2036
2037macro_rules! bool_arg {
2038    ($name:ident) => {
2039        pub fn $name(mut self, val: bool) -> Self {
2040            self.config.$name = val;
2041            self
2042        }
2043    };
2044}
2045
2046macro_rules! reg_list {
2047    ($name:ident) => {
2048        pub fn $name(mut self, regs: &[&str]) -> Self {
2049            {
2050                // FIXME NLL
2051                let arch = self.arch_handle.borrow();
2052                let arch_regs = regs
2053                    .iter()
2054                    .filter_map(|&r| arch.register_by_name(r))
2055                    .map(|r| r.id());
2056
2057                self.config.$name = arch_regs.collect();
2058            }
2059
2060            self
2061        }
2062    };
2063}
2064
2065macro_rules! reg {
2066    ($name:ident) => {
2067        pub fn $name(mut self, reg: &str) -> Self {
2068            {
2069                // FIXME NLL
2070                let arch = self.arch_handle.borrow();
2071                self.config.$name = arch.register_by_name(reg).map(|r| r.id());
2072            }
2073
2074            self
2075        }
2076    };
2077}
2078
2079impl<A: Architecture> ConventionBuilder<A> {
2080    pub fn new(arch: &A) -> Self {
2081        Self {
2082            config: ConventionConfig {
2083                caller_saved_registers: Vec::new(),
2084                callee_saved_registers: Vec::new(),
2085                int_arg_registers: Vec::new(),
2086                float_arg_registers: Vec::new(),
2087                required_argument_registers: Vec::new(),
2088                required_clobbered_registers: Vec::new(),
2089
2090                arg_registers_shared_index: false,
2091                reserved_stack_space_for_arg_registers: false,
2092                stack_adjusted_on_return: false,
2093                is_eligible_for_heuristics: false,
2094
2095                return_int_reg: None,
2096                return_hi_int_reg: None,
2097                return_float_reg: None,
2098
2099                global_pointer_reg: None,
2100                global_pointer_regs: Vec::new(),
2101
2102                implicitly_defined_registers: Vec::new(),
2103
2104                are_argument_registers_used_for_var_args: false,
2105                are_stack_arguments_naturally_aligned: false,
2106                are_stack_arguments_pushed_left_to_right: false,
2107
2108                is_non_register_argument_indirect: false,
2109
2110                indirect_return_value_location: None,
2111                returned_indirect_return_value_pointer: None,
2112            },
2113            arch_handle: arch.handle(),
2114            _arch: PhantomData,
2115        }
2116    }
2117
2118    reg_list!(caller_saved_registers);
2119    reg_list!(callee_saved_registers);
2120    reg_list!(int_arg_registers);
2121    reg_list!(float_arg_registers);
2122    reg_list!(required_argument_registers);
2123    reg_list!(required_clobbered_registers);
2124
2125    bool_arg!(arg_registers_shared_index);
2126    bool_arg!(reserved_stack_space_for_arg_registers);
2127    bool_arg!(stack_adjusted_on_return);
2128    bool_arg!(is_eligible_for_heuristics);
2129
2130    reg!(return_int_reg);
2131    reg!(return_hi_int_reg);
2132    reg!(return_float_reg);
2133
2134    /// Deprecated. Use [`Self::global_pointer_regs`] instead.
2135    pub fn global_pointer_reg(mut self, reg: &str) -> Self {
2136        {
2137            // FIXME NLL
2138            let arch = self.arch_handle.borrow();
2139            self.config.global_pointer_reg = arch.register_by_name(reg).map(|r| r.id());
2140            self.config.global_pointer_regs = self.config.global_pointer_reg.into_iter().collect();
2141        }
2142
2143        self
2144    }
2145
2146    pub fn global_pointer_regs(mut self, regs: &[&str]) -> Self {
2147        {
2148            // FIXME NLL
2149            let arch = self.arch_handle.borrow();
2150            let arch_regs = regs
2151                .iter()
2152                .filter_map(|&r| arch.register_by_name(r))
2153                .map(|r| r.id());
2154
2155            self.config.global_pointer_regs = arch_regs.collect();
2156            self.config.global_pointer_reg = self.config.global_pointer_regs.first().copied();
2157        }
2158
2159        self
2160    }
2161
2162    reg_list!(implicitly_defined_registers);
2163
2164    bool_arg!(are_argument_registers_used_for_var_args);
2165    bool_arg!(are_stack_arguments_naturally_aligned);
2166    bool_arg!(are_stack_arguments_pushed_left_to_right);
2167
2168    bool_arg!(is_non_register_argument_indirect);
2169
2170    pub fn indirect_return_value_location(mut self, var: Variable) -> Self {
2171        self.config.indirect_return_value_location = Some(var);
2172        self
2173    }
2174
2175    pub fn returned_indirect_return_value_pointer(mut self, var: Variable) -> Self {
2176        self.config.returned_indirect_return_value_pointer = Some(var);
2177        self
2178    }
2179
2180    pub fn register(self, name: &str) -> Ref<CoreCallingConvention> {
2181        let arch = self.arch_handle.clone();
2182        register_calling_convention(arch.borrow(), name, move |core| RegisteredConvention {
2183            config: self.config,
2184            core,
2185        })
2186    }
2187}
2188
2189/// A registered [`ConventionBuilder`], holding its configuration and core handle.
2190struct RegisteredConvention {
2191    config: ConventionConfig,
2192    core: CoreCallingConvention,
2193}
2194
2195unsafe impl Send for RegisteredConvention {}
2196unsafe impl Sync for RegisteredConvention {}
2197
2198impl AsRef<CoreCallingConvention> for RegisteredConvention {
2199    fn as_ref(&self) -> &CoreCallingConvention {
2200        &self.core
2201    }
2202}
2203
2204impl CallingConvention for RegisteredConvention {
2205    fn caller_saved_registers(&self) -> Vec<RegisterId> {
2206        self.config.caller_saved_registers.clone()
2207    }
2208
2209    fn callee_saved_registers(&self) -> Vec<RegisterId> {
2210        self.config.callee_saved_registers.clone()
2211    }
2212
2213    fn int_arg_registers(&self) -> Vec<RegisterId> {
2214        self.config.int_arg_registers.clone()
2215    }
2216
2217    fn float_arg_registers(&self) -> Vec<RegisterId> {
2218        self.config.float_arg_registers.clone()
2219    }
2220
2221    fn required_argument_registers(&self) -> Vec<RegisterId> {
2222        self.config.required_argument_registers.clone()
2223    }
2224
2225    fn required_clobbered_registers(&self) -> Vec<RegisterId> {
2226        self.config.required_clobbered_registers.clone()
2227    }
2228
2229    fn arg_registers_shared_index(&self) -> bool {
2230        self.config.arg_registers_shared_index
2231    }
2232
2233    fn reserved_stack_space_for_arg_registers(&self) -> bool {
2234        self.config.reserved_stack_space_for_arg_registers
2235    }
2236
2237    fn stack_adjusted_on_return(&self) -> bool {
2238        self.config.stack_adjusted_on_return
2239    }
2240
2241    fn is_eligible_for_heuristics(&self) -> bool {
2242        self.config.is_eligible_for_heuristics
2243    }
2244
2245    fn return_int_reg(&self) -> Option<RegisterId> {
2246        self.config.return_int_reg
2247    }
2248
2249    fn return_hi_int_reg(&self) -> Option<RegisterId> {
2250        self.config.return_hi_int_reg
2251    }
2252
2253    fn return_float_reg(&self) -> Option<RegisterId> {
2254        self.config.return_float_reg
2255    }
2256
2257    fn global_pointer_reg(&self) -> Option<RegisterId> {
2258        self.config
2259            .global_pointer_reg
2260            .or_else(|| self.config.global_pointer_regs.first().copied())
2261    }
2262
2263    fn global_pointer_regs(&self) -> Vec<RegisterId> {
2264        if self.config.global_pointer_regs.is_empty() {
2265            self.config.global_pointer_reg.into_iter().collect()
2266        } else {
2267            self.config.global_pointer_regs.clone()
2268        }
2269    }
2270
2271    fn implicitly_defined_registers(&self) -> Vec<RegisterId> {
2272        self.config.implicitly_defined_registers.clone()
2273    }
2274
2275    fn are_argument_registers_used_for_var_args(&self) -> bool {
2276        self.config.are_argument_registers_used_for_var_args
2277    }
2278
2279    fn are_stack_arguments_naturally_aligned(&self) -> bool {
2280        self.config.are_stack_arguments_naturally_aligned
2281    }
2282
2283    fn are_stack_arguments_pushed_left_to_right(&self) -> bool {
2284        self.config.are_stack_arguments_pushed_left_to_right
2285    }
2286
2287    fn is_non_register_argument_indirect(&self, _view: Option<&BinaryView>, _ty: &Type) -> bool {
2288        self.config.is_non_register_argument_indirect
2289    }
2290
2291    fn indirect_return_value_location(&self) -> Variable {
2292        match self.config.indirect_return_value_location {
2293            Some(var) => var,
2294            None => self.as_ref().default_indirect_return_value_location(),
2295        }
2296    }
2297
2298    fn returned_indirect_return_value_pointer(&self) -> Option<Variable> {
2299        self.config.returned_indirect_return_value_pointer
2300    }
2301}
2302
2303#[derive(Debug, Clone, PartialEq, Eq, Default)]
2304pub struct CallLayout {
2305    pub parameters: Vec<ValueLocation>,
2306    pub return_value: Option<ValueLocation>,
2307    pub stack_adjustment: i64,
2308    pub register_stack_adjustments: BTreeMap<RegisterId, i32>,
2309}
2310
2311impl CallLayout {
2312    pub(crate) fn from_raw(value: &BNCallLayout) -> Self {
2313        let raw_params = unsafe { slice_from_raw_parts(value.parameters, value.parameterCount) };
2314        let parameters = raw_params.iter().map(ValueLocation::from_raw).collect();
2315        let return_value = if value.returnValueValid {
2316            Some(ValueLocation::from_raw(&value.returnValue))
2317        } else {
2318            None
2319        };
2320        let raw_regs = unsafe {
2321            slice_from_raw_parts(
2322                value.registerStackAdjustmentRegisters,
2323                value.registerStackAdjustmentCount,
2324            )
2325        };
2326        let raw_amounts = unsafe {
2327            slice_from_raw_parts(
2328                value.registerStackAdjustmentAmounts,
2329                value.registerStackAdjustmentCount,
2330            )
2331        };
2332        let mut register_stack_adjustments = BTreeMap::new();
2333        for i in 0..value.registerStackAdjustmentCount {
2334            register_stack_adjustments.insert(RegisterId(raw_regs[i]), raw_amounts[i]);
2335        }
2336        Self {
2337            parameters,
2338            return_value,
2339            stack_adjustment: value.stackAdjustment,
2340            register_stack_adjustments,
2341        }
2342    }
2343
2344    /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
2345    pub(crate) fn from_owned_core_raw(mut value: BNCallLayout) -> Self {
2346        let owned = Self::from_raw(&value);
2347        Self::free_core_raw(&mut value);
2348        owned
2349    }
2350
2351    /// Free a CORE ALLOCATED value. Do not use this with [Self::into_rust_raw] values.
2352    pub(crate) fn free_core_raw(value: &mut BNCallLayout) {
2353        unsafe { BNFreeCallLayout(value) }
2354    }
2355
2356    /// Build a RUST ALLOCATED value. Free it only with [Self::free_rust_raw].
2357    pub(crate) fn into_rust_raw(value: &Self) -> BNCallLayout {
2358        let parameters: Box<[BNValueLocation]> = value
2359            .parameters
2360            .iter()
2361            .map(ValueLocation::into_rust_raw)
2362            .collect();
2363        let regs: Box<[u32]> = value
2364            .register_stack_adjustments
2365            .keys()
2366            .map(|r| r.0)
2367            .collect();
2368        let amounts: Box<[i32]> = value.register_stack_adjustments.values().copied().collect();
2369        let return_value =
2370            ValueLocation::into_rust_raw(value.return_value.as_ref().unwrap_or(&ValueLocation {
2371                components: Vec::new(),
2372                indirect: false,
2373                returned_pointer: None,
2374            }));
2375        BNCallLayout {
2376            parameterCount: parameters.len(),
2377            parameters: Box::leak(parameters).as_mut_ptr(),
2378            returnValueValid: value.return_value.is_some(),
2379            returnValue: return_value,
2380            stackAdjustment: value.stack_adjustment,
2381            registerStackAdjustmentCount: regs.len(),
2382            registerStackAdjustmentRegisters: Box::leak(regs).as_mut_ptr(),
2383            registerStackAdjustmentAmounts: Box::leak(amounts).as_mut_ptr(),
2384        }
2385    }
2386
2387    /// Free a RUST ALLOCATED value. Do not use this with CORE ALLOCATED values.
2388    pub(crate) fn free_rust_raw(value: &mut BNCallLayout) {
2389        unsafe {
2390            let params = Box::from_raw(ptr::slice_from_raw_parts_mut(
2391                value.parameters,
2392                value.parameterCount,
2393            ));
2394            for loc in params.into_vec() {
2395                ValueLocation::free_rust_raw(loc);
2396            }
2397            ValueLocation::free_rust_raw(ptr::read(&value.returnValue));
2398            let _ = Box::from_raw(ptr::slice_from_raw_parts_mut(
2399                value.registerStackAdjustmentRegisters,
2400                value.registerStackAdjustmentCount,
2401            ));
2402            let _ = Box::from_raw(ptr::slice_from_raw_parts_mut(
2403                value.registerStackAdjustmentAmounts,
2404                value.registerStackAdjustmentCount,
2405            ));
2406        }
2407    }
2408}