Add method to get PHDR from aux vector
This commit is contained in:
parent
b6f7d85be5
commit
5364967c0e
@ -19,6 +19,8 @@ gimli = { git = "https://github.com/gimli-rs/gimli.git" }
|
|||||||
alloc = []
|
alloc = []
|
||||||
unwinder = []
|
unwinder = []
|
||||||
fde-phdr = ["libc"]
|
fde-phdr = ["libc"]
|
||||||
|
fde-phdr-dl = ["fde-phdr"]
|
||||||
|
fde-phdr-aux = ["fde-phdr"]
|
||||||
fde-registry = ["alloc"]
|
fde-registry = ["alloc"]
|
||||||
fde-static = []
|
fde-static = []
|
||||||
fde-gnu-eh-frame-hdr = []
|
fde-gnu-eh-frame-hdr = []
|
||||||
@ -31,7 +33,7 @@ panic = ["alloc"]
|
|||||||
panic-handler = ["print", "panic"]
|
panic-handler = ["print", "panic"]
|
||||||
panic-handler-dummy = []
|
panic-handler-dummy = []
|
||||||
system-alloc = []
|
system-alloc = []
|
||||||
default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"]
|
default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr-dl", "fde-registry"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
# Must be turned on due to Rust bug https://github.com/rust-lang/rust/issues/50007
|
# Must be turned on due to Rust bug https://github.com/rust-lang/rust/issues/50007
|
||||||
|
@ -5,12 +5,12 @@ use core::ffi::c_void;
|
|||||||
use core::mem;
|
use core::mem;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection};
|
use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection};
|
||||||
use libc::{dl_iterate_phdr, dl_phdr_info, PT_DYNAMIC, PT_GNU_EH_FRAME, PT_LOAD};
|
use libc::{PT_DYNAMIC, PT_GNU_EH_FRAME, PT_LOAD};
|
||||||
|
|
||||||
struct CallbackData {
|
#[cfg(target_pointer_width = "32")]
|
||||||
pc: usize,
|
use libc::Elf32_Phdr as Elf_Phdr;
|
||||||
result: Option<FDESearchResult>,
|
#[cfg(target_pointer_width = "64")]
|
||||||
}
|
use libc::Elf64_Phdr as Elf_Phdr;
|
||||||
|
|
||||||
pub struct PhdrFinder(());
|
pub struct PhdrFinder(());
|
||||||
|
|
||||||
@ -20,32 +20,76 @@ pub fn get_finder() -> &'static PhdrFinder {
|
|||||||
|
|
||||||
impl super::FDEFinder for PhdrFinder {
|
impl super::FDEFinder for PhdrFinder {
|
||||||
fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
|
fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
|
||||||
let mut data = CallbackData { pc, result: None };
|
#[cfg(feature = "fde-phdr-aux")]
|
||||||
unsafe { dl_iterate_phdr(Some(phdr_callback), &mut data as *mut CallbackData as _) };
|
if let Some(v) = search_aux_phdr(pc) {
|
||||||
data.result
|
return Some(v);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "fde-phdr-dl")]
|
||||||
|
if let Some(v) = search_dl_phdr(pc) {
|
||||||
|
return Some(v);
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn phdr_callback(
|
#[cfg(feature = "fde-phdr-aux")]
|
||||||
info: *mut dl_phdr_info,
|
fn search_aux_phdr(pc: usize) -> Option<FDESearchResult> {
|
||||||
_size: usize,
|
use libc::{getauxval, AT_PHDR, AT_PHNUM, PT_PHDR};
|
||||||
data: *mut c_void,
|
|
||||||
) -> c_int {
|
|
||||||
unsafe {
|
|
||||||
let data = &mut *(data as *mut CallbackData);
|
|
||||||
let phdrs = slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize);
|
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let phdr = getauxval(AT_PHDR) as *const Elf_Phdr;
|
||||||
|
let phnum = getauxval(AT_PHNUM) as usize;
|
||||||
|
let phdrs = slice::from_raw_parts(phdr, phnum);
|
||||||
|
// With known address of PHDR, we can calculate the base address in reverse.
|
||||||
|
let base =
|
||||||
|
phdrs.as_ptr() as usize - phdrs.iter().find(|x| x.p_type == PT_PHDR)?.p_vaddr as usize;
|
||||||
|
search_phdr(phdrs, base, pc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fde-phdr-dl")]
|
||||||
|
fn search_dl_phdr(pc: usize) -> Option<FDESearchResult> {
|
||||||
|
use libc::{dl_iterate_phdr, dl_phdr_info};
|
||||||
|
|
||||||
|
struct CallbackData {
|
||||||
|
pc: usize,
|
||||||
|
result: Option<FDESearchResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn phdr_callback(
|
||||||
|
info: *mut dl_phdr_info,
|
||||||
|
_size: usize,
|
||||||
|
data: *mut c_void,
|
||||||
|
) -> c_int {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut *(data as *mut CallbackData);
|
||||||
|
let phdrs = slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize);
|
||||||
|
if let Some(v) = search_phdr(phdrs, (*info).dlpi_addr as _, data.pc) {
|
||||||
|
data.result = Some(v);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = CallbackData { pc, result: None };
|
||||||
|
unsafe { dl_iterate_phdr(Some(phdr_callback), &mut data as *mut CallbackData as _) };
|
||||||
|
data.result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_phdr(phdrs: &[Elf_Phdr], base: usize, pc: usize) -> Option<FDESearchResult> {
|
||||||
|
unsafe {
|
||||||
let mut text = None;
|
let mut text = None;
|
||||||
let mut eh_frame_hdr = None;
|
let mut eh_frame_hdr = None;
|
||||||
let mut dynamic = None;
|
let mut dynamic = None;
|
||||||
|
|
||||||
for phdr in phdrs {
|
for phdr in phdrs {
|
||||||
let start = (*info).dlpi_addr + phdr.p_vaddr;
|
let start = base + phdr.p_vaddr as usize;
|
||||||
match phdr.p_type {
|
match phdr.p_type {
|
||||||
PT_LOAD => {
|
PT_LOAD => {
|
||||||
let end = start + phdr.p_memsz;
|
let end = start + phdr.p_memsz as usize;
|
||||||
let range = start..end;
|
let range = start..end;
|
||||||
if range.contains(&(data.pc as _)) {
|
if range.contains(&pc) {
|
||||||
text = Some(range);
|
text = Some(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,15 +103,8 @@ unsafe extern "C" fn phdr_callback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = match text {
|
let text = text?;
|
||||||
Some(v) => v,
|
let eh_frame_hdr = eh_frame_hdr?;
|
||||||
None => return 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let eh_frame_hdr = match eh_frame_hdr {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut bases = BaseAddresses::default()
|
let mut bases = BaseAddresses::default()
|
||||||
.set_eh_frame_hdr(eh_frame_hdr as _)
|
.set_eh_frame_hdr(eh_frame_hdr as _)
|
||||||
@ -95,11 +132,8 @@ unsafe extern "C" fn phdr_callback(
|
|||||||
get_unlimited_slice(eh_frame_hdr as usize as _),
|
get_unlimited_slice(eh_frame_hdr as usize as _),
|
||||||
NativeEndian,
|
NativeEndian,
|
||||||
)
|
)
|
||||||
.parse(&bases, mem::size_of::<usize>() as _);
|
.parse(&bases, mem::size_of::<usize>() as _)
|
||||||
let eh_frame_hdr = match eh_frame_hdr {
|
.ok()?;
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => return 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
|
let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
|
||||||
bases = bases.set_eh_frame(eh_frame as _);
|
bases = bases.set_eh_frame(eh_frame as _);
|
||||||
@ -108,27 +142,25 @@ unsafe extern "C" fn phdr_callback(
|
|||||||
// Use binary search table for address if available.
|
// Use binary search table for address if available.
|
||||||
if let Some(table) = eh_frame_hdr.table() {
|
if let Some(table) = eh_frame_hdr.table() {
|
||||||
if let Ok(fde) =
|
if let Ok(fde) =
|
||||||
table.fde_for_address(&eh_frame, &bases, data.pc as _, EhFrame::cie_from_offset)
|
table.fde_for_address(&eh_frame, &bases, pc as _, EhFrame::cie_from_offset)
|
||||||
{
|
{
|
||||||
data.result = Some(FDESearchResult {
|
return Some(FDESearchResult {
|
||||||
fde,
|
fde,
|
||||||
bases,
|
bases,
|
||||||
eh_frame,
|
eh_frame,
|
||||||
});
|
});
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise do the linear search.
|
// Otherwise do the linear search.
|
||||||
if let Ok(fde) = eh_frame.fde_for_address(&bases, data.pc as _, EhFrame::cie_from_offset) {
|
if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) {
|
||||||
data.result = Some(FDESearchResult {
|
return Some(FDESearchResult {
|
||||||
fde,
|
fde,
|
||||||
bases,
|
bases,
|
||||||
eh_frame,
|
eh_frame,
|
||||||
});
|
});
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
0
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user