summaryrefslogtreecommitdiffstats
path: root/vendor/gimli-0.27.3/src/write/cfi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli-0.27.3/src/write/cfi.rs')
-rw-r--r--vendor/gimli-0.27.3/src/write/cfi.rs1025
1 files changed, 0 insertions, 1025 deletions
diff --git a/vendor/gimli-0.27.3/src/write/cfi.rs b/vendor/gimli-0.27.3/src/write/cfi.rs
deleted file mode 100644
index 718cb69ad..000000000
--- a/vendor/gimli-0.27.3/src/write/cfi.rs
+++ /dev/null
@@ -1,1025 +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)]
-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),
-}
-
-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())?;
- }
- }
- 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::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;
-
- #[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)),
- ];
-
- 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 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);
-
- 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 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);
- }
- }
- }
- }
-}