diff --git a/src/dwarf/parse.rs b/src/dwarf/parse.rs index e7490ce..d58be41 100644 --- a/src/dwarf/parse.rs +++ b/src/dwarf/parse.rs @@ -127,6 +127,7 @@ pub struct Cie<'a> { } /// Frame Description Entry +#[derive(Debug, PartialEq)] pub struct Fde<'a> { /// A constant that gives the number of bytes of the header and instruction /// stream for this function, not including the length field itself (see Section 7.2.2 @@ -326,8 +327,16 @@ pub enum Instruction { Nop, } -pub unsafe fn parse_cfi(ptr: *const u8) { - parse_cie(ptr).unwrap(); +#[derive(Debug, PartialEq)] +enum FrameInfo<'a> { + Cie(Cie<'a>), + Fde(Fde<'a>), +} + +pub unsafe fn parse_cfi(mut ptr: *const u8) { + loop { + ptr = parse_frame_info(ptr).unwrap().1; + } } struct Cursor<'a>(&'a [u8]); @@ -394,19 +403,24 @@ fn read_ileb128(data: &mut Cursor<'_>) -> Result { Ok(result) } -unsafe fn parse_cie<'a>(ptr: *const u8) -> Result> { +unsafe fn parse_frame_info<'a>(ptr: *const u8) -> Result<(FrameInfo<'a>, *const u8)> { let len = ptr.cast::().read(); if len == 0xffffffff { todo!("loooong dwarf, cannot handle."); } let data = &mut Cursor(core::slice::from_raw_parts(ptr.add(4), len as usize)); - trace!("{:x?}", data.0); + trace!("frame info entry: {:x?}", data.0); let cie_id = read_u32(data)?; - if cie_id != 0 { - return Err(Error(format!("not a CIE"))); // TODO: we need to parse an FDE here. + let new_ptr = ptr.add(4).add(len as _); + if cie_id == 0 { + parse_cie(data).map(|cie| (FrameInfo::Cie(cie), new_ptr)) + } else { + parse_fde(data, cie_id).map(|fde| (FrameInfo::Fde(fde), new_ptr)) } +} +fn parse_cie<'a>(data: &mut Cursor<'a>) -> Result> { let version = read_u8(data)?; if version != 1 { return Err(Error(format!("version must be 1: {version}"))); @@ -420,6 +434,9 @@ unsafe fn parse_cie<'a>(ptr: *const u8) -> Result> { let augmentation_data = if augmentation.starts_with('z') { let aug_len = read_uleb128(data)?; let aug_data = read_bytes(data, aug_len as usize)?; + + parse_augmentation_data(augmentation, aug_data)?; + Some(aug_data) } else { None @@ -436,10 +453,60 @@ unsafe fn parse_cie<'a>(ptr: *const u8) -> Result> { initial_instructions, }; - trace!("total_len={len} {cie:#?}"); + trace!("{cie:#?}"); Ok(cie) } +fn parse_fde<'a>(data: &mut Cursor<'a>, cie_id: u32) -> Result> { + trace!("FDE {:x?}", data.0); + Err(Error("aa".into())) +} + +struct AugmentationData { + lsda_pointer_encoding: Option, + pointer_encoding: Option, +} + +fn parse_augmentation_data(string: &str, data: &[u8]) -> Result<()> { + let mut data = &mut Cursor(data); + + let mut codes = string.bytes(); + assert_eq!(codes.next(), Some(b'z')); + trace!("aug data {:x?}", data.0); + + let mut aug_data = AugmentationData {pointer_encoding: None}; + + for code in codes { + match code { + // If present, it indicates the presence of one argument in the Augmentation Data of the CIE, + // and a corresponding argument in the Augmentation Data of the FDE. + // The argument in the Augmentation Data of the CIE is 1-byte and represents the pointer encoding + // used for the argument in the Augmentation Data of the FDE, which is the address of a language-specific + // data area (LSDA). The size of the LSDA pointer is specified by the pointer encoding used. + b'L' => { + let encoding = read_u8(data)?; + aug_data.lsda_pointer_encoding = Some(encoding); + } + // If present, it indicates the presence of two arguments in the Augmentation Data of the CIE. + // The first argument is 1-byte and represents the pointer encoding used for the second argument, + // which is the address of a personality routine handler. The personality routine is used to handle + // language and vendor-specific tasks. The system unwind library interface accesses the language-specific + // exception handling semantics via the pointer to the personality routine. The personality routine does not + // have an ABI-specific name. The size of the personality routine pointer is specified by the pointer encoding used. + b'P' => { + + } + // If present, The Augmentation Data shall include a 1 byte argument that represents the pointer encoding for the address pointers used in the FDE. + b'R' => { + let encoding = read_u8(data)?; + aug_data.pointer_encoding = Some(encoding); + } + } + } + + Ok(()) +} + pub(super) struct InstrIter { data: *const u8, } diff --git a/src/dwarf/parse/tests.rs b/src/dwarf/parse/tests.rs index 7f03324..b293c90 100644 --- a/src/dwarf/parse/tests.rs +++ b/src/dwarf/parse/tests.rs @@ -1,4 +1,4 @@ -use crate::dwarf::parse::Cie; +use crate::dwarf::parse::{Cie, FrameInfo}; #[test] fn parse_simple_cie() { @@ -12,18 +12,18 @@ fn parse_simple_cie() { 0x90, 1, 0, 0, ]; - let cie = unsafe { super::parse_cie(data.as_ptr()) }.unwrap(); + let cie = unsafe { super::parse_frame_info(data.as_ptr()) }.unwrap().0; assert_eq!( cie, - Cie { + FrameInfo::Cie(Cie { augmentation: "zR", code_alignment_factor: 1, data_alignment_factor: -8, return_address_register: 16, augmentation_data: Some(b"\x1B"), initial_instructions: &[0xc, 7, 8, 0x90, 1, 0, 0] - } + }) ); // llvm-dwarfdump output: