diff options
author | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
commit | a990de90fe41456a23e58bd087d2f107d321f3a1 (patch) | |
tree | 15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/gimli/src/write/cfi.rs | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/gimli/src/write/cfi.rs')
-rw-r--r-- | vendor/gimli/src/write/cfi.rs | 1050 |
1 files changed, 0 insertions, 1050 deletions
diff --git a/vendor/gimli/src/write/cfi.rs b/vendor/gimli/src/write/cfi.rs deleted file mode 100644 index 5e108f1..0000000 --- a/vendor/gimli/src/write/cfi.rs +++ /dev/null @@ -1,1050 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId}; -use crate::constants; -use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer}; - -define_section!( - DebugFrame, - DebugFrameOffset, - "A writable `.debug_frame` section." -); - -define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section."); - -define_id!(CieId, "An identifier for a CIE in a `FrameTable`."); - -/// A table of frame description entries. -#[derive(Debug, Default)] -pub struct FrameTable { - /// Base id for CIEs. - base_id: BaseId, - /// The common information entries. - cies: IndexSet<CommonInformationEntry>, - /// The frame description entries. - fdes: Vec<(CieId, FrameDescriptionEntry)>, -} - -impl FrameTable { - /// Add a CIE and return its id. - /// - /// If the CIE already exists, then return the id of the existing CIE. - pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId { - let (index, _) = self.cies.insert_full(cie); - CieId::new(self.base_id, index) - } - - /// The number of CIEs. - pub fn cie_count(&self) -> usize { - self.cies.len() - } - - /// Add a FDE. - /// - /// Does not check for duplicates. - /// - /// # Panics - /// - /// Panics if the CIE id is invalid. - pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) { - debug_assert_eq!(self.base_id, cie.base_id); - self.fdes.push((cie, fde)); - } - - /// The number of FDEs. - pub fn fde_count(&self) -> usize { - self.fdes.len() - } - - /// Write the frame table entries to the given `.debug_frame` section. - pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> { - self.write(&mut w.0, false) - } - - /// Write the frame table entries to the given `.eh_frame` section. - pub fn write_eh_frame<W: Writer>(&self, w: &mut EhFrame<W>) -> Result<()> { - self.write(&mut w.0, true) - } - - fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> { - let mut cie_offsets = vec![None; self.cies.len()]; - for (cie_id, fde) in &self.fdes { - let cie_index = cie_id.index; - let cie = self.cies.get_index(cie_index).unwrap(); - let cie_offset = match cie_offsets[cie_index] { - Some(offset) => offset, - None => { - // Only write CIEs as they are referenced. - let offset = cie.write(w, eh_frame)?; - cie_offsets[cie_index] = Some(offset); - offset - } - }; - - fde.write(w, eh_frame, cie_offset, cie)?; - } - // TODO: write length 0 terminator for eh_frame? - Ok(()) - } -} - -/// A common information entry. This contains information that is shared between FDEs. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CommonInformationEntry { - encoding: Encoding, - - /// A constant that is factored out of code offsets. - /// - /// This should be set to the minimum instruction length. - /// Writing a code offset that is not a multiple of this factor will generate an error. - code_alignment_factor: u8, - - /// A constant that is factored out of data offsets. - /// - /// This should be set to the minimum data alignment for the frame. - /// Writing a data offset that is not a multiple of this factor will generate an error. - data_alignment_factor: i8, - - /// The return address register. This might not correspond to an actual machine register. - return_address_register: Register, - - /// The address of the personality function and its encoding. - pub personality: Option<(constants::DwEhPe, Address)>, - - /// The encoding to use for the LSDA address in FDEs. - /// - /// If set then all FDEs which use this CIE must have a LSDA address. - pub lsda_encoding: Option<constants::DwEhPe>, - - /// The encoding to use for addresses in FDEs. - pub fde_address_encoding: constants::DwEhPe, - - /// True for signal trampolines. - pub signal_trampoline: bool, - - /// The initial instructions upon entry to this function. - instructions: Vec<CallFrameInstruction>, -} - -impl CommonInformationEntry { - /// Create a new common information entry. - /// - /// The encoding version must be a CFI version, not a DWARF version. - pub fn new( - encoding: Encoding, - code_alignment_factor: u8, - data_alignment_factor: i8, - return_address_register: Register, - ) -> Self { - CommonInformationEntry { - encoding, - code_alignment_factor, - data_alignment_factor, - return_address_register, - personality: None, - lsda_encoding: None, - fde_address_encoding: constants::DW_EH_PE_absptr, - signal_trampoline: false, - instructions: Vec::new(), - } - } - - /// Add an initial instruction. - pub fn add_instruction(&mut self, instruction: CallFrameInstruction) { - self.instructions.push(instruction); - } - - fn has_augmentation(&self) -> bool { - self.personality.is_some() - || self.lsda_encoding.is_some() - || self.signal_trampoline - || self.fde_address_encoding != constants::DW_EH_PE_absptr - } - - /// Returns the section offset of the CIE. - fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<usize> { - let encoding = self.encoding; - let offset = w.len(); - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - if eh_frame { - w.write_u32(0)?; - } else { - match encoding.format { - Format::Dwarf32 => w.write_u32(0xffff_ffff)?, - Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?, - } - } - - if eh_frame { - if encoding.version != 1 { - return Err(Error::UnsupportedVersion(encoding.version)); - }; - } else { - match encoding.version { - 1 | 3 | 4 => {} - _ => return Err(Error::UnsupportedVersion(encoding.version)), - }; - } - w.write_u8(encoding.version as u8)?; - - let augmentation = self.has_augmentation(); - if augmentation { - w.write_u8(b'z')?; - if self.lsda_encoding.is_some() { - w.write_u8(b'L')?; - } - if self.personality.is_some() { - w.write_u8(b'P')?; - } - if self.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_u8(b'R')?; - } - if self.signal_trampoline { - w.write_u8(b'S')?; - } - } - w.write_u8(0)?; - - if encoding.version >= 4 { - w.write_u8(encoding.address_size)?; - // TODO: segment_selector_size - w.write_u8(0)?; - } - - w.write_uleb128(self.code_alignment_factor.into())?; - w.write_sleb128(self.data_alignment_factor.into())?; - - if !eh_frame && encoding.version == 1 { - let register = self.return_address_register.0 as u8; - if u16::from(register) != self.return_address_register.0 { - return Err(Error::ValueTooLarge); - } - w.write_u8(register)?; - } else { - w.write_uleb128(self.return_address_register.0.into())?; - } - - if augmentation { - let augmentation_length_offset = w.len(); - w.write_u8(0)?; - let augmentation_length_base = w.len(); - - if let Some(eh_pe) = self.lsda_encoding { - w.write_u8(eh_pe.0)?; - } - if let Some((eh_pe, address)) = self.personality { - w.write_u8(eh_pe.0)?; - w.write_eh_pointer(address, eh_pe, encoding.address_size)?; - } - if self.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_u8(self.fde_address_encoding.0)?; - } - - let augmentation_length = (w.len() - augmentation_length_base) as u64; - debug_assert!(augmentation_length < 0x80); - w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?; - } - - for instruction in &self.instructions { - instruction.write(w, encoding, self)?; - } - - write_nop( - w, - encoding.format.word_size() as usize + w.len() - length_base, - encoding.address_size, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(offset) - } -} - -/// A frame description entry. There should be one FDE per function. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FrameDescriptionEntry { - /// The initial address of the function. - address: Address, - - /// The length in bytes of the function. - length: u32, - - /// The address of the LSDA. - pub lsda: Option<Address>, - - /// The instructions for this function, ordered by offset. - instructions: Vec<(u32, CallFrameInstruction)>, -} - -impl FrameDescriptionEntry { - /// Create a new frame description entry for a function. - pub fn new(address: Address, length: u32) -> Self { - FrameDescriptionEntry { - address, - length, - lsda: None, - instructions: Vec::new(), - } - } - - /// Add an instruction. - /// - /// Instructions must be added in increasing order of offset, or writing will fail. - pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) { - debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset); - self.instructions.push((offset, instruction)); - } - - fn write<W: Writer>( - &self, - w: &mut W, - eh_frame: bool, - cie_offset: usize, - cie: &CommonInformationEntry, - ) -> Result<()> { - let encoding = cie.encoding; - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - if eh_frame { - // .eh_frame uses a relative offset which doesn't need relocation. - w.write_udata((w.len() - cie_offset) as u64, 4)?; - } else { - w.write_offset( - cie_offset, - SectionId::DebugFrame, - encoding.format.word_size(), - )?; - } - - if cie.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_eh_pointer( - self.address, - cie.fde_address_encoding, - encoding.address_size, - )?; - w.write_eh_pointer_data( - self.length.into(), - cie.fde_address_encoding.format(), - encoding.address_size, - )?; - } else { - w.write_address(self.address, encoding.address_size)?; - w.write_udata(self.length.into(), encoding.address_size)?; - } - - if cie.has_augmentation() { - let mut augmentation_length = 0u64; - if self.lsda.is_some() { - augmentation_length += u64::from(encoding.address_size); - } - w.write_uleb128(augmentation_length)?; - - debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some()); - if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) { - w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?; - } - } - - let mut prev_offset = 0; - for (offset, instruction) in &self.instructions { - write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?; - prev_offset = *offset; - instruction.write(w, encoding, cie)?; - } - - write_nop( - w, - encoding.format.word_size() as usize + w.len() - length_base, - encoding.address_size, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(()) - } -} - -/// An instruction in a frame description entry. -/// -/// This may be a CFA definition, a register rule, or some other directive. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum CallFrameInstruction { - /// Define the CFA rule to use the provided register and offset. - Cfa(Register, i32), - /// Update the CFA rule to use the provided register. The offset is unchanged. - CfaRegister(Register), - /// Update the CFA rule to use the provided offset. The register is unchanged. - CfaOffset(i32), - /// Define the CFA rule to use the provided expression. - CfaExpression(Expression), - - /// Restore the initial rule for the register. - Restore(Register), - /// The previous value of the register is not recoverable. - Undefined(Register), - /// The register has not been modified. - SameValue(Register), - /// The previous value of the register is saved at address CFA + offset. - Offset(Register, i32), - /// The previous value of the register is CFA + offset. - ValOffset(Register, i32), - /// The previous value of the register is stored in another register. - Register(Register, Register), - /// The previous value of the register is saved at address given by the expression. - Expression(Register, Expression), - /// The previous value of the register is given by the expression. - ValExpression(Register, Expression), - - /// Push all register rules onto a stack. - RememberState, - /// Pop all register rules off the stack. - RestoreState, - /// The size of the arguments that have been pushed onto the stack. - ArgsSize(u32), - - /// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register. - NegateRaState, -} - -impl CallFrameInstruction { - fn write<W: Writer>( - &self, - w: &mut W, - encoding: Encoding, - cie: &CommonInformationEntry, - ) -> Result<()> { - match *self { - CallFrameInstruction::Cfa(register, offset) => { - if offset < 0 { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - w.write_u8(constants::DW_CFA_def_cfa_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else { - // Unfactored offset. - w.write_u8(constants::DW_CFA_def_cfa.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::CfaRegister(register) => { - w.write_u8(constants::DW_CFA_def_cfa_register.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::CfaOffset(offset) => { - if offset < 0 { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?; - w.write_sleb128(offset.into())?; - } else { - // Unfactored offset. - w.write_u8(constants::DW_CFA_def_cfa_offset.0)?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::CfaExpression(ref expression) => { - w.write_u8(constants::DW_CFA_def_cfa_expression.0)?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::Restore(register) => { - if register.0 < 0x40 { - w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?; - } else { - w.write_u8(constants::DW_CFA_restore_extended.0)?; - w.write_uleb128(register.0.into())?; - } - } - CallFrameInstruction::Undefined(register) => { - w.write_u8(constants::DW_CFA_undefined.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::SameValue(register) => { - w.write_u8(constants::DW_CFA_same_value.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::Offset(register, offset) => { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - if offset < 0 { - w.write_u8(constants::DW_CFA_offset_extended_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else if register.0 < 0x40 { - w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?; - w.write_uleb128(offset as u64)?; - } else { - w.write_u8(constants::DW_CFA_offset_extended.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::ValOffset(register, offset) => { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - if offset < 0 { - w.write_u8(constants::DW_CFA_val_offset_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else { - w.write_u8(constants::DW_CFA_val_offset.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::Register(register1, register2) => { - w.write_u8(constants::DW_CFA_register.0)?; - w.write_uleb128(register1.0.into())?; - w.write_uleb128(register2.0.into())?; - } - CallFrameInstruction::Expression(register, ref expression) => { - w.write_u8(constants::DW_CFA_expression.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::ValExpression(register, ref expression) => { - w.write_u8(constants::DW_CFA_val_expression.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::RememberState => { - w.write_u8(constants::DW_CFA_remember_state.0)?; - } - CallFrameInstruction::RestoreState => { - w.write_u8(constants::DW_CFA_restore_state.0)?; - } - CallFrameInstruction::ArgsSize(size) => { - w.write_u8(constants::DW_CFA_GNU_args_size.0)?; - w.write_uleb128(size.into())?; - } - CallFrameInstruction::NegateRaState => { - w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?; - } - } - Ok(()) - } -} - -fn write_advance_loc<W: Writer>( - w: &mut W, - code_alignment_factor: u8, - prev_offset: u32, - offset: u32, -) -> Result<()> { - if offset == prev_offset { - return Ok(()); - } - let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?; - if delta < 0x40 { - w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?; - } else if delta < 0x100 { - w.write_u8(constants::DW_CFA_advance_loc1.0)?; - w.write_u8(delta as u8)?; - } else if delta < 0x10000 { - w.write_u8(constants::DW_CFA_advance_loc2.0)?; - w.write_u16(delta as u16)?; - } else { - w.write_u8(constants::DW_CFA_advance_loc4.0)?; - w.write_u32(delta)?; - } - Ok(()) -} - -fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> { - debug_assert_eq!(align & (align - 1), 0); - let tail_len = (!len + 1) & (align as usize - 1); - for _ in 0..tail_len { - w.write_u8(constants::DW_CFA_nop.0)?; - } - Ok(()) -} - -fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> { - if offset < prev_offset { - return Err(Error::InvalidFrameCodeOffset(offset)); - } - let delta = offset - prev_offset; - let factor = u32::from(factor); - let factored_delta = delta / factor; - if delta != factored_delta * factor { - return Err(Error::InvalidFrameCodeOffset(offset)); - } - Ok(factored_delta) -} - -fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> { - let factor = i32::from(factor); - let factored_offset = offset / factor; - if offset != factored_offset * factor { - return Err(Error::InvalidFrameDataOffset(offset)); - } - Ok(factored_offset) -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult}; - use std::collections::{hash_map, HashMap}; - - impl FrameTable { - /// Create a frame table by reading the data in the given section. - /// - /// `convert_address` is a function to convert read addresses into the `Address` - /// type. For non-relocatable addresses, this function may simply return - /// `Address::Constant(address)`. For relocatable addresses, it is the caller's - /// responsibility to determine the symbol and addend corresponding to the address - /// and return `Address::Symbol { symbol, addend }`. - pub fn from<R, Section>( - frame: &Section, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<FrameTable> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let bases = read::BaseAddresses::default().set_eh_frame(0); - - let mut frame_table = FrameTable::default(); - - let mut cie_ids = HashMap::new(); - let mut entries = frame.entries(&bases); - while let Some(entry) = entries.next()? { - let partial = match entry { - read::CieOrFde::Cie(_) => continue, - read::CieOrFde::Fde(partial) => partial, - }; - - // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only - // stored a reference. - let from_fde = partial.parse(Section::cie_from_offset)?; - let from_cie = from_fde.cie(); - let cie_id = match cie_ids.entry(from_cie.offset()) { - hash_map::Entry::Occupied(o) => *o.get(), - hash_map::Entry::Vacant(e) => { - let cie = - CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?; - let cie_id = frame_table.add_cie(cie); - e.insert(cie_id); - cie_id - } - }; - let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?; - frame_table.add_fde(cie_id, fde); - } - - Ok(frame_table) - } - } - - impl CommonInformationEntry { - fn from<R, Section>( - from_cie: &read::CommonInformationEntry<R>, - frame: &Section, - bases: &read::BaseAddresses, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<CommonInformationEntry> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let mut cie = CommonInformationEntry::new( - from_cie.encoding(), - from_cie.code_alignment_factor() as u8, - from_cie.data_alignment_factor() as i8, - from_cie.return_address_register(), - ); - - cie.personality = match from_cie.personality_with_encoding() { - // We treat these the same because the encoding already determines - // whether it is indirect. - Some((eh_pe, read::Pointer::Direct(p))) - | Some((eh_pe, read::Pointer::Indirect(p))) => { - let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; - Some((eh_pe, address)) - } - _ => None, - }; - cie.lsda_encoding = from_cie.lsda_encoding(); - cie.fde_address_encoding = from_cie - .fde_address_encoding() - .unwrap_or(constants::DW_EH_PE_absptr); - cie.signal_trampoline = from_cie.is_signal_trampoline(); - - let mut offset = 0; - let mut from_instructions = from_cie.instructions(frame, bases); - while let Some(from_instruction) = from_instructions.next()? { - if let Some(instruction) = CallFrameInstruction::from( - from_instruction, - from_cie, - convert_address, - &mut offset, - )? { - cie.instructions.push(instruction); - } - } - Ok(cie) - } - } - - impl FrameDescriptionEntry { - fn from<R, Section>( - from_fde: &read::FrameDescriptionEntry<R>, - frame: &Section, - bases: &read::BaseAddresses, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<FrameDescriptionEntry> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let address = - convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?; - let length = from_fde.len() as u32; - let mut fde = FrameDescriptionEntry::new(address, length); - - match from_fde.lsda() { - // We treat these the same because the encoding already determines - // whether it is indirect. - Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => { - let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; - fde.lsda = Some(address); - } - None => {} - } - - let from_cie = from_fde.cie(); - let mut offset = 0; - let mut from_instructions = from_fde.instructions(frame, bases); - while let Some(from_instruction) = from_instructions.next()? { - if let Some(instruction) = CallFrameInstruction::from( - from_instruction, - from_cie, - convert_address, - &mut offset, - )? { - fde.instructions.push((offset, instruction)); - } - } - - Ok(fde) - } - } - - impl CallFrameInstruction { - fn from<R: Reader<Offset = usize>>( - from_instruction: read::CallFrameInstruction<R>, - from_cie: &read::CommonInformationEntry<R>, - convert_address: &dyn Fn(u64) -> Option<Address>, - offset: &mut u32, - ) -> ConvertResult<Option<CallFrameInstruction>> { - let convert_expression = - |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address); - // TODO: validate integer type conversions - Ok(Some(match from_instruction { - read::CallFrameInstruction::SetLoc { .. } => { - return Err(ConvertError::UnsupportedCfiInstruction); - } - read::CallFrameInstruction::AdvanceLoc { delta } => { - *offset += delta * from_cie.code_alignment_factor() as u32; - return Ok(None); - } - read::CallFrameInstruction::DefCfa { register, offset } => { - CallFrameInstruction::Cfa(register, offset as i32) - } - read::CallFrameInstruction::DefCfaSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::Cfa(register, offset as i32) - } - read::CallFrameInstruction::DefCfaRegister { register } => { - CallFrameInstruction::CfaRegister(register) - } - - read::CallFrameInstruction::DefCfaOffset { offset } => { - CallFrameInstruction::CfaOffset(offset as i32) - } - read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::CfaOffset(offset as i32) - } - read::CallFrameInstruction::DefCfaExpression { expression } => { - CallFrameInstruction::CfaExpression(convert_expression(expression)?) - } - read::CallFrameInstruction::Undefined { register } => { - CallFrameInstruction::Undefined(register) - } - read::CallFrameInstruction::SameValue { register } => { - CallFrameInstruction::SameValue(register) - } - read::CallFrameInstruction::Offset { - register, - factored_offset, - } => { - let offset = factored_offset as i64 * from_cie.data_alignment_factor(); - CallFrameInstruction::Offset(register, offset as i32) - } - read::CallFrameInstruction::OffsetExtendedSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::Offset(register, offset as i32) - } - read::CallFrameInstruction::ValOffset { - register, - factored_offset, - } => { - let offset = factored_offset as i64 * from_cie.data_alignment_factor(); - CallFrameInstruction::ValOffset(register, offset as i32) - } - read::CallFrameInstruction::ValOffsetSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::ValOffset(register, offset as i32) - } - read::CallFrameInstruction::Register { - dest_register, - src_register, - } => CallFrameInstruction::Register(dest_register, src_register), - read::CallFrameInstruction::Expression { - register, - expression, - } => CallFrameInstruction::Expression(register, convert_expression(expression)?), - read::CallFrameInstruction::ValExpression { - register, - expression, - } => CallFrameInstruction::ValExpression(register, convert_expression(expression)?), - read::CallFrameInstruction::Restore { register } => { - CallFrameInstruction::Restore(register) - } - read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState, - read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState, - read::CallFrameInstruction::ArgsSize { size } => { - CallFrameInstruction::ArgsSize(size as u32) - } - read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState, - read::CallFrameInstruction::Nop => return Ok(None), - })) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::arch::X86_64; - use crate::read; - use crate::write::EndianVec; - use crate::{LittleEndian, Vendor}; - - #[test] - fn test_frame_table() { - for &version in &[1, 3, 4] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut frames = FrameTable::default(); - - let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - let cie1_id = frames.add_cie(cie1.clone()); - assert_eq!(cie1_id, frames.add_cie(cie1.clone())); - - let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr); - cie2.personality = - Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234))); - cie2.signal_trampoline = true; - let cie2_id = frames.add_cie(cie2.clone()); - assert_ne!(cie1_id, cie2_id); - assert_eq!(cie2_id, frames.add_cie(cie2.clone())); - - let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); - frames.add_fde(cie1_id, fde1.clone()); - - let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20); - frames.add_fde(cie1_id, fde2.clone()); - - let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30); - fde3.lsda = Some(Address::Constant(0x3300)); - frames.add_fde(cie2_id, fde3.clone()); - - let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40); - fde4.lsda = Some(Address::Constant(0x4400)); - frames.add_fde(cie2_id, fde4.clone()); - - let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - cie3.fde_address_encoding = constants::DW_EH_PE_pcrel; - cie3.lsda_encoding = Some(constants::DW_EH_PE_pcrel); - cie3.personality = Some((constants::DW_EH_PE_pcrel, Address::Constant(0x1235))); - cie3.signal_trampoline = true; - let cie3_id = frames.add_cie(cie3.clone()); - assert_ne!(cie2_id, cie3_id); - assert_eq!(cie3_id, frames.add_cie(cie3.clone())); - - let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50); - fde5.lsda = Some(Address::Constant(0x5500)); - frames.add_fde(cie3_id, fde5.clone()); - - // Test writing `.debug_frame`. - let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); - frames.write_debug_frame(&mut debug_frame).unwrap(); - - let mut read_debug_frame = - read::DebugFrame::new(debug_frame.slice(), LittleEndian); - read_debug_frame.set_address_size(address_size); - let convert_frames = FrameTable::from(&read_debug_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - assert_eq!(frames.cies, convert_frames.cies); - assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); - for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { - assert_eq!(a.1, b.1); - } - - if version == 1 { - // Test writing `.eh_frame`. - let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian)); - frames.write_eh_frame(&mut eh_frame).unwrap(); - - let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian); - read_eh_frame.set_address_size(address_size); - let convert_frames = FrameTable::from(&read_eh_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - assert_eq!(frames.cies, convert_frames.cies); - assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); - for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { - assert_eq!(a.1, b.1); - } - } - } - } - } - } - - #[test] - fn test_frame_instruction() { - let mut expression = Expression::new(); - expression.op_constu(0); - - let cie_instructions = [ - CallFrameInstruction::Cfa(X86_64::RSP, 8), - CallFrameInstruction::Offset(X86_64::RA, -8), - ]; - - let fde_instructions = [ - (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)), - (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)), - (2, CallFrameInstruction::CfaRegister(X86_64::RBP)), - (4, CallFrameInstruction::CfaOffset(8)), - (4, CallFrameInstruction::CfaOffset(0)), - (4, CallFrameInstruction::CfaOffset(-8)), - (6, CallFrameInstruction::CfaExpression(expression.clone())), - (8, CallFrameInstruction::Restore(Register(1))), - (8, CallFrameInstruction::Restore(Register(101))), - (10, CallFrameInstruction::Undefined(Register(2))), - (12, CallFrameInstruction::SameValue(Register(3))), - (14, CallFrameInstruction::Offset(Register(4), 16)), - (14, CallFrameInstruction::Offset(Register(104), 16)), - (16, CallFrameInstruction::ValOffset(Register(5), -24)), - (16, CallFrameInstruction::ValOffset(Register(5), 24)), - (18, CallFrameInstruction::Register(Register(6), Register(7))), - ( - 20, - CallFrameInstruction::Expression(Register(8), expression.clone()), - ), - ( - 22, - CallFrameInstruction::ValExpression(Register(9), expression.clone()), - ), - (24 + 0x80, CallFrameInstruction::RememberState), - (26 + 0x280, CallFrameInstruction::RestoreState), - (28 + 0x20280, CallFrameInstruction::ArgsSize(23)), - ]; - - let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)]; - - for &version in &[1, 3, 4] { - for &address_size in &[4, 8] { - for &vendor in &[Vendor::Default, Vendor::AArch64] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut frames = FrameTable::default(); - - let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA); - for i in &cie_instructions { - cie.add_instruction(i.clone()); - } - let cie_id = frames.add_cie(cie); - - let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); - for (o, i) in &fde_instructions { - fde.add_instruction(*o, i.clone()); - } - frames.add_fde(cie_id, fde); - - if vendor == Vendor::AArch64 { - let mut fde = - FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10); - for (o, i) in &fde_instructions_aarch64 { - fde.add_instruction(*o, i.clone()); - } - frames.add_fde(cie_id, fde); - } - - let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); - frames.write_debug_frame(&mut debug_frame).unwrap(); - - let mut read_debug_frame = - read::DebugFrame::new(debug_frame.slice(), LittleEndian); - read_debug_frame.set_address_size(address_size); - read_debug_frame.set_vendor(vendor); - let frames = FrameTable::from(&read_debug_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - - assert_eq!( - &frames.cies.get_index(0).unwrap().instructions, - &cie_instructions - ); - assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions); - if vendor == Vendor::AArch64 { - assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64); - } - } - } - } - } - } -} |