From fbe711a42f969d2af8b7796ab7d39172ac0c7447 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 27 Sep 2024 21:33:53 +0800 Subject: [PATCH] Add support of unwind for arm64/aarch64 on Linux Add support of unwind for arm64/aarch64 on Linux by: - adding src/linux/libunwind/bindings_aarch64.rs - enhance src/linux/libunwind/mod.rs Signed-off-by: Jiang Liu --- .github/workflows/build.yml | 2 +- build.rs | 2 +- src/linux/libunwind/bindings_aarch64.rs | 1316 +++++++++++++++++++++++ src/linux/libunwind/mod.rs | 31 +- 4 files changed, 1346 insertions(+), 5 deletions(-) create mode 100644 src/linux/libunwind/bindings_aarch64.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2b7ab1..1bff22a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: - uses: actions/checkout@v2 - name: Build (unwind) run: cargo build --verbose --features unwind --examples - if: matrix.target == 'x86_64-musl' || matrix.target == 'armv7-musleabihf' + if: matrix.target == 'x86_64-musl' || matrix.target == 'armv7-musleabihf' || matrix.target == 'aarch64-musl' - name: Build (no-unwind) run: cargo build --verbose --examples if: matrix.target == 'i686-musl' || matrix.target == 'aarch64-musl' diff --git a/build.rs b/build.rs index 25141e8..410c5c5 100644 --- a/build.rs +++ b/build.rs @@ -4,7 +4,7 @@ fn main() { // We only support native unwinding on some platforms let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); match target_arch.as_str() { - "x86_64" | "arm" => {} + "x86_64" | "arm" | "aarch64" => {} _ => return, }; let target = env::var("TARGET").unwrap(); diff --git a/src/linux/libunwind/bindings_aarch64.rs b/src/linux/libunwind/bindings_aarch64.rs new file mode 100644 index 0000000..43599ef --- /dev/null +++ b/src/linux/libunwind/bindings_aarch64.rs @@ -0,0 +1,1316 @@ +// automatically generated with: +// bindgen /usr/include/arm-linux-gnueabihf/libunwind.h --whitelist-type unw_.* + +#![allow(dead_code)] +#![allow(deref_nullptr)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +pub type __int8_t = ::std::os::raw::c_schar; +pub type __int16_t = ::std::os::raw::c_short; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_long; +pub type __uint64_t = ::std::os::raw::c_ulong; +pub type size_t = ::std::os::raw::c_ulong; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sigset_t { + pub __val: [::std::os::raw::c_ulong; 16usize], +} +#[test] +fn bindgen_test_layout___sigset_t() { + assert_eq!( + ::std::mem::size_of::<__sigset_t>(), + 128usize, + concat!("Size of: ", stringify!(__sigset_t)) + ); + assert_eq!( + ::std::mem::align_of::<__sigset_t>(), + 8usize, + concat!("Alignment of ", stringify!(__sigset_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__sigset_t>())).__val as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__sigset_t), + "::", + stringify!(__val) + ) + ); +} +pub type sigset_t = __sigset_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct stack_t { + pub ss_sp: *mut ::std::os::raw::c_void, + pub ss_flags: ::std::os::raw::c_int, + pub ss_size: size_t, +} +#[test] +fn bindgen_test_layout_stack_t() { + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(stack_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(stack_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).ss_sp as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(stack_t), + "::", + stringify!(ss_sp) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).ss_flags as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(stack_t), + "::", + stringify!(ss_flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).ss_size as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(stack_t), + "::", + stringify!(ss_size) + ) + ); +} +#[repr(C)] +#[repr(align(16))] +#[derive(Debug, Copy, Clone)] +pub struct mcontext_t { + pub fault_address: ::std::os::raw::c_ulonglong, + pub regs: [::std::os::raw::c_ulonglong; 31usize], + pub sp: ::std::os::raw::c_ulonglong, + pub pc: ::std::os::raw::c_ulonglong, + pub pstate: ::std::os::raw::c_ulonglong, + pub __bindgen_padding_0: [u8; 8usize], + pub __reserved: [::std::os::raw::c_uchar; 4096usize], +} +#[test] +fn bindgen_test_layout_mcontext_t() { + assert_eq!( + ::std::mem::size_of::(), + 4384usize, + concat!("Size of: ", stringify!(mcontext_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(mcontext_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).fault_address as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(fault_address) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).regs as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(regs) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).sp as *const _ as usize }, + 256usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(sp) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).pc as *const _ as usize }, + 264usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(pc) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).pstate as *const _ as usize }, + 272usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(pstate) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).__reserved as *const _ as usize }, + 288usize, + concat!( + "Offset of field: ", + stringify!(mcontext_t), + "::", + stringify!(__reserved) + ) + ); +} +#[repr(C)] +#[repr(align(16))] +#[derive(Debug, Copy, Clone)] +pub struct ucontext_t { + pub uc_flags: ::std::os::raw::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: stack_t, + pub uc_sigmask: sigset_t, + pub __bindgen_padding_0: u64, + pub uc_mcontext: mcontext_t, +} +#[test] +fn bindgen_test_layout_ucontext_t() { + assert_eq!( + ::std::mem::size_of::(), + 4560usize, + concat!("Size of: ", stringify!(ucontext_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(ucontext_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).uc_flags as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(ucontext_t), + "::", + stringify!(uc_flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).uc_link as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(ucontext_t), + "::", + stringify!(uc_link) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).uc_stack as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(ucontext_t), + "::", + stringify!(uc_stack) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).uc_sigmask as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(ucontext_t), + "::", + stringify!(uc_sigmask) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).uc_mcontext as *const _ as usize }, + 176usize, + concat!( + "Offset of field: ", + stringify!(ucontext_t), + "::", + stringify!(uc_mcontext) + ) + ); +} +pub type unw_word_t = u64; +pub type unw_sword_t = i64; +pub type unw_tdep_fpreg_t = u128; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_tdep_proc_info_t {} +#[test] +fn bindgen_test_layout_unw_tdep_proc_info_t() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(unw_tdep_proc_info_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(unw_tdep_proc_info_t)) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_tdep_save_loc {} +#[test] +fn bindgen_test_layout_unw_tdep_save_loc() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(unw_tdep_save_loc)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(unw_tdep_save_loc)) + ); +} +pub type unw_tdep_save_loc_t = unw_tdep_save_loc; +pub type unw_tdep_context_t = ucontext_t; +pub const unw_error_t_UNW_ESUCCESS: unw_error_t = 0; +pub const unw_error_t_UNW_EUNSPEC: unw_error_t = 1; +pub const unw_error_t_UNW_ENOMEM: unw_error_t = 2; +pub const unw_error_t_UNW_EBADREG: unw_error_t = 3; +pub const unw_error_t_UNW_EREADONLYREG: unw_error_t = 4; +pub const unw_error_t_UNW_ESTOPUNWIND: unw_error_t = 5; +pub const unw_error_t_UNW_EINVALIDIP: unw_error_t = 6; +pub const unw_error_t_UNW_EBADFRAME: unw_error_t = 7; +pub const unw_error_t_UNW_EINVAL: unw_error_t = 8; +pub const unw_error_t_UNW_EBADVERSION: unw_error_t = 9; +pub const unw_error_t_UNW_ENOINFO: unw_error_t = 10; +pub type unw_error_t = ::std::os::raw::c_uint; +pub const unw_frame_regnum_t_UNW_REG_IP: unw_frame_regnum_t = 30; +pub const unw_frame_regnum_t_UNW_REG_SP: unw_frame_regnum_t = 31; +pub const unw_frame_regnum_t_UNW_REG_EH: unw_frame_regnum_t = 0; +pub const unw_frame_regnum_t_UNW_REG_LAST: unw_frame_regnum_t = 97; +pub type unw_frame_regnum_t = ::std::os::raw::c_uint; +pub const unw_caching_policy_t_UNW_CACHE_NONE: unw_caching_policy_t = 0; +pub const unw_caching_policy_t_UNW_CACHE_GLOBAL: unw_caching_policy_t = 1; +pub const unw_caching_policy_t_UNW_CACHE_PER_THREAD: unw_caching_policy_t = 2; +pub type unw_caching_policy_t = ::std::os::raw::c_uint; +pub const unw_init_local2_flags_t_UNW_INIT_SIGNAL_FRAME: unw_init_local2_flags_t = 1; +pub type unw_init_local2_flags_t = ::std::os::raw::c_uint; +pub type unw_regnum_t = ::std::os::raw::c_int; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_cursor { + pub opaque: [unw_word_t; 512usize], +} +#[test] +fn bindgen_test_layout_unw_cursor() { + assert_eq!( + ::std::mem::size_of::(), + 4096usize, + concat!("Size of: ", stringify!(unw_cursor)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_cursor)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).opaque as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_cursor), + "::", + stringify!(opaque) + ) + ); +} +pub type unw_cursor_t = unw_cursor; +pub type unw_context_t = unw_tdep_context_t; +pub type unw_fpreg_t = unw_tdep_fpreg_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_addr_space { + _unused: [u8; 0], +} +pub type unw_addr_space_t = *mut unw_addr_space; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_proc_info { + pub start_ip: unw_word_t, + pub end_ip: unw_word_t, + pub lsda: unw_word_t, + pub handler: unw_word_t, + pub gp: unw_word_t, + pub flags: unw_word_t, + pub format: ::std::os::raw::c_int, + pub unwind_info_size: ::std::os::raw::c_int, + pub unwind_info: *mut ::std::os::raw::c_void, + pub extra: unw_tdep_proc_info_t, +} +#[test] +fn bindgen_test_layout_unw_proc_info() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(unw_proc_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_proc_info)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).start_ip as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(start_ip) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).end_ip as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(end_ip) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).lsda as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(lsda) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).handler as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(handler) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).gp as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(gp) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).format as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(format) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).unwind_info_size as *const _ as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(unwind_info_size) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).unwind_info as *const _ as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(unwind_info) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).extra as *const _ as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(unw_proc_info), + "::", + stringify!(extra) + ) + ); +} +pub type unw_proc_info_t = unw_proc_info; +pub type unw_reg_states_callback = ::std::option::Option< + unsafe extern "C" fn( + token: *mut ::std::os::raw::c_void, + reg_states_data: *mut ::std::os::raw::c_void, + reg_states_data_size: size_t, + start_ip: unw_word_t, + end_ip: unw_word_t, + ) -> ::std::os::raw::c_int, +>; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_accessors { + pub find_proc_info: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: unw_word_t, + arg3: *mut unw_proc_info_t, + arg4: ::std::os::raw::c_int, + arg5: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub put_unwind_info: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: *mut unw_proc_info_t, + arg3: *mut ::std::os::raw::c_void, + ), + >, + pub get_dyn_info_list_addr: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: *mut unw_word_t, + arg3: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub access_mem: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: unw_word_t, + arg3: *mut unw_word_t, + arg4: ::std::os::raw::c_int, + arg5: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub access_reg: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: unw_regnum_t, + arg3: *mut unw_word_t, + arg4: ::std::os::raw::c_int, + arg5: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub access_fpreg: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: unw_regnum_t, + arg3: *mut unw_fpreg_t, + arg4: ::std::os::raw::c_int, + arg5: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub resume: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: *mut unw_cursor_t, + arg3: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub get_proc_name: ::std::option::Option< + unsafe extern "C" fn( + arg1: unw_addr_space_t, + arg2: unw_word_t, + arg3: *mut ::std::os::raw::c_char, + arg4: size_t, + arg5: *mut unw_word_t, + arg6: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, +} +#[test] +fn bindgen_test_layout_unw_accessors() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(unw_accessors)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_accessors)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).find_proc_info as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(find_proc_info) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).put_unwind_info as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(put_unwind_info) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).get_dyn_info_list_addr as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(get_dyn_info_list_addr) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).access_mem as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(access_mem) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).access_reg as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(access_reg) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).access_fpreg as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(access_fpreg) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).resume as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(resume) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).get_proc_name as *const _ as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(unw_accessors), + "::", + stringify!(get_proc_name) + ) + ); +} +pub type unw_accessors_t = unw_accessors; +pub const unw_save_loc_type_UNW_SLT_NONE: unw_save_loc_type = 0; +pub const unw_save_loc_type_UNW_SLT_MEMORY: unw_save_loc_type = 1; +pub const unw_save_loc_type_UNW_SLT_REG: unw_save_loc_type = 2; +pub type unw_save_loc_type = ::std::os::raw::c_uint; +pub use self::unw_save_loc_type as unw_save_loc_type_t; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct unw_save_loc { + pub type_: unw_save_loc_type_t, + pub u: unw_save_loc__bindgen_ty_1, + pub extra: unw_tdep_save_loc_t, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union unw_save_loc__bindgen_ty_1 { + pub addr: unw_word_t, + pub regnum: unw_regnum_t, +} +#[test] +fn bindgen_test_layout_unw_save_loc__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(unw_save_loc__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_save_loc__bindgen_ty_1)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).addr as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_save_loc__bindgen_ty_1), + "::", + stringify!(addr) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).regnum as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_save_loc__bindgen_ty_1), + "::", + stringify!(regnum) + ) + ); +} +#[test] +fn bindgen_test_layout_unw_save_loc() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(unw_save_loc)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_save_loc)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).type_ as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_save_loc), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_save_loc), + "::", + stringify!(u) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).extra as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_save_loc), + "::", + stringify!(extra) + ) + ); +} +pub type unw_save_loc_t = unw_save_loc; +pub const unw_dyn_operation_t_UNW_DYN_STOP: unw_dyn_operation_t = 0; +pub const unw_dyn_operation_t_UNW_DYN_SAVE_REG: unw_dyn_operation_t = 1; +pub const unw_dyn_operation_t_UNW_DYN_SPILL_FP_REL: unw_dyn_operation_t = 2; +pub const unw_dyn_operation_t_UNW_DYN_SPILL_SP_REL: unw_dyn_operation_t = 3; +pub const unw_dyn_operation_t_UNW_DYN_ADD: unw_dyn_operation_t = 4; +pub const unw_dyn_operation_t_UNW_DYN_POP_FRAMES: unw_dyn_operation_t = 5; +pub const unw_dyn_operation_t_UNW_DYN_LABEL_STATE: unw_dyn_operation_t = 6; +pub const unw_dyn_operation_t_UNW_DYN_COPY_STATE: unw_dyn_operation_t = 7; +pub const unw_dyn_operation_t_UNW_DYN_ALIAS: unw_dyn_operation_t = 8; +pub type unw_dyn_operation_t = ::std::os::raw::c_uint; +pub const unw_dyn_info_format_t_UNW_INFO_FORMAT_DYNAMIC: unw_dyn_info_format_t = 0; +pub const unw_dyn_info_format_t_UNW_INFO_FORMAT_TABLE: unw_dyn_info_format_t = 1; +pub const unw_dyn_info_format_t_UNW_INFO_FORMAT_REMOTE_TABLE: unw_dyn_info_format_t = 2; +pub const unw_dyn_info_format_t_UNW_INFO_FORMAT_ARM_EXIDX: unw_dyn_info_format_t = 3; +pub const unw_dyn_info_format_t_UNW_INFO_FORMAT_IP_OFFSET: unw_dyn_info_format_t = 4; +pub type unw_dyn_info_format_t = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_op { + pub tag: i8, + pub qp: i8, + pub reg: i16, + pub when: i32, + pub val: unw_word_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_op() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(unw_dyn_op)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_op)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).tag as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_op), + "::", + stringify!(tag) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).qp as *const _ as usize }, + 1usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_op), + "::", + stringify!(qp) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).reg as *const _ as usize }, + 2usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_op), + "::", + stringify!(reg) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).when as *const _ as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_op), + "::", + stringify!(when) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).val as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_op), + "::", + stringify!(val) + ) + ); +} +pub type unw_dyn_op_t = unw_dyn_op; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_region_info { + pub next: *mut unw_dyn_region_info, + pub insn_count: i32, + pub op_count: u32, + pub op: [unw_dyn_op_t; 1usize], +} +#[test] +fn bindgen_test_layout_unw_dyn_region_info() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(unw_dyn_region_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_region_info)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).next as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_region_info), + "::", + stringify!(next) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).insn_count as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_region_info), + "::", + stringify!(insn_count) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).op_count as *const _ as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_region_info), + "::", + stringify!(op_count) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).op as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_region_info), + "::", + stringify!(op) + ) + ); +} +pub type unw_dyn_region_info_t = unw_dyn_region_info; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_proc_info { + pub name_ptr: unw_word_t, + pub handler: unw_word_t, + pub flags: u32, + pub pad0: i32, + pub regions: *mut unw_dyn_region_info_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_proc_info() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(unw_dyn_proc_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_proc_info)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).name_ptr as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_proc_info), + "::", + stringify!(name_ptr) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).handler as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_proc_info), + "::", + stringify!(handler) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_proc_info), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).pad0 as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_proc_info), + "::", + stringify!(pad0) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).regions as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_proc_info), + "::", + stringify!(regions) + ) + ); +} +pub type unw_dyn_proc_info_t = unw_dyn_proc_info; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_table_info { + pub name_ptr: unw_word_t, + pub segbase: unw_word_t, + pub table_len: unw_word_t, + pub table_data: *mut unw_word_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_table_info() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(unw_dyn_table_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_table_info)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).name_ptr as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_table_info), + "::", + stringify!(name_ptr) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).segbase as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_table_info), + "::", + stringify!(segbase) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).table_len as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_table_info), + "::", + stringify!(table_len) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).table_data as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_table_info), + "::", + stringify!(table_data) + ) + ); +} +pub type unw_dyn_table_info_t = unw_dyn_table_info; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_remote_table_info { + pub name_ptr: unw_word_t, + pub segbase: unw_word_t, + pub table_len: unw_word_t, + pub table_data: unw_word_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_remote_table_info() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(unw_dyn_remote_table_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_remote_table_info)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).name_ptr as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_remote_table_info), + "::", + stringify!(name_ptr) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).segbase as *const _ as usize + }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_remote_table_info), + "::", + stringify!(segbase) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).table_len as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_remote_table_info), + "::", + stringify!(table_len) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).table_data as *const _ as usize + }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_remote_table_info), + "::", + stringify!(table_data) + ) + ); +} +pub type unw_dyn_remote_table_info_t = unw_dyn_remote_table_info; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct unw_dyn_info { + pub next: *mut unw_dyn_info, + pub prev: *mut unw_dyn_info, + pub start_ip: unw_word_t, + pub end_ip: unw_word_t, + pub gp: unw_word_t, + pub format: i32, + pub pad: i32, + pub u: unw_dyn_info__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union unw_dyn_info__bindgen_ty_1 { + pub pi: unw_dyn_proc_info_t, + pub ti: unw_dyn_table_info_t, + pub rti: unw_dyn_remote_table_info_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_info__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(unw_dyn_info__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_info__bindgen_ty_1)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).pi as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info__bindgen_ty_1), + "::", + stringify!(pi) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).ti as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info__bindgen_ty_1), + "::", + stringify!(ti) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).rti as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info__bindgen_ty_1), + "::", + stringify!(rti) + ) + ); +} +#[test] +fn bindgen_test_layout_unw_dyn_info() { + assert_eq!( + ::std::mem::size_of::(), + 80usize, + concat!("Size of: ", stringify!(unw_dyn_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_info)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).next as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(next) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).prev as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(prev) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).start_ip as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(start_ip) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).end_ip as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(end_ip) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).gp as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(gp) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).format as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(format) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).pad as *const _ as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(pad) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info), + "::", + stringify!(u) + ) + ); +} +pub type unw_dyn_info_t = unw_dyn_info; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct unw_dyn_info_list { + pub version: u32, + pub generation: u32, + pub first: *mut unw_dyn_info_t, +} +#[test] +fn bindgen_test_layout_unw_dyn_info_list() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(unw_dyn_info_list)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(unw_dyn_info_list)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).version as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info_list), + "::", + stringify!(version) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).generation as *const _ as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info_list), + "::", + stringify!(generation) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).first as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(unw_dyn_info_list), + "::", + stringify!(first) + ) + ); +} +pub type unw_dyn_info_list_t = unw_dyn_info_list; diff --git a/src/linux/libunwind/mod.rs b/src/linux/libunwind/mod.rs index 5f34e60..b91383d 100644 --- a/src/linux/libunwind/mod.rs +++ b/src/linux/libunwind/mod.rs @@ -3,6 +3,7 @@ use std; #[cfg_attr(target_arch = "x86_64", path = "bindings_x86_64.rs")] #[cfg_attr(target_arch = "arm", path = "bindings_arm.rs")] +#[cfg_attr(target_arch = "aarch64", path = "bindings_aarch64.rs")] mod bindings; use self::bindings::{ @@ -45,7 +46,7 @@ impl Unwinder { pub fn cursor(&self, thread: &crate::Thread) -> Result { unsafe { let upt = _UPT_create(thread.id()? as _); - let mut cursor = std::mem::MaybeUninit::uninit().assume_init(); + let mut cursor = std::mem::zeroed(); let ret = init_remote(&mut cursor, self.addr_space, upt); if ret != 0 { return Err(crate::Error::LibunwindError(Error::from(-ret))); @@ -89,7 +90,7 @@ impl Cursor { unsafe { self.register(3) } } - #[cfg(target_arch = "arm")] + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] pub fn r5(&self) -> Result { unsafe { self.register(5) } } @@ -106,7 +107,7 @@ impl Cursor { unsafe { let mut name = vec![0_u8 as c_char; 128]; let cursor = &self.cursor as *const _ as *mut _; - let mut raw_offset = std::mem::MaybeUninit::uninit().assume_init(); + let mut raw_offset = std::mem::zeroed(); loop { match get_proc_name(cursor, name.as_mut_ptr(), name.len(), &mut raw_offset) { @@ -244,6 +245,30 @@ extern "C" { fn set_caching_policy(spc: unw_addr_space_t, policy: unw_caching_policy_t) -> c_int; } +#[cfg(target_arch = "aarch64")] +extern "C" { + #[link_name = "_Uaarch64_create_addr_space"] + #[allow(improper_ctypes)] + fn create_addr_space(acc: *mut unw_accessors_t, byteorder: c_int) -> unw_addr_space_t; + #[link_name = "_Uaarch64_destroy_addr_space"] + fn destroy_addr_space(addr: unw_addr_space_t) -> c_void; + #[link_name = "_Uaarch64_init_remote"] + fn init_remote(cursor: *mut unw_cursor_t, addr: unw_addr_space_t, ptr: *mut c_void) -> c_int; + #[link_name = "_Uaarch64_get_reg"] + fn get_reg(cursor: *mut unw_cursor_t, reg: unw_regnum_t, val: *mut unw_word_t) -> c_int; + #[link_name = "_Uaarch64_step"] + fn step(cursor: *mut unw_cursor_t) -> c_int; + #[link_name = "_Uaarch64_get_proc_name"] + fn get_proc_name( + cursor: *mut unw_cursor, + buffer: *mut c_char, + len: size_t, + offset: *mut unw_word_t, + ) -> c_int; + #[link_name = "_Uaarch64_set_caching_policy"] + fn set_caching_policy(spc: unw_addr_space_t, policy: unw_caching_policy_t) -> c_int; +} + impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self {