mirror of
https://github.com/Noratrieb/uwuwind.git
synced 2026-01-14 16:45:08 +01:00
eh_frame_hdr
This commit is contained in:
parent
37a2259f6f
commit
e3246ede0b
7 changed files with 103 additions and 99 deletions
Binary file not shown.
BIN
eh_frame_hdr.bin
BIN
eh_frame_hdr.bin
Binary file not shown.
11
src/arch.rs
11
src/arch.rs
|
|
@ -1,7 +1,8 @@
|
||||||
use core::arch::asm;
|
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;
|
let mut out;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
|
|
@ -10,10 +11,10 @@ pub fn get_rbp() -> *const usize {
|
||||||
options(nostack, readonly)
|
options(nostack, readonly)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
out
|
Addr(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rip() -> *const ffi::c_void {
|
pub(crate) fn get_rip() -> Addr {
|
||||||
let mut out;
|
let mut out;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
|
|
@ -22,5 +23,5 @@ pub fn get_rip() -> *const ffi::c_void {
|
||||||
options(nostack, readonly),
|
options(nostack, readonly),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
out
|
Addr(out)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,12 @@
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![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::stdext::with_last_os_error_str;
|
||||||
|
|
||||||
|
use crate::Addr;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct dl_find_object {
|
struct dl_find_object {
|
||||||
dlfo_flags: ffi::c_ulonglong,
|
dlfo_flags: ffi::c_ulonglong,
|
||||||
|
|
@ -37,62 +39,101 @@ pub struct DwarfInfo {
|
||||||
/// The `.eh_frame_hdr` section.
|
/// The `.eh_frame_hdr` section.
|
||||||
/// See <https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html>
|
/// See <https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html>
|
||||||
/// and <https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html>.
|
/// and <https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html>.
|
||||||
|
#[derive(Debug)]
|
||||||
struct EhFrameHeader {
|
struct EhFrameHeader {
|
||||||
version: u8,
|
version: u8,
|
||||||
eh_frame_ptr_enc: EhHeaderEncoded,
|
eh_frame_ptr_enc: Encoding,
|
||||||
fde_count_enc: EhHeaderEncoded,
|
fde_count_enc: Encoding,
|
||||||
table_enc: EhHeaderEncoded,
|
table_enc: Encoding,
|
||||||
encoded_fields: (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EhFrameHeader {
|
fn eh_frame_hdr_ptr(addr: Addr) -> Option<*const EhFrameHeader> {
|
||||||
unsafe fn encoded_fields(&self) -> *const u8 {
|
unsafe {
|
||||||
addr_of!((*self).encoded_fields).cast::<u8>()
|
let mut out = core::mem::zeroed();
|
||||||
}
|
let ret = _dl_find_object(addr.voidptr(), &mut out);
|
||||||
|
trace!("_dl_find_object returned {ret}");
|
||||||
unsafe fn eh_frame(&self) -> Option<*const u8> {
|
if ret != 0 {
|
||||||
let ValueFormat::DW_EH_PE_sdata4 = self.eh_frame_ptr_enc.format() else {
|
with_last_os_error_str(|err| trace!("dl_find_object error: {err}"));
|
||||||
return None;
|
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;
|
return None;
|
||||||
};
|
}
|
||||||
|
|
||||||
let eh_frame_ptr = unsafe { self.encoded_fields().cast::<i32>().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(
|
if !(out.dlfo_map_start..out.dlfo_map_end).contains(&addr.voidptr()) {
|
||||||
self.encoded_fields()
|
trace!("dl_find_object returned object out of range for addr: {addr:?}");
|
||||||
.cast::<u8>()
|
|
||||||
.offset(eh_frame_ptr as isize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fde_count(&self) -> Option<u64> {
|
|
||||||
let ValueFormat::DW_EH_PE_udata4 = self.fde_count_enc.format() else {
|
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
let ValueApplication::DW_EH_PE_absptr = self.fde_count_enc.application() else {
|
|
||||||
return None;
|
Some(out.dlfo_eh_frame.cast::<EhFrameHeader>())
|
||||||
};
|
|
||||||
let fde_count = unsafe { self.encoded_fields().add(4).cast::<u32>().read() };
|
|
||||||
Some(fde_count as _)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for EhFrameHeader {
|
pub(crate) fn dwarf_info(addr: Addr) -> Option<DwarfInfo> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
unsafe {
|
||||||
f.debug_struct("EhFrameHeader")
|
let ptr = eh_frame_hdr_ptr(addr)?;
|
||||||
.field("version", &self.version)
|
let header = ptr.read();
|
||||||
.field("eh_frame_ptr_enc", &self.eh_frame_ptr_enc)
|
let ptr = ptr.cast::<u8>().add(4);
|
||||||
.field("fde_count_enc", &self.fde_count_enc)
|
|
||||||
.field("table_enc", &self.table_enc)
|
if header.version != 1 {
|
||||||
.field("fde_count", &self.fde_count())
|
trace!("eh_frame_hdr version is not 1");
|
||||||
.finish()
|
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);
|
unsafe fn read_encoded(ptr: *const u8, encoding: Encoding) -> (*const u8, usize) {
|
||||||
impl EhHeaderEncoded {
|
let (new_ptr, value) = match encoding.format() {
|
||||||
|
ValueFormat::DW_EH_PE_uleb128 => todo!("uleb128"),
|
||||||
|
ValueFormat::DW_EH_PE_udata2 => (ptr.add(2), ptr.cast::<u16>().read_unaligned() as usize),
|
||||||
|
ValueFormat::DW_EH_PE_udata4 => (ptr.add(4), ptr.cast::<u32>().read_unaligned() as usize),
|
||||||
|
ValueFormat::DW_EH_PE_udata8 => (ptr.add(8), ptr.cast::<u64>().read_unaligned() as usize),
|
||||||
|
ValueFormat::DW_EH_PE_sleb128 => todo!("sleb128"),
|
||||||
|
ValueFormat::DW_EH_PE_sdata2 => (ptr.add(2), ptr.cast::<i16>().read_unaligned() as usize),
|
||||||
|
ValueFormat::DW_EH_PE_sdata4 => (ptr.add(4), ptr.cast::<i32>().read_unaligned() as usize),
|
||||||
|
ValueFormat::DW_EH_PE_sdata8 => (ptr.add(8), ptr.cast::<i64>().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 {
|
fn format(&self) -> ValueFormat {
|
||||||
match self.0 & 0b1111 {
|
match self.0 & 0b1111 {
|
||||||
0x01 => ValueFormat::DW_EH_PE_uleb128,
|
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 {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{:?} | {:?}", self.application(), self.format())
|
write!(f, "{:?} | {:?}", self.application(), self.format())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dwarf_info(addr: *const ffi::c_void) -> Option<DwarfInfo> {
|
|
||||||
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::<EhFrameHeader>();
|
|
||||||
|
|
||||||
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum ValueFormat {
|
enum ValueFormat {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
mod divination;
|
mod divination;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
pub use divination::{dwarf_info, DwarfInfo};
|
pub(crate) use divination::dwarf_info;
|
||||||
|
|
||||||
pub unsafe fn uwutables(eh_frame: *const u8) {
|
pub unsafe fn uwutables(eh_frame: *const u8) {
|
||||||
trace!("getting uwutables from {:p}", eh_frame);
|
trace!("getting uwutables from {:p}", eh_frame);
|
||||||
|
|
|
||||||
13
src/lib.rs
13
src/lib.rs
|
|
@ -1,7 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use core::sync::atomic::AtomicPtr;
|
use core::{ffi, sync::atomic::AtomicPtr};
|
||||||
|
|
||||||
// Get the macros into our local prelude.
|
// Get the macros into our local prelude.
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
@ -15,12 +15,21 @@ mod identify;
|
||||||
|
|
||||||
mod walk;
|
mod walk;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Addr(*const ());
|
||||||
|
|
||||||
|
impl Addr {
|
||||||
|
fn voidptr(self) -> *const ffi::c_void {
|
||||||
|
self.0.cast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(nonstandard_style)]
|
#[allow(nonstandard_style)]
|
||||||
pub unsafe extern "C" fn _UnwindRaiseException(
|
pub unsafe extern "C" fn _UnwindRaiseException(
|
||||||
exception_object: *mut uw::_Unwind_Exception,
|
exception_object: *mut uw::_Unwind_Exception,
|
||||||
) -> uw::_Unwind_Reason_Code {
|
) -> uw::_Unwind_Reason_Code {
|
||||||
trace!("someone raised an exception with addr {exception_object:p}");
|
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());
|
crate::dwarf::uwutables(core::ptr::null());
|
||||||
|
|
||||||
stdext::abort();
|
stdext::abort();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use crate::arch::get_rbp;
|
||||||
use crate::stdext::trace;
|
use crate::stdext::trace;
|
||||||
|
|
||||||
pub(crate) unsafe fn walk() {
|
pub(crate) unsafe fn walk() {
|
||||||
let mut current_rbp = get_rbp();
|
let mut current_rbp = get_rbp().0.cast::<usize>();
|
||||||
loop {
|
loop {
|
||||||
trace!("walk... rbp={current_rbp:p}");
|
trace!("walk... rbp={current_rbp:p}");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue