use crate::functions::visit_fde_entries::visit_fde_entries;
use crate::macros::codegen_assert::CODEGEN_ASSERT;
#[cfg(not(target_os = "windows"))]
extern "C" {
fn __register_frame(begin: *const core::ffi::c_void);
}
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
extern "C" {
fn dlsym(
handle: *mut core::ffi::c_void,
symbol: *const core::ffi::c_char,
) -> *mut core::ffi::c_void;
}
#[cfg(target_os = "windows")]
extern "system" {
fn RtlAddFunctionTable(
function_table: *mut core::ffi::c_void,
entry_count: u32,
base_address: usize,
) -> i32;
}
pub unsafe extern "C" fn create_block_unwind_info(
context: *mut core::ffi::c_void,
block: *mut u8,
block_size: usize,
begin_offset: &mut usize,
) -> *mut core::ffi::c_void {
const K_CODE_ALIGNMENT: usize = 32;
#[cfg(target_os = "windows")]
let (function_count, builder_begin_offset, unwind_size) = {
let unwind = &mut *(context.cast::<crate::records::unwind_builder_win::UnwindBuilderWin>());
let unwind_size = (unwind.get_unwind_info_size(block_size) + (K_CODE_ALIGNMENT - 1))
& !(K_CODE_ALIGNMENT - 1);
CODEGEN_ASSERT!(block_size >= unwind_size);
let function_count = unwind.finalize(block.cast(), unwind_size, block.cast(), block_size);
(function_count, unwind.get_begin_offset(), unwind_size)
};
#[cfg(not(target_os = "windows"))]
let (builder_begin_offset, unwind_size) = {
let unwind =
&mut *(context.cast::<crate::records::unwind_builder_dwarf_2::UnwindBuilderDwarf2>());
let unwind_size = (unwind.get_unwind_info_size(block_size) + (K_CODE_ALIGNMENT - 1))
& !(K_CODE_ALIGNMENT - 1);
CODEGEN_ASSERT!(block_size >= unwind_size);
unwind.finalize(block.cast(), unwind_size, block.cast(), block_size);
(unwind.get_begin_offset(), unwind_size)
};
#[cfg(target_os = "windows")]
{
if RtlAddFunctionTable(block.cast(), function_count as u32, block as usize) == 0 {
CODEGEN_ASSERT!(false);
return core::ptr::null_mut();
}
}
#[cfg(not(target_os = "windows"))]
{
visit_fde_entries(block.cast(), __register_frame);
}
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
register_macos_a64_unwind_sections();
*begin_offset = unwind_size + builder_begin_offset;
block.cast()
}
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
fn register_macos_a64_unwind_sections() {
use crate::functions::find_dynamic_unwind_sections::find_dynamic_unwind_sections;
use crate::records::unw_dynamic_unwind_sections_t::unw_dynamic_unwind_sections_t;
use crate::type_aliases::unw_add_find_dynamic_unwind_sections_t::unw_add_find_dynamic_unwind_sections_t;
use std::sync::OnceLock;
unsafe extern "C" fn find_dynamic_unwind_sections_thunk(
addr: usize,
info: *mut unw_dynamic_unwind_sections_t,
) -> core::ffi::c_int {
if info.is_null() {
return 0;
}
find_dynamic_unwind_sections(addr, unsafe { &mut *info })
}
static REGISTER_RESULT: OnceLock<i32> = OnceLock::new();
let result = REGISTER_RESULT.get_or_init(|| unsafe {
const RTLD_DEFAULT: *mut core::ffi::c_void = -2_isize as *mut core::ffi::c_void;
let symbol = c"__unw_add_find_dynamic_unwind_sections";
let add_find_dynamic_unwind_sections: unw_add_find_dynamic_unwind_sections_t =
core::mem::transmute(dlsym(RTLD_DEFAULT, symbol.as_ptr()));
match add_find_dynamic_unwind_sections {
Some(register) => register(Some(find_dynamic_unwind_sections_thunk)),
None => 0,
}
});
CODEGEN_ASSERT!(*result == 0);
}