Skip to main content

luaur_code_gen/functions/
create_block_unwind_info.rs

1use 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}