diff --git a/dlfo_eh_frame_100k_head b/dlfo_eh_frame_100k_head deleted file mode 100644 index 741f6f2..0000000 Binary files a/dlfo_eh_frame_100k_head and /dev/null differ diff --git a/eh_frame_hdr.bin b/eh_frame_hdr.bin deleted file mode 100644 index 28c33db..0000000 Binary files a/eh_frame_hdr.bin and /dev/null differ diff --git a/src/arch.rs b/src/arch.rs index 32ca5c0..1b8cc1a 100644 --- a/src/arch.rs +++ b/src/arch.rs @@ -1,7 +1,8 @@ use core::arch::asm; -use core::ffi; -pub fn get_rbp() -> *const usize { +use crate::Addr; + +pub(crate) fn get_rbp() -> Addr { let mut out; unsafe { asm!( @@ -10,10 +11,10 @@ pub fn get_rbp() -> *const usize { options(nostack, readonly) ); } - out + Addr(out) } -pub fn get_rip() -> *const ffi::c_void { +pub(crate) fn get_rip() -> Addr { let mut out; unsafe { asm!( @@ -22,5 +23,5 @@ pub fn get_rip() -> *const ffi::c_void { options(nostack, readonly), ); } - out + Addr(out) } diff --git a/src/dwarf/divination.rs b/src/dwarf/divination.rs index 7e37e12..e51df69 100644 --- a/src/dwarf/divination.rs +++ b/src/dwarf/divination.rs @@ -11,10 +11,12 @@ #![allow(non_camel_case_types)] -use core::{ffi, fmt, ptr::addr_of}; +use core::{ffi, fmt}; use crate::stdext::with_last_os_error_str; +use crate::Addr; + #[repr(C)] struct dl_find_object { dlfo_flags: ffi::c_ulonglong, @@ -37,62 +39,101 @@ pub struct DwarfInfo { /// The `.eh_frame_hdr` section. /// See /// and . +#[derive(Debug)] struct EhFrameHeader { version: u8, - eh_frame_ptr_enc: EhHeaderEncoded, - fde_count_enc: EhHeaderEncoded, - table_enc: EhHeaderEncoded, - encoded_fields: (), + eh_frame_ptr_enc: Encoding, + fde_count_enc: Encoding, + table_enc: Encoding, } -impl EhFrameHeader { - unsafe fn encoded_fields(&self) -> *const u8 { - addr_of!((*self).encoded_fields).cast::() - } - - unsafe fn eh_frame(&self) -> Option<*const u8> { - let ValueFormat::DW_EH_PE_sdata4 = self.eh_frame_ptr_enc.format() else { +fn eh_frame_hdr_ptr(addr: Addr) -> Option<*const EhFrameHeader> { + unsafe { + let mut out = core::mem::zeroed(); + let ret = _dl_find_object(addr.voidptr(), &mut out); + trace!("_dl_find_object returned {ret}"); + if ret != 0 { + with_last_os_error_str(|err| trace!("dl_find_object error: {err}")); return None; - }; - let ValueApplication::DW_EH_PE_pcrel = self.eh_frame_ptr_enc.application() else { + } + if out.dlfo_eh_frame.is_null() { + trace!("dlfo_eh_frame is null"); return None; - }; + } - let eh_frame_ptr = unsafe { self.encoded_fields().cast::().read_unaligned() }; + let text_len = out.dlfo_map_end as usize - out.dlfo_map_start as usize; + trace!( + "dwarf info; map: ({:p}, {:x}), dlfo_map_end: {:p}", + out.dlfo_map_start, + text_len, + out.dlfo_eh_frame + ); - Some( - self.encoded_fields() - .cast::() - .offset(eh_frame_ptr as isize), - ) - } - - fn fde_count(&self) -> Option { - let ValueFormat::DW_EH_PE_udata4 = self.fde_count_enc.format() else { + if !(out.dlfo_map_start..out.dlfo_map_end).contains(&addr.voidptr()) { + trace!("dl_find_object returned object out of range for addr: {addr:?}"); return None; - }; - let ValueApplication::DW_EH_PE_absptr = self.fde_count_enc.application() else { - return None; - }; - let fde_count = unsafe { self.encoded_fields().add(4).cast::().read() }; - Some(fde_count as _) + } + + Some(out.dlfo_eh_frame.cast::()) } } -impl fmt::Debug for EhFrameHeader { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EhFrameHeader") - .field("version", &self.version) - .field("eh_frame_ptr_enc", &self.eh_frame_ptr_enc) - .field("fde_count_enc", &self.fde_count_enc) - .field("table_enc", &self.table_enc) - .field("fde_count", &self.fde_count()) - .finish() +pub(crate) fn dwarf_info(addr: Addr) -> Option { + unsafe { + let ptr = eh_frame_hdr_ptr(addr)?; + let header = ptr.read(); + let ptr = ptr.cast::().add(4); + + if header.version != 1 { + trace!("eh_frame_hdr version is not 1"); + return None; + } + + trace!("eh_frame_hdr: {:#?}", header); + + let (ptr, eh_frame_ptr) = read_encoded(ptr, header.eh_frame_ptr_enc); + let (_ptr, fde_count) = read_encoded(ptr, header.fde_count_enc); + + trace!("eh_frame: {eh_frame_ptr:?}"); + trace!("fde_count: {fde_count:?}"); + + trace!( + "eh_frame start: {:x?}", + core::slice::from_raw_parts(eh_frame_ptr as *const u8, 10) + ); + + crate::stdext::abort(); } } -struct EhHeaderEncoded(u8); -impl EhHeaderEncoded { +unsafe fn read_encoded(ptr: *const u8, encoding: Encoding) -> (*const u8, usize) { + let (new_ptr, value) = match encoding.format() { + ValueFormat::DW_EH_PE_uleb128 => todo!("uleb128"), + ValueFormat::DW_EH_PE_udata2 => (ptr.add(2), ptr.cast::().read_unaligned() as usize), + ValueFormat::DW_EH_PE_udata4 => (ptr.add(4), ptr.cast::().read_unaligned() as usize), + ValueFormat::DW_EH_PE_udata8 => (ptr.add(8), ptr.cast::().read_unaligned() as usize), + ValueFormat::DW_EH_PE_sleb128 => todo!("sleb128"), + ValueFormat::DW_EH_PE_sdata2 => (ptr.add(2), ptr.cast::().read_unaligned() as usize), + ValueFormat::DW_EH_PE_sdata4 => (ptr.add(4), ptr.cast::().read_unaligned() as usize), + ValueFormat::DW_EH_PE_sdata8 => (ptr.add(8), ptr.cast::().read_unaligned() as usize), + }; + + trace!("{ptr:p}, {value}"); + + let value = match encoding.application() { + ValueApplication::DW_EH_PE_absptr => value, + ValueApplication::DW_EH_PE_pcrel => ((value as isize) + (ptr as isize)) as usize, + ValueApplication::DW_EH_PE_textrel => todo!("textrel"), + ValueApplication::DW_EH_PE_datarel => todo!("datarel"), + ValueApplication::DW_EH_PE_funcrel => todo!("funcrel"), + ValueApplication::DW_EH_PE_aligned => todo!("aligned"), + }; + + (new_ptr, value) +} + +struct Encoding(u8); +impl Encoding { fn format(&self) -> ValueFormat { match self.0 & 0b1111 { 0x01 => ValueFormat::DW_EH_PE_uleb128, @@ -119,59 +160,12 @@ impl EhHeaderEncoded { } } -impl fmt::Debug for EhHeaderEncoded { +impl fmt::Debug for Encoding { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?} | {:?}", self.application(), self.format()) } } -pub fn dwarf_info(addr: *const ffi::c_void) -> Option { - unsafe { - let mut out = core::mem::zeroed(); - let ret = _dl_find_object(addr, &mut out); - trace!("_dl_find_object returned {ret}"); - if ret != 0 { - with_last_os_error_str(|err| trace!("dl_find_object error: {err}")); - return None; - } - if out.dlfo_eh_frame.is_null() { - trace!("dlfo_eh_frame is null"); - return None; - } - - let text_len = out.dlfo_map_end as usize - out.dlfo_map_start as usize; - trace!( - "dwarf info; map: ({:p}, {:x}), dlfo_map_end: {:p}", - out.dlfo_map_start, - text_len, - out.dlfo_eh_frame - ); - - if !(out.dlfo_map_start..out.dlfo_map_end).contains(&addr) { - trace!("dl_find_object returned object out of range for addr: {addr:p}"); - return None; - } - - let header = &*out.dlfo_eh_frame.cast::(); - - if header.version != 1 { - trace!("eh_frame_hdr version is not 1"); - return None; - } - trace!("eh_frame_hdr: {:#?}", header); - - let Some(ptr) = header.eh_frame() else { - trace!("could not find .eh_frame"); - return None; - }; - trace!("eh_frame pointer: {ptr:?}"); - - trace!("eh_frame start: {:?}", core::slice::from_raw_parts(ptr, 10)); - - crate::stdext::abort(); - } -} - #[derive(Debug, Clone, Copy)] #[repr(u8)] enum ValueFormat { diff --git a/src/dwarf/mod.rs b/src/dwarf/mod.rs index ca224b4..da28389 100644 --- a/src/dwarf/mod.rs +++ b/src/dwarf/mod.rs @@ -6,7 +6,7 @@ mod divination; mod parse; -pub use divination::{dwarf_info, DwarfInfo}; +pub(crate) use divination::dwarf_info; pub unsafe fn uwutables(eh_frame: *const u8) { trace!("getting uwutables from {:p}", eh_frame); diff --git a/src/lib.rs b/src/lib.rs index 992b608..53089eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] #![allow(dead_code)] -use core::sync::atomic::AtomicPtr; +use core::{ffi, sync::atomic::AtomicPtr}; // Get the macros into our local prelude. #[macro_use] @@ -15,12 +15,21 @@ mod identify; mod walk; +#[derive(Debug, Clone, Copy)] +struct Addr(*const ()); + +impl Addr { + fn voidptr(self) -> *const ffi::c_void { + self.0.cast() + } +} + #[allow(nonstandard_style)] pub unsafe extern "C" fn _UnwindRaiseException( exception_object: *mut uw::_Unwind_Exception, ) -> uw::_Unwind_Reason_Code { trace!("someone raised an exception with addr {exception_object:p}"); - let _di = crate::dwarf::dwarf_info(arch::get_rip() as _).unwrap(); + let _di = crate::dwarf::dwarf_info(arch::get_rip()).unwrap(); crate::dwarf::uwutables(core::ptr::null()); stdext::abort(); diff --git a/src/walk/fp.rs b/src/walk/fp.rs index fd39fec..65d4342 100644 --- a/src/walk/fp.rs +++ b/src/walk/fp.rs @@ -4,7 +4,7 @@ use crate::arch::get_rbp; use crate::stdext::trace; pub(crate) unsafe fn walk() { - let mut current_rbp = get_rbp(); + let mut current_rbp = get_rbp().0.cast::(); loop { trace!("walk... rbp={current_rbp:p}");