diff options
Diffstat (limited to 'vendor/gimli/src/write/unit.rs')
-rw-r--r-- | vendor/gimli/src/write/unit.rs | 3152 |
1 files changed, 0 insertions, 3152 deletions
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()); - } -} |