mirror of
https://github.com/Noratrieb/uwuwind.git
synced 2026-01-14 16:45:08 +01:00
stuff
This commit is contained in:
parent
c0cf3786f4
commit
94f3233c55
7 changed files with 292 additions and 220 deletions
34
src/arch.rs
34
src/arch.rs
|
|
@ -25,3 +25,37 @@ pub(crate) fn get_rip() -> Addr {
|
||||||
}
|
}
|
||||||
Addr(out)
|
Addr(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Context {
|
||||||
|
pub(crate) registers: [usize; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn capture_context() -> Context {
|
||||||
|
let mut context = Context { registers: [0; 32] };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"mov [{regs}+1*8], rdx", // required special
|
||||||
|
"mov [{regs}+2*8], rcx", // required special
|
||||||
|
"mov [{regs}+3*8], rbx", // required callee-saved
|
||||||
|
"mov [{regs}+4*8], rsi", // required special
|
||||||
|
"mov [{regs}+5*8], rdi", // required special
|
||||||
|
"mov [{regs}+6*8], rbp", // required callee-saved
|
||||||
|
"mov [{regs}+7*8], rsp", // required callee-saved
|
||||||
|
|
||||||
|
"mov [{regs}+12*8], r12", // required callee-saved
|
||||||
|
"mov [{regs}+13*8], r13", // required callee-saved
|
||||||
|
"mov [{regs}+14*8], r14", // required callee-saved
|
||||||
|
"mov [{regs}+15*8], r15", // required callee-saved
|
||||||
|
|
||||||
|
"lea rax, [rip + 0]", // must use rip as a base register
|
||||||
|
"mov [{regs}+16*8], rax", // return address
|
||||||
|
|
||||||
|
out ("rax") _, // clobbers rax
|
||||||
|
regs = in(reg) &mut context.registers,
|
||||||
|
options(readonly),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
context
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,10 @@ pub(crate) fn eh_frame(addr: Addr) -> Option<*const u8> {
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub(crate) fn frame_info(addr: Addr) -> Option<()> {
|
pub(crate) fn frame_info(addr: Addr) -> Option<()> {
|
||||||
|
let symbol = crate::identify::identify(addr.addr());
|
||||||
|
|
||||||
|
debug!("getting frame information of {symbol:?}");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let header_ptr = eh_frame_hdr_ptr(addr)?;
|
let header_ptr = eh_frame_hdr_ptr(addr)?;
|
||||||
let eh_frame_header_addr = header_ptr.addr();
|
let eh_frame_header_addr = header_ptr.addr();
|
||||||
|
|
@ -128,6 +132,7 @@ pub(crate) fn frame_info(addr: Addr) -> Option<()> {
|
||||||
|
|
||||||
let table_ptr = ptr.add(fde_count_size);
|
let table_ptr = ptr.add(fde_count_size);
|
||||||
|
|
||||||
|
/*
|
||||||
let mut walk_table_ptr = table_ptr;
|
let mut walk_table_ptr = table_ptr;
|
||||||
for i in 0..fde_count {
|
for i in 0..fde_count {
|
||||||
let (read, initial_loc) =
|
let (read, initial_loc) =
|
||||||
|
|
@ -139,6 +144,7 @@ pub(crate) fn frame_info(addr: Addr) -> Option<()> {
|
||||||
|
|
||||||
trace!(idx = ?i, "eh_frame_hdr table initial_loc={initial_loc:x} address={address:x}");
|
trace!(idx = ?i, "eh_frame_hdr table initial_loc={initial_loc:x} address={address:x}");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
let table_half_entry_size = header.table_enc.size();
|
let table_half_entry_size = header.table_enc.size();
|
||||||
|
|
||||||
|
|
@ -195,10 +201,24 @@ pub(crate) fn frame_info(addr: Addr) -> Option<()> {
|
||||||
|
|
||||||
trace!("ptr is valid");
|
trace!("ptr is valid");
|
||||||
|
|
||||||
trace!("FDE offset to .eh_frame: {:x}", fde_ptr.addr() - (eh_frame_ptr));
|
trace!(
|
||||||
|
"FDE offset to .eh_frame: {:x}",
|
||||||
|
fde_ptr.addr() - (eh_frame_ptr)
|
||||||
|
);
|
||||||
|
|
||||||
let fde = crate::dwarf::parse::parse_fde_from_ptr(fde_ptr, eh_frame_ptr).unwrap();
|
let fde = crate::dwarf::parse::parse_fde_from_ptr(fde_ptr, eh_frame_ptr).unwrap();
|
||||||
|
|
||||||
|
let fde_base_offset = addr.addr() - fde.initial_location;
|
||||||
|
|
||||||
|
trace!("fde initial location {:x}, address offset of {fde_base_offset}", fde.initial_location);
|
||||||
|
|
||||||
|
crate::dwarf::parse::process_instructions_cfa(
|
||||||
|
&fde.cie,
|
||||||
|
fde.initial_instructions,
|
||||||
|
fde.instructions,
|
||||||
|
fde_base_offset,
|
||||||
|
);
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,6 @@
|
||||||
//! from .debug_frame from DWARF.
|
//! from .debug_frame from DWARF.
|
||||||
|
|
||||||
mod divination;
|
mod divination;
|
||||||
mod parse;
|
pub(crate) mod parse;
|
||||||
|
|
||||||
pub(crate) use divination::{eh_frame, frame_info};
|
pub(crate) use divination::{eh_frame, frame_info};
|
||||||
|
|
||||||
/// The `.eh_frame` section contains a list of call frame information records.
|
|
||||||
/// Each CFI contains a CIE followed be one or more FDE records.
|
|
||||||
#[instrument]
|
|
||||||
pub unsafe fn uwutables(eh_frame: *const u8) {
|
|
||||||
trace!("getting uwutables from {:p}", eh_frame);
|
|
||||||
unsafe {
|
|
||||||
parse::parse_cfi(eh_frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use alloc::{format, string::String};
|
use alloc::{format, string::String};
|
||||||
use core::{ffi::CStr, fmt};
|
use core::{ffi::CStr, fmt, ops::ControlFlow};
|
||||||
|
|
||||||
/// The dwarf is invalid. This is fatal and should never happen.
|
/// The dwarf is invalid. This is fatal and should never happen.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -85,7 +85,7 @@ impl ILeb128 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common Information Entry
|
/// Common Information Entry
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub struct Cie<'a> {
|
pub struct Cie<'a> {
|
||||||
/// A null-terminated UTF-8 string that identifies the augmentation to this
|
/// A null-terminated UTF-8 string that identifies the augmentation to this
|
||||||
/// CIE or to the FDEs that use it. If a reader encounters an
|
/// CIE or to the FDEs that use it. If a reader encounters an
|
||||||
|
|
@ -110,15 +110,15 @@ pub struct Cie<'a> {
|
||||||
/// A constant that is factored out of all advance location instructions
|
/// A constant that is factored out of all advance location instructions
|
||||||
/// (see Section 6.4.2.1 on page 177). The resulting value is
|
/// (see Section 6.4.2.1 on page 177). The resulting value is
|
||||||
/// (operand * code_alignment_factor).
|
/// (operand * code_alignment_factor).
|
||||||
pub code_alignment_factor: u128,
|
pub code_alignment_factor: usize,
|
||||||
/// A constant that is factored out of certain offset instructions (see
|
/// A constant that is factored out of certain offset instructions (see
|
||||||
/// Sections 6.4.2.2 on page 177 and 6.4.2.3 on page 179). The resulting
|
/// Sections 6.4.2.2 on page 177 and 6.4.2.3 on page 179). The resulting
|
||||||
/// value is (operand * data_alignment_factor).
|
/// value is (operand * data_alignment_factor).
|
||||||
pub data_alignment_factor: i128,
|
pub data_alignment_factor: isize,
|
||||||
/// An unsigned LEB128 constant that indicates which column in the rule
|
/// An unsigned LEB128 constant that indicates which column in the rule
|
||||||
/// table represents the return address of the function. Note that this
|
/// table represents the return address of the function. Note that this
|
||||||
/// column might not correspond to an actual machine register.
|
/// column might not correspond to an actual machine register.
|
||||||
pub return_address_register: u128,
|
pub return_address_register: usize,
|
||||||
/// A sequence of rules that are interpreted to create the initial setting
|
/// A sequence of rules that are interpreted to create the initial setting
|
||||||
/// of each column in the table.
|
/// of each column in the table.
|
||||||
/// The default rule for all columns before interpretation of the initial
|
/// The default rule for all columns before interpretation of the initial
|
||||||
|
|
@ -353,12 +353,6 @@ enum FrameInfo<'a> {
|
||||||
Fde(Fde<'a>),
|
Fde(Fde<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn parse_cfi(mut ptr: *const u8) {
|
|
||||||
loop {
|
|
||||||
ptr = parse_frame_info(ptr).unwrap().2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cursor<'a>(&'a [u8]);
|
struct Cursor<'a>(&'a [u8]);
|
||||||
|
|
||||||
/// Returns `(read_size, value)`
|
/// Returns `(read_size, value)`
|
||||||
|
|
@ -513,12 +507,12 @@ fn read_utf8_cstr<'a>(data: &mut Cursor<'a>) -> Result<&'a str> {
|
||||||
data.0 = &data.0[(utf8.len() + 1)..];
|
data.0 = &data.0[(utf8.len() + 1)..];
|
||||||
Ok(utf8)
|
Ok(utf8)
|
||||||
}
|
}
|
||||||
fn read_uleb128(data: &mut Cursor<'_>) -> Result<u128> {
|
fn read_uleb128(data: &mut Cursor<'_>) -> Result<usize> {
|
||||||
let mut result = 0;
|
let mut result = 0;
|
||||||
let mut shift = 0;
|
let mut shift = 0;
|
||||||
loop {
|
loop {
|
||||||
let byte = read_u8(data)?;
|
let byte = read_u8(data)?;
|
||||||
result |= ((byte & 0b0111_1111) << shift) as u128;
|
result |= ((byte & 0b0111_1111) << shift) as usize;
|
||||||
if (byte >> 7) == 0 {
|
if (byte >> 7) == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -526,14 +520,14 @@ fn read_uleb128(data: &mut Cursor<'_>) -> Result<u128> {
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
fn read_ileb128(data: &mut Cursor<'_>) -> Result<i128> {
|
fn read_ileb128(data: &mut Cursor<'_>) -> Result<isize> {
|
||||||
let mut result = 0;
|
let mut result = 0;
|
||||||
let mut shift = 0;
|
let mut shift = 0;
|
||||||
let size = 8;
|
let size = 8;
|
||||||
|
|
||||||
let sign_bit_set = loop {
|
let sign_bit_set = loop {
|
||||||
let byte = read_u8(data)?;
|
let byte = read_u8(data)?;
|
||||||
result |= ((byte & 0b0111_1111) << shift) as i128;
|
result |= ((byte & 0b0111_1111) << shift) as isize;
|
||||||
shift += 7;
|
shift += 7;
|
||||||
if (byte >> 7) == 0 {
|
if (byte >> 7) == 0 {
|
||||||
let sign_bit_set = ((byte >> 6) & 1) == 1;
|
let sign_bit_set = ((byte >> 6) & 1) == 1;
|
||||||
|
|
@ -546,37 +540,11 @@ fn read_ileb128(data: &mut Cursor<'_>) -> Result<i128> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(ret)]
|
|
||||||
unsafe fn parse_frame_info<'a>(
|
|
||||||
ptr: *const u8,
|
|
||||||
) -> Result<(Cie<'a>, alloc::vec::Vec<Fde<'a>>, *const u8)> {
|
|
||||||
let (cie_id, data, mut prev_ptr) = parse_frame_head(ptr)?;
|
|
||||||
if cie_id != 0 {
|
|
||||||
return Err(Error(format!("CIE must have cie_id=0")));
|
|
||||||
}
|
|
||||||
let data = &mut Cursor(data);
|
|
||||||
let cie = parse_cie(data)?;
|
|
||||||
|
|
||||||
let mut fdes = alloc::vec::Vec::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let (cie_id, data, newer_ptr) = parse_frame_head(ptr)?;
|
|
||||||
trace!("cie id: {cie_id}");
|
|
||||||
if cie_id != 0 {
|
|
||||||
return Ok((cie, fdes, prev_ptr));
|
|
||||||
}
|
|
||||||
prev_ptr = newer_ptr;
|
|
||||||
let data = &mut Cursor(data);
|
|
||||||
let fde = parse_fde(data, cie_id, &cie)?;
|
|
||||||
trace!("FDE: {fde:?}");
|
|
||||||
fdes.push(fde);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn parse_frame_head<'a>(ptr: *const u8) -> Result<(u32, &'a [u8], *const u8)> {
|
unsafe fn parse_frame_head<'a>(ptr: *const u8) -> Result<(u32, &'a [u8], *const u8)> {
|
||||||
let len = ptr.cast::<u32>().read();
|
let len = ptr.cast::<u32>().read();
|
||||||
if len == 0xffffffff {
|
if len == 0xffffffff {
|
||||||
// be careful, if you handle this you need to adjust the callers offsets lol lmao
|
// be careful, if you handle this you need to adjust the callers offsets lol
|
||||||
|
// lmao
|
||||||
todo!("loooong dwarf, cannot handle.");
|
todo!("loooong dwarf, cannot handle.");
|
||||||
}
|
}
|
||||||
let data = &mut Cursor(core::slice::from_raw_parts(ptr.add(4), len as usize));
|
let data = &mut Cursor(core::slice::from_raw_parts(ptr.add(4), len as usize));
|
||||||
|
|
@ -630,7 +598,7 @@ fn parse_cie<'a>(data: &mut Cursor<'a>) -> Result<Cie<'a>> {
|
||||||
pub(crate) unsafe fn parse_fde_from_ptr<'a>(
|
pub(crate) unsafe fn parse_fde_from_ptr<'a>(
|
||||||
ptr: *const u8,
|
ptr: *const u8,
|
||||||
eh_frame_base: usize,
|
eh_frame_base: usize,
|
||||||
) -> Result<Fde<'a>> {
|
) -> Result<ParsedFde<'a>> {
|
||||||
let (fde_cie_id, fde_data, _) = parse_frame_head(ptr)?;
|
let (fde_cie_id, fde_data, _) = parse_frame_head(ptr)?;
|
||||||
let fde_data = &mut Cursor(fde_data);
|
let fde_data = &mut Cursor(fde_data);
|
||||||
|
|
||||||
|
|
@ -651,15 +619,23 @@ pub(crate) unsafe fn parse_fde_from_ptr<'a>(
|
||||||
return Err(Error(format!("CIE must have cie_id=0")));
|
return Err(Error(format!("CIE must have cie_id=0")));
|
||||||
}
|
}
|
||||||
let cie_data = &mut Cursor(cie_data);
|
let cie_data = &mut Cursor(cie_data);
|
||||||
let cie = parse_cie(cie_data)?;
|
let cie = parse_cie(cie_data).unwrap();
|
||||||
|
|
||||||
let fde = parse_fde(fde_data, fde_cie_id, &cie)?;
|
let fde = parse_fde(fde_data, fde_cie_id, cie).unwrap();
|
||||||
|
|
||||||
Ok(fde)
|
Ok(fde)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ParsedFde<'a> {
|
||||||
|
pub(crate) initial_location: usize,
|
||||||
|
pub(crate) address_range: usize,
|
||||||
|
pub(crate) initial_instructions: &'a [u8],
|
||||||
|
pub(crate) instructions: &'a [u8],
|
||||||
|
pub(crate) cie: Cie<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(data))]
|
#[instrument(skip(data))]
|
||||||
fn parse_fde<'a>(data: &mut Cursor<'a>, cie_id: u32, cie: &Cie<'_>) -> Result<Fde<'a>> {
|
fn parse_fde<'a>(data: &mut Cursor<'a>, cie_id: u32, cie: Cie<'a>) -> Result<ParsedFde<'a>> {
|
||||||
trace!("FDE {:x?}", data.0);
|
trace!("FDE {:x?}", data.0);
|
||||||
|
|
||||||
let augmentation = cie
|
let augmentation = cie
|
||||||
|
|
@ -673,23 +649,39 @@ fn parse_fde<'a>(data: &mut Cursor<'a>, cie_id: u32, cie: &Cie<'_>) -> Result<Fd
|
||||||
Error("pointer encoding not present in augmentation for CIE with FDEs".into())
|
Error("pointer encoding not present in augmentation for CIE with FDEs".into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (read_size, pc_begin) = unsafe { read_encoded(data.0.as_ptr(), pointer_encoding, None) };
|
let (read_size, initial_location) =
|
||||||
|
unsafe { read_encoded(data.0.as_ptr(), pointer_encoding, None) };
|
||||||
data.0 = &data.0[read_size..];
|
data.0 = &data.0[read_size..];
|
||||||
|
|
||||||
let (read_size, pc_range) = unsafe { read_encoded(data.0.as_ptr(), pointer_encoding, None) };
|
let (read_size, address_range) =
|
||||||
|
unsafe { read_encoded(data.0.as_ptr(), pointer_encoding, None) };
|
||||||
data.0 = &data.0[read_size..];
|
data.0 = &data.0[read_size..];
|
||||||
|
|
||||||
// This is only present if the aug data of the CIE contains z. But that is
|
// This is only present if the aug data of the CIE contains z. But that is
|
||||||
// always the case?
|
// always the case?
|
||||||
let augmentation_len = read_uleb128(data)?;
|
if cie.augmentation.is_some() {
|
||||||
let augmentation_data = &data.0[..(augmentation_len as usize)];
|
let augmentation_len = read_uleb128(data)?;
|
||||||
let data = parse_augmentation_data(cie.augmentation_string, augmentation_data)?;
|
if augmentation_len != 0 {
|
||||||
trace!("debug data: {data:?}");
|
trace!(%augmentation_len, "augmentation length");
|
||||||
|
let augmentation_data = &data.0[..(augmentation_len as usize)];
|
||||||
|
let data = parse_augmentation_data(cie.augmentation_string, augmentation_data)?;
|
||||||
|
trace!("debug data: {data:?}");
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Err(Error("aa".into()))
|
trace!("fde rest: {:x?}", data.0);
|
||||||
|
|
||||||
|
Ok(ParsedFde {
|
||||||
|
initial_location,
|
||||||
|
address_range,
|
||||||
|
instructions: data.0,
|
||||||
|
initial_instructions: cie.initial_instructions,
|
||||||
|
cie,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub struct AugmentationData {
|
pub struct AugmentationData {
|
||||||
pub(super) lsda_pointer_encoding: Option<Encoding>,
|
pub(super) lsda_pointer_encoding: Option<Encoding>,
|
||||||
pub(super) pointer_encoding: Option<Encoding>,
|
pub(super) pointer_encoding: Option<Encoding>,
|
||||||
|
|
@ -751,38 +743,32 @@ fn parse_augmentation_data(string: &str, data: &[u8]) -> Result<AugmentationData
|
||||||
Ok(aug_data)
|
Ok(aug_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct InstrIter {
|
pub(super) struct InstructionParser<'a> {
|
||||||
data: *const u8,
|
data: core::slice::Iter<'a, u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstrIter {
|
impl<'a> InstructionParser<'a> {
|
||||||
/// Create a new `InstrIter` that will parse DWARF call frame information
|
pub(super) fn new(data: &'a [u8]) -> Self {
|
||||||
/// from `data`. # Safety
|
Self { data: data.iter() }
|
||||||
/// `data` must be a pointer to valid DWARF call frame information with a
|
|
||||||
/// null terminator.
|
|
||||||
pub(super) unsafe fn new(data: *const u8) -> Self {
|
|
||||||
// SAFETY: uses random ass pointer
|
|
||||||
Self { data }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn advance(&mut self) -> Option<u8> {
|
fn advance(&mut self) -> Option<u8> {
|
||||||
// SAFETY: First, we assume that `data` currently points at a valid location.
|
self.data.next().copied()
|
||||||
// After we read from it, we increment it. This has implications. We must assume
|
|
||||||
// that the dwarf parsing code in this module never calls `advance` more than it
|
|
||||||
// has to. This means that really `advance` should be unsafe, but
|
|
||||||
// marking it as unsafe would only make the code in here harder to read
|
|
||||||
// and not provide practical safety improvements. We do eagerly move the
|
|
||||||
// data pointer outside the bounds of the allocation, but only one
|
|
||||||
// past the end, which is fine.
|
|
||||||
unsafe {
|
|
||||||
let first = self.data.read();
|
|
||||||
self.data = self.data.add(1);
|
|
||||||
Some(first)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uleb128(&mut self) -> ULeb128 {
|
fn uleb128(&mut self) -> usize {
|
||||||
ULeb128::parse()
|
let mut acc = 0_usize;
|
||||||
|
loop {
|
||||||
|
let b = self.advance().unwrap();
|
||||||
|
let most = b & 0b1000_0000;
|
||||||
|
let rest = b & 0b0111_1111;
|
||||||
|
|
||||||
|
acc = (acc << 7) | (rest as usize);
|
||||||
|
|
||||||
|
if most == 0 {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -816,82 +802,143 @@ const DW_CFA_val_expression: u8 = 0x16;
|
||||||
const DW_CFA_lo_user: u8 = 0x1c;
|
const DW_CFA_lo_user: u8 = 0x1c;
|
||||||
const DW_CFA_hi_user: u8 = 0x3f;
|
const DW_CFA_hi_user: u8 = 0x3f;
|
||||||
|
|
||||||
impl Iterator for InstrIter {
|
#[cfg(target_arch = "x86_64")]
|
||||||
type Item = Instruction;
|
pub(crate) mod arch {
|
||||||
|
pub(crate) const REG_FRAME_POINTER: usize = 6;
|
||||||
|
pub(crate) const RETURN_ADDRESS: usize = 16;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unreachable_code)]
|
#[derive(Debug)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
struct CfaState {
|
||||||
let b = self.advance()?;
|
cfa_rule_register: usize,
|
||||||
let high_2 = b & !(u8::MAX >> 2);
|
cfa_rule_offset: usize,
|
||||||
Some(match high_2 {
|
register_states: [RegisterState; 32],
|
||||||
DW_CFA_advance_loc_hi => {
|
current_offset: usize,
|
||||||
let delta = b & (u8::MAX >> 2);
|
target_offset: usize,
|
||||||
Instruction::AdvanceLoc(delta)
|
}
|
||||||
}
|
|
||||||
DW_CFA_offset_hi => {
|
impl CfaState {
|
||||||
let register = b & (u8::MAX >> 2);
|
fn advance(&mut self, count: usize) -> ControlFlow<()> {
|
||||||
Instruction::Offset {
|
if self.current_offset + count > self.target_offset {
|
||||||
register_number: register as _,
|
ControlFlow::Break(())
|
||||||
factored_offset: self.uleb128(),
|
} else {
|
||||||
}
|
self.current_offset += count;
|
||||||
}
|
ControlFlow::Continue(())
|
||||||
DW_CFA_restore_hi => {
|
}
|
||||||
let register = b & (u8::MAX >> 2);
|
|
||||||
Instruction::Restore(register as _)
|
|
||||||
}
|
|
||||||
_ => match b {
|
|
||||||
DW_CFA_nop => Instruction::Nop,
|
|
||||||
DW_CFA_set_loc => Instruction::SetLoc(todo!()),
|
|
||||||
DW_CFA_advance_loc1 => Instruction::AdvanceLoc1(todo!()),
|
|
||||||
DW_CFA_advance_loc2 => Instruction::AdvanceLoc2(todo!()),
|
|
||||||
DW_CFA_advance_loc4 => Instruction::AdvanceLoc4(todo!()),
|
|
||||||
DW_CFA_offset_extended => Instruction::OffsetExtended {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
factored_offset: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_restore_extended => Instruction::RestoreExtended(self.uleb128()),
|
|
||||||
DW_CFA_undefined => Instruction::Undefined(self.uleb128()),
|
|
||||||
DW_CFA_same_value => Instruction::SameValue(self.uleb128()),
|
|
||||||
DW_CFA_register => Instruction::Register {
|
|
||||||
target_register: self.uleb128(),
|
|
||||||
from_register: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_remember_state => Instruction::RememberState,
|
|
||||||
DW_CFA_restore_state => Instruction::RestoreState,
|
|
||||||
DW_CFA_def_cfa => Instruction::DefCfa {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
offset: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_def_cfa_register => Instruction::DefCfaRegister(self.uleb128()),
|
|
||||||
DW_CFA_def_cfa_offset => Instruction::DefCfaOffset(self.uleb128()),
|
|
||||||
DW_CFA_def_cfa_expression => Instruction::DefCfaExpression(todo!()),
|
|
||||||
DW_CFA_expression => Instruction::Expression {
|
|
||||||
register: self.uleb128(),
|
|
||||||
expr: todo!(),
|
|
||||||
},
|
|
||||||
DW_CFA_offset_extended_sf => Instruction::OffsetExtendedSf {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
factored_offste: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_def_cfa_sf => Instruction::DefCfaSf {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
offset: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_def_cfa_offset_sf => Instruction::DefCfaOffsetSf(self.uleb128()),
|
|
||||||
DW_CFA_val_offset => Instruction::ValOffset {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
factored_offste: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_val_offset_sf => Instruction::ValOffsetSf {
|
|
||||||
register_number: self.uleb128(),
|
|
||||||
factored_offste: self.uleb128(),
|
|
||||||
},
|
|
||||||
DW_CFA_val_expression => Instruction::ValExpression {
|
|
||||||
register: self.uleb128(),
|
|
||||||
expr: todo!(),
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum RegisterState {
|
||||||
|
Undefined,
|
||||||
|
SameValue,
|
||||||
|
Offset(isize),
|
||||||
|
ValOffset(isize),
|
||||||
|
Register(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
const DATA_ALIGNMENT_FACTOR: usize = 1;
|
||||||
|
|
||||||
|
fn process_instruction_cfa_inner(ins: &mut InstructionParser, cfa: &mut CfaState, cie: &Cie<'_>) {
|
||||||
|
let span = tracing::info_span!("process_instruction_cfa_inner");
|
||||||
|
let _guard = span.enter();
|
||||||
|
|
||||||
|
while let Some(b) = ins.advance() {
|
||||||
|
match b >> 6 {
|
||||||
|
DW_CFA_advance_loc_hi => {
|
||||||
|
let delta = (b << 2) >> 2;
|
||||||
|
|
||||||
|
trace!(?delta, "DW_CFA_advance_loc");
|
||||||
|
|
||||||
|
match cfa.advance(delta as usize) {
|
||||||
|
ControlFlow::Continue(()) => {}
|
||||||
|
ControlFlow::Break(()) => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DW_CFA_offset_hi => {
|
||||||
|
let register = (b << 2) >> 2;
|
||||||
|
let factored_offset = ins.uleb128();
|
||||||
|
|
||||||
|
trace!(?register, ?factored_offset, "DW_CFA_offset");
|
||||||
|
|
||||||
|
cfa.register_states[register as usize] =
|
||||||
|
RegisterState::Offset(factored_offset as isize * cie.data_alignment_factor);
|
||||||
|
}
|
||||||
|
DW_CFA_restore_hi => {
|
||||||
|
let register = (b << 2) >> 2;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
_ => match b {
|
||||||
|
DW_CFA_nop => {
|
||||||
|
trace!("DW_CFA_nop");
|
||||||
|
}
|
||||||
|
DW_CFA_set_loc => todo!(),
|
||||||
|
DW_CFA_advance_loc1 => todo!(),
|
||||||
|
DW_CFA_advance_loc2 => todo!(),
|
||||||
|
DW_CFA_advance_loc4 => todo!(),
|
||||||
|
DW_CFA_offset_extended => {
|
||||||
|
let register_number = ins.uleb128();
|
||||||
|
let factored_offset = ins.uleb128();
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
DW_CFA_restore_extended => todo!(),
|
||||||
|
DW_CFA_undefined => todo!(),
|
||||||
|
DW_CFA_same_value => todo!(),
|
||||||
|
DW_CFA_register => todo!(),
|
||||||
|
DW_CFA_remember_state => todo!(),
|
||||||
|
DW_CFA_restore_state => todo!(),
|
||||||
|
DW_CFA_def_cfa => {
|
||||||
|
let register = ins.uleb128();
|
||||||
|
let offset = ins.uleb128();
|
||||||
|
trace!(?register, ?offset, "def_cfa");
|
||||||
|
cfa.cfa_rule_register = register;
|
||||||
|
cfa.cfa_rule_offset = offset;
|
||||||
|
}
|
||||||
|
DW_CFA_def_cfa_register => {
|
||||||
|
let register = ins.uleb128();
|
||||||
|
trace!(?register, "DW_CFA_def_cfa_register");
|
||||||
|
cfa.cfa_rule_register = register;
|
||||||
|
}
|
||||||
|
DW_CFA_def_cfa_offset => {
|
||||||
|
let offset = ins.uleb128();
|
||||||
|
trace!(?offset, "DW_CFA_def_cfa_offset");
|
||||||
|
cfa.cfa_rule_offset = offset;
|
||||||
|
}
|
||||||
|
DW_CFA_def_cfa_expression => todo!(),
|
||||||
|
DW_CFA_expression => todo!(),
|
||||||
|
DW_CFA_offset_extended_sf => todo!(),
|
||||||
|
DW_CFA_def_cfa_sf => todo!(),
|
||||||
|
DW_CFA_def_cfa_offset_sf => todo!(),
|
||||||
|
DW_CFA_val_offset => todo!(),
|
||||||
|
DW_CFA_val_offset_sf => todo!(),
|
||||||
|
DW_CFA_val_expression => todo!(),
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn process_instructions_cfa(
|
||||||
|
cie: &Cie<'_>,
|
||||||
|
initial_instructions: &[u8],
|
||||||
|
instructions: &[u8],
|
||||||
|
to_offset: usize,
|
||||||
|
) {
|
||||||
|
debug!("process instructions: {initial_instructions:x?}, {instructions:x?}");
|
||||||
|
|
||||||
|
let mut cfa = CfaState {
|
||||||
|
cfa_rule_offset: 0,
|
||||||
|
cfa_rule_register: 0,
|
||||||
|
register_states: [RegisterState::Undefined; 32],
|
||||||
|
current_offset: 0,
|
||||||
|
target_offset: to_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ins = InstructionParser::new(initial_instructions);
|
||||||
|
process_instruction_cfa_inner(&mut ins, &mut cfa, cie);
|
||||||
|
|
||||||
|
let mut ins = InstructionParser::new(instructions);
|
||||||
|
process_instruction_cfa_inner(&mut ins, &mut cfa, cie);
|
||||||
|
|
||||||
|
trace!("{cfa:?}");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,36 +2,37 @@ use crate::dwarf::parse::{AugmentationData, Cie, Encoding, ValueApplication, Val
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_simple_cie() {
|
fn parse_simple_cie() {
|
||||||
#[rustfmt::skip]
|
/*
|
||||||
let data = [
|
#[rustfmt::skip]
|
||||||
0x14, 0, 0, 0,
|
let data = [
|
||||||
0, 0, 0, 0, 1,
|
0x14, 0, 0, 0,
|
||||||
0x7a, 0x52, 0, 1,
|
0, 0, 0, 0, 1,
|
||||||
0x78, 0x10, 1,
|
0x7a, 0x52, 0, 1,
|
||||||
0x1b, 0xc, 7, 8,
|
0x78, 0x10, 1,
|
||||||
0x90, 1, 0, 0,
|
0x1b, 0xc, 7, 8,
|
||||||
];
|
0x90, 1, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
let cie = unsafe { super::parse_frame_info(data.as_ptr()) }.unwrap().0;
|
let cie = unsafe { super::parse_frame_info(data.as_ptr()) }.unwrap().0;
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
cie,
|
|
||||||
Cie {
|
|
||||||
augmentation: Some(AugmentationData {
|
|
||||||
lsda_pointer_encoding: None,
|
|
||||||
pointer_encoding: Some(Encoding(
|
|
||||||
(ValueApplication::DW_EH_PE_pcrel as u8) | (ValueFormat::DW_EH_PE_sdata4 as u8)
|
|
||||||
)),
|
|
||||||
personality: None
|
|
||||||
}),
|
|
||||||
augmentation_string: "meow",
|
|
||||||
code_alignment_factor: 1,
|
|
||||||
data_alignment_factor: -8,
|
|
||||||
return_address_register: 16,
|
|
||||||
initial_instructions: &[0xc, 7, 8, 0x90, 1, 0, 0]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cie,
|
||||||
|
Cie {
|
||||||
|
augmentation: Some(AugmentationData {
|
||||||
|
lsda_pointer_encoding: None,
|
||||||
|
pointer_encoding: Some(Encoding(
|
||||||
|
(ValueApplication::DW_EH_PE_pcrel as u8) | (ValueFormat::DW_EH_PE_sdata4 as u8)
|
||||||
|
)),
|
||||||
|
personality: None
|
||||||
|
}),
|
||||||
|
augmentation_string: "meow",
|
||||||
|
code_alignment_factor: 1,
|
||||||
|
data_alignment_factor: -8,
|
||||||
|
return_address_register: 16,
|
||||||
|
initial_instructions: &[0xc, 7, 8, 0x90, 1, 0, 0]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
*/
|
||||||
// llvm-dwarfdump output:
|
// llvm-dwarfdump output:
|
||||||
/*
|
/*
|
||||||
00000000 00000014 00000000 CIE
|
00000000 00000014 00000000 CIE
|
||||||
|
|
|
||||||
16
src/lib.rs
16
src/lib.rs
|
|
@ -37,19 +37,11 @@ pub unsafe extern "C-unwind" fn _UnwindRaiseException(
|
||||||
) -> uw::_Unwind_Reason_Code {
|
) -> uw::_Unwind_Reason_Code {
|
||||||
let _span = info_span!("_UnwindRaiseException", ?exception_object).entered();
|
let _span = info_span!("_UnwindRaiseException", ?exception_object).entered();
|
||||||
|
|
||||||
let frame = crate::dwarf::frame_info(arch::get_rip());
|
let ctx = arch::capture_context();
|
||||||
|
|
||||||
let eh_frame = crate::dwarf::eh_frame(arch::get_rip()).unwrap();
|
let frame = crate::dwarf::frame_info(Addr(core::ptr::with_exposed_provenance(
|
||||||
crate::dwarf::uwutables(eh_frame);
|
ctx.registers[dwarf::parse::arch::RETURN_ADDRESS],
|
||||||
|
)));
|
||||||
|
|
||||||
stdext::abort();
|
stdext::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is normally provided by the language runtime through the unwind info
|
|
||||||
// block. We don't want to access that usually because Rust messes with it :(.
|
|
||||||
static PERSONALITY_ROUTINE: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
|
|
||||||
|
|
||||||
pub unsafe fn set_personality_routine(routine: uw::PersonalityRoutine) {
|
|
||||||
let ptr: *mut () = core::mem::transmute(routine);
|
|
||||||
PERSONALITY_ROUTINE.store(ptr, core::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ fn main() {
|
||||||
|
|
||||||
registry.with(tree_layer).init();
|
registry.with(tree_layer).init();
|
||||||
unsafe {
|
unsafe {
|
||||||
uwuwind::set_personality_routine(personality_routine);
|
|
||||||
|
|
||||||
let exception = Box::into_raw(Box::new(Exception {
|
let exception = Box::into_raw(Box::new(Exception {
|
||||||
_uwe: uw::_Unwind_Exception {
|
_uwe: uw::_Unwind_Exception {
|
||||||
exception_class: 123456,
|
exception_class: 123456,
|
||||||
|
|
@ -36,13 +34,3 @@ fn main() {
|
||||||
uwuwind::_UnwindRaiseException(exception.cast::<uw::_Unwind_Exception>());
|
uwuwind::_UnwindRaiseException(exception.cast::<uw::_Unwind_Exception>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn personality_routine(
|
|
||||||
_version: i32,
|
|
||||||
_actions: uw::_UnwindAction,
|
|
||||||
_exception_class: u64,
|
|
||||||
_exception_object: *mut uw::_Unwind_Exception,
|
|
||||||
_context: *mut uw::_Unwind_Context,
|
|
||||||
) -> uw::_Unwind_Reason_Code {
|
|
||||||
uw::_Unwind_Reason_Code::_URC_NO_REASON
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue