1use 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
39pub trait CallingConvention: 'static + Sync + Sized + AsRef<CoreCallingConvention> {
51 fn caller_saved_registers(&self) -> Vec<RegisterId>;
54
55 fn callee_saved_registers(&self) -> Vec<RegisterId>;
58
59 fn int_arg_registers(&self) -> Vec<RegisterId>;
61
62 fn float_arg_registers(&self) -> Vec<RegisterId>;
64
65 fn required_argument_registers(&self) -> Vec<RegisterId> {
68 Vec::new()
69 }
70
71 fn required_clobbered_registers(&self) -> Vec<RegisterId> {
74 Vec::new()
75 }
76
77 fn arg_registers_shared_index(&self) -> bool;
83
84 fn reserved_stack_space_for_arg_registers(&self) -> bool;
87
88 fn stack_adjusted_on_return(&self) -> bool;
91
92 fn is_eligible_for_heuristics(&self) -> bool;
94
95 fn return_int_reg(&self) -> Option<RegisterId>;
97
98 fn return_hi_int_reg(&self) -> Option<RegisterId>;
101
102 fn return_float_reg(&self) -> Option<RegisterId>;
104
105 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 fn implicitly_defined_registers(&self) -> Vec<RegisterId>;
116
117 fn are_argument_registers_used_for_var_args(&self) -> bool;
119
120 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 fn incoming_flag_value(&self, _flag: FlagId, _func: Option<&Function>) -> RegisterValue {
138 RegisterValue::new(RegisterValueType::UndeterminedValue, 0, 0, 0)
139 }
140
141 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 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 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 fn indirect_return_value_location(&self) -> Variable {
174 self.as_ref().default_indirect_return_value_location()
175 }
176
177 fn returned_indirect_return_value_pointer(&self) -> Option<Variable> {
180 None
181 }
182
183 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 fn is_non_register_argument_indirect(&self, _view: Option<&BinaryView>, _ty: &Type) -> bool {
194 false
195 }
196
197 fn are_stack_arguments_naturally_aligned(&self) -> bool {
200 false
201 }
202
203 fn are_stack_arguments_pushed_left_to_right(&self) -> bool {
206 false
207 }
208
209 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 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 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 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 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 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
318pub 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 ¶ms,
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 ¶ms,
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 ¶m_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 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
1993pub struct ConventionBuilder<A: Architecture> {
1998 config: ConventionConfig,
1999 arch_handle: A::Handle,
2000 _arch: PhantomData<*const A>,
2001}
2002
2003struct 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 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 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 pub fn global_pointer_reg(mut self, reg: &str) -> Self {
2136 {
2137 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 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
2189struct 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 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 pub(crate) fn free_core_raw(value: &mut BNCallLayout) {
2353 unsafe { BNFreeCallLayout(value) }
2354 }
2355
2356 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 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}