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 | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/gimli/src/write')
-rw-r--r-- | vendor/gimli/src/write/abbrev.rs | 188 | ||||
-rw-r--r-- | vendor/gimli/src/write/cfi.rs | 1050 | ||||
-rw-r--r-- | vendor/gimli/src/write/dwarf.rs | 138 | ||||
-rw-r--r-- | vendor/gimli/src/write/endian_vec.rs | 117 | ||||
-rw-r--r-- | vendor/gimli/src/write/line.rs | 1957 | ||||
-rw-r--r-- | vendor/gimli/src/write/loc.rs | 550 | ||||
-rw-r--r-- | vendor/gimli/src/write/mod.rs | 425 | ||||
-rw-r--r-- | vendor/gimli/src/write/op.rs | 1618 | ||||
-rw-r--r-- | vendor/gimli/src/write/range.rs | 416 | ||||
-rw-r--r-- | vendor/gimli/src/write/section.rs | 172 | ||||
-rw-r--r-- | vendor/gimli/src/write/str.rs | 172 | ||||
-rw-r--r-- | vendor/gimli/src/write/unit.rs | 3152 | ||||
-rw-r--r-- | vendor/gimli/src/write/writer.rs | 494 |
13 files changed, 0 insertions, 10449 deletions
diff --git a/vendor/gimli/src/write/abbrev.rs b/vendor/gimli/src/write/abbrev.rs deleted file mode 100644 index 7cdfa96..0000000 --- a/vendor/gimli/src/write/abbrev.rs +++ /dev/null @@ -1,188 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugAbbrevOffset, SectionId}; -use crate::constants; -use crate::write::{Result, Section, Writer}; - -/// A table of abbreviations that will be stored in a `.debug_abbrev` section. -// Requirements: -// - values are `Abbreviation` -// - insertion returns an abbreviation code for use in writing a DIE -// - inserting a duplicate returns the code of the existing value -#[derive(Debug, Default)] -pub(crate) struct AbbreviationTable { - abbrevs: IndexSet<Abbreviation>, -} - -impl AbbreviationTable { - /// Add an abbreviation to the table and return its code. - pub fn add(&mut self, abbrev: Abbreviation) -> u64 { - let (code, _) = self.abbrevs.insert_full(abbrev); - // Code must be non-zero - (code + 1) as u64 - } - - /// Write the abbreviation table to the `.debug_abbrev` section. - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - for (code, abbrev) in self.abbrevs.iter().enumerate() { - w.write_uleb128((code + 1) as u64)?; - abbrev.write(w)?; - } - // Null abbreviation code - w.write_u8(0) - } -} - -/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: -/// its tag type, whether it has children, and its set of attributes. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Abbreviation { - tag: constants::DwTag, - has_children: bool, - attributes: Vec<AttributeSpecification>, -} - -impl Abbreviation { - /// Construct a new `Abbreviation`. - #[inline] - pub fn new( - tag: constants::DwTag, - has_children: bool, - attributes: Vec<AttributeSpecification>, - ) -> Abbreviation { - Abbreviation { - tag, - has_children, - attributes, - } - } - - /// Write the abbreviation to the `.debug_abbrev` section. - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - w.write_uleb128(self.tag.0.into())?; - w.write_u8(if self.has_children { - constants::DW_CHILDREN_yes.0 - } else { - constants::DW_CHILDREN_no.0 - })?; - for attr in &self.attributes { - attr.write(w)?; - } - // Null name and form - w.write_u8(0)?; - w.write_u8(0) - } -} - -/// The description of an attribute in an abbreviated type. -// TODO: support implicit const -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct AttributeSpecification { - name: constants::DwAt, - form: constants::DwForm, -} - -impl AttributeSpecification { - /// Construct a new `AttributeSpecification`. - #[inline] - pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification { - AttributeSpecification { name, form } - } - - /// Write the attribute specification to the `.debug_abbrev` section. - #[inline] - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - w.write_uleb128(self.name.0.into())?; - w.write_uleb128(self.form.0.into()) - } -} - -define_section!( - DebugAbbrev, - DebugAbbrevOffset, - "A writable `.debug_abbrev` section." -); - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::constants; - use crate::read; - use crate::write::EndianVec; - use crate::LittleEndian; - - #[test] - fn test_abbreviation_table() { - let mut abbrevs = AbbreviationTable::default(); - let abbrev1 = Abbreviation::new( - constants::DW_TAG_subprogram, - false, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_string, - )], - ); - let abbrev2 = Abbreviation::new( - constants::DW_TAG_compile_unit, - true, - vec![ - AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp), - AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2), - ], - ); - let code1 = abbrevs.add(abbrev1.clone()); - assert_eq!(code1, 1); - let code2 = abbrevs.add(abbrev2.clone()); - assert_eq!(code2, 2); - assert_eq!(abbrevs.add(abbrev1.clone()), code1); - assert_eq!(abbrevs.add(abbrev2.clone()), code2); - - let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian)); - let debug_abbrev_offset = debug_abbrev.offset(); - assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0)); - abbrevs.write(&mut debug_abbrev).unwrap(); - assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17)); - - let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian); - let read_abbrevs = read_debug_abbrev - .abbreviations(debug_abbrev_offset) - .unwrap(); - - let read_abbrev1 = read_abbrevs.get(code1).unwrap(); - assert_eq!(abbrev1.tag, read_abbrev1.tag()); - assert_eq!(abbrev1.has_children, read_abbrev1.has_children()); - assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len()); - assert_eq!( - abbrev1.attributes[0].name, - read_abbrev1.attributes()[0].name() - ); - assert_eq!( - abbrev1.attributes[0].form, - read_abbrev1.attributes()[0].form() - ); - - let read_abbrev2 = read_abbrevs.get(code2).unwrap(); - assert_eq!(abbrev2.tag, read_abbrev2.tag()); - assert_eq!(abbrev2.has_children, read_abbrev2.has_children()); - assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len()); - assert_eq!( - abbrev2.attributes[0].name, - read_abbrev2.attributes()[0].name() - ); - assert_eq!( - abbrev2.attributes[0].form, - read_abbrev2.attributes()[0].form() - ); - assert_eq!( - abbrev2.attributes[1].name, - read_abbrev2.attributes()[1].name() - ); - assert_eq!( - abbrev2.attributes[1].form, - read_abbrev2.attributes()[1].form() - ); - } -} 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); - } - } - } - } - } - } -} diff --git a/vendor/gimli/src/write/dwarf.rs b/vendor/gimli/src/write/dwarf.rs deleted file mode 100644 index ea50712..0000000 --- a/vendor/gimli/src/write/dwarf.rs +++ /dev/null @@ -1,138 +0,0 @@ -use alloc::vec::Vec; - -use crate::common::Encoding; -use crate::write::{ - AbbreviationTable, LineProgram, LineStringTable, Result, Sections, StringTable, Unit, - UnitTable, Writer, -}; - -/// Writable DWARF information for more than one unit. -#[derive(Debug, Default)] -pub struct Dwarf { - /// A table of units. These are primarily stored in the `.debug_info` section, - /// but they also contain information that is stored in other sections. - pub units: UnitTable, - - /// Extra line number programs that are not associated with a unit. - /// - /// These should only be used when generating DWARF5 line-only debug - /// information. - pub line_programs: Vec<LineProgram>, - - /// A table of strings that will be stored in the `.debug_line_str` section. - pub line_strings: LineStringTable, - - /// A table of strings that will be stored in the `.debug_str` section. - pub strings: StringTable, -} - -impl Dwarf { - /// Create a new `Dwarf` instance. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Write the DWARF information to the given sections. - pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> { - let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; - let strings = self.strings.write(&mut sections.debug_str)?; - self.units.write(sections, &line_strings, &strings)?; - for line_program in &self.line_programs { - line_program.write( - &mut sections.debug_line, - line_program.encoding(), - &line_strings, - &strings, - )?; - } - Ok(()) - } -} - -/// Writable DWARF information for a single unit. -#[derive(Debug)] -pub struct DwarfUnit { - /// A unit. This is primarily stored in the `.debug_info` section, - /// but also contains information that is stored in other sections. - pub unit: Unit, - - /// A table of strings that will be stored in the `.debug_line_str` section. - pub line_strings: LineStringTable, - - /// A table of strings that will be stored in the `.debug_str` section. - pub strings: StringTable, -} - -impl DwarfUnit { - /// Create a new `DwarfUnit`. - /// - /// Note: you should set `self.unit.line_program` after creation. - /// This cannot be done earlier because it may need to reference - /// `self.line_strings`. - pub fn new(encoding: Encoding) -> Self { - let unit = Unit::new(encoding, LineProgram::none()); - DwarfUnit { - unit, - line_strings: LineStringTable::default(), - strings: StringTable::default(), - } - } - - /// Write the DWARf information to the given sections. - pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> { - let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; - let strings = self.strings.write(&mut sections.debug_str)?; - - let abbrev_offset = sections.debug_abbrev.offset(); - let mut abbrevs = AbbreviationTable::default(); - - self.unit.write( - sections, - abbrev_offset, - &mut abbrevs, - &line_strings, - &strings, - )?; - // None should exist because we didn't give out any UnitId. - assert!(sections.debug_info_refs.is_empty()); - assert!(sections.debug_loc_refs.is_empty()); - assert!(sections.debug_loclists_refs.is_empty()); - - abbrevs.write(&mut sections.debug_abbrev)?; - Ok(()) - } -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{Address, ConvertResult}; - - impl Dwarf { - /// Create a `write::Dwarf` by converting a `read::Dwarf`. - /// - /// `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: Reader<Offset = usize>>( - dwarf: &read::Dwarf<R>, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Dwarf> { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - let units = UnitTable::from(dwarf, &mut line_strings, &mut strings, convert_address)?; - // TODO: convert the line programs that were not referenced by a unit. - let line_programs = Vec::new(); - Ok(Dwarf { - units, - line_programs, - line_strings, - strings, - }) - } - } -} diff --git a/vendor/gimli/src/write/endian_vec.rs b/vendor/gimli/src/write/endian_vec.rs deleted file mode 100644 index 7b04060..0000000 --- a/vendor/gimli/src/write/endian_vec.rs +++ /dev/null @@ -1,117 +0,0 @@ -use alloc::vec::Vec; -use std::mem; - -use crate::endianity::Endianity; -use crate::write::{Error, Result, Writer}; - -/// A `Vec<u8>` with endianity metadata. -/// -/// This implements the `Writer` trait, which is used for all writing of DWARF sections. -#[derive(Debug, Clone)] -pub struct EndianVec<Endian> -where - Endian: Endianity, -{ - vec: Vec<u8>, - endian: Endian, -} - -impl<Endian> EndianVec<Endian> -where - Endian: Endianity, -{ - /// Construct an empty `EndianVec` with the given endianity. - pub fn new(endian: Endian) -> EndianVec<Endian> { - EndianVec { - vec: Vec::new(), - endian, - } - } - - /// Return a reference to the raw slice. - pub fn slice(&self) -> &[u8] { - &self.vec - } - - /// Convert into a `Vec<u8>`. - pub fn into_vec(self) -> Vec<u8> { - self.vec - } - - /// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place. - pub fn take(&mut self) -> Vec<u8> { - let mut vec = Vec::new(); - mem::swap(&mut self.vec, &mut vec); - vec - } -} - -impl<Endian> Writer for EndianVec<Endian> -where - Endian: Endianity, -{ - type Endian = Endian; - - #[inline] - fn endian(&self) -> Self::Endian { - self.endian - } - - #[inline] - fn len(&self) -> usize { - self.vec.len() - } - - fn write(&mut self, bytes: &[u8]) -> Result<()> { - self.vec.extend(bytes); - Ok(()) - } - - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - if offset > self.vec.len() { - return Err(Error::OffsetOutOfBounds); - } - let to = &mut self.vec[offset..]; - if bytes.len() > to.len() { - return Err(Error::LengthOutOfBounds); - } - let to = &mut to[..bytes.len()]; - to.copy_from_slice(bytes); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::LittleEndian; - - #[test] - fn test_endian_vec() { - let mut w = EndianVec::new(LittleEndian); - assert_eq!(w.endian(), LittleEndian); - assert_eq!(w.len(), 0); - - w.write(&[1, 2]).unwrap(); - assert_eq!(w.slice(), &[1, 2]); - assert_eq!(w.len(), 2); - - w.write(&[3, 4, 5]).unwrap(); - assert_eq!(w.slice(), &[1, 2, 3, 4, 5]); - assert_eq!(w.len(), 5); - - w.write_at(0, &[6, 7]).unwrap(); - assert_eq!(w.slice(), &[6, 7, 3, 4, 5]); - assert_eq!(w.len(), 5); - - w.write_at(3, &[8, 9]).unwrap(); - assert_eq!(w.slice(), &[6, 7, 3, 8, 9]); - assert_eq!(w.len(), 5); - - assert_eq!(w.write_at(4, &[6, 7]), Err(Error::LengthOutOfBounds)); - assert_eq!(w.write_at(5, &[6, 7]), Err(Error::LengthOutOfBounds)); - assert_eq!(w.write_at(6, &[6, 7]), Err(Error::OffsetOutOfBounds)); - - assert_eq!(w.into_vec(), vec![6, 7, 3, 8, 9]); - } -} diff --git a/vendor/gimli/src/write/line.rs b/vendor/gimli/src/write/line.rs deleted file mode 100644 index c88b735..0000000 --- a/vendor/gimli/src/write/line.rs +++ /dev/null @@ -1,1957 +0,0 @@ -use alloc::vec::Vec; -use indexmap::{IndexMap, IndexSet}; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugLineOffset, Encoding, Format, LineEncoding, SectionId}; -use crate::constants; -use crate::leb128; -use crate::write::{ - Address, DebugLineStrOffsets, DebugStrOffsets, Error, LineStringId, LineStringTable, Result, - Section, StringId, Writer, -}; - -/// The number assigned to the first special opcode. -// -// We output all instructions for all DWARF versions, since readers -// should be able to ignore instructions they don't support. -const OPCODE_BASE: u8 = 13; - -/// A line number program. -#[derive(Debug, Clone)] -pub struct LineProgram { - /// True if this line program was created with `LineProgram::none()`. - none: bool, - encoding: Encoding, - line_encoding: LineEncoding, - - /// A list of source directory path names. - /// - /// If a path is relative, then the directory is located relative to the working - /// directory of the compilation unit. - /// - /// The first entry is for the working directory of the compilation unit. - directories: IndexSet<LineString>, - - /// A list of source file entries. - /// - /// Each entry has a path name and a directory. - /// - /// If a path is a relative, then the file is located relative to the - /// directory. Otherwise the directory is meaningless. - /// - /// Does not include comp_file, even for version >= 5. - files: IndexMap<(LineString, DirectoryId), FileInfo>, - - /// The primary source file of the compilation unit. - /// This is required for version >= 5, but we never reference it elsewhere - /// because DWARF defines DW_AT_decl_file=0 to mean not specified. - comp_file: (LineString, FileInfo), - - /// True if the file entries may have valid timestamps. - /// - /// Entries may still have a timestamp of 0 even if this is set. - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_timestamp`. - pub file_has_timestamp: bool, - - /// True if the file entries may have valid sizes. - /// - /// Entries may still have a size of 0 even if this is set. - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_size`. - pub file_has_size: bool, - - /// True if the file entries have valid MD5 checksums. - /// - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_MD5`. - pub file_has_md5: bool, - - prev_row: LineRow, - row: LineRow, - // TODO: this probably should be either rows or sequences instead - instructions: Vec<LineInstruction>, - in_sequence: bool, -} - -impl LineProgram { - /// Create a new `LineProgram`. - /// - /// `comp_dir` defines the working directory of the compilation unit, - /// and must be the same as the `DW_AT_comp_dir` attribute - /// of the compilation unit DIE. - /// - /// `comp_file` and `comp_file_info` define the primary source file - /// of the compilation unit and must be the same as the `DW_AT_name` - /// attribute of the compilation unit DIE. - /// - /// # Panics - /// - /// Panics if `line_encoding.line_base` > 0. - /// - /// Panics if `line_encoding.line_base` + `line_encoding.line_range` <= 0. - /// - /// Panics if `comp_dir` is empty or contains a null byte. - /// - /// Panics if `comp_file` is empty or contains a null byte. - pub fn new( - encoding: Encoding, - line_encoding: LineEncoding, - comp_dir: LineString, - comp_file: LineString, - comp_file_info: Option<FileInfo>, - ) -> LineProgram { - // We require a special opcode for a line advance of 0. - // See the debug_asserts in generate_row(). - assert!(line_encoding.line_base <= 0); - assert!(line_encoding.line_base + line_encoding.line_range as i8 > 0); - let mut program = LineProgram { - none: false, - encoding, - line_encoding, - directories: IndexSet::new(), - files: IndexMap::new(), - comp_file: (comp_file, comp_file_info.unwrap_or_default()), - prev_row: LineRow::initial_state(line_encoding), - row: LineRow::initial_state(line_encoding), - instructions: Vec::new(), - in_sequence: false, - file_has_timestamp: false, - file_has_size: false, - file_has_md5: false, - }; - // For all DWARF versions, directory index 0 is comp_dir. - // For version <= 4, the entry is implicit. We still add - // it here so that we use it, but we don't emit it. - program.add_directory(comp_dir); - program - } - - /// Create a new `LineProgram` with no fields set. - /// - /// This can be used when the `LineProgram` will not be used. - /// - /// You should not attempt to add files or line instructions to - /// this line program, or write it to the `.debug_line` section. - pub fn none() -> Self { - let line_encoding = LineEncoding::default(); - LineProgram { - none: true, - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 0, - }, - line_encoding, - directories: IndexSet::new(), - files: IndexMap::new(), - comp_file: (LineString::String(Vec::new()), FileInfo::default()), - prev_row: LineRow::initial_state(line_encoding), - row: LineRow::initial_state(line_encoding), - instructions: Vec::new(), - in_sequence: false, - file_has_timestamp: false, - file_has_size: false, - file_has_md5: false, - } - } - - /// Return true if this line program was created with `LineProgram::none()`. - #[inline] - pub fn is_none(&self) -> bool { - self.none - } - - /// Return the encoding parameters for this line program. - #[inline] - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Return the DWARF version for this line program. - #[inline] - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Return the address size in bytes for this line program. - #[inline] - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Return the DWARF format for this line program. - #[inline] - pub fn format(&self) -> Format { - self.encoding.format - } - - /// Return the id for the working directory of the compilation unit. - #[inline] - pub fn default_directory(&self) -> DirectoryId { - DirectoryId(0) - } - - /// Add a directory entry and return its id. - /// - /// If the directory already exists, then return the id of the existing entry. - /// - /// If the path is relative, then the directory is located relative to the working - /// directory of the compilation unit. - /// - /// # Panics - /// - /// Panics if `directory` is empty or contains a null byte. - pub fn add_directory(&mut self, directory: LineString) -> DirectoryId { - if let LineString::String(ref val) = directory { - // For DWARF version <= 4, directories must not be empty. - // The first directory isn't emitted so skip the check for it. - if self.encoding.version <= 4 && !self.directories.is_empty() { - assert!(!val.is_empty()); - } - assert!(!val.contains(&0)); - } - let (index, _) = self.directories.insert_full(directory); - DirectoryId(index) - } - - /// Get a reference to a directory entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_directory(&self, id: DirectoryId) -> &LineString { - self.directories.get_index(id.0).unwrap() - } - - /// Add a file entry and return its id. - /// - /// If the file already exists, then return the id of the existing entry. - /// - /// If the file path is relative, then the file is located relative - /// to the directory. Otherwise the directory is meaningless, but it - /// is still used as a key for file entries. - /// - /// If `info` is `None`, then new entries are assigned - /// default information, and existing entries are unmodified. - /// - /// If `info` is not `None`, then it is always assigned to the - /// entry, even if the entry already exists. - /// - /// # Panics - /// - /// Panics if 'file' is empty or contains a null byte. - pub fn add_file( - &mut self, - file: LineString, - directory: DirectoryId, - info: Option<FileInfo>, - ) -> FileId { - if let LineString::String(ref val) = file { - assert!(!val.is_empty()); - assert!(!val.contains(&0)); - } - - let key = (file, directory); - let index = if let Some(info) = info { - let (index, _) = self.files.insert_full(key, info); - index - } else { - let entry = self.files.entry(key); - let index = entry.index(); - entry.or_default(); - index - }; - FileId::new(index) - } - - /// Get a reference to a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file(&self, id: FileId) -> (&LineString, DirectoryId) { - match id.index() { - None => (&self.comp_file.0, DirectoryId(0)), - Some(index) => self - .files - .get_index(index) - .map(|entry| (&(entry.0).0, (entry.0).1)) - .unwrap(), - } - } - - /// Get a reference to the info for a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file_info(&self, id: FileId) -> &FileInfo { - match id.index() { - None => &self.comp_file.1, - Some(index) => self.files.get_index(index).map(|entry| entry.1).unwrap(), - } - } - - /// Get a mutable reference to the info for a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file_info_mut(&mut self, id: FileId) -> &mut FileInfo { - match id.index() { - None => &mut self.comp_file.1, - Some(index) => self - .files - .get_index_mut(index) - .map(|entry| entry.1) - .unwrap(), - } - } - - /// Begin a new sequence and set its base address. - /// - /// # Panics - /// - /// Panics if a sequence has already begun. - pub fn begin_sequence(&mut self, address: Option<Address>) { - assert!(!self.in_sequence); - self.in_sequence = true; - if let Some(address) = address { - self.instructions.push(LineInstruction::SetAddress(address)); - } - } - - /// End the sequence, and reset the row to its default values. - /// - /// Only the `address_offset` and op_index` fields of the current row are used. - /// - /// # Panics - /// - /// Panics if a sequence has not begun. - pub fn end_sequence(&mut self, address_offset: u64) { - assert!(self.in_sequence); - self.in_sequence = false; - self.row.address_offset = address_offset; - let op_advance = self.op_advance(); - if op_advance != 0 { - self.instructions - .push(LineInstruction::AdvancePc(op_advance)); - } - self.instructions.push(LineInstruction::EndSequence); - self.prev_row = LineRow::initial_state(self.line_encoding); - self.row = LineRow::initial_state(self.line_encoding); - } - - /// Return true if a sequence has begun. - #[inline] - pub fn in_sequence(&self) -> bool { - self.in_sequence - } - - /// Returns a reference to the data for the current row. - #[inline] - pub fn row(&mut self) -> &mut LineRow { - &mut self.row - } - - /// Generates the line number information instructions for the current row. - /// - /// After the instructions are generated, it sets `discriminator` to 0, and sets - /// `basic_block`, `prologue_end`, and `epilogue_begin` to false. - /// - /// # Panics - /// - /// Panics if a sequence has not begun. - /// Panics if the address_offset decreases. - pub fn generate_row(&mut self) { - assert!(self.in_sequence); - - // Output fields that are reset on every row. - if self.row.discriminator != 0 { - self.instructions - .push(LineInstruction::SetDiscriminator(self.row.discriminator)); - self.row.discriminator = 0; - } - if self.row.basic_block { - self.instructions.push(LineInstruction::SetBasicBlock); - self.row.basic_block = false; - } - if self.row.prologue_end { - self.instructions.push(LineInstruction::SetPrologueEnd); - self.row.prologue_end = false; - } - if self.row.epilogue_begin { - self.instructions.push(LineInstruction::SetEpilogueBegin); - self.row.epilogue_begin = false; - } - - // Output fields that are not reset on every row. - if self.row.is_statement != self.prev_row.is_statement { - self.instructions.push(LineInstruction::NegateStatement); - } - if self.row.file != self.prev_row.file { - self.instructions - .push(LineInstruction::SetFile(self.row.file)); - } - if self.row.column != self.prev_row.column { - self.instructions - .push(LineInstruction::SetColumn(self.row.column)); - } - if self.row.isa != self.prev_row.isa { - self.instructions - .push(LineInstruction::SetIsa(self.row.isa)); - } - - // Advance the line, address, and operation index. - let line_base = i64::from(self.line_encoding.line_base) as u64; - let line_range = u64::from(self.line_encoding.line_range); - let line_advance = self.row.line as i64 - self.prev_row.line as i64; - let op_advance = self.op_advance(); - - // Default to special advances of 0. - let special_base = u64::from(OPCODE_BASE); - // TODO: handle lack of special opcodes for 0 line advance - debug_assert!(self.line_encoding.line_base <= 0); - debug_assert!(self.line_encoding.line_base + self.line_encoding.line_range as i8 >= 0); - let special_default = special_base.wrapping_sub(line_base); - let mut special = special_default; - let mut use_special = false; - - if line_advance != 0 { - let special_line = (line_advance as u64).wrapping_sub(line_base); - if special_line < line_range { - special = special_base + special_line; - use_special = true; - } else { - self.instructions - .push(LineInstruction::AdvanceLine(line_advance)); - } - } - - if op_advance != 0 { - // Using ConstAddPc can save a byte. - let (special_op_advance, const_add_pc) = if special + op_advance * line_range <= 255 { - (op_advance, false) - } else { - let op_range = (255 - special_base) / line_range; - (op_advance - op_range, true) - }; - - let special_op = special_op_advance * line_range; - if special + special_op <= 255 { - special += special_op; - use_special = true; - if const_add_pc { - self.instructions.push(LineInstruction::ConstAddPc); - } - } else { - self.instructions - .push(LineInstruction::AdvancePc(op_advance)); - } - } - - if use_special && special != special_default { - debug_assert!(special >= special_base); - debug_assert!(special <= 255); - self.instructions - .push(LineInstruction::Special(special as u8)); - } else { - self.instructions.push(LineInstruction::Copy); - } - - self.prev_row = self.row; - } - - fn op_advance(&self) -> u64 { - debug_assert!(self.row.address_offset >= self.prev_row.address_offset); - let mut address_advance = self.row.address_offset - self.prev_row.address_offset; - if self.line_encoding.minimum_instruction_length != 1 { - debug_assert_eq!( - self.row.address_offset % u64::from(self.line_encoding.minimum_instruction_length), - 0 - ); - address_advance /= u64::from(self.line_encoding.minimum_instruction_length); - } - address_advance * u64::from(self.line_encoding.maximum_operations_per_instruction) - + self.row.op_index - - self.prev_row.op_index - } - - /// Returns true if the line number program has no instructions. - /// - /// Does not check the file or directory entries. - #[inline] - pub fn is_empty(&self) -> bool { - self.instructions.is_empty() - } - - /// Write the line number program to the given section. - /// - /// # Panics - /// - /// Panics if `self.is_none()`. - pub fn write<W: Writer>( - &self, - w: &mut DebugLine<W>, - encoding: Encoding, - debug_line_str_offsets: &DebugLineStrOffsets, - debug_str_offsets: &DebugStrOffsets, - ) -> Result<DebugLineOffset> { - assert!(!self.is_none()); - - if encoding.version < self.version() - || encoding.format != self.format() - || encoding.address_size != self.address_size() - { - return Err(Error::IncompatibleLineProgramEncoding); - } - - let offset = w.offset(); - - let length_offset = w.write_initial_length(self.format())?; - let length_base = w.len(); - - if self.version() < 2 || self.version() > 5 { - return Err(Error::UnsupportedVersion(self.version())); - } - w.write_u16(self.version())?; - - if self.version() >= 5 { - w.write_u8(self.address_size())?; - // Segment selector size. - w.write_u8(0)?; - } - - let header_length_offset = w.len(); - w.write_udata(0, self.format().word_size())?; - let header_length_base = w.len(); - - w.write_u8(self.line_encoding.minimum_instruction_length)?; - if self.version() >= 4 { - w.write_u8(self.line_encoding.maximum_operations_per_instruction)?; - } else if self.line_encoding.maximum_operations_per_instruction != 1 { - return Err(Error::NeedVersion(4)); - }; - w.write_u8(if self.line_encoding.default_is_stmt { - 1 - } else { - 0 - })?; - w.write_u8(self.line_encoding.line_base as u8)?; - w.write_u8(self.line_encoding.line_range)?; - w.write_u8(OPCODE_BASE)?; - w.write(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1])?; - - if self.version() <= 4 { - // The first directory is stored as DW_AT_comp_dir. - for dir in self.directories.iter().skip(1) { - dir.write( - w, - constants::DW_FORM_string, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - } - w.write_u8(0)?; - - for ((file, dir), info) in self.files.iter() { - file.write( - w, - constants::DW_FORM_string, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - w.write_uleb128(dir.0 as u64)?; - w.write_uleb128(info.timestamp)?; - w.write_uleb128(info.size)?; - } - w.write_u8(0)?; - } else { - // Directory entry formats (only ever 1). - w.write_u8(1)?; - w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; - let dir_form = self.directories.get_index(0).unwrap().form(); - w.write_uleb128(dir_form.0.into())?; - - // Directory entries. - w.write_uleb128(self.directories.len() as u64)?; - for dir in self.directories.iter() { - dir.write( - w, - dir_form, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - } - - // File name entry formats. - let count = 2 - + if self.file_has_timestamp { 1 } else { 0 } - + if self.file_has_size { 1 } else { 0 } - + if self.file_has_md5 { 1 } else { 0 }; - w.write_u8(count)?; - w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; - let file_form = self.comp_file.0.form(); - w.write_uleb128(file_form.0.into())?; - w.write_uleb128(u64::from(constants::DW_LNCT_directory_index.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - if self.file_has_timestamp { - w.write_uleb128(u64::from(constants::DW_LNCT_timestamp.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - } - if self.file_has_size { - w.write_uleb128(u64::from(constants::DW_LNCT_size.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - } - if self.file_has_md5 { - w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?; - w.write_uleb128(constants::DW_FORM_data16.0.into())?; - } - - // File name entries. - w.write_uleb128(self.files.len() as u64 + 1)?; - let mut write_file = |file: &LineString, dir: DirectoryId, info: &FileInfo| { - file.write( - w, - file_form, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - w.write_uleb128(dir.0 as u64)?; - if self.file_has_timestamp { - w.write_uleb128(info.timestamp)?; - } - if self.file_has_size { - w.write_uleb128(info.size)?; - } - if self.file_has_md5 { - w.write(&info.md5)?; - } - Ok(()) - }; - write_file(&self.comp_file.0, DirectoryId(0), &self.comp_file.1)?; - for ((file, dir), info) in self.files.iter() { - write_file(file, *dir, info)?; - } - } - - let header_length = (w.len() - header_length_base) as u64; - w.write_udata_at( - header_length_offset, - header_length, - self.format().word_size(), - )?; - - for instruction in &self.instructions { - instruction.write(w, self.address_size())?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, self.format())?; - - Ok(offset) - } -} - -/// A row in the line number table that corresponds to a machine instruction. -#[derive(Debug, Clone, Copy)] -pub struct LineRow { - /// The offset of the instruction from the start address of the sequence. - pub address_offset: u64, - /// The index of an operation within a VLIW instruction. - /// - /// The index of the first operation is 0. - /// Set to 0 for non-VLIW instructions. - pub op_index: u64, - - /// The source file corresponding to the instruction. - pub file: FileId, - /// The line number within the source file. - /// - /// Lines are numbered beginning at 1. Set to 0 if there is no source line. - pub line: u64, - /// The column number within the source line. - /// - /// Columns are numbered beginning at 1. Set to 0 for the "left edge" of the line. - pub column: u64, - /// An additional discriminator used to distinguish between source locations. - /// This value is assigned arbitrarily by the DWARF producer. - pub discriminator: u64, - - /// Set to true if the instruction is a recommended breakpoint for a statement. - pub is_statement: bool, - /// Set to true if the instruction is the beginning of a basic block. - pub basic_block: bool, - /// Set to true if the instruction is a recommended breakpoint at the entry of a - /// function. - pub prologue_end: bool, - /// Set to true if the instruction is a recommended breakpoint prior to the exit of - /// a function. - pub epilogue_begin: bool, - - /// The instruction set architecture of the instruction. - /// - /// Set to 0 for the default ISA. Other values are defined by the architecture ABI. - pub isa: u64, -} - -impl LineRow { - /// Return the initial state as specified in the DWARF standard. - fn initial_state(line_encoding: LineEncoding) -> Self { - LineRow { - address_offset: 0, - op_index: 0, - - file: FileId::initial_state(), - line: 1, - column: 0, - discriminator: 0, - - is_statement: line_encoding.default_is_stmt, - basic_block: false, - prologue_end: false, - epilogue_begin: false, - - isa: 0, - } - } -} - -/// An instruction in a line number program. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum LineInstruction { - // Special opcodes - Special(u8), - - // Standard opcodes - Copy, - AdvancePc(u64), - AdvanceLine(i64), - SetFile(FileId), - SetColumn(u64), - NegateStatement, - SetBasicBlock, - ConstAddPc, - // DW_LNS_fixed_advance_pc is not supported. - SetPrologueEnd, - SetEpilogueBegin, - SetIsa(u64), - - // Extended opcodes - EndSequence, - // TODO: this doubles the size of this enum. - SetAddress(Address), - // DW_LNE_define_file is not supported. - SetDiscriminator(u64), -} - -impl LineInstruction { - /// Write the line number instruction to the given section. - fn write<W: Writer>(self, w: &mut DebugLine<W>, address_size: u8) -> Result<()> { - use self::LineInstruction::*; - match self { - Special(val) => w.write_u8(val)?, - Copy => w.write_u8(constants::DW_LNS_copy.0)?, - AdvancePc(val) => { - w.write_u8(constants::DW_LNS_advance_pc.0)?; - w.write_uleb128(val)?; - } - AdvanceLine(val) => { - w.write_u8(constants::DW_LNS_advance_line.0)?; - w.write_sleb128(val)?; - } - SetFile(val) => { - w.write_u8(constants::DW_LNS_set_file.0)?; - w.write_uleb128(val.raw())?; - } - SetColumn(val) => { - w.write_u8(constants::DW_LNS_set_column.0)?; - w.write_uleb128(val)?; - } - NegateStatement => w.write_u8(constants::DW_LNS_negate_stmt.0)?, - SetBasicBlock => w.write_u8(constants::DW_LNS_set_basic_block.0)?, - ConstAddPc => w.write_u8(constants::DW_LNS_const_add_pc.0)?, - SetPrologueEnd => w.write_u8(constants::DW_LNS_set_prologue_end.0)?, - SetEpilogueBegin => w.write_u8(constants::DW_LNS_set_epilogue_begin.0)?, - SetIsa(val) => { - w.write_u8(constants::DW_LNS_set_isa.0)?; - w.write_uleb128(val)?; - } - EndSequence => { - w.write_u8(0)?; - w.write_uleb128(1)?; - w.write_u8(constants::DW_LNE_end_sequence.0)?; - } - SetAddress(address) => { - w.write_u8(0)?; - w.write_uleb128(1 + u64::from(address_size))?; - w.write_u8(constants::DW_LNE_set_address.0)?; - w.write_address(address, address_size)?; - } - SetDiscriminator(val) => { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); - w.write_u8(0)?; - w.write_uleb128(1 + len as u64)?; - w.write_u8(constants::DW_LNE_set_discriminator.0)?; - w.write(&bytes[..len])?; - } - } - Ok(()) - } -} - -/// A string value for use in defining paths in line number programs. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LineString { - /// A slice of bytes representing a string. Must not include null bytes. - /// Not guaranteed to be UTF-8 or anything like that. - String(Vec<u8>), - - /// A reference to a string in the `.debug_str` section. - StringRef(StringId), - - /// A reference to a string in the `.debug_line_str` section. - LineStringRef(LineStringId), -} - -impl LineString { - /// Create a `LineString` using the normal form for the given encoding. - pub fn new<T>(val: T, encoding: Encoding, line_strings: &mut LineStringTable) -> Self - where - T: Into<Vec<u8>>, - { - let val = val.into(); - if encoding.version <= 4 { - LineString::String(val) - } else { - LineString::LineStringRef(line_strings.add(val)) - } - } - - fn form(&self) -> constants::DwForm { - match *self { - LineString::String(..) => constants::DW_FORM_string, - LineString::StringRef(..) => constants::DW_FORM_strp, - LineString::LineStringRef(..) => constants::DW_FORM_line_strp, - } - } - - fn write<W: Writer>( - &self, - w: &mut DebugLine<W>, - form: constants::DwForm, - encoding: Encoding, - debug_line_str_offsets: &DebugLineStrOffsets, - debug_str_offsets: &DebugStrOffsets, - ) -> Result<()> { - if form != self.form() { - return Err(Error::LineStringFormMismatch); - } - - match *self { - LineString::String(ref val) => { - if encoding.version <= 4 { - debug_assert!(!val.is_empty()); - } - w.write(val)?; - w.write_u8(0)?; - } - LineString::StringRef(val) => { - if encoding.version < 5 { - return Err(Error::NeedVersion(5)); - } - w.write_offset( - debug_str_offsets.get(val).0, - SectionId::DebugStr, - encoding.format.word_size(), - )?; - } - LineString::LineStringRef(val) => { - if encoding.version < 5 { - return Err(Error::NeedVersion(5)); - } - w.write_offset( - debug_line_str_offsets.get(val).0, - SectionId::DebugLineStr, - encoding.format.word_size(), - )?; - } - } - Ok(()) - } -} - -/// An identifier for a directory in a `LineProgram`. -/// -/// Defaults to the working directory of the compilation unit. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DirectoryId(usize); - -// Force FileId access via the methods. -mod id { - /// An identifier for a file in a `LineProgram`. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct FileId(usize); - - impl FileId { - /// Create a FileId given an index into `LineProgram::files`. - pub(crate) fn new(index: usize) -> Self { - FileId(index + 1) - } - - /// The index of the file in `LineProgram::files`. - pub(super) fn index(self) -> Option<usize> { - if self.0 == 0 { - None - } else { - Some(self.0 - 1) - } - } - - /// The initial state of the file register. - pub(super) fn initial_state() -> Self { - FileId(1) - } - - /// The raw value used when writing. - pub(crate) fn raw(self) -> u64 { - self.0 as u64 - } - - /// The id for file index 0 in DWARF version 5. - /// Only used when converting. - // Used for tests only. - #[allow(unused)] - pub(super) fn zero() -> Self { - FileId(0) - } - } -} -pub use self::id::*; - -/// Extra information for file in a `LineProgram`. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -pub struct FileInfo { - /// The implementation defined timestamp of the last modification of the file, - /// or 0 if not available. - pub timestamp: u64, - - /// The size of the file in bytes, or 0 if not available. - pub size: u64, - - /// A 16-byte MD5 digest of the file contents. - /// - /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`. - pub md5: [u8; 16], -} - -define_section!( - DebugLine, - DebugLineOffset, - "A writable `.debug_line` section." -); - -#[cfg(feature = "read")] -mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{self, ConvertError, ConvertResult}; - - impl LineProgram { - /// Create a line number program by reading the data from the given program. - /// - /// Return the program and a mapping from file index to `FileId`. - pub fn from<R: Reader<Offset = usize>>( - mut from_program: read::IncompleteLineProgram<R>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<(LineProgram, Vec<FileId>)> { - // Create mappings in case the source has duplicate files or directories. - let mut dirs = Vec::new(); - let mut files = Vec::new(); - - let mut program = { - let from_header = from_program.header(); - let encoding = from_header.encoding(); - - let comp_dir = match from_header.directory(0) { - Some(comp_dir) => LineString::from(comp_dir, dwarf, line_strings, strings)?, - None => LineString::new(&[][..], encoding, line_strings), - }; - - let (comp_name, comp_file_info) = match from_header.file(0) { - Some(comp_file) => { - if comp_file.directory_index() != 0 { - return Err(ConvertError::InvalidDirectoryIndex); - } - ( - LineString::from(comp_file.path_name(), dwarf, line_strings, strings)?, - Some(FileInfo { - timestamp: comp_file.timestamp(), - size: comp_file.size(), - md5: *comp_file.md5(), - }), - ) - } - None => (LineString::new(&[][..], encoding, line_strings), None), - }; - - if from_header.line_base() > 0 { - return Err(ConvertError::InvalidLineBase); - } - let mut program = LineProgram::new( - encoding, - from_header.line_encoding(), - comp_dir, - comp_name, - comp_file_info, - ); - - let file_skip; - if from_header.version() <= 4 { - // The first directory is implicit. - dirs.push(DirectoryId(0)); - // A file index of 0 is invalid for version <= 4, but putting - // something there makes the indexing easier. - file_skip = 0; - files.push(FileId::zero()); - } else { - // We don't add the first file to `files`, but still allow - // it to be referenced from converted instructions. - file_skip = 1; - files.push(FileId::zero()); - } - - for from_dir in from_header.include_directories() { - let from_dir = - LineString::from(from_dir.clone(), dwarf, line_strings, strings)?; - dirs.push(program.add_directory(from_dir)); - } - - program.file_has_timestamp = from_header.file_has_timestamp(); - program.file_has_size = from_header.file_has_size(); - program.file_has_md5 = from_header.file_has_md5(); - for from_file in from_header.file_names().iter().skip(file_skip) { - let from_name = - LineString::from(from_file.path_name(), dwarf, line_strings, strings)?; - let from_dir = from_file.directory_index(); - if from_dir >= dirs.len() as u64 { - return Err(ConvertError::InvalidDirectoryIndex); - } - let from_dir = dirs[from_dir as usize]; - let from_info = Some(FileInfo { - timestamp: from_file.timestamp(), - size: from_file.size(), - md5: *from_file.md5(), - }); - files.push(program.add_file(from_name, from_dir, from_info)); - } - - program - }; - - // We can't use the `from_program.rows()` because that wouldn't let - // us preserve address relocations. - let mut from_row = read::LineRow::new(from_program.header()); - let mut instructions = from_program.header().instructions(); - let mut address = None; - while let Some(instruction) = instructions.next_instruction(from_program.header())? { - match instruction { - read::LineInstruction::SetAddress(val) => { - if program.in_sequence() { - return Err(ConvertError::UnsupportedLineInstruction); - } - match convert_address(val) { - Some(val) => address = Some(val), - None => return Err(ConvertError::InvalidAddress), - } - from_row.execute(read::LineInstruction::SetAddress(0), &mut from_program); - } - read::LineInstruction::DefineFile(_) => { - return Err(ConvertError::UnsupportedLineInstruction); - } - _ => { - if from_row.execute(instruction, &mut from_program) { - if !program.in_sequence() { - program.begin_sequence(address); - address = None; - } - if from_row.end_sequence() { - program.end_sequence(from_row.address()); - } else { - program.row().address_offset = from_row.address(); - program.row().op_index = from_row.op_index(); - program.row().file = { - let file = from_row.file_index(); - if file >= files.len() as u64 { - return Err(ConvertError::InvalidFileIndex); - } - if file == 0 && program.version() <= 4 { - return Err(ConvertError::InvalidFileIndex); - } - files[file as usize] - }; - program.row().line = match from_row.line() { - Some(line) => line.get(), - None => 0, - }; - program.row().column = match from_row.column() { - read::ColumnType::LeftEdge => 0, - read::ColumnType::Column(val) => val.get(), - }; - program.row().discriminator = from_row.discriminator(); - program.row().is_statement = from_row.is_stmt(); - program.row().basic_block = from_row.basic_block(); - program.row().prologue_end = from_row.prologue_end(); - program.row().epilogue_begin = from_row.epilogue_begin(); - program.row().isa = from_row.isa(); - program.generate_row(); - } - from_row.reset(from_program.header()); - } - } - }; - } - Ok((program, files)) - } - } - - impl LineString { - fn from<R: Reader<Offset = usize>>( - from_attr: read::AttributeValue<R>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - ) -> ConvertResult<LineString> { - Ok(match from_attr { - read::AttributeValue::String(r) => LineString::String(r.to_slice()?.to_vec()), - read::AttributeValue::DebugStrRef(offset) => { - let r = dwarf.debug_str.get_str(offset)?; - let id = strings.add(r.to_slice()?); - LineString::StringRef(id) - } - read::AttributeValue::DebugLineStrRef(offset) => { - let r = dwarf.debug_line_str.get_str(offset)?; - let id = line_strings.add(r.to_slice()?); - LineString::LineStringRef(id) - } - _ => return Err(ConvertError::UnsupportedLineStringForm), - }) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::read; - use crate::write::{DebugLineStr, DebugStr, EndianVec, StringTable}; - use crate::LittleEndian; - - #[test] - fn test_line_program_table() { - let dir1 = LineString::String(b"dir1".to_vec()); - let file1 = LineString::String(b"file1".to_vec()); - let dir2 = LineString::String(b"dir2".to_vec()); - let file2 = LineString::String(b"file2".to_vec()); - - let mut programs = Vec::new(); - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut program = LineProgram::new( - encoding, - LineEncoding::default(), - dir1.clone(), - file1.clone(), - None, - ); - - { - assert_eq!(&dir1, program.get_directory(program.default_directory())); - program.file_has_timestamp = true; - program.file_has_size = true; - if encoding.version >= 5 { - program.file_has_md5 = true; - } - - let dir_id = program.add_directory(dir2.clone()); - assert_eq!(&dir2, program.get_directory(dir_id)); - assert_eq!(dir_id, program.add_directory(dir2.clone())); - - let file_info = FileInfo { - timestamp: 1, - size: 2, - md5: if encoding.version >= 5 { - [3; 16] - } else { - [0; 16] - }, - }; - let file_id = program.add_file(file2.clone(), dir_id, Some(file_info)); - assert_eq!((&file2, dir_id), program.get_file(file_id)); - assert_eq!(file_info, *program.get_file_info(file_id)); - - program.get_file_info_mut(file_id).size = 3; - assert_ne!(file_info, *program.get_file_info(file_id)); - assert_eq!(file_id, program.add_file(file2.clone(), dir_id, None)); - assert_ne!(file_info, *program.get_file_info(file_id)); - assert_eq!( - file_id, - program.add_file(file2.clone(), dir_id, Some(file_info)) - ); - assert_eq!(file_info, *program.get_file_info(file_id)); - - programs.push((program, file_id, encoding)); - } - } - } - } - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let mut debug_line_offsets = Vec::new(); - for (program, _, encoding) in &programs { - debug_line_offsets.push( - program - .write( - &mut debug_line, - *encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(), - ); - } - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - - let convert_address = &|address| Some(Address::Constant(address)); - for ((program, file_id, encoding), offset) in programs.iter().zip(debug_line_offsets.iter()) - { - let read_program = read_debug_line - .program( - *offset, - encoding.address_size, - Some(read::EndianSlice::new(b"dir1", LittleEndian)), - Some(read::EndianSlice::new(b"file1", LittleEndian)), - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (convert_program, convert_files) = LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - assert_eq!(convert_program.version(), program.version()); - assert_eq!(convert_program.address_size(), program.address_size()); - assert_eq!(convert_program.format(), program.format()); - - let convert_file_id = convert_files[file_id.raw() as usize]; - let (file, dir) = program.get_file(*file_id); - let (convert_file, convert_dir) = convert_program.get_file(convert_file_id); - assert_eq!(file, convert_file); - assert_eq!( - program.get_directory(dir), - convert_program.get_directory(convert_dir) - ); - assert_eq!( - program.get_file_info(*file_id), - convert_program.get_file_info(convert_file_id) - ); - } - } - - #[test] - fn test_line_row() { - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - let file2 = &b"file2"[..]; - let convert_address = &|address| Some(Address::Constant(address)); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let line_base = -5; - let line_range = 14; - let neg_line_base = (-line_base) as u8; - let mut program = LineProgram::new( - encoding, - LineEncoding { - line_base, - line_range, - ..Default::default() - }, - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - let dir_id = program.default_directory(); - program.add_file(LineString::String(file1.to_vec()), dir_id, None); - let file_id = - program.add_file(LineString::String(file2.to_vec()), dir_id, None); - - // Test sequences. - { - let mut program = program.clone(); - let address = Address::Constant(0x12); - program.begin_sequence(Some(address)); - assert_eq!( - program.instructions, - vec![LineInstruction::SetAddress(address)] - ); - } - - { - let mut program = program.clone(); - program.begin_sequence(None); - assert_eq!(program.instructions, Vec::new()); - } - - { - let mut program = program.clone(); - program.begin_sequence(None); - program.end_sequence(0x1234); - assert_eq!( - program.instructions, - vec![ - LineInstruction::AdvancePc(0x1234), - LineInstruction::EndSequence - ] - ); - } - - // Create a base program. - program.begin_sequence(None); - program.row.line = 0x1000; - program.generate_row(); - let base_row = program.row; - let base_instructions = program.instructions.clone(); - - // Create test cases. - let mut tests = Vec::new(); - - let row = base_row; - tests.push((row, vec![LineInstruction::Copy])); - - let mut row = base_row; - row.line -= u64::from(neg_line_base); - tests.push((row, vec![LineInstruction::Special(OPCODE_BASE)])); - - let mut row = base_row; - row.line += u64::from(line_range) - 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special(OPCODE_BASE + line_range - 1)], - )); - - let mut row = base_row; - row.line += u64::from(line_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvanceLine(i64::from(line_range - neg_line_base)), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.address_offset = 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special(OPCODE_BASE + line_range)], - )); - - let op_range = (255 - OPCODE_BASE) / line_range; - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special( - OPCODE_BASE + op_range * line_range, - )], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); - row.line -= u64::from(neg_line_base); - tests.push((row, vec![LineInstruction::Special(255)])); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::ConstAddPc, LineInstruction::Copy], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::ConstAddPc, - LineInstruction::Special(OPCODE_BASE + 6), - ], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::ConstAddPc, LineInstruction::Special(255)], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvancePc(row.address_offset), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvancePc(row.address_offset), - LineInstruction::Special(OPCODE_BASE + 6), - ], - )); - - let mut row = base_row; - row.address_offset = 0x1234; - tests.push(( - row, - vec![LineInstruction::AdvancePc(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.line += 0x1234; - tests.push(( - row, - vec![LineInstruction::AdvanceLine(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.file = file_id; - tests.push(( - row, - vec![LineInstruction::SetFile(file_id), LineInstruction::Copy], - )); - - let mut row = base_row; - row.column = 0x1234; - tests.push(( - row, - vec![LineInstruction::SetColumn(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.discriminator = 0x1234; - tests.push(( - row, - vec![ - LineInstruction::SetDiscriminator(0x1234), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.is_statement = !row.is_statement; - tests.push(( - row, - vec![LineInstruction::NegateStatement, LineInstruction::Copy], - )); - - let mut row = base_row; - row.basic_block = true; - tests.push(( - row, - vec![LineInstruction::SetBasicBlock, LineInstruction::Copy], - )); - - let mut row = base_row; - row.prologue_end = true; - tests.push(( - row, - vec![LineInstruction::SetPrologueEnd, LineInstruction::Copy], - )); - - let mut row = base_row; - row.epilogue_begin = true; - tests.push(( - row, - vec![LineInstruction::SetEpilogueBegin, LineInstruction::Copy], - )); - - let mut row = base_row; - row.isa = 0x1234; - tests.push(( - row, - vec![LineInstruction::SetIsa(0x1234), LineInstruction::Copy], - )); - - for test in tests { - // Test generate_row(). - let mut program = program.clone(); - program.row = test.0; - program.generate_row(); - assert_eq!( - &program.instructions[base_instructions.len()..], - &test.1[..] - ); - - // Test LineProgram::from(). - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (convert_program, _convert_files) = LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - assert_eq!( - &convert_program.instructions[base_instructions.len()..], - &test.1[..] - ); - } - } - } - } - } - - #[test] - fn test_line_instruction() { - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - let dir_id = program.default_directory(); - let file_id = - program.add_file(LineString::String(file1.to_vec()), dir_id, None); - - for &(ref inst, ref expect_inst) in &[ - ( - LineInstruction::Special(OPCODE_BASE), - read::LineInstruction::Special(OPCODE_BASE), - ), - ( - LineInstruction::Special(255), - read::LineInstruction::Special(255), - ), - (LineInstruction::Copy, read::LineInstruction::Copy), - ( - LineInstruction::AdvancePc(0x12), - read::LineInstruction::AdvancePc(0x12), - ), - ( - LineInstruction::AdvanceLine(0x12), - read::LineInstruction::AdvanceLine(0x12), - ), - ( - LineInstruction::SetFile(file_id), - read::LineInstruction::SetFile(file_id.raw()), - ), - ( - LineInstruction::SetColumn(0x12), - read::LineInstruction::SetColumn(0x12), - ), - ( - LineInstruction::NegateStatement, - read::LineInstruction::NegateStatement, - ), - ( - LineInstruction::SetBasicBlock, - read::LineInstruction::SetBasicBlock, - ), - ( - LineInstruction::ConstAddPc, - read::LineInstruction::ConstAddPc, - ), - ( - LineInstruction::SetPrologueEnd, - read::LineInstruction::SetPrologueEnd, - ), - ( - LineInstruction::SetEpilogueBegin, - read::LineInstruction::SetEpilogueBegin, - ), - ( - LineInstruction::SetIsa(0x12), - read::LineInstruction::SetIsa(0x12), - ), - ( - LineInstruction::EndSequence, - read::LineInstruction::EndSequence, - ), - ( - LineInstruction::SetAddress(Address::Constant(0x12)), - read::LineInstruction::SetAddress(0x12), - ), - ( - LineInstruction::SetDiscriminator(0x12), - read::LineInstruction::SetDiscriminator(0x12), - ), - ][..] - { - let mut program = program.clone(); - program.instructions.push(*inst); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - let read_header = read_program.header(); - let mut read_insts = read_header.instructions(); - assert_eq!( - *expect_inst, - read_insts.next_instruction(read_header).unwrap().unwrap() - ); - assert_eq!(None, read_insts.next_instruction(read_header).unwrap()); - } - } - } - } - } - - // Test that the address/line advance is correct. We don't test for optimality. - #[test] - fn test_advance() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - - let addresses = 0..50; - let lines = -10..25i64; - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for minimum_instruction_length in vec![1, 4] { - for maximum_operations_per_instruction in vec![1, 3] { - for line_base in vec![-5, 0] { - for line_range in vec![10, 20] { - let line_encoding = LineEncoding { - minimum_instruction_length, - maximum_operations_per_instruction, - line_base, - line_range, - default_is_stmt: true, - }; - let mut program = LineProgram::new( - encoding, - line_encoding, - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - for address_advance in addresses.clone() { - program.begin_sequence(Some(Address::Constant(0x1000))); - program.row().line = 0x10000; - program.generate_row(); - for line_advance in lines.clone() { - { - let row = program.row(); - row.address_offset += - address_advance * u64::from(minimum_instruction_length); - row.line = row.line.wrapping_add(line_advance as u64); - } - program.generate_row(); - } - let address_offset = program.row().address_offset - + u64::from(minimum_instruction_length); - program.end_sequence(address_offset); - } - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - 8, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - - let mut rows = read_program.rows(); - for address_advance in addresses.clone() { - let mut address; - let mut line; - { - let row = rows.next_row().unwrap().unwrap().1; - address = row.address(); - line = row.line().unwrap().get(); - } - assert_eq!(address, 0x1000); - assert_eq!(line, 0x10000); - for line_advance in lines.clone() { - let row = rows.next_row().unwrap().unwrap().1; - assert_eq!( - row.address() - address, - address_advance * u64::from(minimum_instruction_length) - ); - assert_eq!( - (row.line().unwrap().get() as i64) - (line as i64), - line_advance - ); - address = row.address(); - line = row.line().unwrap().get(); - } - let row = rows.next_row().unwrap().unwrap().1; - assert!(row.end_sequence()); - } - } - } - } - } - } - - #[test] - fn test_line_string() { - let version = 5; - - let file = b"file1"; - - let mut strings = StringTable::default(); - let string_id = strings.add("file2"); - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let debug_str_offsets = strings.write(&mut debug_str).unwrap(); - - let mut line_strings = LineStringTable::default(); - let line_string_id = line_strings.add("file3"); - let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); - - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - for (file, expect_file) in vec![ - ( - LineString::String(file.to_vec()), - read::AttributeValue::String(read::EndianSlice::new(file, LittleEndian)), - ), - ( - LineString::StringRef(string_id), - read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), - ), - ( - LineString::LineStringRef(line_string_id), - read::AttributeValue::DebugLineStrRef( - debug_line_str_offsets.get(line_string_id), - ), - ), - ] { - let program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"dir".to_vec()), - file, - None, - ); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program(debug_line_offset, address_size, None, None) - .unwrap(); - let read_header = read_program.header(); - assert_eq!(read_header.file(0).unwrap().path_name(), expect_file); - } - } - } - } - - #[test] - fn test_missing_comp_dir() { - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(Vec::new()), - LineString::String(Vec::new()), - None, - ); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - // Testing missing comp_dir/comp_name. - None, - None, - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_address = &|address| Some(Address::Constant(address)); - LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - } - } - } - } -} diff --git a/vendor/gimli/src/write/loc.rs b/vendor/gimli/src/write/loc.rs deleted file mode 100644 index 6dfe45a..0000000 --- a/vendor/gimli/src/write/loc.rs +++ /dev/null @@ -1,550 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{Encoding, LocationListsOffset, SectionId}; -use crate::write::{ - Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets, - Writer, -}; - -define_section!( - DebugLoc, - LocationListsOffset, - "A writable `.debug_loc` section." -); -define_section!( - DebugLocLists, - LocationListsOffset, - "A writable `.debug_loclists` section." -); - -define_offsets!( - LocationListOffsets: LocationListId => LocationListsOffset, - "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections." -); - -define_id!( - LocationListId, - "An identifier for a location list in a `LocationListTable`." -); - -/// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section. -#[derive(Debug, Default)] -pub struct LocationListTable { - base_id: BaseId, - locations: IndexSet<LocationList>, -} - -impl LocationListTable { - /// Add a location list to the table. - pub fn add(&mut self, loc_list: LocationList) -> LocationListId { - let (index, _) = self.locations.insert_full(loc_list); - LocationListId::new(self.base_id, index) - } - - /// Write the location list table to the appropriate section for the given DWARF version. - pub(crate) fn write<W: Writer>( - &self, - sections: &mut Sections<W>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - if self.locations.is_empty() { - return Ok(LocationListOffsets::none()); - } - - match encoding.version { - 2..=4 => self.write_loc( - &mut sections.debug_loc, - &mut sections.debug_loc_refs, - encoding, - unit_offsets, - ), - 5 => self.write_loclists( - &mut sections.debug_loclists, - &mut sections.debug_loclists_refs, - encoding, - unit_offsets, - ), - _ => Err(Error::UnsupportedVersion(encoding.version)), - } - } - - /// Write the location list table to the `.debug_loc` section. - fn write_loc<W: Writer>( - &self, - w: &mut DebugLoc<W>, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - let address_size = encoding.address_size; - let mut offsets = Vec::new(); - for loc_list in self.locations.iter() { - offsets.push(w.offset()); - for loc in &loc_list.0 { - // Note that we must ensure none of the ranges have both begin == 0 and end == 0. - // We do this by ensuring that begin != end, which is a bit more restrictive - // than required, but still seems reasonable. - match *loc { - Location::BaseAddress { address } => { - let marker = !0 >> (64 - address_size * 8); - w.write_udata(marker, address_size)?; - w.write_address(address, address_size)?; - } - Location::OffsetPair { - begin, - end, - ref data, - } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_udata(begin, address_size)?; - w.write_udata(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartEnd { - begin, - end, - ref data, - } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartLength { - begin, - length, - ref data, - } => { - let end = match begin { - Address::Constant(begin) => Address::Constant(begin + length), - Address::Symbol { symbol, addend } => Address::Symbol { - symbol, - addend: addend + length as i64, - }, - }; - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::DefaultLocation { .. } => { - return Err(Error::InvalidRange); - } - } - } - w.write_udata(0, address_size)?; - w.write_udata(0, address_size)?; - } - Ok(LocationListOffsets { - base_id: self.base_id, - offsets, - }) - } - - /// Write the location list table to the `.debug_loclists` section. - fn write_loclists<W: Writer>( - &self, - w: &mut DebugLocLists<W>, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - let mut offsets = Vec::new(); - - if encoding.version != 5 { - return Err(Error::NeedVersion(5)); - } - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - w.write_u16(encoding.version)?; - w.write_u8(encoding.address_size)?; - w.write_u8(0)?; // segment_selector_size - w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) - // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list - - for loc_list in self.locations.iter() { - offsets.push(w.offset()); - for loc in &loc_list.0 { - match *loc { - Location::BaseAddress { address } => { - w.write_u8(crate::constants::DW_LLE_base_address.0)?; - w.write_address(address, encoding.address_size)?; - } - Location::OffsetPair { - begin, - end, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_offset_pair.0)?; - w.write_uleb128(begin)?; - w.write_uleb128(end)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartEnd { - begin, - end, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_start_end.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_address(end, encoding.address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartLength { - begin, - length, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_start_length.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_uleb128(length)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::DefaultLocation { ref data } => { - w.write_u8(crate::constants::DW_LLE_default_location.0)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - } - } - - w.write_u8(crate::constants::DW_LLE_end_of_list.0)?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(LocationListOffsets { - base_id: self.base_id, - offsets, - }) - } -} - -/// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct LocationList(pub Vec<Location>); - -/// A single location. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum Location { - /// DW_LLE_base_address - BaseAddress { - /// Base address. - address: Address, - }, - /// DW_LLE_offset_pair - OffsetPair { - /// Start of range relative to base address. - begin: u64, - /// End of range relative to base address. - end: u64, - /// Location description. - data: Expression, - }, - /// DW_LLE_start_end - StartEnd { - /// Start of range. - begin: Address, - /// End of range. - end: Address, - /// Location description. - data: Expression, - }, - /// DW_LLE_start_length - StartLength { - /// Start of range. - begin: Address, - /// Length of range. - length: u64, - /// Location description. - data: Expression, - }, - /// DW_LLE_default_location - DefaultLocation { - /// Location description. - data: Expression, - }, -} - -fn write_expression<W: Writer>( - w: &mut W, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - val: &Expression, -) -> Result<()> { - let size = val.size(encoding, unit_offsets) as u64; - if encoding.version <= 4 { - w.write_udata(size, 2)?; - } else { - w.write_uleb128(size)?; - } - val.write(w, Some(refs), encoding, unit_offsets)?; - Ok(()) -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; - - impl LocationList { - /// Create a location list by reading the data from the give location list iter. - pub(crate) fn from<R: Reader<Offset = usize>>( - mut from: read::RawLocListIter<R>, - context: &ConvertUnitContext<R>, - ) -> ConvertResult<Self> { - let mut have_base_address = context.base_address != Address::Constant(0); - let convert_address = - |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); - let convert_expression = |x| { - Expression::from( - x, - context.unit.encoding(), - Some(context.dwarf), - Some(context.unit), - Some(context.entry_ids), - context.convert_address, - ) - }; - let mut loc_list = Vec::new(); - while let Some(from_loc) = from.next()? { - let loc = match from_loc { - read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => { - // These were parsed as addresses, even if they are offsets. - let begin = convert_address(begin)?; - let end = convert_address(end)?; - let data = convert_expression(data)?; - match (begin, end) { - (Address::Constant(begin_offset), Address::Constant(end_offset)) => { - if have_base_address { - Location::OffsetPair { - begin: begin_offset, - end: end_offset, - data, - } - } else { - Location::StartEnd { begin, end, data } - } - } - _ => { - if have_base_address { - // At least one of begin/end is an address, but we also have - // a base address. Adding addresses is undefined. - return Err(ConvertError::InvalidRangeRelativeAddress); - } - Location::StartEnd { begin, end, data } - } - } - } - read::RawLocListEntry::BaseAddress { addr } => { - have_base_address = true; - let address = convert_address(addr)?; - Location::BaseAddress { address } - } - read::RawLocListEntry::BaseAddressx { addr } => { - have_base_address = true; - let address = convert_address(context.dwarf.address(context.unit, addr)?)?; - Location::BaseAddress { address } - } - read::RawLocListEntry::StartxEndx { begin, end, data } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let end = convert_address(context.dwarf.address(context.unit, end)?)?; - let data = convert_expression(data)?; - Location::StartEnd { begin, end, data } - } - read::RawLocListEntry::StartxLength { - begin, - length, - data, - } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let data = convert_expression(data)?; - Location::StartLength { - begin, - length, - data, - } - } - read::RawLocListEntry::OffsetPair { begin, end, data } => { - let data = convert_expression(data)?; - Location::OffsetPair { begin, end, data } - } - read::RawLocListEntry::StartEnd { begin, end, data } => { - let begin = convert_address(begin)?; - let end = convert_address(end)?; - let data = convert_expression(data)?; - Location::StartEnd { begin, end, data } - } - read::RawLocListEntry::StartLength { - begin, - length, - data, - } => { - let begin = convert_address(begin)?; - let data = convert_expression(data)?; - Location::StartLength { - begin, - length, - data, - } - } - read::RawLocListEntry::DefaultLocation { data } => { - let data = convert_expression(data)?; - Location::DefaultLocation { data } - } - }; - // In some cases, existing data may contain begin == end, filtering - // these out. - match loc { - Location::StartLength { length, .. } if length == 0 => continue, - Location::StartEnd { begin, end, .. } if begin == end => continue, - Location::OffsetPair { begin, end, .. } if begin == end => continue, - _ => (), - } - loc_list.push(loc); - } - Ok(LocationList(loc_list)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, - }; - use crate::read; - use crate::write::{ - ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_loc_list() { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - let mut expression = Expression::new(); - expression.op_constu(0); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut loc_list = LocationList(vec![ - Location::StartLength { - begin: Address::Constant(6666), - length: 7777, - data: expression.clone(), - }, - Location::StartEnd { - begin: Address::Constant(4444), - end: Address::Constant(5555), - data: expression.clone(), - }, - Location::BaseAddress { - address: Address::Constant(1111), - }, - Location::OffsetPair { - begin: 2222, - end: 3333, - data: expression.clone(), - }, - ]); - if version >= 5 { - loc_list.0.push(Location::DefaultLocation { - data: expression.clone(), - }); - } - - let mut locations = LocationListTable::default(); - let loc_list_id = locations.add(loc_list.clone()); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap(); - assert!(sections.debug_loc_refs.is_empty()); - assert!(sections.debug_loclists_refs.is_empty()); - - let read_debug_loc = - read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); - let read_debug_loclists = - read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); - let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists); - let offset = loc_list_offsets.get(loc_list_id); - let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap(); - - let dwarf = read::Dwarf { - locations: read_loc, - ..Default::default() - }; - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::default(), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - let context = ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut RangeListTable::default(), - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap(); - - if version <= 4 { - loc_list.0[0] = Location::StartEnd { - begin: Address::Constant(6666), - end: Address::Constant(6666 + 7777), - data: expression.clone(), - }; - } - assert_eq!(loc_list, convert_loc_list); - } - } - } - } -} diff --git a/vendor/gimli/src/write/mod.rs b/vendor/gimli/src/write/mod.rs deleted file mode 100644 index 47ba631..0000000 --- a/vendor/gimli/src/write/mod.rs +++ /dev/null @@ -1,425 +0,0 @@ -//! Write DWARF debugging information. -//! -//! ## API Structure -//! -//! This module works by building up a representation of the debugging information -//! in memory, and then writing it all at once. It supports two major use cases: -//! -//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF -//! for a single compilation unit. -//! -//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple -//! compilation units. -//! -//! The module also supports reading in DWARF debugging information and writing it out -//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) -//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert -//! it to a writable instance. -//! -//! ## Example Usage -//! -//! Write a compilation unit containing only the top level DIE. -//! -//! ```rust -//! use gimli::write::{ -//! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, -//! }; -//! -//! fn example() -> Result<(), Error> { -//! // Choose the encoding parameters. -//! let encoding = gimli::Encoding { -//! format: gimli::Format::Dwarf32, -//! version: 5, -//! address_size: 8, -//! }; -//! // Create a container for a single compilation unit. -//! let mut dwarf = DwarfUnit::new(encoding); -//! // Set a range attribute on the root DIE. -//! let range_list = RangeList(vec![Range::StartLength { -//! begin: Address::Constant(0x100), -//! length: 42, -//! }]); -//! let range_list_id = dwarf.unit.ranges.add(range_list); -//! let root = dwarf.unit.root(); -//! dwarf.unit.get_mut(root).set( -//! gimli::DW_AT_ranges, -//! AttributeValue::RangeListRef(range_list_id), -//! ); -//! // Create a `Vec` for each DWARF section. -//! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); -//! // Finally, write the DWARF data to the sections. -//! dwarf.write(&mut sections)?; -//! sections.for_each(|id, data| { -//! // Here you can add the data to the output object file. -//! Ok(()) -//! }) -//! } -//! # fn main() { -//! # example().unwrap(); -//! # } - -use std::error; -use std::fmt; -use std::result; - -use crate::constants; - -mod endian_vec; -pub use self::endian_vec::*; - -mod writer; -pub use self::writer::*; - -#[macro_use] -mod section; -pub use self::section::*; - -macro_rules! define_id { - ($name:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct $name { - base_id: BaseId, - index: usize, - } - - impl $name { - #[inline] - fn new(base_id: BaseId, index: usize) -> Self { - $name { base_id, index } - } - } - }; -} - -macro_rules! define_offsets { - ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { - #[doc=$off_doc] - #[derive(Debug)] - pub struct $offsets { - base_id: BaseId, - // We know ids start at 0. - offsets: Vec<$offset>, - } - - impl $offsets { - /// Return an empty list of offsets. - #[inline] - pub fn none() -> Self { - $offsets { - base_id: BaseId::default(), - offsets: Vec::new(), - } - } - - /// Get the offset - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: $id) -> $offset { - debug_assert_eq!(self.base_id, id.base_id); - self.offsets[id.index] - } - - /// Return the number of offsets. - #[inline] - pub fn count(&self) -> usize { - self.offsets.len() - } - } - }; -} - -mod abbrev; -pub use self::abbrev::*; - -mod cfi; -pub use self::cfi::*; - -mod dwarf; -pub use self::dwarf::*; - -mod line; -pub use self::line::*; - -mod loc; -pub use self::loc::*; - -mod op; -pub use self::op::*; - -mod range; -pub use self::range::*; - -mod str; -pub use self::str::*; - -mod unit; -pub use self::unit::*; - -/// An error that occurred when writing. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { - /// The given offset is out of bounds. - OffsetOutOfBounds, - /// The given length is out of bounds. - LengthOutOfBounds, - /// The attribute value is an invalid for writing. - InvalidAttributeValue, - /// The value is too large for the encoding form. - ValueTooLarge, - /// Unsupported word size. - UnsupportedWordSize(u8), - /// Unsupported DWARF version. - UnsupportedVersion(u16), - /// The unit length is too large for the requested DWARF format. - InitialLengthOverflow, - /// The address is invalid. - InvalidAddress, - /// The reference is invalid. - InvalidReference, - /// A requested feature requires a different DWARF version. - NeedVersion(u16), - /// Strings in line number program have mismatched forms. - LineStringFormMismatch, - /// The range is empty or otherwise invalid. - InvalidRange, - /// The line number program encoding is incompatible with the unit encoding. - IncompatibleLineProgramEncoding, - /// Could not encode code offset for a frame instruction. - InvalidFrameCodeOffset(u32), - /// Could not encode data offset for a frame instruction. - InvalidFrameDataOffset(i32), - /// Unsupported eh_frame pointer encoding. - UnsupportedPointerEncoding(constants::DwEhPe), - /// Unsupported reference in CFI expression. - UnsupportedCfiExpressionReference, - /// Unsupported forward reference in expression. - UnsupportedExpressionForwardReference, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - match *self { - Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), - Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), - Error::InvalidAttributeValue => { - write!(f, "The attribute value is an invalid for writing.") - } - Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), - Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), - Error::UnsupportedVersion(version) => { - write!(f, "Unsupported DWARF version: {}", version) - } - Error::InitialLengthOverflow => write!( - f, - "The unit length is too large for the requested DWARF format." - ), - Error::InvalidAddress => write!(f, "The address is invalid."), - Error::InvalidReference => write!(f, "The reference is invalid."), - Error::NeedVersion(version) => write!( - f, - "A requested feature requires a DWARF version {}.", - version - ), - Error::LineStringFormMismatch => { - write!(f, "Strings in line number program have mismatched forms.") - } - Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), - Error::IncompatibleLineProgramEncoding => write!( - f, - "The line number program encoding is incompatible with the unit encoding." - ), - Error::InvalidFrameCodeOffset(offset) => write!( - f, - "Could not encode code offset ({}) for a frame instruction.", - offset, - ), - Error::InvalidFrameDataOffset(offset) => write!( - f, - "Could not encode data offset ({}) for a frame instruction.", - offset, - ), - Error::UnsupportedPointerEncoding(eh_pe) => { - write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) - } - Error::UnsupportedCfiExpressionReference => { - write!(f, "Unsupported reference in CFI expression.") - } - Error::UnsupportedExpressionForwardReference => { - write!(f, "Unsupported forward reference in expression.") - } - } - } -} - -impl error::Error for Error {} - -/// The result of a write. -pub type Result<T> = result::Result<T, Error>; - -/// An address. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Address { - /// A fixed address that does not require relocation. - Constant(u64), - /// An address that is relative to a symbol which may be relocated. - Symbol { - /// The symbol that the address is relative to. - /// - /// The meaning of this value is decided by the writer, but - /// will typically be an index into a symbol table. - symbol: usize, - /// The offset of the address relative to the symbol. - /// - /// This will typically be used as the addend in a relocation. - addend: i64, - }, -} - -/// A reference to a `.debug_info` entry. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Reference { - /// An external symbol. - /// - /// The meaning of this value is decided by the writer, but - /// will typically be an index into a symbol table. - Symbol(usize), - /// An entry in the same section. - /// - /// This only supports references in units that are emitted together. - Entry(UnitId, UnitEntryId), -} - -// This type is only used in debug assertions. -#[cfg(not(debug_assertions))] -type BaseId = (); - -#[cfg(debug_assertions)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -struct BaseId(usize); - -#[cfg(debug_assertions)] -impl Default for BaseId { - fn default() -> Self { - use std::sync::atomic; - static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) - } -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - use crate::read; - - pub(crate) use super::unit::convert::*; - - /// An error that occurred when converting a read value into a write value. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum ConvertError { - /// An error occurred when reading. - Read(read::Error), - /// Writing of this attribute value is not implemented yet. - UnsupportedAttributeValue, - /// This attribute value is an invalid name/form combination. - InvalidAttributeValue, - /// A `.debug_info` reference does not refer to a valid entry. - InvalidDebugInfoOffset, - /// An address could not be converted. - InvalidAddress, - /// Writing this line number instruction is not implemented yet. - UnsupportedLineInstruction, - /// Writing this form of line string is not implemented yet. - UnsupportedLineStringForm, - /// A `.debug_line` file index is invalid. - InvalidFileIndex, - /// A `.debug_line` directory index is invalid. - InvalidDirectoryIndex, - /// A `.debug_line` line base is invalid. - InvalidLineBase, - /// A `.debug_line` reference is invalid. - InvalidLineRef, - /// A `.debug_info` unit entry reference is invalid. - InvalidUnitRef, - /// A `.debug_info` reference is invalid. - InvalidDebugInfoRef, - /// Invalid relative address in a range list. - InvalidRangeRelativeAddress, - /// Writing this CFI instruction is not implemented yet. - UnsupportedCfiInstruction, - /// Writing indirect pointers is not implemented yet. - UnsupportedIndirectAddress, - /// Writing this expression operation is not implemented yet. - UnsupportedOperation, - /// Operation branch target is invalid. - InvalidBranchTarget, - /// Writing this unit type is not supported yet. - UnsupportedUnitType, - } - - impl fmt::Display for ConvertError { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - use self::ConvertError::*; - match *self { - Read(ref e) => e.fmt(f), - UnsupportedAttributeValue => { - write!(f, "Writing of this attribute value is not implemented yet.") - } - InvalidAttributeValue => write!( - f, - "This attribute value is an invalid name/form combination." - ), - InvalidDebugInfoOffset => write!( - f, - "A `.debug_info` reference does not refer to a valid entry." - ), - InvalidAddress => write!(f, "An address could not be converted."), - UnsupportedLineInstruction => write!( - f, - "Writing this line number instruction is not implemented yet." - ), - UnsupportedLineStringForm => write!( - f, - "Writing this form of line string is not implemented yet." - ), - InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), - InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), - InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), - InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), - InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."), - InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."), - InvalidRangeRelativeAddress => { - write!(f, "Invalid relative address in a range list.") - } - UnsupportedCfiInstruction => { - write!(f, "Writing this CFI instruction is not implemented yet.") - } - UnsupportedIndirectAddress => { - write!(f, "Writing indirect pointers is not implemented yet.") - } - UnsupportedOperation => write!( - f, - "Writing this expression operation is not implemented yet." - ), - InvalidBranchTarget => write!(f, "Operation branch target is invalid."), - UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), - } - } - } - - impl error::Error for ConvertError {} - - impl From<read::Error> for ConvertError { - fn from(e: read::Error) -> Self { - ConvertError::Read(e) - } - } - - /// The result of a conversion. - pub type ConvertResult<T> = result::Result<T, ConvertError>; -} -#[cfg(feature = "read")] -pub use self::convert::*; diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs deleted file mode 100644 index 287083b..0000000 --- a/vendor/gimli/src/write/op.rs +++ /dev/null @@ -1,1618 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use crate::common::{Encoding, Register}; -use crate::constants::{self, DwOp}; -use crate::leb128::write::{sleb128_size, uleb128_size}; -use crate::write::{ - Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer, -}; - -/// The bytecode for a DWARF expression or location description. -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] -pub struct Expression { - operations: Vec<Operation>, -} - -impl Expression { - /// Create an empty expression. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Create an expression from raw bytecode. - /// - /// This does not support operations that require references, such as `DW_OP_addr`. - #[inline] - pub fn raw(bytecode: Vec<u8>) -> Self { - Expression { - operations: vec![Operation::Raw(bytecode)], - } - } - - /// Add an operation to the expression. - /// - /// This should only be used for operations that have no explicit operands. - pub fn op(&mut self, opcode: DwOp) { - self.operations.push(Operation::Simple(opcode)); - } - - /// Add a `DW_OP_addr` operation to the expression. - pub fn op_addr(&mut self, address: Address) { - self.operations.push(Operation::Address(address)); - } - - /// Add a `DW_OP_constu` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_constu(&mut self, value: u64) { - self.operations.push(Operation::UnsignedConstant(value)); - } - - /// Add a `DW_OP_consts` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_consts(&mut self, value: i64) { - self.operations.push(Operation::SignedConstant(value)); - } - - /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression. - pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) { - self.operations.push(Operation::ConstantType(base, value)); - } - - /// Add a `DW_OP_fbreg` operation to the expression. - pub fn op_fbreg(&mut self, offset: i64) { - self.operations.push(Operation::FrameOffset(offset)); - } - - /// Add a `DW_OP_bregx` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_breg(&mut self, register: Register, offset: i64) { - self.operations - .push(Operation::RegisterOffset(register, offset)); - } - - /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) { - self.operations - .push(Operation::RegisterType(register, base)); - } - - /// Add a `DW_OP_pick` operation to the expression. - /// - /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation. - pub fn op_pick(&mut self, index: u8) { - self.operations.push(Operation::Pick(index)); - } - - /// Add a `DW_OP_deref` operation to the expression. - pub fn op_deref(&mut self) { - self.operations.push(Operation::Deref { space: false }); - } - - /// Add a `DW_OP_xderef` operation to the expression. - pub fn op_xderef(&mut self) { - self.operations.push(Operation::Deref { space: true }); - } - - /// Add a `DW_OP_deref_size` operation to the expression. - pub fn op_deref_size(&mut self, size: u8) { - self.operations - .push(Operation::DerefSize { size, space: false }); - } - - /// Add a `DW_OP_xderef_size` operation to the expression. - pub fn op_xderef_size(&mut self, size: u8) { - self.operations - .push(Operation::DerefSize { size, space: true }); - } - - /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression. - pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) { - self.operations.push(Operation::DerefType { - size, - base, - space: false, - }); - } - - /// Add a `DW_OP_xderef_type` operation to the expression. - pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) { - self.operations.push(Operation::DerefType { - size, - base, - space: true, - }); - } - - /// Add a `DW_OP_plus_uconst` operation to the expression. - pub fn op_plus_uconst(&mut self, value: u64) { - self.operations.push(Operation::PlusConstant(value)); - } - - /// Add a `DW_OP_skip` operation to the expression. - /// - /// Returns the index of the operation. The caller must call `set_target` with - /// this index to set the target of the branch. - pub fn op_skip(&mut self) -> usize { - let index = self.next_index(); - self.operations.push(Operation::Skip(!0)); - index - } - - /// Add a `DW_OP_bra` operation to the expression. - /// - /// Returns the index of the operation. The caller must call `set_target` with - /// this index to set the target of the branch. - pub fn op_bra(&mut self) -> usize { - let index = self.next_index(); - self.operations.push(Operation::Branch(!0)); - index - } - - /// Return the index that will be assigned to the next operation. - /// - /// This can be passed to `set_target`. - #[inline] - pub fn next_index(&self) -> usize { - self.operations.len() - } - - /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation . - pub fn set_target(&mut self, operation: usize, new_target: usize) { - debug_assert!(new_target <= self.next_index()); - debug_assert_ne!(operation, new_target); - match self.operations[operation] { - Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => { - *target = new_target; - } - _ => unimplemented!(), - } - } - - /// Add a `DW_OP_call4` operation to the expression. - pub fn op_call(&mut self, entry: UnitEntryId) { - self.operations.push(Operation::Call(entry)); - } - - /// Add a `DW_OP_call_ref` operation to the expression. - pub fn op_call_ref(&mut self, entry: Reference) { - self.operations.push(Operation::CallRef(entry)); - } - - /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression. - /// - /// `base` is the DIE of the base type, or `None` for the generic type. - pub fn op_convert(&mut self, base: Option<UnitEntryId>) { - self.operations.push(Operation::Convert(base)); - } - - /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression. - /// - /// `base` is the DIE of the base type, or `None` for the generic type. - pub fn op_reinterpret(&mut self, base: Option<UnitEntryId>) { - self.operations.push(Operation::Reinterpret(base)); - } - - /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression. - pub fn op_entry_value(&mut self, expression: Expression) { - self.operations.push(Operation::EntryValue(expression)); - } - - /// Add a `DW_OP_regx` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_reg(&mut self, register: Register) { - self.operations.push(Operation::Register(register)); - } - - /// Add a `DW_OP_implicit_value` operation to the expression. - pub fn op_implicit_value(&mut self, data: Box<[u8]>) { - self.operations.push(Operation::ImplicitValue(data)); - } - - /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression. - pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) { - self.operations - .push(Operation::ImplicitPointer { entry, byte_offset }); - } - - /// Add a `DW_OP_piece` operation to the expression. - pub fn op_piece(&mut self, size_in_bytes: u64) { - self.operations.push(Operation::Piece { size_in_bytes }); - } - - /// Add a `DW_OP_bit_piece` operation to the expression. - pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) { - self.operations.push(Operation::BitPiece { - size_in_bits, - bit_offset, - }); - } - - /// Add a `DW_OP_GNU_parameter_ref` operation to the expression. - pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) { - self.operations.push(Operation::ParameterRef(entry)); - } - - /// Add a `DW_OP_WASM_location 0x0` operation to the expression. - pub fn op_wasm_local(&mut self, index: u32) { - self.operations.push(Operation::WasmLocal(index)); - } - - /// Add a `DW_OP_WASM_location 0x1` operation to the expression. - pub fn op_wasm_global(&mut self, index: u32) { - self.operations.push(Operation::WasmGlobal(index)); - } - - /// Add a `DW_OP_WASM_location 0x2` operation to the expression. - pub fn op_wasm_stack(&mut self, index: u32) { - self.operations.push(Operation::WasmStack(index)); - } - - pub(crate) fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { - let mut size = 0; - for operation in &self.operations { - size += operation.size(encoding, unit_offsets); - } - size - } - - pub(crate) fn write<W: Writer>( - &self, - w: &mut W, - mut refs: Option<&mut Vec<DebugInfoReference>>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<()> { - // TODO: only calculate offsets if needed? - let mut offsets = Vec::with_capacity(self.operations.len()); - let mut offset = w.len(); - for operation in &self.operations { - offsets.push(offset); - offset += operation.size(encoding, unit_offsets); - } - offsets.push(offset); - for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) { - debug_assert_eq!(w.len(), offset); - operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?; - } - Ok(()) - } -} - -/// A single DWARF operation. -// -// This type is intentionally not public so that we can change the -// representation of expressions as needed. -// -// Variants are listed in the order they appear in Section 2.5. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum Operation { - /// Raw bytecode. - /// - /// Does not support references. - Raw(Vec<u8>), - /// An operation that has no explicit operands. - /// - /// Represents: - /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot` - /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa` - /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`, - /// `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`, - /// `DW_OP_shra`, `DW_OP_xor` - /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne` - /// - `DW_OP_nop` - /// - `DW_OP_stack_value` - Simple(DwOp), - /// Relocate the address if needed, and push it on the stack. - /// - /// Represents `DW_OP_addr`. - Address(Address), - /// Push an unsigned constant value on the stack. - /// - /// Represents `DW_OP_constu`. - UnsignedConstant(u64), - /// Push a signed constant value on the stack. - /// - /// Represents `DW_OP_consts`. - SignedConstant(i64), - /* TODO: requires .debug_addr write support - /// Read the address at the given index in `.debug_addr, relocate the address if needed, - /// and push it on the stack. - /// - /// Represents `DW_OP_addrx`. - AddressIndex(DebugAddrIndex<Offset>), - /// Read the address at the given index in `.debug_addr, and push it on the stack. - /// Do not relocate the address. - /// - /// Represents `DW_OP_constx`. - ConstantIndex(DebugAddrIndex<Offset>), - */ - /// Interpret the value bytes as a constant of a given type, and push it on the stack. - /// - /// Represents `DW_OP_const_type`. - ConstantType(UnitEntryId, Box<[u8]>), - /// Compute the frame base (using `DW_AT_frame_base`), add the - /// given offset, and then push the resulting sum on the stack. - /// - /// Represents `DW_OP_fbreg`. - FrameOffset(i64), - /// Find the contents of the given register, add the offset, and then - /// push the resulting sum on the stack. - /// - /// Represents `DW_OP_bregx`. - RegisterOffset(Register, i64), - /// Interpret the contents of the given register as a value of the given type, - /// and push it on the stack. - /// - /// Represents `DW_OP_regval_type`. - RegisterType(Register, UnitEntryId), - /// Copy the item at a stack index and push it on top of the stack. - /// - /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`. - Pick(u8), - /// Pop the topmost value of the stack, dereference it, and push the - /// resulting value. - /// - /// Represents `DW_OP_deref` and `DW_OP_xderef`. - Deref { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - }, - /// Pop the topmost value of the stack, dereference it to obtain a value - /// of the given size, and push the resulting value. - /// - /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`. - DerefSize { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - /// The size of the data to dereference. - size: u8, - }, - /// Pop the topmost value of the stack, dereference it to obtain a value - /// of the given type, and push the resulting value. - /// - /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`. - DerefType { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - /// The size of the data to dereference. - size: u8, - /// The DIE of the base type, or `None` for the generic type. - base: UnitEntryId, - }, - /// Add an unsigned constant to the topmost value on the stack. - /// - /// Represents `DW_OP_plus_uconst`. - PlusConstant(u64), - /// Unconditional branch to the target location. - /// - /// The value is the index within the expression of the operation to branch to. - /// This will be converted to a relative offset when writing. - /// - /// Represents `DW_OP_skip`. - Skip(usize), - /// Branch to the target location if the top of stack is nonzero. - /// - /// The value is the index within the expression of the operation to branch to. - /// This will be converted to a relative offset when writing. - /// - /// Represents `DW_OP_bra`. - Branch(usize), - /// Evaluate a DWARF expression as a subroutine. - /// - /// The expression comes from the `DW_AT_location` attribute of the indicated DIE. - /// - /// Represents `DW_OP_call4`. - Call(UnitEntryId), - /// Evaluate an external DWARF expression as a subroutine. - /// - /// The expression comes from the `DW_AT_location` attribute of the indicated DIE, - /// which may be in another compilation unit or shared object. - /// - /// Represents `DW_OP_call_ref`. - CallRef(Reference), - /// Pop the top stack entry, convert it to a different type, and push it on the stack. - /// - /// Represents `DW_OP_convert`. - Convert(Option<UnitEntryId>), - /// Pop the top stack entry, reinterpret the bits in its value as a different type, - /// and push it on the stack. - /// - /// Represents `DW_OP_reinterpret`. - Reinterpret(Option<UnitEntryId>), - /// Evaluate an expression at the entry to the current subprogram, and push it on the stack. - /// - /// Represents `DW_OP_entry_value`. - EntryValue(Expression), - // FIXME: EntryRegister - /// Indicate that this piece's location is in the given register. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_regx`. - Register(Register), - /// The object has no location, but has a known constant value. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_implicit_value`. - ImplicitValue(Box<[u8]>), - /// The object is a pointer to a value which has no actual location, such as - /// an implicit value or a stack value. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_implicit_pointer`. - ImplicitPointer { - /// The DIE of the value that this is an implicit pointer into. - entry: Reference, - /// The byte offset into the value that the implicit pointer points to. - byte_offset: i64, - }, - /// Terminate a piece. - /// - /// Represents `DW_OP_piece`. - Piece { - /// The size of this piece in bytes. - size_in_bytes: u64, - }, - /// Terminate a piece with a size in bits. - /// - /// Represents `DW_OP_bit_piece`. - BitPiece { - /// The size of this piece in bits. - size_in_bits: u64, - /// The bit offset of this piece. - bit_offset: u64, - }, - /// This represents a parameter that was optimized out. - /// - /// The entry is the definition of the parameter, and is matched to - /// the `DW_TAG_GNU_call_site_parameter` in the caller that also - /// points to the same definition of the parameter. - /// - /// Represents `DW_OP_GNU_parameter_ref`. - ParameterRef(UnitEntryId), - /// The index of a local in the currently executing function. - /// - /// Represents `DW_OP_WASM_location 0x00`. - WasmLocal(u32), - /// The index of a global. - /// - /// Represents `DW_OP_WASM_location 0x01`. - WasmGlobal(u32), - /// The index of an item on the operand stack. - /// - /// Represents `DW_OP_WASM_location 0x02`. - WasmStack(u32), -} - -impl Operation { - fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { - let base_size = |base| { - // Errors are handled during writes. - match unit_offsets { - Some(offsets) => uleb128_size(offsets.unit_offset(base)), - None => 0, - } - }; - 1 + match *self { - Operation::Raw(ref bytecode) => return bytecode.len(), - Operation::Simple(_) => 0, - Operation::Address(_) => encoding.address_size as usize, - Operation::UnsignedConstant(value) => { - if value < 32 { - 0 - } else { - uleb128_size(value) - } - } - Operation::SignedConstant(value) => sleb128_size(value), - Operation::ConstantType(base, ref value) => base_size(base) + 1 + value.len(), - Operation::FrameOffset(offset) => sleb128_size(offset), - Operation::RegisterOffset(register, offset) => { - if register.0 < 32 { - sleb128_size(offset) - } else { - uleb128_size(register.0.into()) + sleb128_size(offset) - } - } - Operation::RegisterType(register, base) => { - uleb128_size(register.0.into()) + base_size(base) - } - Operation::Pick(index) => { - if index > 1 { - 1 - } else { - 0 - } - } - Operation::Deref { .. } => 0, - Operation::DerefSize { .. } => 1, - Operation::DerefType { base, .. } => 1 + base_size(base), - Operation::PlusConstant(value) => uleb128_size(value), - Operation::Skip(_) => 2, - Operation::Branch(_) => 2, - Operation::Call(_) => 4, - Operation::CallRef(_) => encoding.format.word_size() as usize, - Operation::Convert(base) => match base { - Some(base) => base_size(base), - None => 1, - }, - Operation::Reinterpret(base) => match base { - Some(base) => base_size(base), - None => 1, - }, - Operation::EntryValue(ref expression) => { - let length = expression.size(encoding, unit_offsets); - uleb128_size(length as u64) + length - } - Operation::Register(register) => { - if register.0 < 32 { - 0 - } else { - uleb128_size(register.0.into()) - } - } - Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(), - Operation::ImplicitPointer { byte_offset, .. } => { - encoding.format.word_size() as usize + sleb128_size(byte_offset) - } - Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes), - Operation::BitPiece { - size_in_bits, - bit_offset, - } => uleb128_size(size_in_bits) + uleb128_size(bit_offset), - Operation::ParameterRef(_) => 4, - Operation::WasmLocal(index) - | Operation::WasmGlobal(index) - | Operation::WasmStack(index) => 1 + uleb128_size(index.into()), - } - } - - pub(crate) fn write<W: Writer>( - &self, - w: &mut W, - refs: Option<&mut Vec<DebugInfoReference>>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - offsets: &[usize], - ) -> Result<()> { - let entry_offset = |entry| match unit_offsets { - Some(offsets) => { - let offset = offsets.unit_offset(entry); - if offset == 0 { - Err(Error::UnsupportedExpressionForwardReference) - } else { - Ok(offset) - } - } - None => Err(Error::UnsupportedCfiExpressionReference), - }; - match *self { - Operation::Raw(ref bytecode) => w.write(bytecode)?, - Operation::Simple(opcode) => w.write_u8(opcode.0)?, - Operation::Address(address) => { - w.write_u8(constants::DW_OP_addr.0)?; - w.write_address(address, encoding.address_size)?; - } - Operation::UnsignedConstant(value) => { - if value < 32 { - w.write_u8(constants::DW_OP_lit0.0 + value as u8)?; - } else { - w.write_u8(constants::DW_OP_constu.0)?; - w.write_uleb128(value)?; - } - } - Operation::SignedConstant(value) => { - w.write_u8(constants::DW_OP_consts.0)?; - w.write_sleb128(value)?; - } - Operation::ConstantType(base, ref value) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_const_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_const_type.0)?; - } - w.write_uleb128(entry_offset(base)?)?; - w.write_udata(value.len() as u64, 1)?; - w.write(value)?; - } - Operation::FrameOffset(offset) => { - w.write_u8(constants::DW_OP_fbreg.0)?; - w.write_sleb128(offset)?; - } - Operation::RegisterOffset(register, offset) => { - if register.0 < 32 { - w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?; - } else { - w.write_u8(constants::DW_OP_bregx.0)?; - w.write_uleb128(register.0.into())?; - } - w.write_sleb128(offset)?; - } - Operation::RegisterType(register, base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_regval_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_regval_type.0)?; - } - w.write_uleb128(register.0.into())?; - w.write_uleb128(entry_offset(base)?)?; - } - Operation::Pick(index) => match index { - 0 => w.write_u8(constants::DW_OP_dup.0)?, - 1 => w.write_u8(constants::DW_OP_over.0)?, - _ => { - w.write_u8(constants::DW_OP_pick.0)?; - w.write_u8(index)?; - } - }, - Operation::Deref { space } => { - if space { - w.write_u8(constants::DW_OP_xderef.0)?; - } else { - w.write_u8(constants::DW_OP_deref.0)?; - } - } - Operation::DerefSize { space, size } => { - if space { - w.write_u8(constants::DW_OP_xderef_size.0)?; - } else { - w.write_u8(constants::DW_OP_deref_size.0)?; - } - w.write_u8(size)?; - } - Operation::DerefType { space, size, base } => { - if space { - w.write_u8(constants::DW_OP_xderef_type.0)?; - } else { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_deref_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_deref_type.0)?; - } - } - w.write_u8(size)?; - w.write_uleb128(entry_offset(base)?)?; - } - Operation::PlusConstant(value) => { - w.write_u8(constants::DW_OP_plus_uconst.0)?; - w.write_uleb128(value)?; - } - Operation::Skip(target) => { - w.write_u8(constants::DW_OP_skip.0)?; - let offset = offsets[target] as i64 - (w.len() as i64 + 2); - w.write_sdata(offset, 2)?; - } - Operation::Branch(target) => { - w.write_u8(constants::DW_OP_bra.0)?; - let offset = offsets[target] as i64 - (w.len() as i64 + 2); - w.write_sdata(offset, 2)?; - } - Operation::Call(entry) => { - w.write_u8(constants::DW_OP_call4.0)?; - // TODO: this probably won't work in practice, because we may - // only know the offsets of base type DIEs at this point. - w.write_udata(entry_offset(entry)?, 4)?; - } - Operation::CallRef(entry) => { - w.write_u8(constants::DW_OP_call_ref.0)?; - let size = encoding.format.word_size(); - match entry { - Reference::Symbol(symbol) => w.write_reference(symbol, size)?, - Reference::Entry(unit, entry) => { - let refs = refs.ok_or(Error::InvalidReference)?; - refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - } - Operation::Convert(base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_convert.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_convert.0)?; - } - match base { - Some(base) => w.write_uleb128(entry_offset(base)?)?, - None => w.write_u8(0)?, - } - } - Operation::Reinterpret(base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_reinterpret.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_reinterpret.0)?; - } - match base { - Some(base) => w.write_uleb128(entry_offset(base)?)?, - None => w.write_u8(0)?, - } - } - Operation::EntryValue(ref expression) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_entry_value.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_entry_value.0)?; - } - let length = expression.size(encoding, unit_offsets); - w.write_uleb128(length as u64)?; - expression.write(w, refs, encoding, unit_offsets)?; - } - Operation::Register(register) => { - if register.0 < 32 { - w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?; - } else { - w.write_u8(constants::DW_OP_regx.0)?; - w.write_uleb128(register.0.into())?; - } - } - Operation::ImplicitValue(ref data) => { - w.write_u8(constants::DW_OP_implicit_value.0)?; - w.write_uleb128(data.len() as u64)?; - w.write(data)?; - } - Operation::ImplicitPointer { entry, byte_offset } => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_implicit_pointer.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?; - } - let size = if encoding.version == 2 { - encoding.address_size - } else { - encoding.format.word_size() - }; - match entry { - Reference::Symbol(symbol) => { - w.write_reference(symbol, size)?; - } - Reference::Entry(unit, entry) => { - let refs = refs.ok_or(Error::InvalidReference)?; - refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - w.write_sleb128(byte_offset)?; - } - Operation::Piece { size_in_bytes } => { - w.write_u8(constants::DW_OP_piece.0)?; - w.write_uleb128(size_in_bytes)?; - } - Operation::BitPiece { - size_in_bits, - bit_offset, - } => { - w.write_u8(constants::DW_OP_bit_piece.0)?; - w.write_uleb128(size_in_bits)?; - w.write_uleb128(bit_offset)?; - } - Operation::ParameterRef(entry) => { - w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?; - w.write_udata(entry_offset(entry)?, 4)?; - } - Operation::WasmLocal(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 0])?; - w.write_uleb128(index.into())?; - } - Operation::WasmGlobal(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 1])?; - w.write_uleb128(index.into())?; - } - Operation::WasmStack(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 2])?; - w.write_uleb128(index.into())?; - } - } - Ok(()) - } -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::common::UnitSectionOffset; - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, UnitEntryId, UnitId}; - use std::collections::HashMap; - - impl Expression { - /// Create an expression from the input expression. - pub fn from<R: Reader<Offset = usize>>( - from_expression: read::Expression<R>, - encoding: Encoding, - dwarf: Option<&read::Dwarf<R>>, - unit: Option<&read::Unit<R>>, - entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Expression> { - let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> { - let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let id = entry_ids - .get(&offset.to_unit_section_offset(unit)) - .ok_or(ConvertError::InvalidUnitRef)?; - Ok(id.1) - }; - let convert_debug_info_offset = |offset| -> ConvertResult<_> { - // TODO: support relocations - let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; - let id = entry_ids - .get(&UnitSectionOffset::DebugInfoOffset(offset)) - .ok_or(ConvertError::InvalidDebugInfoRef)?; - Ok(Reference::Entry(id.0, id.1)) - }; - - // Calculate offsets for use in branch/skip operations. - let mut offsets = Vec::new(); - let mut offset = 0; - let mut from_operations = from_expression.clone().operations(encoding); - while from_operations.next()?.is_some() { - offsets.push(offset); - offset = from_operations.offset_from(&from_expression); - } - offsets.push(from_expression.0.len()); - - let mut from_operations = from_expression.clone().operations(encoding); - let mut operations = Vec::new(); - while let Some(from_operation) = from_operations.next()? { - let operation = match from_operation { - read::Operation::Deref { - base_type, - size, - space, - } => { - if base_type.0 != 0 { - let base = convert_unit_offset(base_type)?; - Operation::DerefType { space, size, base } - } else if size != encoding.address_size { - Operation::DerefSize { space, size } - } else { - Operation::Deref { space } - } - } - read::Operation::Drop => Operation::Simple(constants::DW_OP_drop), - read::Operation::Pick { index } => Operation::Pick(index), - read::Operation::Swap => Operation::Simple(constants::DW_OP_swap), - read::Operation::Rot => Operation::Simple(constants::DW_OP_rot), - read::Operation::Abs => Operation::Simple(constants::DW_OP_abs), - read::Operation::And => Operation::Simple(constants::DW_OP_and), - read::Operation::Div => Operation::Simple(constants::DW_OP_div), - read::Operation::Minus => Operation::Simple(constants::DW_OP_minus), - read::Operation::Mod => Operation::Simple(constants::DW_OP_mod), - read::Operation::Mul => Operation::Simple(constants::DW_OP_mul), - read::Operation::Neg => Operation::Simple(constants::DW_OP_neg), - read::Operation::Not => Operation::Simple(constants::DW_OP_not), - read::Operation::Or => Operation::Simple(constants::DW_OP_or), - read::Operation::Plus => Operation::Simple(constants::DW_OP_plus), - read::Operation::PlusConstant { value } => Operation::PlusConstant(value), - read::Operation::Shl => Operation::Simple(constants::DW_OP_shl), - read::Operation::Shr => Operation::Simple(constants::DW_OP_shr), - read::Operation::Shra => Operation::Simple(constants::DW_OP_shra), - read::Operation::Xor => Operation::Simple(constants::DW_OP_xor), - read::Operation::Eq => Operation::Simple(constants::DW_OP_eq), - read::Operation::Ge => Operation::Simple(constants::DW_OP_ge), - read::Operation::Gt => Operation::Simple(constants::DW_OP_gt), - read::Operation::Le => Operation::Simple(constants::DW_OP_le), - read::Operation::Lt => Operation::Simple(constants::DW_OP_lt), - read::Operation::Ne => Operation::Simple(constants::DW_OP_ne), - read::Operation::Bra { target } => { - let offset = from_operations - .offset_from(&from_expression) - .wrapping_add(i64::from(target) as usize); - let index = offsets - .binary_search(&offset) - .map_err(|_| ConvertError::InvalidBranchTarget)?; - Operation::Branch(index) - } - read::Operation::Skip { target } => { - let offset = from_operations - .offset_from(&from_expression) - .wrapping_add(i64::from(target) as usize); - let index = offsets - .binary_search(&offset) - .map_err(|_| ConvertError::InvalidBranchTarget)?; - Operation::Skip(index) - } - read::Operation::UnsignedConstant { value } => { - Operation::UnsignedConstant(value) - } - read::Operation::SignedConstant { value } => Operation::SignedConstant(value), - read::Operation::Register { register } => Operation::Register(register), - read::Operation::RegisterOffset { - register, - offset, - base_type, - } => { - if base_type.0 != 0 { - Operation::RegisterType(register, convert_unit_offset(base_type)?) - } else { - Operation::RegisterOffset(register, offset) - } - } - read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset), - read::Operation::Nop => Operation::Simple(constants::DW_OP_nop), - read::Operation::PushObjectAddress => { - Operation::Simple(constants::DW_OP_push_object_address) - } - read::Operation::Call { offset } => match offset { - read::DieReference::UnitRef(offset) => { - Operation::Call(convert_unit_offset(offset)?) - } - read::DieReference::DebugInfoRef(offset) => { - Operation::CallRef(convert_debug_info_offset(offset)?) - } - }, - read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address), - read::Operation::CallFrameCFA => { - Operation::Simple(constants::DW_OP_call_frame_cfa) - } - read::Operation::Piece { - size_in_bits, - bit_offset: None, - } => Operation::Piece { - size_in_bytes: size_in_bits / 8, - }, - read::Operation::Piece { - size_in_bits, - bit_offset: Some(bit_offset), - } => Operation::BitPiece { - size_in_bits, - bit_offset, - }, - read::Operation::ImplicitValue { data } => { - Operation::ImplicitValue(data.to_slice()?.into_owned().into()) - } - read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value), - read::Operation::ImplicitPointer { value, byte_offset } => { - let entry = convert_debug_info_offset(value)?; - Operation::ImplicitPointer { entry, byte_offset } - } - read::Operation::EntryValue { expression } => { - let expression = Expression::from( - read::Expression(expression), - encoding, - dwarf, - unit, - entry_ids, - convert_address, - )?; - Operation::EntryValue(expression) - } - read::Operation::ParameterRef { offset } => { - let entry = convert_unit_offset(offset)?; - Operation::ParameterRef(entry) - } - read::Operation::Address { address } => { - let address = - convert_address(address).ok_or(ConvertError::InvalidAddress)?; - Operation::Address(address) - } - read::Operation::AddressIndex { index } => { - let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let val = dwarf.address(unit, index)?; - let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?; - Operation::Address(address) - } - read::Operation::ConstantIndex { index } => { - let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let val = dwarf.address(unit, index)?; - Operation::UnsignedConstant(val) - } - read::Operation::TypedLiteral { base_type, value } => { - let entry = convert_unit_offset(base_type)?; - Operation::ConstantType(entry, value.to_slice()?.into_owned().into()) - } - read::Operation::Convert { base_type } => { - if base_type.0 == 0 { - Operation::Convert(None) - } else { - let entry = convert_unit_offset(base_type)?; - Operation::Convert(Some(entry)) - } - } - read::Operation::Reinterpret { base_type } => { - if base_type.0 == 0 { - Operation::Reinterpret(None) - } else { - let entry = convert_unit_offset(base_type)?; - Operation::Reinterpret(Some(entry)) - } - } - read::Operation::WasmLocal { index } => Operation::WasmLocal(index), - read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index), - read::Operation::WasmStack { index } => Operation::WasmStack(index), - }; - operations.push(operation); - } - Ok(Expression { operations }) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, SectionId, - }; - use crate::read; - use crate::write::{ - DebugLineStrOffsets, DebugStrOffsets, EndianVec, LineProgram, Sections, Unit, UnitTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_operation() { - for &version in &[3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut units = UnitTable::default(); - let unit_id = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get_mut(unit_id); - let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type); - let reference = Reference::Entry(unit_id, entry_id); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let debug_info_offsets = units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - let unit_offsets = debug_info_offsets.unit_offsets(unit_id); - let debug_info_offset = unit_offsets.debug_info_offset(entry_id); - let entry_offset = - read::UnitOffset(unit_offsets.unit_offset(entry_id) as usize); - - let mut reg_expression = Expression::new(); - reg_expression.op_reg(Register(23)); - - let operations: &[(&dyn Fn(&mut Expression), Operation, read::Operation<_>)] = - &[ - ( - &|x| x.op_deref(), - Operation::Deref { space: false }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: address_size, - space: false, - }, - ), - ( - &|x| x.op_xderef(), - Operation::Deref { space: true }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: address_size, - space: true, - }, - ), - ( - &|x| x.op_deref_size(2), - Operation::DerefSize { - space: false, - size: 2, - }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: 2, - space: false, - }, - ), - ( - &|x| x.op_xderef_size(2), - Operation::DerefSize { - space: true, - size: 2, - }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: 2, - space: true, - }, - ), - ( - &|x| x.op_deref_type(2, entry_id), - Operation::DerefType { - space: false, - size: 2, - base: entry_id, - }, - read::Operation::Deref { - base_type: entry_offset, - size: 2, - space: false, - }, - ), - ( - &|x| x.op_xderef_type(2, entry_id), - Operation::DerefType { - space: true, - size: 2, - base: entry_id, - }, - read::Operation::Deref { - base_type: entry_offset, - size: 2, - space: true, - }, - ), - ( - &|x| x.op(constants::DW_OP_drop), - Operation::Simple(constants::DW_OP_drop), - read::Operation::Drop, - ), - ( - &|x| x.op_pick(0), - Operation::Pick(0), - read::Operation::Pick { index: 0 }, - ), - ( - &|x| x.op_pick(1), - Operation::Pick(1), - read::Operation::Pick { index: 1 }, - ), - ( - &|x| x.op_pick(2), - Operation::Pick(2), - read::Operation::Pick { index: 2 }, - ), - ( - &|x| x.op(constants::DW_OP_swap), - Operation::Simple(constants::DW_OP_swap), - read::Operation::Swap, - ), - ( - &|x| x.op(constants::DW_OP_rot), - Operation::Simple(constants::DW_OP_rot), - read::Operation::Rot, - ), - ( - &|x| x.op(constants::DW_OP_abs), - Operation::Simple(constants::DW_OP_abs), - read::Operation::Abs, - ), - ( - &|x| x.op(constants::DW_OP_and), - Operation::Simple(constants::DW_OP_and), - read::Operation::And, - ), - ( - &|x| x.op(constants::DW_OP_div), - Operation::Simple(constants::DW_OP_div), - read::Operation::Div, - ), - ( - &|x| x.op(constants::DW_OP_minus), - Operation::Simple(constants::DW_OP_minus), - read::Operation::Minus, - ), - ( - &|x| x.op(constants::DW_OP_mod), - Operation::Simple(constants::DW_OP_mod), - read::Operation::Mod, - ), - ( - &|x| x.op(constants::DW_OP_mul), - Operation::Simple(constants::DW_OP_mul), - read::Operation::Mul, - ), - ( - &|x| x.op(constants::DW_OP_neg), - Operation::Simple(constants::DW_OP_neg), - read::Operation::Neg, - ), - ( - &|x| x.op(constants::DW_OP_not), - Operation::Simple(constants::DW_OP_not), - read::Operation::Not, - ), - ( - &|x| x.op(constants::DW_OP_or), - Operation::Simple(constants::DW_OP_or), - read::Operation::Or, - ), - ( - &|x| x.op(constants::DW_OP_plus), - Operation::Simple(constants::DW_OP_plus), - read::Operation::Plus, - ), - ( - &|x| x.op_plus_uconst(23), - Operation::PlusConstant(23), - read::Operation::PlusConstant { value: 23 }, - ), - ( - &|x| x.op(constants::DW_OP_shl), - Operation::Simple(constants::DW_OP_shl), - read::Operation::Shl, - ), - ( - &|x| x.op(constants::DW_OP_shr), - Operation::Simple(constants::DW_OP_shr), - read::Operation::Shr, - ), - ( - &|x| x.op(constants::DW_OP_shra), - Operation::Simple(constants::DW_OP_shra), - read::Operation::Shra, - ), - ( - &|x| x.op(constants::DW_OP_xor), - Operation::Simple(constants::DW_OP_xor), - read::Operation::Xor, - ), - ( - &|x| x.op(constants::DW_OP_eq), - Operation::Simple(constants::DW_OP_eq), - read::Operation::Eq, - ), - ( - &|x| x.op(constants::DW_OP_ge), - Operation::Simple(constants::DW_OP_ge), - read::Operation::Ge, - ), - ( - &|x| x.op(constants::DW_OP_gt), - Operation::Simple(constants::DW_OP_gt), - read::Operation::Gt, - ), - ( - &|x| x.op(constants::DW_OP_le), - Operation::Simple(constants::DW_OP_le), - read::Operation::Le, - ), - ( - &|x| x.op(constants::DW_OP_lt), - Operation::Simple(constants::DW_OP_lt), - read::Operation::Lt, - ), - ( - &|x| x.op(constants::DW_OP_ne), - Operation::Simple(constants::DW_OP_ne), - read::Operation::Ne, - ), - ( - &|x| x.op_constu(23), - Operation::UnsignedConstant(23), - read::Operation::UnsignedConstant { value: 23 }, - ), - ( - &|x| x.op_consts(-23), - Operation::SignedConstant(-23), - read::Operation::SignedConstant { value: -23 }, - ), - ( - &|x| x.op_reg(Register(23)), - Operation::Register(Register(23)), - read::Operation::Register { - register: Register(23), - }, - ), - ( - &|x| x.op_reg(Register(123)), - Operation::Register(Register(123)), - read::Operation::Register { - register: Register(123), - }, - ), - ( - &|x| x.op_breg(Register(23), 34), - Operation::RegisterOffset(Register(23), 34), - read::Operation::RegisterOffset { - register: Register(23), - offset: 34, - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_breg(Register(123), 34), - Operation::RegisterOffset(Register(123), 34), - read::Operation::RegisterOffset { - register: Register(123), - offset: 34, - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_regval_type(Register(23), entry_id), - Operation::RegisterType(Register(23), entry_id), - read::Operation::RegisterOffset { - register: Register(23), - offset: 0, - base_type: entry_offset, - }, - ), - ( - &|x| x.op_fbreg(34), - Operation::FrameOffset(34), - read::Operation::FrameOffset { offset: 34 }, - ), - ( - &|x| x.op(constants::DW_OP_nop), - Operation::Simple(constants::DW_OP_nop), - read::Operation::Nop, - ), - ( - &|x| x.op(constants::DW_OP_push_object_address), - Operation::Simple(constants::DW_OP_push_object_address), - read::Operation::PushObjectAddress, - ), - ( - &|x| x.op_call(entry_id), - Operation::Call(entry_id), - read::Operation::Call { - offset: read::DieReference::UnitRef(entry_offset), - }, - ), - ( - &|x| x.op_call_ref(reference), - Operation::CallRef(reference), - read::Operation::Call { - offset: read::DieReference::DebugInfoRef(debug_info_offset), - }, - ), - ( - &|x| x.op(constants::DW_OP_form_tls_address), - Operation::Simple(constants::DW_OP_form_tls_address), - read::Operation::TLS, - ), - ( - &|x| x.op(constants::DW_OP_call_frame_cfa), - Operation::Simple(constants::DW_OP_call_frame_cfa), - read::Operation::CallFrameCFA, - ), - ( - &|x| x.op_piece(23), - Operation::Piece { size_in_bytes: 23 }, - read::Operation::Piece { - size_in_bits: 23 * 8, - bit_offset: None, - }, - ), - ( - &|x| x.op_bit_piece(23, 34), - Operation::BitPiece { - size_in_bits: 23, - bit_offset: 34, - }, - read::Operation::Piece { - size_in_bits: 23, - bit_offset: Some(34), - }, - ), - ( - &|x| x.op_implicit_value(vec![23].into()), - Operation::ImplicitValue(vec![23].into()), - read::Operation::ImplicitValue { - data: read::EndianSlice::new(&[23], LittleEndian), - }, - ), - ( - &|x| x.op(constants::DW_OP_stack_value), - Operation::Simple(constants::DW_OP_stack_value), - read::Operation::StackValue, - ), - ( - &|x| x.op_implicit_pointer(reference, 23), - Operation::ImplicitPointer { - entry: reference, - byte_offset: 23, - }, - read::Operation::ImplicitPointer { - value: debug_info_offset, - byte_offset: 23, - }, - ), - ( - &|x| x.op_entry_value(reg_expression.clone()), - Operation::EntryValue(reg_expression.clone()), - read::Operation::EntryValue { - expression: read::EndianSlice::new( - &[constants::DW_OP_reg23.0], - LittleEndian, - ), - }, - ), - ( - &|x| x.op_gnu_parameter_ref(entry_id), - Operation::ParameterRef(entry_id), - read::Operation::ParameterRef { - offset: entry_offset, - }, - ), - ( - &|x| x.op_addr(Address::Constant(23)), - Operation::Address(Address::Constant(23)), - read::Operation::Address { address: 23 }, - ), - ( - &|x| x.op_const_type(entry_id, vec![23].into()), - Operation::ConstantType(entry_id, vec![23].into()), - read::Operation::TypedLiteral { - base_type: entry_offset, - value: read::EndianSlice::new(&[23], LittleEndian), - }, - ), - ( - &|x| x.op_convert(None), - Operation::Convert(None), - read::Operation::Convert { - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_convert(Some(entry_id)), - Operation::Convert(Some(entry_id)), - read::Operation::Convert { - base_type: entry_offset, - }, - ), - ( - &|x| x.op_reinterpret(None), - Operation::Reinterpret(None), - read::Operation::Reinterpret { - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_reinterpret(Some(entry_id)), - Operation::Reinterpret(Some(entry_id)), - read::Operation::Reinterpret { - base_type: entry_offset, - }, - ), - ( - &|x| x.op_wasm_local(1000), - Operation::WasmLocal(1000), - read::Operation::WasmLocal { index: 1000 }, - ), - ( - &|x| x.op_wasm_global(1000), - Operation::WasmGlobal(1000), - read::Operation::WasmGlobal { index: 1000 }, - ), - ( - &|x| x.op_wasm_stack(1000), - Operation::WasmStack(1000), - read::Operation::WasmStack { index: 1000 }, - ), - ]; - - let mut expression = Expression::new(); - let start_index = expression.next_index(); - for (f, o, _) in operations { - f(&mut expression); - assert_eq!(expression.operations.last(), Some(o)); - } - - let bra_index = expression.op_bra(); - let skip_index = expression.op_skip(); - expression.op(constants::DW_OP_nop); - let end_index = expression.next_index(); - expression.set_target(bra_index, start_index); - expression.set_target(skip_index, end_index); - - let mut w = EndianVec::new(LittleEndian); - let mut refs = Vec::new(); - expression - .write(&mut w, Some(&mut refs), encoding, Some(&unit_offsets)) - .unwrap(); - for r in &refs { - assert_eq!(r.unit, unit_id); - assert_eq!(r.entry, entry_id); - w.write_offset_at( - r.offset, - debug_info_offset.0, - SectionId::DebugInfo, - r.size, - ) - .unwrap(); - } - - let read_expression = - read::Expression(read::EndianSlice::new(w.slice(), LittleEndian)); - let mut read_operations = read_expression.operations(encoding); - for (_, _, operation) in operations { - assert_eq!(read_operations.next(), Ok(Some(*operation))); - } - - // 4 = DW_OP_skip + i16 + DW_OP_nop - assert_eq!( - read_operations.next(), - Ok(Some(read::Operation::Bra { - target: -(w.len() as i16) + 4 - })) - ); - // 1 = DW_OP_nop - assert_eq!( - read_operations.next(), - Ok(Some(read::Operation::Skip { target: 1 })) - ); - assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop))); - assert_eq!(read_operations.next(), Ok(None)); - - // Fake the unit. - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut entry_ids = HashMap::new(); - entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id)); - let convert_expression = Expression::from( - read_expression, - encoding, - None, /* dwarf */ - Some(&unit), - Some(&entry_ids), - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - let mut convert_operations = convert_expression.operations.iter(); - for (_, operation, _) in operations { - assert_eq!(convert_operations.next(), Some(operation)); - } - assert_eq!( - convert_operations.next(), - Some(&Operation::Branch(start_index)) - ); - assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index))); - assert_eq!( - convert_operations.next(), - Some(&Operation::Simple(constants::DW_OP_nop)) - ); - } - } - } - } -} diff --git a/vendor/gimli/src/write/range.rs b/vendor/gimli/src/write/range.rs deleted file mode 100644 index c707e1e..0000000 --- a/vendor/gimli/src/write/range.rs +++ /dev/null @@ -1,416 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{Encoding, RangeListsOffset, SectionId}; -use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer}; - -define_section!( - DebugRanges, - RangeListsOffset, - "A writable `.debug_ranges` section." -); -define_section!( - DebugRngLists, - RangeListsOffset, - "A writable `.debug_rnglists` section." -); - -define_offsets!( - RangeListOffsets: RangeListId => RangeListsOffset, - "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections." -); - -define_id!( - RangeListId, - "An identifier for a range list in a `RangeListTable`." -); - -/// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section. -#[derive(Debug, Default)] -pub struct RangeListTable { - base_id: BaseId, - ranges: IndexSet<RangeList>, -} - -impl RangeListTable { - /// Add a range list to the table. - pub fn add(&mut self, range_list: RangeList) -> RangeListId { - let (index, _) = self.ranges.insert_full(range_list); - RangeListId::new(self.base_id, index) - } - - /// Write the range list table to the appropriate section for the given DWARF version. - pub(crate) fn write<W: Writer>( - &self, - sections: &mut Sections<W>, - encoding: Encoding, - ) -> Result<RangeListOffsets> { - if self.ranges.is_empty() { - return Ok(RangeListOffsets::none()); - } - - match encoding.version { - 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size), - 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding), - _ => Err(Error::UnsupportedVersion(encoding.version)), - } - } - - /// Write the range list table to the `.debug_ranges` section. - fn write_ranges<W: Writer>( - &self, - w: &mut DebugRanges<W>, - address_size: u8, - ) -> Result<RangeListOffsets> { - let mut offsets = Vec::new(); - for range_list in self.ranges.iter() { - offsets.push(w.offset()); - for range in &range_list.0 { - // Note that we must ensure none of the ranges have both begin == 0 and end == 0. - // We do this by ensuring that begin != end, which is a bit more restrictive - // than required, but still seems reasonable. - match *range { - Range::BaseAddress { address } => { - let marker = !0 >> (64 - address_size * 8); - w.write_udata(marker, address_size)?; - w.write_address(address, address_size)?; - } - Range::OffsetPair { begin, end } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_udata(begin, address_size)?; - w.write_udata(end, address_size)?; - } - Range::StartEnd { begin, end } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - } - Range::StartLength { begin, length } => { - let end = match begin { - Address::Constant(begin) => Address::Constant(begin + length), - Address::Symbol { symbol, addend } => Address::Symbol { - symbol, - addend: addend + length as i64, - }, - }; - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - } - } - } - w.write_udata(0, address_size)?; - w.write_udata(0, address_size)?; - } - Ok(RangeListOffsets { - base_id: self.base_id, - offsets, - }) - } - - /// Write the range list table to the `.debug_rnglists` section. - fn write_rnglists<W: Writer>( - &self, - w: &mut DebugRngLists<W>, - encoding: Encoding, - ) -> Result<RangeListOffsets> { - let mut offsets = Vec::new(); - - if encoding.version != 5 { - return Err(Error::NeedVersion(5)); - } - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - w.write_u16(encoding.version)?; - w.write_u8(encoding.address_size)?; - w.write_u8(0)?; // segment_selector_size - w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) - // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list - - for range_list in self.ranges.iter() { - offsets.push(w.offset()); - for range in &range_list.0 { - match *range { - Range::BaseAddress { address } => { - w.write_u8(crate::constants::DW_RLE_base_address.0)?; - w.write_address(address, encoding.address_size)?; - } - Range::OffsetPair { begin, end } => { - w.write_u8(crate::constants::DW_RLE_offset_pair.0)?; - w.write_uleb128(begin)?; - w.write_uleb128(end)?; - } - Range::StartEnd { begin, end } => { - w.write_u8(crate::constants::DW_RLE_start_end.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_address(end, encoding.address_size)?; - } - Range::StartLength { begin, length } => { - w.write_u8(crate::constants::DW_RLE_start_length.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_uleb128(length)?; - } - } - } - - w.write_u8(crate::constants::DW_RLE_end_of_list.0)?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(RangeListOffsets { - base_id: self.base_id, - offsets, - }) - } -} - -/// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct RangeList(pub Vec<Range>); - -/// A single range. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum Range { - /// DW_RLE_base_address - BaseAddress { - /// Base address. - address: Address, - }, - /// DW_RLE_offset_pair - OffsetPair { - /// Start of range relative to base address. - begin: u64, - /// End of range relative to base address. - end: u64, - }, - /// DW_RLE_start_end - StartEnd { - /// Start of range. - begin: Address, - /// End of range. - end: Address, - }, - /// DW_RLE_start_length - StartLength { - /// Start of range. - begin: Address, - /// Length of range. - length: u64, - }, -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; - - impl RangeList { - /// Create a range list by reading the data from the give range list iter. - pub(crate) fn from<R: Reader<Offset = usize>>( - mut from: read::RawRngListIter<R>, - context: &ConvertUnitContext<R>, - ) -> ConvertResult<Self> { - let mut have_base_address = context.base_address != Address::Constant(0); - let convert_address = - |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); - let mut ranges = Vec::new(); - while let Some(from_range) = from.next()? { - let range = match from_range { - read::RawRngListEntry::AddressOrOffsetPair { begin, end } => { - // These were parsed as addresses, even if they are offsets. - let begin = convert_address(begin)?; - let end = convert_address(end)?; - match (begin, end) { - (Address::Constant(begin_offset), Address::Constant(end_offset)) => { - if have_base_address { - Range::OffsetPair { - begin: begin_offset, - end: end_offset, - } - } else { - Range::StartEnd { begin, end } - } - } - _ => { - if have_base_address { - // At least one of begin/end is an address, but we also have - // a base address. Adding addresses is undefined. - return Err(ConvertError::InvalidRangeRelativeAddress); - } - Range::StartEnd { begin, end } - } - } - } - read::RawRngListEntry::BaseAddress { addr } => { - have_base_address = true; - let address = convert_address(addr)?; - Range::BaseAddress { address } - } - read::RawRngListEntry::BaseAddressx { addr } => { - have_base_address = true; - let address = convert_address(context.dwarf.address(context.unit, addr)?)?; - Range::BaseAddress { address } - } - read::RawRngListEntry::StartxEndx { begin, end } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let end = convert_address(context.dwarf.address(context.unit, end)?)?; - Range::StartEnd { begin, end } - } - read::RawRngListEntry::StartxLength { begin, length } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - Range::StartLength { begin, length } - } - read::RawRngListEntry::OffsetPair { begin, end } => { - Range::OffsetPair { begin, end } - } - read::RawRngListEntry::StartEnd { begin, end } => { - let begin = convert_address(begin)?; - let end = convert_address(end)?; - Range::StartEnd { begin, end } - } - read::RawRngListEntry::StartLength { begin, length } => { - let begin = convert_address(begin)?; - Range::StartLength { begin, length } - } - }; - // Filtering empty ranges out. - match range { - Range::StartLength { length, .. } if length == 0 => continue, - Range::StartEnd { begin, end, .. } if begin == end => continue, - Range::OffsetPair { begin, end, .. } if begin == end => continue, - _ => (), - } - ranges.push(range); - } - Ok(RangeList(ranges)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, - }; - use crate::read; - use crate::write::{ - ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable, - StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_range() { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut range_list = RangeList(vec![ - Range::StartLength { - begin: Address::Constant(6666), - length: 7777, - }, - Range::StartEnd { - begin: Address::Constant(4444), - end: Address::Constant(5555), - }, - Range::BaseAddress { - address: Address::Constant(1111), - }, - Range::OffsetPair { - begin: 2222, - end: 3333, - }, - ]); - - let mut ranges = RangeListTable::default(); - let range_list_id = ranges.add(range_list.clone()); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); - - let read_debug_ranges = - read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); - let read_debug_rnglists = - read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); - let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists); - let offset = range_list_offsets.get(range_list_id); - let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap(); - - let dwarf = read::Dwarf { - ranges: read_ranges, - ..Default::default() - }; - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::default(), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - let context = ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut LocationListTable::default(), - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - let convert_range_list = RangeList::from(read_range_list, &context).unwrap(); - - if version <= 4 { - range_list.0[0] = Range::StartEnd { - begin: Address::Constant(6666), - end: Address::Constant(6666 + 7777), - }; - } - assert_eq!(range_list, convert_range_list); - } - } - } - } -} diff --git a/vendor/gimli/src/write/section.rs b/vendor/gimli/src/write/section.rs deleted file mode 100644 index db5eb9a..0000000 --- a/vendor/gimli/src/write/section.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::ops::DerefMut; -use std::result; -use std::vec::Vec; - -use crate::common::SectionId; -use crate::write::{ - DebugAbbrev, DebugFrame, DebugInfo, DebugInfoReference, DebugLine, DebugLineStr, DebugLoc, - DebugLocLists, DebugRanges, DebugRngLists, DebugStr, EhFrame, Writer, -}; - -macro_rules! define_section { - ($name:ident, $offset:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Default)] - pub struct $name<W: Writer>(pub W); - - impl<W: Writer> $name<W> { - /// Return the offset of the next write. - pub fn offset(&self) -> $offset { - $offset(self.len()) - } - } - - impl<W: Writer> From<W> for $name<W> { - #[inline] - fn from(w: W) -> Self { - $name(w) - } - } - - impl<W: Writer> Deref for $name<W> { - type Target = W; - - #[inline] - fn deref(&self) -> &W { - &self.0 - } - } - - impl<W: Writer> DerefMut for $name<W> { - #[inline] - fn deref_mut(&mut self) -> &mut W { - &mut self.0 - } - } - - impl<W: Writer> Section<W> for $name<W> { - #[inline] - fn id(&self) -> SectionId { - SectionId::$name - } - } - }; -} - -/// Functionality common to all writable DWARF sections. -pub trait Section<W: Writer>: DerefMut<Target = W> { - /// Returns the DWARF section kind for this type. - fn id(&self) -> SectionId; - - /// Returns the ELF section name for this type. - fn name(&self) -> &'static str { - self.id().name() - } -} - -/// All of the writable DWARF sections. -#[derive(Debug, Default)] -pub struct Sections<W: Writer> { - /// The `.debug_abbrev` section. - pub debug_abbrev: DebugAbbrev<W>, - /// The `.debug_info` section. - pub debug_info: DebugInfo<W>, - /// The `.debug_line` section. - pub debug_line: DebugLine<W>, - /// The `.debug_line_str` section. - pub debug_line_str: DebugLineStr<W>, - /// The `.debug_ranges` section. - pub debug_ranges: DebugRanges<W>, - /// The `.debug_rnglists` section. - pub debug_rnglists: DebugRngLists<W>, - /// The `.debug_loc` section. - pub debug_loc: DebugLoc<W>, - /// The `.debug_loclists` section. - pub debug_loclists: DebugLocLists<W>, - /// The `.debug_str` section. - pub debug_str: DebugStr<W>, - /// The `.debug_frame` section. - pub debug_frame: DebugFrame<W>, - /// The `.eh_frame` section. - pub eh_frame: EhFrame<W>, - /// Unresolved references in the `.debug_info` section. - pub(crate) debug_info_refs: Vec<DebugInfoReference>, - /// Unresolved references in the `.debug_loc` section. - pub(crate) debug_loc_refs: Vec<DebugInfoReference>, - /// Unresolved references in the `.debug_loclists` section. - pub(crate) debug_loclists_refs: Vec<DebugInfoReference>, -} - -impl<W: Writer + Clone> Sections<W> { - /// Create a new `Sections` using clones of the given `section`. - pub fn new(section: W) -> Self { - Sections { - debug_abbrev: DebugAbbrev(section.clone()), - debug_info: DebugInfo(section.clone()), - debug_line: DebugLine(section.clone()), - debug_line_str: DebugLineStr(section.clone()), - debug_ranges: DebugRanges(section.clone()), - debug_rnglists: DebugRngLists(section.clone()), - debug_loc: DebugLoc(section.clone()), - debug_loclists: DebugLocLists(section.clone()), - debug_str: DebugStr(section.clone()), - debug_frame: DebugFrame(section.clone()), - eh_frame: EhFrame(section), - debug_info_refs: Vec::new(), - debug_loc_refs: Vec::new(), - debug_loclists_refs: Vec::new(), - } - } -} - -impl<W: Writer> Sections<W> { - /// For each section, call `f` once with a shared reference. - pub fn for_each<F, E>(&self, mut f: F) -> result::Result<(), E> - where - F: FnMut(SectionId, &W) -> result::Result<(), E>, - { - macro_rules! f { - ($s:expr) => { - f($s.id(), &$s) - }; - } - // Ordered so that earlier sections do not reference later sections. - f!(self.debug_abbrev)?; - f!(self.debug_str)?; - f!(self.debug_line_str)?; - f!(self.debug_line)?; - f!(self.debug_ranges)?; - f!(self.debug_rnglists)?; - f!(self.debug_loc)?; - f!(self.debug_loclists)?; - f!(self.debug_info)?; - f!(self.debug_frame)?; - f!(self.eh_frame)?; - Ok(()) - } - - /// For each section, call `f` once with a mutable reference. - pub fn for_each_mut<F, E>(&mut self, mut f: F) -> result::Result<(), E> - where - F: FnMut(SectionId, &mut W) -> result::Result<(), E>, - { - macro_rules! f { - ($s:expr) => { - f($s.id(), &mut $s) - }; - } - // Ordered so that earlier sections do not reference later sections. - f!(self.debug_abbrev)?; - f!(self.debug_str)?; - f!(self.debug_line_str)?; - f!(self.debug_line)?; - f!(self.debug_ranges)?; - f!(self.debug_rnglists)?; - f!(self.debug_loc)?; - f!(self.debug_loclists)?; - f!(self.debug_info)?; - f!(self.debug_frame)?; - f!(self.eh_frame)?; - Ok(()) - } -} diff --git a/vendor/gimli/src/write/str.rs b/vendor/gimli/src/write/str.rs deleted file mode 100644 index 83285c0..0000000 --- a/vendor/gimli/src/write/str.rs +++ /dev/null @@ -1,172 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugLineStrOffset, DebugStrOffset, SectionId}; -use crate::write::{BaseId, Result, Section, Writer}; - -// Requirements: -// - values are `[u8]`, null bytes are not allowed -// - insertion returns a fixed id -// - inserting a duplicate returns the id of the existing value -// - able to convert an id to a section offset -// Optional? -// - able to get an existing value given an id -// -// Limitations of current implementation (using IndexSet): -// - inserting requires either an allocation for duplicates, -// or a double lookup for non-duplicates -// - doesn't preserve offsets when updating an existing `.debug_str` section -// -// Possible changes: -// - calculate offsets as we add values, and use that as the id. -// This would avoid the need for DebugStrOffsets but would make it -// hard to implement `get`. -macro_rules! define_string_table { - ($name:ident, $id:ident, $section:ident, $offsets:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Default)] - pub struct $name { - base_id: BaseId, - strings: IndexSet<Vec<u8>>, - } - - impl $name { - /// Add a string to the string table and return its id. - /// - /// If the string already exists, then return the id of the existing string. - /// - /// # Panics - /// - /// Panics if `bytes` contains a null byte. - pub fn add<T>(&mut self, bytes: T) -> $id - where - T: Into<Vec<u8>>, - { - let bytes = bytes.into(); - assert!(!bytes.contains(&0)); - let (index, _) = self.strings.insert_full(bytes); - $id::new(self.base_id, index) - } - - /// Return the number of strings in the table. - #[inline] - pub fn count(&self) -> usize { - self.strings.len() - } - - /// Get a reference to a string in the table. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get(&self, id: $id) -> &[u8] { - debug_assert_eq!(self.base_id, id.base_id); - self.strings.get_index(id.index).map(Vec::as_slice).unwrap() - } - - /// Write the string table to the `.debug_str` section. - /// - /// Returns the offsets at which the strings are written. - pub fn write<W: Writer>(&self, w: &mut $section<W>) -> Result<$offsets> { - let mut offsets = Vec::new(); - for bytes in self.strings.iter() { - offsets.push(w.offset()); - w.write(bytes)?; - w.write_u8(0)?; - } - - Ok($offsets { - base_id: self.base_id, - offsets, - }) - } - } - }; -} - -define_id!(StringId, "An identifier for a string in a `StringTable`."); - -define_string_table!( - StringTable, - StringId, - DebugStr, - DebugStrOffsets, - "A table of strings that will be stored in a `.debug_str` section." -); - -define_section!(DebugStr, DebugStrOffset, "A writable `.debug_str` section."); - -define_offsets!( - DebugStrOffsets: StringId => DebugStrOffset, - "The section offsets of all strings within a `.debug_str` section." -); - -define_id!( - LineStringId, - "An identifier for a string in a `LineStringTable`." -); - -define_string_table!( - LineStringTable, - LineStringId, - DebugLineStr, - DebugLineStrOffsets, - "A table of strings that will be stored in a `.debug_line_str` section." -); - -define_section!( - DebugLineStr, - DebugLineStrOffset, - "A writable `.debug_line_str` section." -); - -define_offsets!( - DebugLineStrOffsets: LineStringId => DebugLineStrOffset, - "The section offsets of all strings within a `.debug_line_str` section." -); - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::read; - use crate::write::EndianVec; - use crate::LittleEndian; - - #[test] - fn test_string_table() { - let mut strings = StringTable::default(); - assert_eq!(strings.count(), 0); - let id1 = strings.add(&b"one"[..]); - let id2 = strings.add(&b"two"[..]); - assert_eq!(strings.add(&b"one"[..]), id1); - assert_eq!(strings.add(&b"two"[..]), id2); - assert_eq!(strings.get(id1), &b"one"[..]); - assert_eq!(strings.get(id2), &b"two"[..]); - assert_eq!(strings.count(), 2); - - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let offsets = strings.write(&mut debug_str).unwrap(); - assert_eq!(debug_str.slice(), b"one\0two\0"); - assert_eq!(offsets.get(id1), DebugStrOffset(0)); - assert_eq!(offsets.get(id2), DebugStrOffset(4)); - assert_eq!(offsets.count(), 2); - } - - #[test] - fn test_string_table_read() { - let mut strings = StringTable::default(); - let id1 = strings.add(&b"one"[..]); - let id2 = strings.add(&b"two"[..]); - - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let offsets = strings.write(&mut debug_str).unwrap(); - - let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); - let str1 = read_debug_str.get_str(offsets.get(id1)).unwrap(); - let str2 = read_debug_str.get_str(offsets.get(id2)).unwrap(); - assert_eq!(str1.slice(), &b"one"[..]); - assert_eq!(str2.slice(), &b"two"[..]); - } -} diff --git a/vendor/gimli/src/write/unit.rs b/vendor/gimli/src/write/unit.rs deleted file mode 100644 index dd8ba67..0000000 --- a/vendor/gimli/src/write/unit.rs +++ /dev/null @@ -1,3152 +0,0 @@ -use alloc::vec::Vec; -use std::ops::{Deref, DerefMut}; -use std::{slice, usize}; - -use crate::common::{ - DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset, - DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId, -}; -use crate::constants; -use crate::leb128::write::{sleb128_size, uleb128_size}; -use crate::write::{ - Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets, - DebugStrOffsets, Error, Expression, FileId, LineProgram, LineStringId, LocationListId, - LocationListOffsets, LocationListTable, RangeListId, RangeListOffsets, RangeListTable, - Reference, Result, Section, Sections, StringId, Writer, -}; - -define_id!(UnitId, "An identifier for a unit in a `UnitTable`."); - -define_id!(UnitEntryId, "An identifier for an entry in a `Unit`."); - -/// A table of units that will be stored in the `.debug_info` section. -#[derive(Debug, Default)] -pub struct UnitTable { - base_id: BaseId, - units: Vec<Unit>, -} - -impl UnitTable { - /// Create a new unit and add it to the table. - /// - /// `address_size` must be in bytes. - /// - /// Returns the `UnitId` of the new unit. - #[inline] - pub fn add(&mut self, unit: Unit) -> UnitId { - let id = UnitId::new(self.base_id, self.units.len()); - self.units.push(unit); - id - } - - /// Return the number of units. - #[inline] - pub fn count(&self) -> usize { - self.units.len() - } - - /// Return the id of a unit. - /// - /// # Panics - /// - /// Panics if `index >= self.count()`. - #[inline] - pub fn id(&self, index: usize) -> UnitId { - assert!(index < self.count()); - UnitId::new(self.base_id, index) - } - - /// Get a reference to a unit. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: UnitId) -> &Unit { - debug_assert_eq!(self.base_id, id.base_id); - &self.units[id.index] - } - - /// Get a mutable reference to a unit. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get_mut(&mut self, id: UnitId) -> &mut Unit { - debug_assert_eq!(self.base_id, id.base_id); - &mut self.units[id.index] - } - - /// Write the units to the given sections. - /// - /// `strings` must contain the `.debug_str` offsets of the corresponding - /// `StringTable`. - pub fn write<W: Writer>( - &mut self, - sections: &mut Sections<W>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - ) -> Result<DebugInfoOffsets> { - let mut offsets = DebugInfoOffsets { - base_id: self.base_id, - units: Vec::new(), - }; - for unit in &mut self.units { - // TODO: maybe share abbreviation tables - let abbrev_offset = sections.debug_abbrev.offset(); - let mut abbrevs = AbbreviationTable::default(); - - offsets.units.push(unit.write( - sections, - abbrev_offset, - &mut abbrevs, - line_strings, - strings, - )?); - - abbrevs.write(&mut sections.debug_abbrev)?; - } - - write_section_refs( - &mut sections.debug_info_refs, - &mut sections.debug_info.0, - &offsets, - )?; - write_section_refs( - &mut sections.debug_loc_refs, - &mut sections.debug_loc.0, - &offsets, - )?; - write_section_refs( - &mut sections.debug_loclists_refs, - &mut sections.debug_loclists.0, - &offsets, - )?; - - Ok(offsets) - } -} - -fn write_section_refs<W: Writer>( - references: &mut Vec<DebugInfoReference>, - w: &mut W, - offsets: &DebugInfoOffsets, -) -> Result<()> { - for r in references.drain(..) { - let entry_offset = offsets.entry(r.unit, r.entry).0; - debug_assert_ne!(entry_offset, 0); - w.write_offset_at(r.offset, entry_offset, SectionId::DebugInfo, r.size)?; - } - Ok(()) -} - -/// A unit's debugging information. -#[derive(Debug)] -pub struct Unit { - base_id: BaseId, - /// The encoding parameters for this unit. - encoding: Encoding, - /// The line number program for this unit. - pub line_program: LineProgram, - /// A table of range lists used by this unit. - pub ranges: RangeListTable, - /// A table of location lists used by this unit. - pub locations: LocationListTable, - /// All entries in this unit. The order is unrelated to the tree order. - // Requirements: - // - entries form a tree - // - entries can be added in any order - // - entries have a fixed id - // - able to quickly lookup an entry from its id - // Limitations of current implementation: - // - mutable iteration of children is messy due to borrow checker - entries: Vec<DebuggingInformationEntry>, - /// The index of the root entry in entries. - root: UnitEntryId, -} - -impl Unit { - /// Create a new `Unit`. - pub fn new(encoding: Encoding, line_program: LineProgram) -> Self { - let base_id = BaseId::default(); - let ranges = RangeListTable::default(); - let locations = LocationListTable::default(); - let mut entries = Vec::new(); - let root = DebuggingInformationEntry::new( - base_id, - &mut entries, - None, - constants::DW_TAG_compile_unit, - ); - Unit { - base_id, - encoding, - line_program, - ranges, - locations, - entries, - root, - } - } - - /// Return the encoding parameters for this unit. - #[inline] - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Return the DWARF version for this unit. - #[inline] - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Return the address size in bytes for this unit. - #[inline] - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Return the DWARF format for this unit. - #[inline] - pub fn format(&self) -> Format { - self.encoding.format - } - - /// Return the number of `DebuggingInformationEntry`s created for this unit. - /// - /// This includes entries that no longer have a parent. - #[inline] - pub fn count(&self) -> usize { - self.entries.len() - } - - /// Return the id of the root entry. - #[inline] - pub fn root(&self) -> UnitEntryId { - self.root - } - - /// Add a new `DebuggingInformationEntry` to this unit and return its id. - /// - /// The `parent` must be within the same unit. - /// - /// # Panics - /// - /// Panics if `parent` is invalid. - #[inline] - pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId { - debug_assert_eq!(self.base_id, parent.base_id); - DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag) - } - - /// Get a reference to an entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry { - debug_assert_eq!(self.base_id, id.base_id); - &self.entries[id.index] - } - - /// Get a mutable reference to an entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry { - debug_assert_eq!(self.base_id, id.base_id); - &mut self.entries[id.index] - } - - /// Return true if `self.line_program` is used by a DIE. - fn line_program_in_use(&self) -> bool { - if self.line_program.is_none() { - return false; - } - if !self.line_program.is_empty() { - return true; - } - - for entry in &self.entries { - for attr in &entry.attrs { - if let AttributeValue::FileIndex(Some(_)) = attr.value { - return true; - } - } - } - - false - } - - /// Write the unit to the given sections. - pub(crate) fn write<W: Writer>( - &mut self, - sections: &mut Sections<W>, - abbrev_offset: DebugAbbrevOffset, - abbrevs: &mut AbbreviationTable, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - ) -> Result<UnitOffsets> { - let line_program = if self.line_program_in_use() { - self.entries[self.root.index] - .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); - Some(self.line_program.write( - &mut sections.debug_line, - self.encoding, - line_strings, - strings, - )?) - } else { - self.entries[self.root.index].delete(constants::DW_AT_stmt_list); - None - }; - - // TODO: use .debug_types for type units in DWARF v4. - let w = &mut sections.debug_info; - - let mut offsets = UnitOffsets { - base_id: self.base_id, - unit: w.offset(), - // Entries can be written in any order, so create the complete vec now. - entries: vec![EntryOffset::none(); self.entries.len()], - }; - - let length_offset = w.write_initial_length(self.format())?; - let length_base = w.len(); - - w.write_u16(self.version())?; - if 2 <= self.version() && self.version() <= 4 { - w.write_offset( - abbrev_offset.0, - SectionId::DebugAbbrev, - self.format().word_size(), - )?; - w.write_u8(self.address_size())?; - } else if self.version() == 5 { - w.write_u8(constants::DW_UT_compile.0)?; - w.write_u8(self.address_size())?; - w.write_offset( - abbrev_offset.0, - SectionId::DebugAbbrev, - self.format().word_size(), - )?; - } else { - return Err(Error::UnsupportedVersion(self.version())); - } - - // Calculate all DIE offsets, so that we are able to output references to them. - // However, references to base types in expressions use ULEB128, so base types - // must be moved to the front before we can calculate offsets. - self.reorder_base_types(); - let mut offset = w.len(); - self.entries[self.root.index].calculate_offsets( - self, - &mut offset, - &mut offsets, - abbrevs, - )?; - - let range_lists = self.ranges.write(sections, self.encoding)?; - // Location lists can't be written until we have DIE offsets. - let loc_lists = self - .locations - .write(sections, self.encoding, Some(&offsets))?; - - let w = &mut sections.debug_info; - let mut unit_refs = Vec::new(); - self.entries[self.root.index].write( - w, - &mut sections.debug_info_refs, - &mut unit_refs, - self, - &mut offsets, - line_program, - line_strings, - strings, - &range_lists, - &loc_lists, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, self.format())?; - - for (offset, entry) in unit_refs { - // This does not need relocation. - w.write_udata_at( - offset.0, - offsets.unit_offset(entry), - self.format().word_size(), - )?; - } - - Ok(offsets) - } - - /// Reorder base types to come first so that typed stack operations - /// can get their offset. - fn reorder_base_types(&mut self) { - let root = &self.entries[self.root.index]; - let mut root_children = Vec::with_capacity(root.children.len()); - for entry in &root.children { - if self.entries[entry.index].tag == constants::DW_TAG_base_type { - root_children.push(*entry); - } - } - for entry in &root.children { - if self.entries[entry.index].tag != constants::DW_TAG_base_type { - root_children.push(*entry); - } - } - self.entries[self.root.index].children = root_children; - } -} - -/// A Debugging Information Entry (DIE). -/// -/// DIEs have a set of attributes and optionally have children DIEs as well. -/// -/// DIEs form a tree without any cycles. This is enforced by specifying the -/// parent when creating a DIE, and disallowing changes of parent. -#[derive(Debug)] -pub struct DebuggingInformationEntry { - id: UnitEntryId, - parent: Option<UnitEntryId>, - tag: constants::DwTag, - /// Whether to emit `DW_AT_sibling`. - sibling: bool, - attrs: Vec<Attribute>, - children: Vec<UnitEntryId>, -} - -impl DebuggingInformationEntry { - /// Create a new `DebuggingInformationEntry`. - /// - /// # Panics - /// - /// Panics if `parent` is invalid. - #[allow(clippy::new_ret_no_self)] - fn new( - base_id: BaseId, - entries: &mut Vec<DebuggingInformationEntry>, - parent: Option<UnitEntryId>, - tag: constants::DwTag, - ) -> UnitEntryId { - let id = UnitEntryId::new(base_id, entries.len()); - entries.push(DebuggingInformationEntry { - id, - parent, - tag, - sibling: false, - attrs: Vec::new(), - children: Vec::new(), - }); - if let Some(parent) = parent { - debug_assert_eq!(base_id, parent.base_id); - assert_ne!(parent, id); - entries[parent.index].children.push(id); - } - id - } - - /// Return the id of this entry. - #[inline] - pub fn id(&self) -> UnitEntryId { - self.id - } - - /// Return the parent of this entry. - #[inline] - pub fn parent(&self) -> Option<UnitEntryId> { - self.parent - } - - /// Return the tag of this entry. - #[inline] - pub fn tag(&self) -> constants::DwTag { - self.tag - } - - /// Return `true` if a `DW_AT_sibling` attribute will be emitted. - #[inline] - pub fn sibling(&self) -> bool { - self.sibling - } - - /// Set whether a `DW_AT_sibling` attribute will be emitted. - /// - /// The attribute will only be emitted if the DIE has children. - #[inline] - pub fn set_sibling(&mut self, sibling: bool) { - self.sibling = sibling; - } - - /// Iterate over the attributes of this entry. - #[inline] - pub fn attrs(&self) -> slice::Iter<Attribute> { - self.attrs.iter() - } - - /// Iterate over the attributes of this entry for modification. - #[inline] - pub fn attrs_mut(&mut self) -> slice::IterMut<Attribute> { - self.attrs.iter_mut() - } - - /// Get an attribute. - pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> { - self.attrs - .iter() - .find(|attr| attr.name == name) - .map(|attr| &attr.value) - } - - /// Get an attribute for modification. - pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> { - self.attrs - .iter_mut() - .find(|attr| attr.name == name) - .map(|attr| &mut attr.value) - } - - /// Set an attribute. - /// - /// Replaces any existing attribute with the same name. - /// - /// # Panics - /// - /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead. - pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) { - assert_ne!(name, constants::DW_AT_sibling); - if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) { - attr.value = value; - return; - } - self.attrs.push(Attribute { name, value }); - } - - /// Delete an attribute. - /// - /// Replaces any existing attribute with the same name. - pub fn delete(&mut self, name: constants::DwAt) { - self.attrs.retain(|x| x.name != name); - } - - /// Iterate over the children of this entry. - /// - /// Note: use `Unit::add` to add a new child to this entry. - #[inline] - pub fn children(&self) -> slice::Iter<UnitEntryId> { - self.children.iter() - } - - /// Delete a child entry and all of its children. - pub fn delete_child(&mut self, id: UnitEntryId) { - self.children.retain(|&child| child != id); - } - - /// Return the type abbreviation for this DIE. - fn abbreviation(&self, encoding: Encoding) -> Result<Abbreviation> { - let mut attrs = Vec::new(); - - if self.sibling && !self.children.is_empty() { - let form = match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref4, - Format::Dwarf64 => constants::DW_FORM_ref8, - }; - attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form)); - } - - for attr in &self.attrs { - attrs.push(attr.specification(encoding)?); - } - - Ok(Abbreviation::new( - self.tag, - !self.children.is_empty(), - attrs, - )) - } - - fn calculate_offsets( - &self, - unit: &Unit, - offset: &mut usize, - offsets: &mut UnitOffsets, - abbrevs: &mut AbbreviationTable, - ) -> Result<()> { - offsets.entries[self.id.index].offset = DebugInfoOffset(*offset); - offsets.entries[self.id.index].abbrev = abbrevs.add(self.abbreviation(unit.encoding())?); - *offset += self.size(unit, offsets); - if !self.children.is_empty() { - for child in &self.children { - unit.entries[child.index].calculate_offsets(unit, offset, offsets, abbrevs)?; - } - // Null child - *offset += 1; - } - Ok(()) - } - - fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { - let mut size = uleb128_size(offsets.abbrev(self.id)); - if self.sibling && !self.children.is_empty() { - size += unit.format().word_size() as usize; - } - for attr in &self.attrs { - size += attr.value.size(unit, offsets); - } - size - } - - /// Write the entry to the given sections. - fn write<W: Writer>( - &self, - w: &mut DebugInfo<W>, - debug_info_refs: &mut Vec<DebugInfoReference>, - unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, - unit: &Unit, - offsets: &mut UnitOffsets, - line_program: Option<DebugLineOffset>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - range_lists: &RangeListOffsets, - loc_lists: &LocationListOffsets, - ) -> Result<()> { - debug_assert_eq!(offsets.debug_info_offset(self.id), w.offset()); - w.write_uleb128(offsets.abbrev(self.id))?; - - let sibling_offset = if self.sibling && !self.children.is_empty() { - let offset = w.offset(); - w.write_udata(0, unit.format().word_size())?; - Some(offset) - } else { - None - }; - - for attr in &self.attrs { - attr.value.write( - w, - debug_info_refs, - unit_refs, - unit, - offsets, - line_program, - line_strings, - strings, - range_lists, - loc_lists, - )?; - } - - if !self.children.is_empty() { - for child in &self.children { - unit.entries[child.index].write( - w, - debug_info_refs, - unit_refs, - unit, - offsets, - line_program, - line_strings, - strings, - range_lists, - loc_lists, - )?; - } - // Null child - w.write_u8(0)?; - } - - if let Some(offset) = sibling_offset { - let next_offset = (w.offset().0 - offsets.unit.0) as u64; - // This does not need relocation. - w.write_udata_at(offset.0, next_offset, unit.format().word_size())?; - } - Ok(()) - } -} - -/// An attribute in a `DebuggingInformationEntry`, consisting of a name and -/// associated value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Attribute { - name: constants::DwAt, - value: AttributeValue, -} - -impl Attribute { - /// Get the name of this attribute. - #[inline] - pub fn name(&self) -> constants::DwAt { - self.name - } - - /// Get the value of this attribute. - #[inline] - pub fn get(&self) -> &AttributeValue { - &self.value - } - - /// Set the value of this attribute. - #[inline] - pub fn set(&mut self, value: AttributeValue) { - self.value = value; - } - - /// Return the type specification for this attribute. - fn specification(&self, encoding: Encoding) -> Result<AttributeSpecification> { - Ok(AttributeSpecification::new( - self.name, - self.value.form(encoding)?, - )) - } -} - -/// The value of an attribute in a `DebuggingInformationEntry`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum AttributeValue { - /// "Refers to some location in the address space of the described program." - Address(Address), - - /// A slice of an arbitrary number of bytes. - Block(Vec<u8>), - - /// A one byte constant data value. How to interpret the byte depends on context. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data1(u8), - - /// A two byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data2(u16), - - /// A four byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data4(u32), - - /// An eight byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data8(u64), - - /// A signed integer constant. - Sdata(i64), - - /// An unsigned integer constant. - Udata(u64), - - /// "The information bytes contain a DWARF expression (see Section 2.5) or - /// location description (see Section 2.6)." - Exprloc(Expression), - - /// A boolean that indicates presence or absence of the attribute. - Flag(bool), - - /// An attribute that is always present. - FlagPresent, - - /// A reference to a `DebuggingInformationEntry` in this unit. - UnitRef(UnitEntryId), - - /// A reference to a `DebuggingInformationEntry` in a potentially different unit. - DebugInfoRef(Reference), - - /// An offset into the `.debug_info` section of the supplementary object file. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// supplementary object files is implemented. - DebugInfoRefSup(DebugInfoOffset), - - /// A reference to a line number program. - LineProgramRef, - - /// A reference to a location list. - LocationListRef(LocationListId), - - /// An offset into the `.debug_macinfo` section. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// `.debug_macinfo` sections is implemented. - DebugMacinfoRef(DebugMacinfoOffset), - - /// An offset into the `.debug_macro` section. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// `.debug_macro` sections is implemented. - DebugMacroRef(DebugMacroOffset), - - /// A reference to a range list. - RangeListRef(RangeListId), - - /// A type signature. - /// - /// The API does not currently assist with generating this signature. - /// This variant will be removed from the API once support for writing - /// `.debug_types` sections is implemented. - DebugTypesRef(DebugTypeSignature), - - /// A reference to a string in the `.debug_str` section. - StringRef(StringId), - - /// An offset into the `.debug_str` section of the supplementary object file. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// supplementary object files is implemented. - DebugStrRefSup(DebugStrOffset), - - /// A reference to a string in the `.debug_line_str` section. - LineStringRef(LineStringId), - - /// A slice of bytes representing a string. Must not include null bytes. - /// Not guaranteed to be UTF-8 or anything like that. - String(Vec<u8>), - - /// The value of a `DW_AT_encoding` attribute. - Encoding(constants::DwAte), - - /// The value of a `DW_AT_decimal_sign` attribute. - DecimalSign(constants::DwDs), - - /// The value of a `DW_AT_endianity` attribute. - Endianity(constants::DwEnd), - - /// The value of a `DW_AT_accessibility` attribute. - Accessibility(constants::DwAccess), - - /// The value of a `DW_AT_visibility` attribute. - Visibility(constants::DwVis), - - /// The value of a `DW_AT_virtuality` attribute. - Virtuality(constants::DwVirtuality), - - /// The value of a `DW_AT_language` attribute. - Language(constants::DwLang), - - /// The value of a `DW_AT_address_class` attribute. - AddressClass(constants::DwAddr), - - /// The value of a `DW_AT_identifier_case` attribute. - IdentifierCase(constants::DwId), - - /// The value of a `DW_AT_calling_convention` attribute. - CallingConvention(constants::DwCc), - - /// The value of a `DW_AT_inline` attribute. - Inline(constants::DwInl), - - /// The value of a `DW_AT_ordering` attribute. - Ordering(constants::DwOrd), - - /// An index into the filename entries from the line number information - /// table for the unit containing this value. - FileIndex(Option<FileId>), -} - -impl AttributeValue { - /// Return the form that will be used to encode this value. - pub fn form(&self, encoding: Encoding) -> Result<constants::DwForm> { - // TODO: missing forms: - // - DW_FORM_indirect - // - DW_FORM_implicit_const - // - FW_FORM_block1/block2/block4 - // - DW_FORM_str/strx1/strx2/strx3/strx4 - // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4 - // - DW_FORM_data16 - // - DW_FORM_line_strp - // - DW_FORM_loclistx - // - DW_FORM_rnglistx - let form = match *self { - AttributeValue::Address(_) => constants::DW_FORM_addr, - AttributeValue::Block(_) => constants::DW_FORM_block, - AttributeValue::Data1(_) => constants::DW_FORM_data1, - AttributeValue::Data2(_) => constants::DW_FORM_data2, - AttributeValue::Data4(_) => constants::DW_FORM_data4, - AttributeValue::Data8(_) => constants::DW_FORM_data8, - AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc, - AttributeValue::Flag(_) => constants::DW_FORM_flag, - AttributeValue::FlagPresent => constants::DW_FORM_flag_present, - AttributeValue::UnitRef(_) => { - // Using a fixed size format lets us write a placeholder before we know - // the value. - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref4, - Format::Dwarf64 => constants::DW_FORM_ref8, - } - } - AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr, - AttributeValue::DebugInfoRefSup(_) => { - // TODO: should this depend on the size of supplementary section? - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref_sup4, - Format::Dwarf64 => constants::DW_FORM_ref_sup8, - } - } - AttributeValue::LineProgramRef - | AttributeValue::LocationListRef(_) - | AttributeValue::DebugMacinfoRef(_) - | AttributeValue::DebugMacroRef(_) - | AttributeValue::RangeListRef(_) => { - if encoding.version == 2 || encoding.version == 3 { - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_data4, - Format::Dwarf64 => constants::DW_FORM_data8, - } - } else { - constants::DW_FORM_sec_offset - } - } - AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8, - AttributeValue::StringRef(_) => constants::DW_FORM_strp, - AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup, - AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp, - AttributeValue::String(_) => constants::DW_FORM_string, - AttributeValue::Encoding(_) - | AttributeValue::DecimalSign(_) - | AttributeValue::Endianity(_) - | AttributeValue::Accessibility(_) - | AttributeValue::Visibility(_) - | AttributeValue::Virtuality(_) - | AttributeValue::Language(_) - | AttributeValue::AddressClass(_) - | AttributeValue::IdentifierCase(_) - | AttributeValue::CallingConvention(_) - | AttributeValue::Inline(_) - | AttributeValue::Ordering(_) - | AttributeValue::FileIndex(_) - | AttributeValue::Udata(_) => constants::DW_FORM_udata, - AttributeValue::Sdata(_) => constants::DW_FORM_sdata, - }; - Ok(form) - } - - fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { - macro_rules! debug_assert_form { - ($form:expr) => { - debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) - }; - } - match *self { - AttributeValue::Address(_) => { - debug_assert_form!(constants::DW_FORM_addr); - unit.address_size() as usize - } - AttributeValue::Block(ref val) => { - debug_assert_form!(constants::DW_FORM_block); - uleb128_size(val.len() as u64) + val.len() - } - AttributeValue::Data1(_) => { - debug_assert_form!(constants::DW_FORM_data1); - 1 - } - AttributeValue::Data2(_) => { - debug_assert_form!(constants::DW_FORM_data2); - 2 - } - AttributeValue::Data4(_) => { - debug_assert_form!(constants::DW_FORM_data4); - 4 - } - AttributeValue::Data8(_) => { - debug_assert_form!(constants::DW_FORM_data8); - 8 - } - AttributeValue::Sdata(val) => { - debug_assert_form!(constants::DW_FORM_sdata); - sleb128_size(val) - } - AttributeValue::Udata(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val) - } - AttributeValue::Exprloc(ref val) => { - debug_assert_form!(constants::DW_FORM_exprloc); - let size = val.size(unit.encoding(), Some(offsets)); - uleb128_size(size as u64) + size - } - AttributeValue::Flag(_) => { - debug_assert_form!(constants::DW_FORM_flag); - 1 - } - AttributeValue::FlagPresent => { - debug_assert_form!(constants::DW_FORM_flag_present); - 0 - } - AttributeValue::UnitRef(_) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), - } - unit.format().word_size() as usize - } - AttributeValue::DebugInfoRef(_) => { - debug_assert_form!(constants::DW_FORM_ref_addr); - if unit.version() == 2 { - unit.address_size() as usize - } else { - unit.format().word_size() as usize - } - } - AttributeValue::DebugInfoRefSup(_) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), - } - unit.format().word_size() as usize - } - AttributeValue::LineProgramRef => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::LocationListRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugMacinfoRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugMacroRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::RangeListRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugTypesRef(_) => { - debug_assert_form!(constants::DW_FORM_ref_sig8); - 8 - } - AttributeValue::StringRef(_) => { - debug_assert_form!(constants::DW_FORM_strp); - unit.format().word_size() as usize - } - AttributeValue::DebugStrRefSup(_) => { - debug_assert_form!(constants::DW_FORM_strp_sup); - unit.format().word_size() as usize - } - AttributeValue::LineStringRef(_) => { - debug_assert_form!(constants::DW_FORM_line_strp); - unit.format().word_size() as usize - } - AttributeValue::String(ref val) => { - debug_assert_form!(constants::DW_FORM_string); - val.len() + 1 - } - AttributeValue::Encoding(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::DecimalSign(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Endianity(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Accessibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Visibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Virtuality(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Language(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::AddressClass(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::IdentifierCase(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::CallingConvention(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Inline(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Ordering(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::FileIndex(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.map(FileId::raw).unwrap_or(0)) - } - } - } - - /// Write the attribute value to the given sections. - fn write<W: Writer>( - &self, - w: &mut DebugInfo<W>, - debug_info_refs: &mut Vec<DebugInfoReference>, - unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, - unit: &Unit, - offsets: &UnitOffsets, - line_program: Option<DebugLineOffset>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - range_lists: &RangeListOffsets, - loc_lists: &LocationListOffsets, - ) -> Result<()> { - macro_rules! debug_assert_form { - ($form:expr) => { - debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) - }; - } - match *self { - AttributeValue::Address(val) => { - debug_assert_form!(constants::DW_FORM_addr); - w.write_address(val, unit.address_size())?; - } - AttributeValue::Block(ref val) => { - debug_assert_form!(constants::DW_FORM_block); - w.write_uleb128(val.len() as u64)?; - w.write(val)?; - } - AttributeValue::Data1(val) => { - debug_assert_form!(constants::DW_FORM_data1); - w.write_u8(val)?; - } - AttributeValue::Data2(val) => { - debug_assert_form!(constants::DW_FORM_data2); - w.write_u16(val)?; - } - AttributeValue::Data4(val) => { - debug_assert_form!(constants::DW_FORM_data4); - w.write_u32(val)?; - } - AttributeValue::Data8(val) => { - debug_assert_form!(constants::DW_FORM_data8); - w.write_u64(val)?; - } - AttributeValue::Sdata(val) => { - debug_assert_form!(constants::DW_FORM_sdata); - w.write_sleb128(val)?; - } - AttributeValue::Udata(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val)?; - } - AttributeValue::Exprloc(ref val) => { - debug_assert_form!(constants::DW_FORM_exprloc); - w.write_uleb128(val.size(unit.encoding(), Some(offsets)) as u64)?; - val.write( - &mut w.0, - Some(debug_info_refs), - unit.encoding(), - Some(offsets), - )?; - } - AttributeValue::Flag(val) => { - debug_assert_form!(constants::DW_FORM_flag); - w.write_u8(val as u8)?; - } - AttributeValue::FlagPresent => { - debug_assert_form!(constants::DW_FORM_flag_present); - } - AttributeValue::UnitRef(id) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), - } - unit_refs.push((w.offset(), id)); - w.write_udata(0, unit.format().word_size())?; - } - AttributeValue::DebugInfoRef(reference) => { - debug_assert_form!(constants::DW_FORM_ref_addr); - let size = if unit.version() == 2 { - unit.address_size() - } else { - unit.format().word_size() - }; - match reference { - Reference::Symbol(symbol) => w.write_reference(symbol, size)?, - Reference::Entry(unit, entry) => { - debug_info_refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - } - AttributeValue::DebugInfoRefSup(val) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), - } - w.write_udata(val.0 as u64, unit.format().word_size())?; - } - AttributeValue::LineProgramRef => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - match line_program { - Some(line_program) => { - w.write_offset( - line_program.0, - SectionId::DebugLine, - unit.format().word_size(), - )?; - } - None => return Err(Error::InvalidAttributeValue), - } - } - AttributeValue::LocationListRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - let section = if unit.version() <= 4 { - SectionId::DebugLoc - } else { - SectionId::DebugLocLists - }; - w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?; - } - AttributeValue::DebugMacinfoRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?; - } - AttributeValue::DebugMacroRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?; - } - AttributeValue::RangeListRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - let section = if unit.version() <= 4 { - SectionId::DebugRanges - } else { - SectionId::DebugRngLists - }; - w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?; - } - AttributeValue::DebugTypesRef(val) => { - debug_assert_form!(constants::DW_FORM_ref_sig8); - w.write_u64(val.0)?; - } - AttributeValue::StringRef(val) => { - debug_assert_form!(constants::DW_FORM_strp); - w.write_offset( - strings.get(val).0, - SectionId::DebugStr, - unit.format().word_size(), - )?; - } - AttributeValue::DebugStrRefSup(val) => { - debug_assert_form!(constants::DW_FORM_strp_sup); - w.write_udata(val.0 as u64, unit.format().word_size())?; - } - AttributeValue::LineStringRef(val) => { - debug_assert_form!(constants::DW_FORM_line_strp); - w.write_offset( - line_strings.get(val).0, - SectionId::DebugLineStr, - unit.format().word_size(), - )?; - } - AttributeValue::String(ref val) => { - debug_assert_form!(constants::DW_FORM_string); - w.write(val)?; - w.write_u8(0)?; - } - AttributeValue::Encoding(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::DecimalSign(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Endianity(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Accessibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Visibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Virtuality(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Language(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::AddressClass(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val.0)?; - } - AttributeValue::IdentifierCase(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::CallingConvention(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Inline(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Ordering(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::FileIndex(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val.map(FileId::raw).unwrap_or(0))?; - } - } - Ok(()) - } -} - -define_section!( - DebugInfo, - DebugInfoOffset, - "A writable `.debug_info` section." -); - -/// The section offsets of all elements within a `.debug_info` section. -#[derive(Debug, Default)] -pub struct DebugInfoOffsets { - base_id: BaseId, - units: Vec<UnitOffsets>, -} - -impl DebugInfoOffsets { - #[cfg(test)] - #[cfg(feature = "read")] - pub(crate) fn unit_offsets(&self, unit: UnitId) -> &UnitOffsets { - debug_assert_eq!(self.base_id, unit.base_id); - &self.units[unit.index] - } - - /// Get the `.debug_info` section offset for the given unit. - #[inline] - pub fn unit(&self, unit: UnitId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, unit.base_id); - self.units[unit.index].unit - } - - /// Get the `.debug_info` section offset for the given entry. - #[inline] - pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, unit.base_id); - self.units[unit.index].debug_info_offset(entry) - } -} - -/// The section offsets of all elements of a unit within a `.debug_info` section. -#[derive(Debug)] -pub(crate) struct UnitOffsets { - base_id: BaseId, - unit: DebugInfoOffset, - entries: Vec<EntryOffset>, -} - -impl UnitOffsets { - #[cfg(test)] - #[cfg(feature = "read")] - fn none() -> Self { - UnitOffsets { - base_id: BaseId::default(), - unit: DebugInfoOffset(0), - entries: Vec::new(), - } - } - - /// Get the .debug_info offset for the given entry. - #[inline] - pub(crate) fn debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, entry.base_id); - let offset = self.entries[entry.index].offset; - debug_assert_ne!(offset.0, 0); - offset - } - - /// Get the unit offset for the given entry. - #[inline] - pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> u64 { - let offset = self.debug_info_offset(entry); - (offset.0 - self.unit.0) as u64 - } - - /// Get the abbreviation code for the given entry. - #[inline] - pub(crate) fn abbrev(&self, entry: UnitEntryId) -> u64 { - debug_assert_eq!(self.base_id, entry.base_id); - self.entries[entry.index].abbrev - } -} - -#[derive(Debug, Clone, Copy)] -pub(crate) struct EntryOffset { - offset: DebugInfoOffset, - abbrev: u64, -} - -impl EntryOffset { - fn none() -> Self { - EntryOffset { - offset: DebugInfoOffset(0), - abbrev: 0, - } - } -} - -/// A reference to a `.debug_info` entry that has yet to be resolved. -#[derive(Debug, Clone, Copy)] -pub(crate) struct DebugInfoReference { - /// The offset within the section of the reference. - pub offset: usize, - /// The size of the reference. - pub size: u8, - /// The unit containing the entry. - pub unit: UnitId, - /// The entry being referenced. - pub entry: UnitEntryId, -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::common::{DwoId, UnitSectionOffset}; - use crate::read::{self, Reader}; - use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList}; - use std::collections::HashMap; - - pub(crate) struct ConvertUnit<R: Reader<Offset = usize>> { - from_unit: read::Unit<R>, - base_id: BaseId, - encoding: Encoding, - entries: Vec<DebuggingInformationEntry>, - entry_offsets: Vec<read::UnitOffset>, - root: UnitEntryId, - } - - pub(crate) struct ConvertUnitContext<'a, R: Reader<Offset = usize>> { - pub dwarf: &'a read::Dwarf<R>, - pub unit: &'a read::Unit<R>, - pub line_strings: &'a mut write::LineStringTable, - pub strings: &'a mut write::StringTable, - pub ranges: &'a mut write::RangeListTable, - pub locations: &'a mut write::LocationListTable, - pub convert_address: &'a dyn Fn(u64) -> Option<Address>, - pub base_address: Address, - pub line_program_offset: Option<DebugLineOffset>, - pub line_program_files: Vec<FileId>, - pub entry_ids: &'a HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - } - - impl UnitTable { - /// Create a unit table by reading the data in the given sections. - /// - /// This also updates the given tables with the values that are referenced from - /// attributes in this 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: Reader<Offset = usize>>( - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<UnitTable> { - let base_id = BaseId::default(); - let mut unit_entries = Vec::new(); - let mut entry_ids = HashMap::new(); - - let mut from_units = dwarf.units(); - while let Some(from_unit) = from_units.next()? { - let unit_id = UnitId::new(base_id, unit_entries.len()); - unit_entries.push(Unit::convert_entries( - from_unit, - unit_id, - &mut entry_ids, - dwarf, - )?); - } - - // Attributes must be converted in a separate pass so that we can handle - // references to other compilation units. - let mut units = Vec::new(); - for unit_entries in unit_entries.drain(..) { - units.push(Unit::convert_attributes( - unit_entries, - &entry_ids, - dwarf, - line_strings, - strings, - convert_address, - )?); - } - - Ok(UnitTable { base_id, units }) - } - } - - impl Unit { - /// Create a unit by reading the data in the input sections. - /// - /// Does not add entry attributes. - pub(crate) fn convert_entries<R: Reader<Offset = usize>>( - from_header: read::UnitHeader<R>, - unit_id: UnitId, - entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - dwarf: &read::Dwarf<R>, - ) -> ConvertResult<ConvertUnit<R>> { - match from_header.type_() { - read::UnitType::Compilation => (), - _ => return Err(ConvertError::UnsupportedUnitType), - } - let base_id = BaseId::default(); - - let from_unit = dwarf.unit(from_header)?; - let encoding = from_unit.encoding(); - - let mut entries = Vec::new(); - let mut entry_offsets = Vec::new(); - - let mut from_tree = from_unit.entries_tree(None)?; - let from_root = from_tree.root()?; - let root = DebuggingInformationEntry::convert_entry( - from_root, - &from_unit, - base_id, - &mut entries, - &mut entry_offsets, - entry_ids, - None, - unit_id, - )?; - - Ok(ConvertUnit { - from_unit, - base_id, - encoding, - entries, - entry_offsets, - root, - }) - } - - /// Create entry attributes by reading the data in the input sections. - fn convert_attributes<R: Reader<Offset = usize>>( - unit: ConvertUnit<R>, - entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Unit> { - let from_unit = unit.from_unit; - let base_address = - convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?; - - let (line_program_offset, line_program, line_program_files) = - match from_unit.line_program { - Some(ref from_program) => { - let from_program = from_program.clone(); - let line_program_offset = from_program.header().offset(); - let (line_program, line_program_files) = LineProgram::from( - from_program, - dwarf, - line_strings, - strings, - convert_address, - )?; - (Some(line_program_offset), line_program, line_program_files) - } - None => (None, LineProgram::none(), Vec::new()), - }; - - let mut ranges = RangeListTable::default(); - let mut locations = LocationListTable::default(); - - let mut context = ConvertUnitContext { - entry_ids, - dwarf, - unit: &from_unit, - line_strings, - strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address, - base_address, - line_program_offset, - line_program_files, - }; - - let mut entries = unit.entries; - for entry in &mut entries { - entry.convert_attributes(&mut context, &unit.entry_offsets)?; - } - - Ok(Unit { - base_id: unit.base_id, - encoding: unit.encoding, - line_program, - ranges, - locations, - entries, - root: unit.root, - }) - } - } - - impl DebuggingInformationEntry { - /// Create an entry by reading the data in the input sections. - /// - /// Does not add the entry attributes. - fn convert_entry<R: Reader<Offset = usize>>( - from: read::EntriesTreeNode<R>, - from_unit: &read::Unit<R>, - base_id: BaseId, - entries: &mut Vec<DebuggingInformationEntry>, - entry_offsets: &mut Vec<read::UnitOffset>, - entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - parent: Option<UnitEntryId>, - unit_id: UnitId, - ) -> ConvertResult<UnitEntryId> { - let from_entry = from.entry(); - let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag()); - let offset = from_entry.offset(); - entry_offsets.push(offset); - entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id)); - - let mut from_children = from.children(); - while let Some(from_child) = from_children.next()? { - DebuggingInformationEntry::convert_entry( - from_child, - from_unit, - base_id, - entries, - entry_offsets, - entry_ids, - Some(id), - unit_id, - )?; - } - Ok(id) - } - - /// Create an entry's attributes by reading the data in the input sections. - fn convert_attributes<R: Reader<Offset = usize>>( - &mut self, - context: &mut ConvertUnitContext<R>, - entry_offsets: &[read::UnitOffset], - ) -> ConvertResult<()> { - let offset = entry_offsets[self.id.index]; - let from = context.unit.entry(offset)?; - let mut from_attrs = from.attrs(); - while let Some(from_attr) = from_attrs.next()? { - if from_attr.name() == constants::DW_AT_sibling { - // This may point to a null entry, so we have to treat it differently. - self.set_sibling(true); - } else if let Some(attr) = Attribute::from(context, &from_attr)? { - self.set(attr.name, attr.value); - } - } - Ok(()) - } - } - - impl Attribute { - /// Create an attribute by reading the data in the given sections. - pub(crate) fn from<R: Reader<Offset = usize>>( - context: &mut ConvertUnitContext<R>, - from: &read::Attribute<R>, - ) -> ConvertResult<Option<Attribute>> { - let value = AttributeValue::from(context, from.value())?; - Ok(value.map(|value| Attribute { - name: from.name(), - value, - })) - } - } - - impl AttributeValue { - /// Create an attribute value by reading the data in the given sections. - pub(crate) fn from<R: Reader<Offset = usize>>( - context: &mut ConvertUnitContext<R>, - from: read::AttributeValue<R>, - ) -> ConvertResult<Option<AttributeValue>> { - let to = match from { - read::AttributeValue::Addr(val) => match (context.convert_address)(val) { - Some(val) => AttributeValue::Address(val), - None => return Err(ConvertError::InvalidAddress), - }, - read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()), - read::AttributeValue::Data1(val) => AttributeValue::Data1(val), - read::AttributeValue::Data2(val) => AttributeValue::Data2(val), - read::AttributeValue::Data4(val) => AttributeValue::Data4(val), - read::AttributeValue::Data8(val) => AttributeValue::Data8(val), - read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val), - read::AttributeValue::Udata(val) => AttributeValue::Udata(val), - read::AttributeValue::Exprloc(expression) => { - let expression = Expression::from( - expression, - context.unit.encoding(), - Some(context.dwarf), - Some(context.unit), - Some(context.entry_ids), - context.convert_address, - )?; - AttributeValue::Exprloc(expression) - } - // TODO: it would be nice to preserve the flag form. - read::AttributeValue::Flag(val) => AttributeValue::Flag(val), - read::AttributeValue::DebugAddrBase(_base) => { - // We convert all address indices to addresses, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugAddrIndex(index) => { - let val = context.dwarf.address(context.unit, index)?; - match (context.convert_address)(val) { - Some(val) => AttributeValue::Address(val), - None => return Err(ConvertError::InvalidAddress), - } - } - read::AttributeValue::UnitRef(val) => { - if !context.unit.header.is_valid_offset(val) { - return Err(ConvertError::InvalidUnitRef); - } - let id = context - .entry_ids - .get(&val.to_unit_section_offset(context.unit)) - .ok_or(ConvertError::InvalidUnitRef)?; - AttributeValue::UnitRef(id.1) - } - read::AttributeValue::DebugInfoRef(val) => { - // TODO: support relocation of this value - let id = context - .entry_ids - .get(&UnitSectionOffset::DebugInfoOffset(val)) - .ok_or(ConvertError::InvalidDebugInfoRef)?; - AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1)) - } - read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val), - read::AttributeValue::DebugLineRef(val) => { - // There should only be the line program in the CU DIE which we've already - // converted, so check if it matches that. - if Some(val) == context.line_program_offset { - AttributeValue::LineProgramRef - } else { - return Err(ConvertError::InvalidLineRef); - } - } - read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val), - read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val), - read::AttributeValue::LocationListsRef(val) => { - let iter = context - .dwarf - .locations - .raw_locations(val, context.unit.encoding())?; - let loc_list = LocationList::from(iter, context)?; - let loc_id = context.locations.add(loc_list); - AttributeValue::LocationListRef(loc_id) - } - read::AttributeValue::DebugLocListsBase(_base) => { - // We convert all location list indices to offsets, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugLocListsIndex(index) => { - let offset = context.dwarf.locations_offset(context.unit, index)?; - let iter = context - .dwarf - .locations - .raw_locations(offset, context.unit.encoding())?; - let loc_list = LocationList::from(iter, context)?; - let loc_id = context.locations.add(loc_list); - AttributeValue::LocationListRef(loc_id) - } - read::AttributeValue::RangeListsRef(offset) => { - let offset = context.dwarf.ranges_offset_from_raw(context.unit, offset); - let iter = context.dwarf.raw_ranges(context.unit, offset)?; - let range_list = RangeList::from(iter, context)?; - let range_id = context.ranges.add(range_list); - AttributeValue::RangeListRef(range_id) - } - read::AttributeValue::DebugRngListsBase(_base) => { - // We convert all range list indices to offsets, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugRngListsIndex(index) => { - let offset = context.dwarf.ranges_offset(context.unit, index)?; - let iter = context - .dwarf - .ranges - .raw_ranges(offset, context.unit.encoding())?; - let range_list = RangeList::from(iter, context)?; - let range_id = context.ranges.add(range_list); - AttributeValue::RangeListRef(range_id) - } - read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val), - read::AttributeValue::DebugStrRef(offset) => { - let r = context.dwarf.string(offset)?; - let id = context.strings.add(r.to_slice()?); - AttributeValue::StringRef(id) - } - read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val), - read::AttributeValue::DebugStrOffsetsBase(_base) => { - // We convert all string offsets to `.debug_str` references, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugStrOffsetsIndex(index) => { - let offset = context.dwarf.string_offset(context.unit, index)?; - let r = context.dwarf.string(offset)?; - let id = context.strings.add(r.to_slice()?); - AttributeValue::StringRef(id) - } - read::AttributeValue::DebugLineStrRef(offset) => { - let r = context.dwarf.line_string(offset)?; - let id = context.line_strings.add(r.to_slice()?); - AttributeValue::LineStringRef(id) - } - read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()), - read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val), - read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val), - read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val), - read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val), - read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val), - read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val), - read::AttributeValue::Language(val) => AttributeValue::Language(val), - read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val), - read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val), - read::AttributeValue::CallingConvention(val) => { - AttributeValue::CallingConvention(val) - } - read::AttributeValue::Inline(val) => AttributeValue::Inline(val), - read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val), - read::AttributeValue::FileIndex(val) => { - if val == 0 { - // 0 means not specified, even for version 5. - AttributeValue::FileIndex(None) - } else { - match context.line_program_files.get(val as usize) { - Some(id) => AttributeValue::FileIndex(Some(*id)), - None => return Err(ConvertError::InvalidFileIndex), - } - } - } - // Should always be a more specific section reference. - read::AttributeValue::SecOffset(_) => { - return Err(ConvertError::InvalidAttributeValue); - } - read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val), - }; - Ok(Some(to)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding, - }; - use crate::constants; - use crate::read; - use crate::write::{ - DebugLine, DebugLineStr, DebugStr, DwarfUnit, EndianVec, LineString, LineStringTable, - Location, LocationList, LocationListTable, Range, RangeList, RangeListOffsets, - RangeListTable, StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::mem; - use std::sync::Arc; - - #[test] - fn test_unit_table() { - let mut strings = StringTable::default(); - - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new( - Encoding { - version: 4, - address_size: 8, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - let unit2 = units.add(Unit::new( - Encoding { - version: 2, - address_size: 4, - format: Format::Dwarf64, - }, - LineProgram::none(), - )); - let unit3 = units.add(Unit::new( - Encoding { - version: 5, - address_size: 4, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - assert_eq!(units.count(), 3); - { - let unit1 = units.get_mut(unit_id1); - assert_eq!(unit1.version(), 4); - assert_eq!(unit1.address_size(), 8); - assert_eq!(unit1.format(), Format::Dwarf32); - assert_eq!(unit1.count(), 1); - - let root_id = unit1.root(); - assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0)); - { - let root = unit1.get_mut(root_id); - assert_eq!(root.id(), root_id); - assert!(root.parent().is_none()); - assert_eq!(root.tag(), constants::DW_TAG_compile_unit); - - // Test get/get_mut - assert!(root.get(constants::DW_AT_producer).is_none()); - assert!(root.get_mut(constants::DW_AT_producer).is_none()); - let mut producer = AttributeValue::String(b"root"[..].into()); - root.set(constants::DW_AT_producer, producer.clone()); - assert_eq!(root.get(constants::DW_AT_producer), Some(&producer)); - assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer)); - - // Test attrs - let mut attrs = root.attrs(); - let attr = attrs.next().unwrap(); - assert_eq!(attr.name(), constants::DW_AT_producer); - assert_eq!(attr.get(), &producer); - assert!(attrs.next().is_none()); - } - - let child1 = unit1.add(root_id, constants::DW_TAG_subprogram); - assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1)); - { - let child1 = unit1.get_mut(child1); - assert_eq!(child1.parent(), Some(root_id)); - - let tmp = AttributeValue::String(b"tmp"[..].into()); - child1.set(constants::DW_AT_name, tmp.clone()); - assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp)); - - // Test attrs_mut - let name = AttributeValue::StringRef(strings.add(&b"child1"[..])); - { - let attr = child1.attrs_mut().next().unwrap(); - assert_eq!(attr.name(), constants::DW_AT_name); - attr.set(name.clone()); - } - assert_eq!(child1.get(constants::DW_AT_name), Some(&name)); - } - - let child2 = unit1.add(root_id, constants::DW_TAG_subprogram); - assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2)); - { - let child2 = unit1.get_mut(child2); - assert_eq!(child2.parent(), Some(root_id)); - - let tmp = AttributeValue::String(b"tmp"[..].into()); - child2.set(constants::DW_AT_name, tmp.clone()); - assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp)); - - // Test replace - let name = AttributeValue::StringRef(strings.add(&b"child2"[..])); - child2.set(constants::DW_AT_name, name.clone()); - assert_eq!(child2.get(constants::DW_AT_name), Some(&name)); - } - - { - let root = unit1.get(root_id); - assert_eq!( - root.children().cloned().collect::<Vec<_>>(), - vec![child1, child2] - ); - } - } - { - let unit2 = units.get(unit2); - assert_eq!(unit2.version(), 2); - assert_eq!(unit2.address_size(), 4); - assert_eq!(unit2.format(), Format::Dwarf64); - assert_eq!(unit2.count(), 1); - - let root = unit2.root(); - assert_eq!(root, UnitEntryId::new(unit2.base_id, 0)); - let root = unit2.get(root); - assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0)); - assert!(root.parent().is_none()); - assert_eq!(root.tag(), constants::DW_TAG_compile_unit); - } - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap(); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_str); - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let dwarf = read::Dwarf { - debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), - debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), - debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian), - ..Default::default() - }; - let mut read_units = dwarf.units(); - - { - let read_unit1 = read_units.next().unwrap().unwrap(); - let unit1 = units.get(unit_id1); - assert_eq!(unit1.version(), read_unit1.version()); - assert_eq!(unit1.address_size(), read_unit1.address_size()); - assert_eq!(unit1.format(), read_unit1.format()); - - let read_unit1 = dwarf.unit(read_unit1).unwrap(); - let mut read_entries = read_unit1.entries(); - - let root = unit1.get(unit1.root()); - { - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(read_root.has_children()); - - let producer = match root.get(constants::DW_AT_producer).unwrap() { - AttributeValue::String(ref producer) => &**producer, - otherwise => panic!("unexpected {:?}", otherwise), - }; - assert_eq!(producer, b"root"); - let read_producer = read_root - .attr_value(constants::DW_AT_producer) - .unwrap() - .unwrap(); - assert_eq!( - dwarf - .attr_string(&read_unit1, read_producer) - .unwrap() - .slice(), - producer - ); - } - - let mut children = root.children().cloned(); - - { - let child = children.next().unwrap(); - assert_eq!(child, UnitEntryId::new(unit1.base_id, 1)); - let child = unit1.get(child); - let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 1); - assert_eq!(child.tag(), read_child.tag()); - assert!(!read_child.has_children()); - - let name = match child.get(constants::DW_AT_name).unwrap() { - AttributeValue::StringRef(name) => *name, - otherwise => panic!("unexpected {:?}", otherwise), - }; - let name = strings.get(name); - assert_eq!(name, b"child1"); - let read_name = read_child - .attr_value(constants::DW_AT_name) - .unwrap() - .unwrap(); - assert_eq!( - dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), - name - ); - } - - { - let child = children.next().unwrap(); - assert_eq!(child, UnitEntryId::new(unit1.base_id, 2)); - let child = unit1.get(child); - let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(child.tag(), read_child.tag()); - assert!(!read_child.has_children()); - - let name = match child.get(constants::DW_AT_name).unwrap() { - AttributeValue::StringRef(name) => *name, - otherwise => panic!("unexpected {:?}", otherwise), - }; - let name = strings.get(name); - assert_eq!(name, b"child2"); - let read_name = read_child - .attr_value(constants::DW_AT_name) - .unwrap() - .unwrap(); - assert_eq!( - dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), - name - ); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - { - let read_unit2 = read_units.next().unwrap().unwrap(); - let unit2 = units.get(unit2); - assert_eq!(unit2.version(), read_unit2.version()); - assert_eq!(unit2.address_size(), read_unit2.address_size()); - assert_eq!(unit2.format(), read_unit2.format()); - - let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); - let mut read_entries = read_unit2.entries(&abbrevs); - - { - let root = unit2.get(unit2.root()); - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(!read_root.has_children()); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - { - let read_unit3 = read_units.next().unwrap().unwrap(); - let unit3 = units.get(unit3); - assert_eq!(unit3.version(), read_unit3.version()); - assert_eq!(unit3.address_size(), read_unit3.address_size()); - assert_eq!(unit3.format(), read_unit3.format()); - - let abbrevs = dwarf.abbreviations(&read_unit3).unwrap(); - let mut read_entries = read_unit3.entries(&abbrevs); - - { - let root = unit3.get(unit3.root()); - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(!read_root.has_children()); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - assert!(read_units.next().unwrap().is_none()); - - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_units = UnitTable::from( - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - assert_eq!(convert_units.count(), units.count()); - - for i in 0..convert_units.count() { - let unit_id = units.id(i); - let unit = units.get(unit_id); - let convert_unit_id = convert_units.id(i); - let convert_unit = convert_units.get(convert_unit_id); - assert_eq!(convert_unit.version(), unit.version()); - assert_eq!(convert_unit.address_size(), unit.address_size()); - assert_eq!(convert_unit.format(), unit.format()); - assert_eq!(convert_unit.count(), unit.count()); - - let root = unit.get(unit.root()); - let convert_root = convert_unit.get(convert_unit.root()); - assert_eq!(convert_root.tag(), root.tag()); - for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { - assert_eq!(convert_attr, attr); - } - } - } - - #[test] - fn test_attribute_value() { - // Create a string table and a string with a non-zero id/offset. - let mut strings = StringTable::default(); - strings.add("string one"); - let string_id = strings.add("string two"); - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let debug_str_offsets = strings.write(&mut debug_str).unwrap(); - let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); - - let mut line_strings = LineStringTable::default(); - line_strings.add("line string one"); - let line_string_id = line_strings.add("line string two"); - let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); - let read_debug_line_str = - read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian)); - - let data = vec![1, 2, 3, 4]; - let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian); - - let mut expression = Expression::new(); - expression.op_constu(57); - let read_expression = read::Expression(read::EndianSlice::new( - &[constants::DW_OP_constu.0, 57], - LittleEndian, - )); - - let mut ranges = RangeListTable::default(); - let range_id = ranges.add(RangeList(vec![Range::StartEnd { - begin: Address::Constant(0x1234), - end: Address::Constant(0x2345), - }])); - - let mut locations = LocationListTable::default(); - let loc_id = locations.add(LocationList(vec![Location::StartEnd { - begin: Address::Constant(0x1234), - end: Address::Constant(0x2345), - data: expression.clone(), - }])); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); - let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap(); - - let read_debug_ranges = - read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); - let read_debug_rnglists = - read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); - - let read_debug_loc = - read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); - let read_debug_loclists = - read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); - - let mut units = UnitTable::default(); - let unit = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get(unit); - let encoding = Encoding { - format, - version, - address_size, - }; - let from_unit = read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ); - - for &(ref name, ref value, ref expect_value) in &[ - ( - constants::DW_AT_name, - AttributeValue::Address(Address::Constant(0x1234)), - read::AttributeValue::Addr(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Block(data.clone()), - read::AttributeValue::Block(read_data), - ), - ( - constants::DW_AT_name, - AttributeValue::Data1(0x12), - read::AttributeValue::Data1(0x12), - ), - ( - constants::DW_AT_name, - AttributeValue::Data2(0x1234), - read::AttributeValue::Data2(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Data4(0x1234), - read::AttributeValue::Data4(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Data8(0x1234), - read::AttributeValue::Data8(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Sdata(0x1234), - read::AttributeValue::Sdata(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Udata(0x1234), - read::AttributeValue::Udata(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Exprloc(expression.clone()), - read::AttributeValue::Exprloc(read_expression), - ), - ( - constants::DW_AT_name, - AttributeValue::Flag(false), - read::AttributeValue::Flag(false), - ), - /* - ( - constants::DW_AT_name, - AttributeValue::FlagPresent, - read::AttributeValue::Flag(true), - ), - */ - ( - constants::DW_AT_name, - AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), - read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), - ), - ( - constants::DW_AT_location, - AttributeValue::LocationListRef(loc_id), - read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0), - ), - ( - constants::DW_AT_macro_info, - AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)), - read::AttributeValue::SecOffset(0x1234), - ), - ( - constants::DW_AT_macros, - AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)), - read::AttributeValue::SecOffset(0x1234), - ), - ( - constants::DW_AT_ranges, - AttributeValue::RangeListRef(range_id), - read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0), - ), - ( - constants::DW_AT_name, - AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), - read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), - ), - ( - constants::DW_AT_name, - AttributeValue::StringRef(string_id), - read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), - ), - ( - constants::DW_AT_name, - AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), - read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), - ), - ( - constants::DW_AT_name, - AttributeValue::LineStringRef(line_string_id), - read::AttributeValue::DebugLineStrRef( - debug_line_str_offsets.get(line_string_id), - ), - ), - ( - constants::DW_AT_name, - AttributeValue::String(data.clone()), - read::AttributeValue::String(read_data), - ), - ( - constants::DW_AT_encoding, - AttributeValue::Encoding(constants::DwAte(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_decimal_sign, - AttributeValue::DecimalSign(constants::DwDs(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_endianity, - AttributeValue::Endianity(constants::DwEnd(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_accessibility, - AttributeValue::Accessibility(constants::DwAccess(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_visibility, - AttributeValue::Visibility(constants::DwVis(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_virtuality, - AttributeValue::Virtuality(constants::DwVirtuality(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_language, - AttributeValue::Language(constants::DwLang(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_address_class, - AttributeValue::AddressClass(constants::DwAddr(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_identifier_case, - AttributeValue::IdentifierCase(constants::DwId(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_calling_convention, - AttributeValue::CallingConvention(constants::DwCc(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_ordering, - AttributeValue::Ordering(constants::DwOrd(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_inline, - AttributeValue::Inline(constants::DwInl(0x12)), - read::AttributeValue::Udata(0x12), - ), - ][..] - { - let form = value.form(encoding).unwrap(); - let attr = Attribute { - name: *name, - value: value.clone(), - }; - - let offsets = UnitOffsets::none(); - let line_program_offset = None; - let mut debug_info_refs = Vec::new(); - let mut unit_refs = Vec::new(); - let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); - attr.value - .write( - &mut debug_info, - &mut debug_info_refs, - &mut unit_refs, - &unit, - &offsets, - line_program_offset, - &debug_line_str_offsets, - &debug_str_offsets, - &range_list_offsets, - &loc_list_offsets, - ) - .unwrap(); - - let spec = read::AttributeSpecification::new(*name, form, None); - let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); - let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap(); - let read_value = &read_attr.raw_value(); - // read::AttributeValue is invariant in the lifetime of R. - // The lifetimes here are all okay, so transmute it. - let read_value = unsafe { - mem::transmute::< - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - >(read_value) - }; - assert_eq!(read_value, expect_value); - - let dwarf = read::Dwarf { - debug_str: read_debug_str.clone(), - debug_line_str: read_debug_line_str.clone(), - ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists), - locations: read::LocationLists::new( - read_debug_loc, - read_debug_loclists, - ), - ..Default::default() - }; - - let unit = read::Unit { - header: from_unit, - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut context = convert::ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - - let convert_attr = - Attribute::from(&mut context, &read_attr).unwrap().unwrap(); - assert_eq!(convert_attr, attr); - } - } - } - } - } - - #[test] - fn test_unit_ref() { - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new( - Encoding { - version: 4, - address_size: 8, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - assert_eq!(unit_id1, units.id(0)); - let unit_id2 = units.add(Unit::new( - Encoding { - version: 2, - address_size: 4, - format: Format::Dwarf64, - }, - LineProgram::none(), - )); - assert_eq!(unit_id2, units.id(1)); - let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1); - let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2); - let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1); - let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2); - { - let unit1 = units.get_mut(unit_id1); - let root = unit1.root(); - let child_id1 = unit1.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id1, unit1_child1); - let child_id2 = unit1.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id2, unit1_child2); - { - let child1 = unit1.get_mut(child_id1); - child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); - } - { - let child2 = unit1.get_mut(child_id2); - child2.set( - constants::DW_AT_type, - AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)), - ); - } - } - { - let unit2 = units.get_mut(unit_id2); - let root = unit2.root(); - let child_id1 = unit2.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id1, unit2_child1); - let child_id2 = unit2.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id2, unit2_child2); - { - let child1 = unit2.get_mut(child_id1); - child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); - } - { - let child2 = unit2.get_mut(child_id2); - child2.set( - constants::DW_AT_type, - AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)), - ); - } - } - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_info_offsets = units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let dwarf = read::Dwarf { - debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), - debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), - ..Default::default() - }; - - let mut read_units = dwarf.units(); - { - let read_unit1 = read_units.next().unwrap().unwrap(); - assert_eq!( - read_unit1.offset(), - debug_info_offsets.unit(unit_id1).into() - ); - - let abbrevs = dwarf.abbreviations(&read_unit1).unwrap(); - let mut read_entries = read_unit1.entries(&abbrevs); - { - let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); - } - { - let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets - .entry(unit_id1, unit1_child2) - .to_unit_offset(&read_unit1) - .unwrap(); - assert_eq!( - read_child1.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::UnitRef(offset)) - ); - } - { - let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets.entry(unit_id2, unit2_child1); - assert_eq!( - read_child2.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::DebugInfoRef(offset)) - ); - } - } - { - let read_unit2 = read_units.next().unwrap().unwrap(); - assert_eq!( - read_unit2.offset(), - debug_info_offsets.unit(unit_id2).into() - ); - - let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); - let mut read_entries = read_unit2.entries(&abbrevs); - { - let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); - } - { - let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets - .entry(unit_id2, unit2_child2) - .to_unit_offset(&read_unit2) - .unwrap(); - assert_eq!( - read_child1.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::UnitRef(offset)) - ); - } - { - let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets.entry(unit_id1, unit1_child1); - assert_eq!( - read_child2.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::DebugInfoRef(offset)) - ); - } - } - - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_units = UnitTable::from( - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - assert_eq!(convert_units.count(), units.count()); - - for i in 0..convert_units.count() { - let unit = units.get(units.id(i)); - let convert_unit = convert_units.get(convert_units.id(i)); - assert_eq!(convert_unit.version(), unit.version()); - assert_eq!(convert_unit.address_size(), unit.address_size()); - assert_eq!(convert_unit.format(), unit.format()); - assert_eq!(convert_unit.count(), unit.count()); - - let root = unit.get(unit.root()); - let convert_root = convert_unit.get(convert_unit.root()); - assert_eq!(convert_root.tag(), root.tag()); - for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { - assert_eq!(convert_attr, attr); - } - - let child1 = unit.get(UnitEntryId::new(unit.base_id, 1)); - let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1)); - assert_eq!(convert_child1.tag(), child1.tag()); - for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) { - assert_eq!(convert_attr.name, attr.name); - match (convert_attr.value.clone(), attr.value.clone()) { - ( - AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), - AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), - ) => { - assert_eq!(convert_unit.index, unit.index); - assert_eq!(convert_entry.index, entry.index); - } - (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { - assert_eq!(convert_id.index, id.index); - } - (convert_value, value) => assert_eq!(convert_value, value), - } - } - - let child2 = unit.get(UnitEntryId::new(unit.base_id, 2)); - let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2)); - assert_eq!(convert_child2.tag(), child2.tag()); - for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) { - assert_eq!(convert_attr.name, attr.name); - match (convert_attr.value.clone(), attr.value.clone()) { - ( - AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), - AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), - ) => { - assert_eq!(convert_unit.index, unit.index); - assert_eq!(convert_entry.index, entry.index); - } - (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { - assert_eq!(convert_id.index, id.index); - } - (convert_value, value) => assert_eq!(convert_value, value), - } - } - } - } - - #[test] - fn test_sibling() { - fn add_child( - unit: &mut Unit, - parent: UnitEntryId, - tag: constants::DwTag, - name: &str, - ) -> UnitEntryId { - let id = unit.add(parent, tag); - let child = unit.get_mut(id); - child.set(constants::DW_AT_name, AttributeValue::String(name.into())); - child.set_sibling(true); - id - } - - fn add_children(units: &mut UnitTable, unit_id: UnitId) { - let unit = units.get_mut(unit_id); - let root = unit.root(); - let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1"); - add_child(unit, child1, constants::DW_TAG_variable, "grandchild1"); - add_child(unit, root, constants::DW_TAG_subprogram, "child2"); - add_child(unit, root, constants::DW_TAG_subprogram, "child3"); - } - - fn next_child<R: read::Reader<Offset = usize>>( - entries: &mut read::EntriesCursor<R>, - ) -> (read::UnitOffset, Option<read::UnitOffset>) { - let (_, entry) = entries.next_dfs().unwrap().unwrap(); - let offset = entry.offset(); - let sibling = - entry - .attr_value(constants::DW_AT_sibling) - .unwrap() - .map(|attr| match attr { - read::AttributeValue::UnitRef(offset) => offset, - _ => panic!("bad sibling value"), - }); - (offset, sibling) - } - - fn check_sibling<R: read::Reader<Offset = usize>>( - unit: &read::UnitHeader<R>, - debug_abbrev: &read::DebugAbbrev<R>, - ) { - let abbrevs = unit.abbreviations(debug_abbrev).unwrap(); - let mut entries = unit.entries(&abbrevs); - // root - entries.next_dfs().unwrap().unwrap(); - // child1 - let (_, sibling1) = next_child(&mut entries); - // grandchild1 - entries.next_dfs().unwrap().unwrap(); - // child2 - let (offset2, sibling2) = next_child(&mut entries); - // child3 - let (_, _) = next_child(&mut entries); - assert_eq!(sibling1, Some(offset2)); - assert_eq!(sibling2, None); - } - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new(encoding, LineProgram::none())); - add_children(&mut units, unit_id1); - let unit_id2 = units.add(Unit::new(encoding, LineProgram::none())); - add_children(&mut units, unit_id2); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian); - let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian); - let mut read_units = read_debug_info.units(); - check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); - check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); - } - - #[test] - fn test_line_ref() { - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - // The line program we'll be referencing. - let mut line_program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"comp_dir".to_vec()), - LineString::String(b"comp_name".to_vec()), - None, - ); - let dir = line_program.default_directory(); - let file1 = - line_program.add_file(LineString::String(b"file1".to_vec()), dir, None); - let file2 = - line_program.add_file(LineString::String(b"file2".to_vec()), dir, None); - - // Write, read, and convert the line program, so that we have the info - // required to convert the attributes. - let line_strings = DebugLineStrOffsets::none(); - let strings = DebugStrOffsets::none(); - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let line_program_offset = line_program - .write(&mut debug_line, encoding, &line_strings, &strings) - .unwrap(); - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_line_program = read_debug_line - .program( - line_program_offset, - address_size, - Some(read::EndianSlice::new(b"comp_dir", LittleEndian)), - Some(read::EndianSlice::new(b"comp_name", LittleEndian)), - ) - .unwrap(); - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (_, line_program_files) = LineProgram::from( - read_line_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - - // Fake the unit. - let mut units = UnitTable::default(); - let unit = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get(unit); - let from_unit = read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ); - - for &(ref name, ref value, ref expect_value) in &[ - ( - constants::DW_AT_stmt_list, - AttributeValue::LineProgramRef, - read::AttributeValue::SecOffset(line_program_offset.0), - ), - ( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(Some(file1)), - read::AttributeValue::Udata(file1.raw()), - ), - ( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(Some(file2)), - read::AttributeValue::Udata(file2.raw()), - ), - ][..] - { - let mut ranges = RangeListTable::default(); - let mut locations = LocationListTable::default(); - let mut strings = StringTable::default(); - let mut line_strings = LineStringTable::default(); - - let form = value.form(encoding).unwrap(); - let attr = Attribute { - name: *name, - value: value.clone(), - }; - - let mut debug_info_refs = Vec::new(); - let mut unit_refs = Vec::new(); - let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); - let offsets = UnitOffsets::none(); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let range_list_offsets = RangeListOffsets::none(); - let loc_list_offsets = LocationListOffsets::none(); - attr.value - .write( - &mut debug_info, - &mut debug_info_refs, - &mut unit_refs, - &unit, - &offsets, - Some(line_program_offset), - &debug_line_str_offsets, - &debug_str_offsets, - &range_list_offsets, - &loc_list_offsets, - ) - .unwrap(); - - let spec = read::AttributeSpecification::new(*name, form, None); - let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); - let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap(); - let read_value = &read_attr.raw_value(); - // read::AttributeValue is invariant in the lifetime of R. - // The lifetimes here are all okay, so transmute it. - let read_value = unsafe { - mem::transmute::< - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - >(read_value) - }; - assert_eq!(read_value, expect_value); - - let unit = read::Unit { - header: from_unit, - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut context = convert::ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: Some(line_program_offset), - line_program_files: line_program_files.clone(), - entry_ids: &HashMap::new(), - }; - - let convert_attr = - Attribute::from(&mut context, &read_attr).unwrap().unwrap(); - assert_eq!(convert_attr, attr); - } - } - } - } - } - - #[test] - fn test_line_program_used() { - for used in vec![false, true] { - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - - let line_program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"comp_dir".to_vec()), - LineString::String(b"comp_name".to_vec()), - None, - ); - - let mut unit = Unit::new(encoding, line_program); - let file_id = if used { Some(FileId::new(0)) } else { None }; - let root = unit.root(); - unit.get_mut(root).set( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(file_id), - ); - - let mut units = UnitTable::default(); - units.add(unit); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - assert_eq!(!used, sections.debug_line.slice().is_empty()); - } - } - - #[test] - fn test_delete_child() { - fn set_name(unit: &mut Unit, id: UnitEntryId, name: &str) { - let entry = unit.get_mut(id); - entry.set(constants::DW_AT_name, AttributeValue::String(name.into())); - } - fn check_name<R: read::Reader>( - entry: &read::DebuggingInformationEntry<R>, - debug_str: &read::DebugStr<R>, - name: &str, - ) { - let name_attr = entry.attr(constants::DW_AT_name).unwrap().unwrap(); - let entry_name = name_attr.string_value(debug_str).unwrap(); - let entry_name_str = entry_name.to_string().unwrap(); - assert_eq!(entry_name_str, name); - } - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut dwarf = DwarfUnit::new(encoding); - let root = dwarf.unit.root(); - - // Add and delete entries in the root unit - let child1 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child1, "child1"); - let grandchild1 = dwarf.unit.add(child1, constants::DW_TAG_variable); - set_name(&mut dwarf.unit, grandchild1, "grandchild1"); - let child2 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child2, "child2"); - // This deletes both `child1` and its child `grandchild1` - dwarf.unit.get_mut(root).delete_child(child1); - let child3 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child3, "child3"); - let child4 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child4, "child4"); - let grandchild4 = dwarf.unit.add(child4, constants::DW_TAG_variable); - set_name(&mut dwarf.unit, grandchild4, "grandchild4"); - dwarf.unit.get_mut(child4).delete_child(grandchild4); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - - // Write DWARF data which should only include `child2`, `child3` and `child4` - dwarf.write(&mut sections).unwrap(); - - let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian); - let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian); - let read_debug_str = read::DebugStr::new(sections.debug_str.slice(), LittleEndian); - let read_unit = read_debug_info.units().next().unwrap().unwrap(); - let abbrevs = read_unit.abbreviations(&read_debug_abbrev).unwrap(); - let mut entries = read_unit.entries(&abbrevs); - // root - entries.next_dfs().unwrap().unwrap(); - // child2 - let (_, read_child2) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child2, &read_debug_str, "child2"); - // child3 - let (_, read_child3) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child3, &read_debug_str, "child3"); - // child4 - let (_, read_child4) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child4, &read_debug_str, "child4"); - // There should be no more entries - assert!(entries.next_dfs().unwrap().is_none()); - } -} diff --git a/vendor/gimli/src/write/writer.rs b/vendor/gimli/src/write/writer.rs deleted file mode 100644 index 1ce3641..0000000 --- a/vendor/gimli/src/write/writer.rs +++ /dev/null @@ -1,494 +0,0 @@ -use crate::common::{Format, SectionId}; -use crate::constants; -use crate::endianity::Endianity; -use crate::leb128; -use crate::write::{Address, Error, Result}; - -/// A trait for writing the data to a DWARF section. -/// -/// All write operations append to the section unless otherwise specified. -#[allow(clippy::len_without_is_empty)] -pub trait Writer { - /// The endianity of bytes that are written. - type Endian: Endianity; - - /// Return the endianity of bytes that are written. - fn endian(&self) -> Self::Endian; - - /// Return the current section length. - /// - /// This may be used as an offset for future `write_at` calls. - fn len(&self) -> usize; - - /// Write a slice. - fn write(&mut self, bytes: &[u8]) -> Result<()>; - - /// Write a slice at a given offset. - /// - /// The write must not extend past the current section length. - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; - - /// Write an address. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - // TODO: use write_reference instead? - fn write_address(&mut self, address: Address, size: u8) -> Result<()> { - match address { - Address::Constant(val) => self.write_udata(val, size), - Address::Symbol { .. } => Err(Error::InvalidAddress), - } - } - - /// Write an address with a `.eh_frame` pointer encoding. - /// - /// The given size is only used for `DW_EH_PE_absptr` formats. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_eh_pointer( - &mut self, - address: Address, - eh_pe: constants::DwEhPe, - size: u8, - ) -> Result<()> { - match address { - Address::Constant(val) => { - // Indirect doesn't matter here. - let val = match eh_pe.application() { - constants::DW_EH_PE_absptr => val, - constants::DW_EH_PE_pcrel => { - // TODO: better handling of sign - let offset = self.len() as u64; - val.wrapping_sub(offset) - } - _ => { - return Err(Error::UnsupportedPointerEncoding(eh_pe)); - } - }; - self.write_eh_pointer_data(val, eh_pe.format(), size) - } - Address::Symbol { .. } => Err(Error::InvalidAddress), - } - } - - /// Write a value with a `.eh_frame` pointer format. - /// - /// The given size is only used for `DW_EH_PE_absptr` formats. - /// - /// This must not be used directly for values that may require relocation. - fn write_eh_pointer_data( - &mut self, - val: u64, - format: constants::DwEhPe, - size: u8, - ) -> Result<()> { - match format { - constants::DW_EH_PE_absptr => self.write_udata(val, size), - constants::DW_EH_PE_uleb128 => self.write_uleb128(val), - constants::DW_EH_PE_udata2 => self.write_udata(val, 2), - constants::DW_EH_PE_udata4 => self.write_udata(val, 4), - constants::DW_EH_PE_udata8 => self.write_udata(val, 8), - constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64), - constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2), - constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4), - constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8), - _ => Err(Error::UnsupportedPointerEncoding(format)), - } - } - - /// Write an offset that is relative to the start of the given section. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> { - self.write_udata(val as u64, size) - } - - /// Write an offset that is relative to the start of the given section. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_offset_at( - &mut self, - offset: usize, - val: usize, - _section: SectionId, - size: u8, - ) -> Result<()> { - self.write_udata_at(offset, val as u64, size) - } - - /// Write a reference to a symbol. - /// - /// If the writer supports symbols, then it must provide its own implementation - /// of this method. - fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> { - Err(Error::InvalidReference) - } - - /// Write a u8. - fn write_u8(&mut self, val: u8) -> Result<()> { - let bytes = [val]; - self.write(&bytes) - } - - /// Write a u16. - fn write_u16(&mut self, val: u16) -> Result<()> { - let mut bytes = [0; 2]; - self.endian().write_u16(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u32. - fn write_u32(&mut self, val: u32) -> Result<()> { - let mut bytes = [0; 4]; - self.endian().write_u32(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u64. - fn write_u64(&mut self, val: u64) -> Result<()> { - let mut bytes = [0; 8]; - self.endian().write_u64(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u8 at the given offset. - fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> { - let bytes = [val]; - self.write_at(offset, &bytes) - } - - /// Write a u16 at the given offset. - fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> { - let mut bytes = [0; 2]; - self.endian().write_u16(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write a u32 at the given offset. - fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> { - let mut bytes = [0; 4]; - self.endian().write_u32(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write a u64 at the given offset. - fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> { - let mut bytes = [0; 8]; - self.endian().write_u64(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write unsigned data of the given size. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_udata(&mut self, val: u64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as u8; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8(write_val) - } - 2 => { - let write_val = val as u16; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16(write_val) - } - 4 => { - let write_val = val as u32; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32(write_val) - } - 8 => self.write_u64(val), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write signed data of the given size. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as i8; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8(write_val as u8) - } - 2 => { - let write_val = val as i16; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16(write_val as u16) - } - 4 => { - let write_val = val as i32; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32(write_val as u32) - } - 8 => self.write_u64(val as u64), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write a word of the given size at the given offset. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as u8; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8_at(offset, write_val) - } - 2 => { - let write_val = val as u16; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16_at(offset, write_val) - } - 4 => { - let write_val = val as u32; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32_at(offset, write_val) - } - 8 => self.write_u64_at(offset, val), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write an unsigned LEB128 encoded integer. - fn write_uleb128(&mut self, val: u64) -> Result<()> { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); - self.write(&bytes[..len]) - } - - /// Read an unsigned LEB128 encoded integer. - fn write_sleb128(&mut self, val: i64) -> Result<()> { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap(); - self.write(&bytes[..len]) - } - - /// Write an initial length according to the given DWARF format. - /// - /// This will only write a length of zero, since the length isn't - /// known yet, and a subsequent call to `write_initial_length_at` - /// will write the actual length. - fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> { - if format == Format::Dwarf64 { - self.write_u32(0xffff_ffff)?; - } - let offset = InitialLengthOffset(self.len()); - self.write_udata(0, format.word_size())?; - Ok(offset) - } - - /// Write an initial length at the given offset according to the given DWARF format. - /// - /// `write_initial_length` must have previously returned the offset. - fn write_initial_length_at( - &mut self, - offset: InitialLengthOffset, - length: u64, - format: Format, - ) -> Result<()> { - self.write_udata_at(offset.0, length, format.word_size()) - } -} - -/// The offset at which an initial length should be written. -#[derive(Debug, Clone, Copy)] -pub struct InitialLengthOffset(usize); - -#[cfg(test)] -mod tests { - use super::*; - use crate::write; - use crate::{BigEndian, LittleEndian}; - use std::{i64, u64}; - - #[test] - fn test_writer() { - let mut w = write::EndianVec::new(LittleEndian); - w.write_address(Address::Constant(0x1122_3344), 4).unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - assert_eq!( - w.write_address( - Address::Symbol { - symbol: 0, - addend: 0 - }, - 4 - ), - Err(Error::InvalidAddress) - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_offset(0x1122_3344, SectionId::DebugInfo, 4) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_u8(0x11).unwrap(); - w.write_u16(0x2233).unwrap(); - w.write_u32(0x4455_6677).unwrap(); - w.write_u64(0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x33, 0x22, - 0x77, 0x66, 0x55, 0x44, - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - ]); - w.write_u8_at(14, 0x11).unwrap(); - w.write_u16_at(12, 0x2233).unwrap(); - w.write_u32_at(8, 0x4455_6677).unwrap(); - w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - 0x77, 0x66, 0x55, 0x44, - 0x33, 0x22, - 0x11, - ]); - - let mut w = write::EndianVec::new(BigEndian); - w.write_u8(0x11).unwrap(); - w.write_u16(0x2233).unwrap(); - w.write_u32(0x4455_6677).unwrap(); - w.write_u64(0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x22, 0x33, - 0x44, 0x55, 0x66, 0x77, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - ]); - w.write_u8_at(14, 0x11).unwrap(); - w.write_u16_at(12, 0x2233).unwrap(); - w.write_u32_at(8, 0x4455_6677).unwrap(); - w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x44, 0x55, 0x66, 0x77, - 0x22, 0x33, - 0x11, - ]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_udata(0x11, 1).unwrap(); - w.write_udata(0x2233, 2).unwrap(); - w.write_udata(0x4455_6677, 4).unwrap(); - w.write_udata(0x8081_8283_8485_8687, 8).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x33, 0x22, - 0x77, 0x66, 0x55, 0x44, - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - ]); - assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3))); - w.write_udata_at(14, 0x11, 1).unwrap(); - w.write_udata_at(12, 0x2233, 2).unwrap(); - w.write_udata_at(8, 0x4455_6677, 4).unwrap(); - w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - 0x77, 0x66, 0x55, 0x44, - 0x33, 0x22, - 0x11, - ]); - assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge)); - assert_eq!( - w.write_udata_at(0, 0x1_0000_0000, 4), - Err(Error::ValueTooLarge) - ); - assert_eq!( - w.write_udata_at(0, 0x00, 3), - Err(Error::UnsupportedWordSize(3)) - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_uleb128(0).unwrap(); - assert_eq!(w.slice(), &[0]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_uleb128(u64::MAX).unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1] - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(0).unwrap(); - assert_eq!(w.slice(), &[0]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(i64::MAX).unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0] - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(i64::MIN).unwrap(); - assert_eq!( - w.slice(), - &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f] - ); - - let mut w = write::EndianVec::new(LittleEndian); - let offset = w.write_initial_length(Format::Dwarf32).unwrap(); - assert_eq!(w.slice(), &[0, 0, 0, 0]); - w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - assert_eq!( - w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32), - Err(Error::ValueTooLarge) - ); - - let mut w = write::EndianVec::new(LittleEndian); - let offset = w.write_initial_length(Format::Dwarf64).unwrap(); - assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]); - w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64) - .unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11] - ); - } -} |