luaur_code_gen/functions/
create_block_unwind_info.rs1use crate::functions::visit_fde_entries::visit_fde_entries;
2use crate::macros::codegen_assert::CODEGEN_ASSERT;
3
4#[cfg(not(target_os = "windows"))]
5extern "C" {
6 fn __register_frame(begin: *const core::ffi::c_void);
7}
8
9#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
10extern "C" {
11 fn dlsym(
12 handle: *mut core::ffi::c_void,
13 symbol: *const core::ffi::c_char,
14 ) -> *mut core::ffi::c_void;
15}
16
17#[cfg(target_os = "windows")]
18extern "system" {
19 fn RtlAddFunctionTable(
20 function_table: *mut core::ffi::c_void,
21 entry_count: u32,
22 base_address: usize,
23 ) -> i32;
24}
25
26pub unsafe extern "C" fn create_block_unwind_info(
27 context: *mut core::ffi::c_void,
28 block: *mut u8,
29 block_size: usize,
30 begin_offset: &mut usize,
31) -> *mut core::ffi::c_void {
32 const K_CODE_ALIGNMENT: usize = 32;
33
34 #[cfg(target_os = "windows")]
35 let (function_count, builder_begin_offset, unwind_size) = {
36 let unwind = &mut *(context.cast::<crate::records::unwind_builder_win::UnwindBuilderWin>());
37 let unwind_size = (unwind.get_unwind_info_size(block_size) + (K_CODE_ALIGNMENT - 1))
38 & !(K_CODE_ALIGNMENT - 1);
39
40 CODEGEN_ASSERT!(block_size >= unwind_size);
41
42 let function_count = unwind.finalize(block.cast(), unwind_size, block.cast(), block_size);
43
44 (function_count, unwind.get_begin_offset(), unwind_size)
45 };
46
47 #[cfg(not(target_os = "windows"))]
48 let (builder_begin_offset, unwind_size) = {
49 let unwind =
50 &mut *(context.cast::<crate::records::unwind_builder_dwarf_2::UnwindBuilderDwarf2>());
51 let unwind_size = (unwind.get_unwind_info_size(block_size) + (K_CODE_ALIGNMENT - 1))
52 & !(K_CODE_ALIGNMENT - 1);
53
54 CODEGEN_ASSERT!(block_size >= unwind_size);
55
56 unwind.finalize(block.cast(), unwind_size, block.cast(), block_size);
57
58 (unwind.get_begin_offset(), unwind_size)
59 };
60
61 #[cfg(target_os = "windows")]
62 {
63 if RtlAddFunctionTable(block.cast(), function_count as u32, block as usize) == 0 {
64 CODEGEN_ASSERT!(false);
65 return core::ptr::null_mut();
66 }
67 }
68
69 #[cfg(not(target_os = "windows"))]
70 {
71 visit_fde_entries(block.cast(), __register_frame);
72 }
73
74 #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
75 register_macos_a64_unwind_sections();
76
77 *begin_offset = unwind_size + builder_begin_offset;
78 block.cast()
79}
80
81#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
82fn register_macos_a64_unwind_sections() {
83 use crate::functions::find_dynamic_unwind_sections::find_dynamic_unwind_sections;
84 use crate::records::unw_dynamic_unwind_sections_t::unw_dynamic_unwind_sections_t;
85 use crate::type_aliases::unw_add_find_dynamic_unwind_sections_t::unw_add_find_dynamic_unwind_sections_t;
86 use std::sync::OnceLock;
87
88 unsafe extern "C" fn find_dynamic_unwind_sections_thunk(
89 addr: usize,
90 info: *mut unw_dynamic_unwind_sections_t,
91 ) -> core::ffi::c_int {
92 if info.is_null() {
93 return 0;
94 }
95
96 find_dynamic_unwind_sections(addr, unsafe { &mut *info })
97 }
98
99 static REGISTER_RESULT: OnceLock<i32> = OnceLock::new();
100
101 let result = REGISTER_RESULT.get_or_init(|| unsafe {
102 const RTLD_DEFAULT: *mut core::ffi::c_void = -2_isize as *mut core::ffi::c_void;
103 let symbol = c"__unw_add_find_dynamic_unwind_sections";
104 let add_find_dynamic_unwind_sections: unw_add_find_dynamic_unwind_sections_t =
105 core::mem::transmute(dlsym(RTLD_DEFAULT, symbol.as_ptr()));
106
107 match add_find_dynamic_unwind_sections {
108 Some(register) => register(Some(find_dynamic_unwind_sections_thunk)),
109 None => 0,
110 }
111 });
112
113 CODEGEN_ASSERT!(*result == 0);
114}