Skip to main content

gimli/write/
unit.rs

1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3use core::slice;
4
5use crate::common::{
6    DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset,
7    DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId,
8};
9use crate::constants;
10use crate::leb128::write::{sleb128_size, uleb128_size};
11use crate::write::{
12    Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, Error, Expression,
13    FileId, LineProgram, LineStringId, LineStringTable, LocationListId, LocationListOffsets,
14    LocationListTable, RangeListId, RangeListOffsets, RangeListTable, Result, Section, Sections,
15    StringId, StringTable, Writer,
16};
17
18define_id!(UnitId, "An identifier for a unit in a `UnitTable`.");
19
20define_id!(UnitEntryId, "An identifier for an entry in a `Unit`.");
21
22/// A table of units that will be stored in the `.debug_info` section.
23#[derive(Debug, Default)]
24pub struct UnitTable {
25    base_id: BaseId,
26    units: Vec<Unit>,
27}
28
29impl UnitTable {
30    /// Create a new unit and add it to the table.
31    ///
32    /// `address_size` must be in bytes.
33    ///
34    /// Returns the `UnitId` of the new unit.
35    #[inline]
36    pub fn add(&mut self, unit: Unit) -> UnitId {
37        let id = UnitId::new(self.base_id, self.units.len());
38        self.units.push(unit);
39        id
40    }
41
42    /// Return the number of units.
43    #[inline]
44    pub fn count(&self) -> usize {
45        self.units.len()
46    }
47
48    /// Return the id of a unit.
49    ///
50    /// # Panics
51    ///
52    /// Panics if `index >= self.count()`.
53    #[inline]
54    pub fn id(&self, index: usize) -> UnitId {
55        assert!(index < self.count());
56        UnitId::new(self.base_id, index)
57    }
58
59    /// Get a reference to a unit.
60    ///
61    /// # Panics
62    ///
63    /// Panics if `id` is invalid.
64    #[inline]
65    pub fn get(&self, id: UnitId) -> &Unit {
66        debug_assert_eq!(self.base_id, id.base_id);
67        &self.units[id.index]
68    }
69
70    /// Get a mutable reference to a unit.
71    ///
72    /// # Panics
73    ///
74    /// Panics if `id` is invalid.
75    #[inline]
76    pub fn get_mut(&mut self, id: UnitId) -> &mut Unit {
77        debug_assert_eq!(self.base_id, id.base_id);
78        &mut self.units[id.index]
79    }
80
81    /// Get an iterator for the units.
82    pub fn iter(&self) -> impl Iterator<Item = (UnitId, &Unit)> {
83        self.units
84            .iter()
85            .enumerate()
86            .map(move |(index, unit)| (UnitId::new(self.base_id, index), unit))
87    }
88
89    /// Get a mutable iterator for the units.
90    pub fn iter_mut(&mut self) -> impl Iterator<Item = (UnitId, &mut Unit)> {
91        let base_id = self.base_id;
92        self.units
93            .iter_mut()
94            .enumerate()
95            .map(move |(index, unit)| (UnitId::new(base_id, index), unit))
96    }
97
98    /// Write the units to the given sections.
99    pub fn write<W: Writer>(
100        &mut self,
101        sections: &mut Sections<W>,
102        line_strings: &mut LineStringTable,
103        strings: &mut StringTable,
104    ) -> Result<()> {
105        for unit in &mut self.units {
106            if unit.written {
107                continue;
108            }
109
110            // TODO: maybe share abbreviation tables
111            let abbrev_offset = sections.debug_abbrev.offset();
112            let mut abbrevs = AbbreviationTable::default();
113
114            unit.write(sections, abbrev_offset, &mut abbrevs, line_strings, strings)?;
115
116            abbrevs.write(&mut sections.debug_abbrev)?;
117        }
118
119        self.write_debug_info_fixups(&mut sections.debug_info_fixups, &mut sections.debug_info.0)?;
120        self.write_debug_info_fixups(&mut sections.debug_loc_fixups, &mut sections.debug_loc.0)?;
121        self.write_debug_info_fixups(
122            &mut sections.debug_loclists_fixups,
123            &mut sections.debug_loclists.0,
124        )?;
125
126        Ok(())
127    }
128
129    fn write_debug_info_fixups<W: Writer>(
130        &self,
131        fixups: &mut Vec<DebugInfoFixup>,
132        w: &mut W,
133    ) -> Result<()> {
134        for fixup in fixups.drain(..) {
135            debug_assert_eq!(self.base_id, fixup.unit.base_id);
136            let entry_offset = self.units[fixup.unit.index]
137                .offsets
138                .debug_info_offset(fixup.entry)
139                .ok_or(Error::InvalidReference)?
140                .0;
141            w.write_offset_at(fixup.offset, entry_offset, SectionId::DebugInfo, fixup.size)?;
142        }
143        Ok(())
144    }
145}
146
147/// A unit's debugging information.
148#[derive(Debug)]
149pub struct Unit {
150    base_id: BaseId,
151    /// The encoding parameters for this unit.
152    encoding: Encoding,
153    /// The line number program for this unit.
154    pub line_program: LineProgram,
155    /// A table of range lists used by this unit.
156    pub ranges: RangeListTable,
157    /// A table of location lists used by this unit.
158    pub locations: LocationListTable,
159    /// All entries in this unit. The order is unrelated to the tree order.
160    // Requirements:
161    // - entries form a tree
162    // - entries can be added in any order
163    // - entries have a fixed id
164    // - able to quickly lookup an entry from its id
165    // Limitations of current implementation:
166    // - mutable iteration of children is messy due to borrow checker
167    entries: Vec<DebuggingInformationEntry>,
168    /// The total number of entries, including reserved entries.
169    ///
170    /// This may be greater than `entries.len()`.
171    reserved: usize,
172    /// The index of the root entry in entries.
173    root: UnitEntryId,
174    /// The unit has been written to the output sections.
175    written: bool,
176    /// The section offsets for the unit and DIEs after being written.
177    offsets: UnitOffsets,
178}
179
180impl Unit {
181    /// Create a new `Unit`.
182    pub fn new(encoding: Encoding, line_program: LineProgram) -> Self {
183        let base_id = BaseId::default();
184        let ranges = RangeListTable::default();
185        let locations = LocationListTable::default();
186        let root = UnitEntryId::new(base_id, 0);
187        let mut entry = DebuggingInformationEntry::new_reserved(root);
188        entry.tag = constants::DW_TAG_compile_unit;
189        let entries = vec![entry];
190        let offsets = UnitOffsets {
191            base_id,
192            unit: DebugInfoOffset(!0),
193            entries: Vec::new(),
194        };
195        Unit {
196            base_id,
197            encoding,
198            line_program,
199            ranges,
200            locations,
201            entries,
202            reserved: 1,
203            root,
204            written: false,
205            offsets,
206        }
207    }
208
209    /// Set the encoding parameters for this unit.
210    #[inline]
211    pub fn set_encoding(&mut self, encoding: Encoding) {
212        self.encoding = encoding;
213    }
214
215    /// Return the encoding parameters for this unit.
216    #[inline]
217    pub fn encoding(&self) -> Encoding {
218        self.encoding
219    }
220
221    /// Return the DWARF version for this unit.
222    #[inline]
223    pub fn version(&self) -> u16 {
224        self.encoding.version
225    }
226
227    /// Return the address size in bytes for this unit.
228    #[inline]
229    pub fn address_size(&self) -> u8 {
230        self.encoding.address_size
231    }
232
233    /// Return the DWARF format for this unit.
234    #[inline]
235    pub fn format(&self) -> Format {
236        self.encoding.format
237    }
238
239    /// Return the number of `DebuggingInformationEntry`s created for this unit.
240    ///
241    /// This includes entries that no longer have a parent.
242    #[inline]
243    pub fn count(&self) -> usize {
244        self.entries.len()
245    }
246
247    /// Return the id of the root entry.
248    #[inline]
249    pub fn root(&self) -> UnitEntryId {
250        self.root
251    }
252
253    /// Reserve a `DebuggingInformationEntry` in this unit and return its id.
254    ///
255    /// This method is useful when you need an id to construct a [`DebugInfoRef`]
256    /// before the DIE has been added to the unit.
257    ///
258    /// If the id is used in a reference, it must later be passed to
259    /// [`Self::add_reserved`]. Until then, the ID must not be used with any other
260    /// methods of this unit.
261    ///
262    /// It is valid to reserve an id but never use or add it.
263    pub fn reserve(&mut self) -> UnitEntryId {
264        let id = UnitEntryId::new(self.base_id, self.reserved);
265        self.reserved += 1;
266        id
267    }
268
269    /// Set the parent and tag of a previously reserved `DebuggingInformationEntry`.
270    ///
271    /// The `parent` must be within the same unit.
272    ///
273    /// # Panics
274    ///
275    /// Panics if `child` or `parent` is invalid, or if `child` is not a reserved entry.
276    pub fn add_reserved(&mut self, child: UnitEntryId, parent: UnitEntryId, tag: constants::DwTag) {
277        while self.entries.len() < self.reserved {
278            let id = UnitEntryId::new(self.base_id, self.entries.len());
279            self.entries
280                .push(DebuggingInformationEntry::new_reserved(id));
281        }
282        let entry = self.get_mut(child);
283        debug_assert_eq!(entry.parent, None);
284        debug_assert_eq!(entry.tag, constants::DW_TAG_null);
285        entry.parent = Some(parent);
286        entry.tag = tag;
287        self.get_mut(parent).children.push(child);
288    }
289
290    /// Add a new `DebuggingInformationEntry` to this unit and return its id.
291    ///
292    /// The `parent` must be within the same unit.
293    ///
294    /// # Panics
295    ///
296    /// Panics if `parent` is invalid.
297    #[inline]
298    pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId {
299        let id = self.reserve();
300        self.add_reserved(id, parent, tag);
301        id
302    }
303
304    /// Get a reference to an entry.
305    ///
306    /// # Panics
307    ///
308    /// Panics if `id` is invalid.
309    #[inline]
310    pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry {
311        debug_assert_eq!(self.base_id, id.base_id);
312        &self.entries[id.index]
313    }
314
315    /// Get a mutable reference to an entry.
316    ///
317    /// # Panics
318    ///
319    /// Panics if `id` is invalid.
320    #[inline]
321    pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry {
322        debug_assert_eq!(self.base_id, id.base_id);
323        &mut self.entries[id.index]
324    }
325
326    /// Return true if `self.line_program` is used by a DIE.
327    fn line_program_in_use(&self) -> bool {
328        if self.line_program.is_none() {
329            return false;
330        }
331        if !self.line_program.is_empty() {
332            return true;
333        }
334
335        for entry in &self.entries {
336            for attr in &entry.attrs {
337                if let AttributeValue::FileIndex(Some(_)) = attr.value {
338                    return true;
339                }
340            }
341        }
342
343        false
344    }
345
346    /// Write the unit to the given sections.
347    pub(crate) fn write<W: Writer>(
348        &mut self,
349        sections: &mut Sections<W>,
350        abbrev_offset: DebugAbbrevOffset,
351        abbrevs: &mut AbbreviationTable,
352        line_strings: &mut LineStringTable,
353        strings: &mut StringTable,
354    ) -> Result<()> {
355        debug_assert!(!self.written);
356
357        let line_program = if self.line_program_in_use() {
358            self.entries[self.root.index]
359                .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef);
360            Some(self.line_program.write(
361                &mut sections.debug_line,
362                self.encoding,
363                line_strings,
364                strings,
365            )?)
366        } else {
367            self.entries[self.root.index].delete(constants::DW_AT_stmt_list);
368            None
369        };
370
371        // TODO: use .debug_types for type units in DWARF v4.
372        let w = &mut sections.debug_info;
373
374        let mut offsets = UnitOffsets {
375            base_id: self.base_id,
376            unit: w.offset(),
377            // Entries can be written in any order, so create the complete vec now.
378            entries: vec![DebugInfoOffset(0); self.entries.len()],
379        };
380
381        let length_offset = w.write_initial_length(self.format())?;
382        let length_base = w.len();
383
384        w.write_u16(self.version())?;
385        if 2 <= self.version() && self.version() <= 4 {
386            w.write_offset(
387                abbrev_offset.0,
388                SectionId::DebugAbbrev,
389                self.format().word_size(),
390            )?;
391            w.write_u8(self.address_size())?;
392        } else if self.version() == 5 {
393            w.write_u8(constants::DW_UT_compile.0)?;
394            w.write_u8(self.address_size())?;
395            w.write_offset(
396                abbrev_offset.0,
397                SectionId::DebugAbbrev,
398                self.format().word_size(),
399            )?;
400        } else {
401            return Err(Error::UnsupportedVersion(self.version()));
402        }
403
404        // Calculate all DIE offsets, so that we are able to output references to them.
405        // However, references to base types in expressions use ULEB128, so base types
406        // must be moved to the front before we can calculate offsets.
407        self.reorder_base_types();
408        let mut codes = vec![0; self.entries.len()];
409        let mut offset = w.len();
410        self.entries[self.root.index].calculate_offsets(
411            self,
412            &mut offset,
413            &mut offsets,
414            abbrevs,
415            &mut codes,
416        )?;
417
418        let range_lists = self.ranges.write(sections, self.encoding)?;
419        // Location lists can't be written until we have DIE offsets.
420        let loc_lists = self
421            .locations
422            .write(sections, self.encoding, Some(&offsets))?;
423
424        let w = &mut sections.debug_info;
425        let mut unit_refs = Vec::new();
426        self.entries[self.root.index].write(
427            w,
428            &mut sections.debug_info_fixups,
429            &mut unit_refs,
430            self,
431            &offsets,
432            &codes,
433            line_program,
434            line_strings,
435            strings,
436            &range_lists,
437            &loc_lists,
438        )?;
439
440        let length = (w.len() - length_base) as u64;
441        w.write_initial_length_at(length_offset, length, self.format())?;
442
443        for (offset, entry) in unit_refs {
444            // This does not need relocation.
445            w.write_udata_at(
446                offset.0,
447                offsets.unit_offset(entry).ok_or(Error::InvalidReference)?,
448                self.format().word_size(),
449            )?;
450        }
451
452        self.offsets = offsets;
453        self.written = true;
454        Ok(())
455    }
456
457    fn skip(&mut self) {
458        self.written = true;
459    }
460
461    fn free(&mut self) {
462        self.line_program = LineProgram::none();
463        self.ranges = RangeListTable::default();
464        self.locations = LocationListTable::default();
465        self.entries = Vec::new();
466    }
467
468    /// Reorder base types to come first so that typed stack operations
469    /// can get their offset.
470    fn reorder_base_types(&mut self) {
471        let root = &self.entries[self.root.index];
472        let mut root_children = Vec::with_capacity(root.children.len());
473        for entry in &root.children {
474            if self.entries[entry.index].tag == constants::DW_TAG_base_type {
475                root_children.push(*entry);
476            }
477        }
478        for entry in &root.children {
479            if self.entries[entry.index].tag != constants::DW_TAG_base_type {
480                root_children.push(*entry);
481            }
482        }
483        self.entries[self.root.index].children = root_children;
484    }
485}
486
487/// A Debugging Information Entry (DIE).
488///
489/// DIEs have a set of attributes and optionally have children DIEs as well.
490///
491/// DIEs form a tree without any cycles. This is enforced by specifying the
492/// parent when creating a DIE, and disallowing changes of parent.
493#[derive(Debug)]
494pub struct DebuggingInformationEntry {
495    id: UnitEntryId,
496    parent: Option<UnitEntryId>,
497    tag: constants::DwTag,
498    /// Whether to emit `DW_AT_sibling`.
499    sibling: bool,
500    attrs: Vec<Attribute>,
501    children: Vec<UnitEntryId>,
502}
503
504impl DebuggingInformationEntry {
505    /// Create a new `DebuggingInformationEntry`.
506    fn new_reserved(id: UnitEntryId) -> Self {
507        DebuggingInformationEntry {
508            id,
509            parent: None,
510            tag: constants::DW_TAG_null,
511            sibling: false,
512            attrs: Vec::new(),
513            children: Vec::new(),
514        }
515    }
516
517    /// Return the id of this entry.
518    #[inline]
519    pub fn id(&self) -> UnitEntryId {
520        self.id
521    }
522
523    /// Return the parent of this entry.
524    #[inline]
525    pub fn parent(&self) -> Option<UnitEntryId> {
526        self.parent
527    }
528
529    /// Return the tag of this entry.
530    #[inline]
531    pub fn tag(&self) -> constants::DwTag {
532        self.tag
533    }
534
535    /// Return `true` if a `DW_AT_sibling` attribute will be emitted.
536    #[inline]
537    pub fn sibling(&self) -> bool {
538        self.sibling
539    }
540
541    /// Set whether a `DW_AT_sibling` attribute will be emitted.
542    ///
543    /// The attribute will only be emitted if the DIE has children.
544    #[inline]
545    pub fn set_sibling(&mut self, sibling: bool) {
546        self.sibling = sibling;
547    }
548
549    /// Iterate over the attributes of this entry.
550    #[inline]
551    pub fn attrs(&self) -> slice::Iter<'_, Attribute> {
552        self.attrs.iter()
553    }
554
555    /// Iterate over the attributes of this entry for modification.
556    #[inline]
557    pub fn attrs_mut(&mut self) -> slice::IterMut<'_, Attribute> {
558        self.attrs.iter_mut()
559    }
560
561    /// Get an attribute.
562    pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> {
563        self.attrs
564            .iter()
565            .find(|attr| attr.name == name)
566            .map(|attr| &attr.value)
567    }
568
569    /// Get an attribute for modification.
570    pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> {
571        self.attrs
572            .iter_mut()
573            .find(|attr| attr.name == name)
574            .map(|attr| &mut attr.value)
575    }
576
577    /// Reserve capacity for additional attributes.
578    ///
579    /// This may give a performance improvement when the number of attributes
580    /// is known.
581    pub fn reserve(&mut self, additional: usize) {
582        self.attrs.reserve(additional);
583    }
584
585    /// Set an attribute.
586    ///
587    /// Replaces any existing attribute with the same name.
588    ///
589    /// # Panics
590    ///
591    /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead.
592    pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) {
593        debug_assert_ne!(name, constants::DW_AT_sibling);
594        if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) {
595            attr.value = value;
596            return;
597        }
598        self.attrs.push(Attribute { name, value });
599    }
600
601    /// Delete an attribute.
602    pub fn delete(&mut self, name: constants::DwAt) {
603        self.attrs.retain(|x| x.name != name);
604    }
605
606    /// Iterate over the children of this entry.
607    ///
608    /// Note: use `Unit::add` to add a new child to this entry.
609    #[inline]
610    pub fn children(&self) -> slice::Iter<'_, UnitEntryId> {
611        self.children.iter()
612    }
613
614    /// Delete a child entry and all of its children.
615    pub fn delete_child(&mut self, id: UnitEntryId) {
616        self.children.retain(|&child| child != id);
617    }
618
619    /// Return the type abbreviation for this DIE.
620    fn abbreviation(&self, encoding: Encoding) -> Result<Abbreviation> {
621        let sibling = self.sibling && !self.children.is_empty();
622        let mut attrs = Vec::with_capacity(usize::from(sibling) + self.attrs.len());
623
624        if sibling {
625            let form = match encoding.format {
626                Format::Dwarf32 => constants::DW_FORM_ref4,
627                Format::Dwarf64 => constants::DW_FORM_ref8,
628            };
629            attrs.push(AttributeSpecification::new(
630                constants::DW_AT_sibling,
631                form,
632                None,
633            ));
634        }
635
636        for attr in &self.attrs {
637            attrs.push(attr.specification(encoding)?);
638        }
639
640        Ok(Abbreviation::new(
641            self.tag,
642            !self.children.is_empty(),
643            attrs,
644        ))
645    }
646
647    fn calculate_offsets(
648        &self,
649        unit: &Unit,
650        offset: &mut usize,
651        offsets: &mut UnitOffsets,
652        abbrevs: &mut AbbreviationTable,
653        codes: &mut [u64],
654    ) -> Result<()> {
655        offsets.entries[self.id.index] = DebugInfoOffset(*offset);
656        let code = abbrevs.add(self.abbreviation(unit.encoding())?);
657        codes[self.id.index] = code;
658        *offset += self.size(unit, offsets, code)?;
659        if !self.children.is_empty() {
660            for child in &self.children {
661                unit.entries[child.index]
662                    .calculate_offsets(unit, offset, offsets, abbrevs, codes)?;
663            }
664            // Null child
665            *offset += 1;
666        }
667        Ok(())
668    }
669
670    fn size(&self, unit: &Unit, offsets: &UnitOffsets, code: u64) -> Result<usize> {
671        let mut size = uleb128_size(code);
672        if self.sibling && !self.children.is_empty() {
673            size += unit.format().word_size() as usize;
674        }
675        for attr in &self.attrs {
676            size += attr.value.size(unit, offsets)?;
677        }
678        Ok(size)
679    }
680
681    /// Write the entry to the given sections.
682    fn write<W: Writer>(
683        &self,
684        w: &mut DebugInfo<W>,
685        debug_info_refs: &mut Vec<DebugInfoFixup>,
686        unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
687        unit: &Unit,
688        offsets: &UnitOffsets,
689        codes: &[u64],
690        line_program: Option<DebugLineOffset>,
691        line_strings: &LineStringTable,
692        strings: &StringTable,
693        range_lists: &RangeListOffsets,
694        loc_lists: &LocationListOffsets,
695    ) -> Result<()> {
696        debug_assert_eq!(offsets.debug_info_offset(self.id), Some(w.offset()));
697        w.write_uleb128(codes[self.id.index])?;
698
699        let sibling_offset = if self.sibling && !self.children.is_empty() {
700            let offset = w.offset();
701            w.write_udata(0, unit.format().word_size())?;
702            Some(offset)
703        } else {
704            None
705        };
706
707        for attr in &self.attrs {
708            attr.value.write(
709                w,
710                debug_info_refs,
711                unit_refs,
712                unit,
713                offsets,
714                line_program,
715                line_strings,
716                strings,
717                range_lists,
718                loc_lists,
719            )?;
720        }
721
722        if !self.children.is_empty() {
723            for child in &self.children {
724                unit.entries[child.index].write(
725                    w,
726                    debug_info_refs,
727                    unit_refs,
728                    unit,
729                    offsets,
730                    codes,
731                    line_program,
732                    line_strings,
733                    strings,
734                    range_lists,
735                    loc_lists,
736                )?;
737            }
738            // Null child
739            w.write_u8(0)?;
740        }
741
742        if let Some(offset) = sibling_offset {
743            let next_offset = (w.offset().0 - offsets.unit.0) as u64;
744            // This does not need relocation.
745            w.write_udata_at(offset.0, next_offset, unit.format().word_size())?;
746        }
747        Ok(())
748    }
749}
750
751/// An attribute in a `DebuggingInformationEntry`, consisting of a name and
752/// associated value.
753#[derive(Debug, Clone, PartialEq, Eq)]
754pub struct Attribute {
755    name: constants::DwAt,
756    value: AttributeValue,
757}
758
759impl Attribute {
760    /// Get the name of this attribute.
761    #[inline]
762    pub fn name(&self) -> constants::DwAt {
763        self.name
764    }
765
766    /// Get the value of this attribute.
767    #[inline]
768    pub fn get(&self) -> &AttributeValue {
769        &self.value
770    }
771
772    /// Set the value of this attribute.
773    #[inline]
774    pub fn set(&mut self, value: AttributeValue) {
775        self.value = value;
776    }
777
778    /// Return the type specification for this attribute.
779    fn specification(&self, encoding: Encoding) -> Result<AttributeSpecification> {
780        let (form, implicit_const) = self.value.form(encoding)?;
781        Ok(AttributeSpecification::new(self.name, form, implicit_const))
782    }
783}
784
785/// The value of an attribute in a `DebuggingInformationEntry`.
786#[derive(Debug, Clone, PartialEq, Eq)]
787pub enum AttributeValue {
788    /// "Refers to some location in the address space of the described program."
789    Address(Address),
790
791    /// A slice of an arbitrary number of bytes.
792    Block(Vec<u8>),
793
794    /// A one byte constant data value. How to interpret the byte depends on context.
795    ///
796    /// From section 7 of the standard: "Depending on context, it may be a
797    /// signed integer, an unsigned integer, a floating-point constant, or
798    /// anything else."
799    Data1(u8),
800
801    /// A two byte constant data value. How to interpret the bytes depends on context.
802    ///
803    /// This value will be converted to the target endian before writing.
804    ///
805    /// From section 7 of the standard: "Depending on context, it may be a
806    /// signed integer, an unsigned integer, a floating-point constant, or
807    /// anything else."
808    Data2(u16),
809
810    /// A four byte constant data value. How to interpret the bytes depends on context.
811    ///
812    /// This value will be converted to the target endian before writing.
813    ///
814    /// From section 7 of the standard: "Depending on context, it may be a
815    /// signed integer, an unsigned integer, a floating-point constant, or
816    /// anything else."
817    Data4(u32),
818
819    /// An eight byte constant data value. How to interpret the bytes depends on context.
820    ///
821    /// This value will be converted to the target endian before writing.
822    ///
823    /// From section 7 of the standard: "Depending on context, it may be a
824    /// signed integer, an unsigned integer, a floating-point constant, or
825    /// anything else."
826    Data8(u64),
827
828    /// An sixteen byte constant data value. How to interpret the bytes depends on context.
829    ///
830    /// This value will be converted to the target endian before writing.
831    ///
832    /// From section 7 of the standard: "Depending on context, it may be a
833    /// signed integer, an unsigned integer, a floating-point constant, or
834    /// anything else."
835    Data16(u128),
836
837    /// A signed integer constant.
838    Sdata(i64),
839
840    /// An unsigned integer constant.
841    Udata(u64),
842
843    /// An implicit signed integer constant.
844    ///
845    /// The constant is stored in the abbreviation instead of being repeated
846    /// for each DIE using it.
847    ///
848    /// This may be used for any attribute value that is a constant, such as
849    /// [`AttributeValue::Language`], but you need to specify the raw value
850    /// here instead of using a typed constant.
851    ///
852    /// This is treated as `Sdata` for DWARF version < 5.
853    ImplicitConst(i64),
854
855    /// "The information bytes contain a DWARF expression (see Section 2.5) or
856    /// location description (see Section 2.6)."
857    ///
858    /// This is treated as `Block` for DWARF version < 4.
859    Exprloc(Expression),
860
861    /// A boolean that indicates presence or absence of the attribute.
862    Flag(bool),
863
864    /// An attribute that is always present.
865    ///
866    /// This is treated as `Flag(true)` for DWARF version < 4.
867    FlagPresent,
868
869    /// A reference to a `DebuggingInformationEntry` in this unit.
870    UnitRef(UnitEntryId),
871
872    /// A reference to a `DebuggingInformationEntry` in a potentially different unit.
873    DebugInfoRef(DebugInfoRef),
874
875    /// An offset into the `.debug_info` section of the supplementary object file.
876    ///
877    /// The API does not currently assist with generating this offset.
878    /// This variant will be removed from the API once support for writing
879    /// supplementary object files is implemented.
880    DebugInfoRefSup(DebugInfoOffset),
881
882    /// A reference to a line number program.
883    LineProgramRef,
884
885    /// A reference to a location list.
886    LocationListRef(LocationListId),
887
888    /// An offset into the `.debug_macinfo` section.
889    ///
890    /// The API does not currently assist with generating this offset.
891    /// This variant will be removed from the API once support for writing
892    /// `.debug_macinfo` sections is implemented.
893    DebugMacinfoRef(DebugMacinfoOffset),
894
895    /// An offset into the `.debug_macro` section.
896    ///
897    /// The API does not currently assist with generating this offset.
898    /// This variant will be removed from the API once support for writing
899    /// `.debug_macro` sections is implemented.
900    DebugMacroRef(DebugMacroOffset),
901
902    /// A reference to a range list.
903    RangeListRef(RangeListId),
904
905    /// A type signature.
906    ///
907    /// The API does not currently assist with generating this signature.
908    /// This variant will be removed from the API once support for writing
909    /// `.debug_types` sections is implemented.
910    DebugTypesRef(DebugTypeSignature),
911
912    /// A reference to a string in the `.debug_str` section.
913    StringRef(StringId),
914
915    /// An offset into the `.debug_str` section of the supplementary object file.
916    ///
917    /// The API does not currently assist with generating this offset.
918    /// This variant will be removed from the API once support for writing
919    /// supplementary object files is implemented.
920    DebugStrRefSup(DebugStrOffset),
921
922    /// A reference to a string in the `.debug_line_str` section.
923    LineStringRef(LineStringId),
924
925    /// A slice of bytes representing a string. Must not include null bytes.
926    /// Not guaranteed to be UTF-8 or anything like that.
927    String(Vec<u8>),
928
929    /// The value of a `DW_AT_encoding` attribute.
930    Encoding(constants::DwAte),
931
932    /// The value of a `DW_AT_decimal_sign` attribute.
933    DecimalSign(constants::DwDs),
934
935    /// The value of a `DW_AT_endianity` attribute.
936    Endianity(constants::DwEnd),
937
938    /// The value of a `DW_AT_accessibility` attribute.
939    Accessibility(constants::DwAccess),
940
941    /// The value of a `DW_AT_visibility` attribute.
942    Visibility(constants::DwVis),
943
944    /// The value of a `DW_AT_virtuality` attribute.
945    Virtuality(constants::DwVirtuality),
946
947    /// The value of a `DW_AT_language` attribute.
948    Language(constants::DwLang),
949
950    /// The value of a `DW_AT_address_class` attribute.
951    AddressClass(constants::DwAddr),
952
953    /// The value of a `DW_AT_identifier_case` attribute.
954    IdentifierCase(constants::DwId),
955
956    /// The value of a `DW_AT_calling_convention` attribute.
957    CallingConvention(constants::DwCc),
958
959    /// The value of a `DW_AT_inline` attribute.
960    Inline(constants::DwInl),
961
962    /// The value of a `DW_AT_ordering` attribute.
963    Ordering(constants::DwOrd),
964
965    /// An index into the filename entries from the line number information
966    /// table for the unit containing this value.
967    FileIndex(Option<FileId>),
968}
969
970impl AttributeValue {
971    /// Return the form that will be used to encode this value.
972    pub fn form(&self, encoding: Encoding) -> Result<(constants::DwForm, Option<i64>)> {
973        // TODO: missing forms:
974        // - DW_FORM_indirect
975        // - FW_FORM_block1/block2/block4
976        // - DW_FORM_str/strx1/strx2/strx3/strx4
977        // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4
978        // - DW_FORM_line_strp
979        // - DW_FORM_loclistx
980        // - DW_FORM_rnglistx
981        let form = match *self {
982            AttributeValue::Address(_) => constants::DW_FORM_addr,
983            AttributeValue::Block(_) => constants::DW_FORM_block,
984            AttributeValue::Data1(_) => constants::DW_FORM_data1,
985            AttributeValue::Data2(_) => constants::DW_FORM_data2,
986            AttributeValue::Data4(_) => constants::DW_FORM_data4,
987            AttributeValue::Data8(_) => constants::DW_FORM_data8,
988            AttributeValue::Data16(_) => constants::DW_FORM_data16,
989            AttributeValue::Exprloc(_) => {
990                if encoding.version >= 4 {
991                    constants::DW_FORM_exprloc
992                } else {
993                    constants::DW_FORM_block
994                }
995            }
996            AttributeValue::Flag(_) => constants::DW_FORM_flag,
997            AttributeValue::FlagPresent => {
998                if encoding.version >= 4 {
999                    constants::DW_FORM_flag_present
1000                } else {
1001                    constants::DW_FORM_flag
1002                }
1003            }
1004            AttributeValue::UnitRef(_) => {
1005                // Using a fixed size format lets us write a placeholder before we know
1006                // the value.
1007                match encoding.format {
1008                    Format::Dwarf32 => constants::DW_FORM_ref4,
1009                    Format::Dwarf64 => constants::DW_FORM_ref8,
1010                }
1011            }
1012            AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr,
1013            AttributeValue::DebugInfoRefSup(_) => {
1014                // TODO: should this depend on the size of supplementary section?
1015                match encoding.format {
1016                    Format::Dwarf32 => constants::DW_FORM_ref_sup4,
1017                    Format::Dwarf64 => constants::DW_FORM_ref_sup8,
1018                }
1019            }
1020            AttributeValue::LineProgramRef
1021            | AttributeValue::LocationListRef(_)
1022            | AttributeValue::DebugMacinfoRef(_)
1023            | AttributeValue::DebugMacroRef(_)
1024            | AttributeValue::RangeListRef(_) => {
1025                if encoding.version == 2 || encoding.version == 3 {
1026                    match encoding.format {
1027                        Format::Dwarf32 => constants::DW_FORM_data4,
1028                        Format::Dwarf64 => constants::DW_FORM_data8,
1029                    }
1030                } else {
1031                    constants::DW_FORM_sec_offset
1032                }
1033            }
1034            AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8,
1035            AttributeValue::StringRef(_) => constants::DW_FORM_strp,
1036            AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup,
1037            AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp,
1038            AttributeValue::String(_) => constants::DW_FORM_string,
1039            AttributeValue::Encoding(_)
1040            | AttributeValue::DecimalSign(_)
1041            | AttributeValue::Endianity(_)
1042            | AttributeValue::Accessibility(_)
1043            | AttributeValue::Visibility(_)
1044            | AttributeValue::Virtuality(_)
1045            | AttributeValue::Language(_)
1046            | AttributeValue::AddressClass(_)
1047            | AttributeValue::IdentifierCase(_)
1048            | AttributeValue::CallingConvention(_)
1049            | AttributeValue::Inline(_)
1050            | AttributeValue::Ordering(_)
1051            | AttributeValue::FileIndex(_)
1052            | AttributeValue::Udata(_) => constants::DW_FORM_udata,
1053            AttributeValue::Sdata(_) => constants::DW_FORM_sdata,
1054            AttributeValue::ImplicitConst(val) => {
1055                if encoding.version >= 5 {
1056                    return Ok((constants::DW_FORM_implicit_const, Some(val)));
1057                } else {
1058                    constants::DW_FORM_sdata
1059                }
1060            }
1061        };
1062        Ok((form, None))
1063    }
1064
1065    fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> Result<usize> {
1066        macro_rules! debug_assert_form {
1067            ($form:expr) => {
1068                debug_assert_eq!(self.form(unit.encoding()).unwrap().0, $form)
1069            };
1070        }
1071        Ok(match *self {
1072            AttributeValue::Address(_) => {
1073                debug_assert_form!(constants::DW_FORM_addr);
1074                unit.address_size() as usize
1075            }
1076            AttributeValue::Block(ref val) => {
1077                debug_assert_form!(constants::DW_FORM_block);
1078                uleb128_size(val.len() as u64) + val.len()
1079            }
1080            AttributeValue::Data1(_) => {
1081                debug_assert_form!(constants::DW_FORM_data1);
1082                1
1083            }
1084            AttributeValue::Data2(_) => {
1085                debug_assert_form!(constants::DW_FORM_data2);
1086                2
1087            }
1088            AttributeValue::Data4(_) => {
1089                debug_assert_form!(constants::DW_FORM_data4);
1090                4
1091            }
1092            AttributeValue::Data8(_) => {
1093                debug_assert_form!(constants::DW_FORM_data8);
1094                8
1095            }
1096            AttributeValue::Data16(_) => {
1097                debug_assert_form!(constants::DW_FORM_data16);
1098                16
1099            }
1100            AttributeValue::Sdata(val) => {
1101                debug_assert_form!(constants::DW_FORM_sdata);
1102                sleb128_size(val)
1103            }
1104            AttributeValue::ImplicitConst(val) => {
1105                if unit.version() >= 5 {
1106                    debug_assert_form!(constants::DW_FORM_implicit_const);
1107                    0
1108                } else {
1109                    debug_assert_form!(constants::DW_FORM_sdata);
1110                    sleb128_size(val)
1111                }
1112            }
1113            AttributeValue::Udata(val) => {
1114                debug_assert_form!(constants::DW_FORM_udata);
1115                uleb128_size(val)
1116            }
1117            AttributeValue::Exprloc(ref val) => {
1118                if unit.version() >= 4 {
1119                    debug_assert_form!(constants::DW_FORM_exprloc);
1120                } else {
1121                    debug_assert_form!(constants::DW_FORM_block);
1122                }
1123                let size = val.size(unit.encoding(), Some(offsets))?;
1124                uleb128_size(size as u64) + size
1125            }
1126            AttributeValue::Flag(_) => {
1127                debug_assert_form!(constants::DW_FORM_flag);
1128                1
1129            }
1130            AttributeValue::FlagPresent => {
1131                if unit.version() >= 4 {
1132                    debug_assert_form!(constants::DW_FORM_flag_present);
1133                    0
1134                } else {
1135                    debug_assert_form!(constants::DW_FORM_flag);
1136                    1
1137                }
1138            }
1139            AttributeValue::UnitRef(_) => {
1140                match unit.format() {
1141                    Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
1142                    Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
1143                }
1144                unit.format().word_size() as usize
1145            }
1146            AttributeValue::DebugInfoRef(_) => {
1147                debug_assert_form!(constants::DW_FORM_ref_addr);
1148                if unit.version() == 2 {
1149                    unit.address_size() as usize
1150                } else {
1151                    unit.format().word_size() as usize
1152                }
1153            }
1154            AttributeValue::DebugInfoRefSup(_) => {
1155                match unit.format() {
1156                    Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
1157                    Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
1158                }
1159                unit.format().word_size() as usize
1160            }
1161            AttributeValue::LineProgramRef => {
1162                if unit.version() >= 4 {
1163                    debug_assert_form!(constants::DW_FORM_sec_offset);
1164                }
1165                unit.format().word_size() as usize
1166            }
1167            AttributeValue::LocationListRef(_) => {
1168                if unit.version() >= 4 {
1169                    debug_assert_form!(constants::DW_FORM_sec_offset);
1170                }
1171                unit.format().word_size() as usize
1172            }
1173            AttributeValue::DebugMacinfoRef(_) => {
1174                if unit.version() >= 4 {
1175                    debug_assert_form!(constants::DW_FORM_sec_offset);
1176                }
1177                unit.format().word_size() as usize
1178            }
1179            AttributeValue::DebugMacroRef(_) => {
1180                if unit.version() >= 4 {
1181                    debug_assert_form!(constants::DW_FORM_sec_offset);
1182                }
1183                unit.format().word_size() as usize
1184            }
1185            AttributeValue::RangeListRef(_) => {
1186                if unit.version() >= 4 {
1187                    debug_assert_form!(constants::DW_FORM_sec_offset);
1188                }
1189                unit.format().word_size() as usize
1190            }
1191            AttributeValue::DebugTypesRef(_) => {
1192                debug_assert_form!(constants::DW_FORM_ref_sig8);
1193                8
1194            }
1195            AttributeValue::StringRef(_) => {
1196                debug_assert_form!(constants::DW_FORM_strp);
1197                unit.format().word_size() as usize
1198            }
1199            AttributeValue::DebugStrRefSup(_) => {
1200                debug_assert_form!(constants::DW_FORM_strp_sup);
1201                unit.format().word_size() as usize
1202            }
1203            AttributeValue::LineStringRef(_) => {
1204                debug_assert_form!(constants::DW_FORM_line_strp);
1205                unit.format().word_size() as usize
1206            }
1207            AttributeValue::String(ref val) => {
1208                debug_assert_form!(constants::DW_FORM_string);
1209                val.len() + 1
1210            }
1211            AttributeValue::Encoding(val) => {
1212                debug_assert_form!(constants::DW_FORM_udata);
1213                uleb128_size(val.0 as u64)
1214            }
1215            AttributeValue::DecimalSign(val) => {
1216                debug_assert_form!(constants::DW_FORM_udata);
1217                uleb128_size(val.0 as u64)
1218            }
1219            AttributeValue::Endianity(val) => {
1220                debug_assert_form!(constants::DW_FORM_udata);
1221                uleb128_size(val.0 as u64)
1222            }
1223            AttributeValue::Accessibility(val) => {
1224                debug_assert_form!(constants::DW_FORM_udata);
1225                uleb128_size(val.0 as u64)
1226            }
1227            AttributeValue::Visibility(val) => {
1228                debug_assert_form!(constants::DW_FORM_udata);
1229                uleb128_size(val.0 as u64)
1230            }
1231            AttributeValue::Virtuality(val) => {
1232                debug_assert_form!(constants::DW_FORM_udata);
1233                uleb128_size(val.0 as u64)
1234            }
1235            AttributeValue::Language(val) => {
1236                debug_assert_form!(constants::DW_FORM_udata);
1237                uleb128_size(val.0 as u64)
1238            }
1239            AttributeValue::AddressClass(val) => {
1240                debug_assert_form!(constants::DW_FORM_udata);
1241                uleb128_size(val.0)
1242            }
1243            AttributeValue::IdentifierCase(val) => {
1244                debug_assert_form!(constants::DW_FORM_udata);
1245                uleb128_size(val.0 as u64)
1246            }
1247            AttributeValue::CallingConvention(val) => {
1248                debug_assert_form!(constants::DW_FORM_udata);
1249                uleb128_size(val.0 as u64)
1250            }
1251            AttributeValue::Inline(val) => {
1252                debug_assert_form!(constants::DW_FORM_udata);
1253                uleb128_size(val.0 as u64)
1254            }
1255            AttributeValue::Ordering(val) => {
1256                debug_assert_form!(constants::DW_FORM_udata);
1257                uleb128_size(val.0 as u64)
1258            }
1259            AttributeValue::FileIndex(val) => {
1260                debug_assert_form!(constants::DW_FORM_udata);
1261                uleb128_size(val.map(|id| id.raw(unit.version())).unwrap_or(0))
1262            }
1263        })
1264    }
1265
1266    /// Write the attribute value to the given sections.
1267    fn write<W: Writer>(
1268        &self,
1269        w: &mut DebugInfo<W>,
1270        debug_info_refs: &mut Vec<DebugInfoFixup>,
1271        unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
1272        unit: &Unit,
1273        offsets: &UnitOffsets,
1274        line_program: Option<DebugLineOffset>,
1275        line_strings: &LineStringTable,
1276        strings: &StringTable,
1277        range_lists: &RangeListOffsets,
1278        loc_lists: &LocationListOffsets,
1279    ) -> Result<()> {
1280        macro_rules! debug_assert_form {
1281            ($form:expr) => {
1282                debug_assert_eq!(self.form(unit.encoding()).unwrap().0, $form)
1283            };
1284        }
1285        match *self {
1286            AttributeValue::Address(val) => {
1287                debug_assert_form!(constants::DW_FORM_addr);
1288                w.write_address(val, unit.address_size())?;
1289            }
1290            AttributeValue::Block(ref val) => {
1291                debug_assert_form!(constants::DW_FORM_block);
1292                w.write_uleb128(val.len() as u64)?;
1293                w.write(val)?;
1294            }
1295            AttributeValue::Data1(val) => {
1296                debug_assert_form!(constants::DW_FORM_data1);
1297                w.write_u8(val)?;
1298            }
1299            AttributeValue::Data2(val) => {
1300                debug_assert_form!(constants::DW_FORM_data2);
1301                w.write_u16(val)?;
1302            }
1303            AttributeValue::Data4(val) => {
1304                debug_assert_form!(constants::DW_FORM_data4);
1305                w.write_u32(val)?;
1306            }
1307            AttributeValue::Data8(val) => {
1308                debug_assert_form!(constants::DW_FORM_data8);
1309                w.write_u64(val)?;
1310            }
1311            AttributeValue::Data16(val) => {
1312                debug_assert_form!(constants::DW_FORM_data16);
1313                w.write_u128(val)?;
1314            }
1315            AttributeValue::Sdata(val) => {
1316                debug_assert_form!(constants::DW_FORM_sdata);
1317                w.write_sleb128(val)?;
1318            }
1319            AttributeValue::ImplicitConst(val) => {
1320                if unit.version() >= 5 {
1321                    debug_assert_form!(constants::DW_FORM_implicit_const);
1322                } else {
1323                    debug_assert_form!(constants::DW_FORM_sdata);
1324                    w.write_sleb128(val)?;
1325                }
1326            }
1327            AttributeValue::Udata(val) => {
1328                debug_assert_form!(constants::DW_FORM_udata);
1329                w.write_uleb128(val)?;
1330            }
1331            AttributeValue::Exprloc(ref val) => {
1332                if unit.version() >= 4 {
1333                    debug_assert_form!(constants::DW_FORM_exprloc);
1334                } else {
1335                    debug_assert_form!(constants::DW_FORM_block);
1336                }
1337                w.write_uleb128(val.size(unit.encoding(), Some(offsets))? as u64)?;
1338                val.write(
1339                    &mut w.0,
1340                    Some(debug_info_refs),
1341                    unit.encoding(),
1342                    Some(offsets),
1343                )?;
1344            }
1345            AttributeValue::Flag(val) => {
1346                debug_assert_form!(constants::DW_FORM_flag);
1347                w.write_u8(val as u8)?;
1348            }
1349            AttributeValue::FlagPresent => {
1350                if unit.version() >= 4 {
1351                    debug_assert_form!(constants::DW_FORM_flag_present);
1352                } else {
1353                    debug_assert_form!(constants::DW_FORM_flag);
1354                    w.write_u8(1)?;
1355                }
1356            }
1357            AttributeValue::UnitRef(id) => {
1358                match unit.format() {
1359                    Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
1360                    Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
1361                }
1362                unit_refs.push((w.offset(), id));
1363                w.write_udata(0, unit.format().word_size())?;
1364            }
1365            AttributeValue::DebugInfoRef(reference) => {
1366                debug_assert_form!(constants::DW_FORM_ref_addr);
1367                let size = if unit.version() == 2 {
1368                    unit.address_size()
1369                } else {
1370                    unit.format().word_size()
1371                };
1372                match reference {
1373                    DebugInfoRef::Symbol(symbol) => w.write_reference(symbol, size)?,
1374                    DebugInfoRef::Entry(unit, entry) => {
1375                        debug_info_refs.push(DebugInfoFixup {
1376                            offset: w.len(),
1377                            unit,
1378                            entry,
1379                            size,
1380                        });
1381                        w.write_udata(0, size)?;
1382                    }
1383                }
1384            }
1385            AttributeValue::DebugInfoRefSup(val) => {
1386                match unit.format() {
1387                    Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
1388                    Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
1389                }
1390                w.write_udata(val.0 as u64, unit.format().word_size())?;
1391            }
1392            AttributeValue::LineProgramRef => {
1393                if unit.version() >= 4 {
1394                    debug_assert_form!(constants::DW_FORM_sec_offset);
1395                }
1396                match line_program {
1397                    Some(line_program) => {
1398                        w.write_offset(
1399                            line_program.0,
1400                            SectionId::DebugLine,
1401                            unit.format().word_size(),
1402                        )?;
1403                    }
1404                    None => return Err(Error::InvalidAttributeValue),
1405                }
1406            }
1407            AttributeValue::LocationListRef(val) => {
1408                if unit.version() >= 4 {
1409                    debug_assert_form!(constants::DW_FORM_sec_offset);
1410                }
1411                let section = if unit.version() <= 4 {
1412                    SectionId::DebugLoc
1413                } else {
1414                    SectionId::DebugLocLists
1415                };
1416                w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?;
1417            }
1418            AttributeValue::DebugMacinfoRef(val) => {
1419                if unit.version() >= 4 {
1420                    debug_assert_form!(constants::DW_FORM_sec_offset);
1421                }
1422                w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?;
1423            }
1424            AttributeValue::DebugMacroRef(val) => {
1425                if unit.version() >= 4 {
1426                    debug_assert_form!(constants::DW_FORM_sec_offset);
1427                }
1428                w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?;
1429            }
1430            AttributeValue::RangeListRef(val) => {
1431                if unit.version() >= 4 {
1432                    debug_assert_form!(constants::DW_FORM_sec_offset);
1433                }
1434                let section = if unit.version() <= 4 {
1435                    SectionId::DebugRanges
1436                } else {
1437                    SectionId::DebugRngLists
1438                };
1439                w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?;
1440            }
1441            AttributeValue::DebugTypesRef(val) => {
1442                debug_assert_form!(constants::DW_FORM_ref_sig8);
1443                w.write_u64(val.0)?;
1444            }
1445            AttributeValue::StringRef(val) => {
1446                debug_assert_form!(constants::DW_FORM_strp);
1447                w.write_offset(
1448                    strings.offset(val).0,
1449                    SectionId::DebugStr,
1450                    unit.format().word_size(),
1451                )?;
1452            }
1453            AttributeValue::DebugStrRefSup(val) => {
1454                debug_assert_form!(constants::DW_FORM_strp_sup);
1455                w.write_udata(val.0 as u64, unit.format().word_size())?;
1456            }
1457            AttributeValue::LineStringRef(val) => {
1458                debug_assert_form!(constants::DW_FORM_line_strp);
1459                w.write_offset(
1460                    line_strings.offset(val).0,
1461                    SectionId::DebugLineStr,
1462                    unit.format().word_size(),
1463                )?;
1464            }
1465            AttributeValue::String(ref val) => {
1466                debug_assert_form!(constants::DW_FORM_string);
1467                w.write(val)?;
1468                w.write_u8(0)?;
1469            }
1470            AttributeValue::Encoding(val) => {
1471                debug_assert_form!(constants::DW_FORM_udata);
1472                w.write_uleb128(u64::from(val.0))?;
1473            }
1474            AttributeValue::DecimalSign(val) => {
1475                debug_assert_form!(constants::DW_FORM_udata);
1476                w.write_uleb128(u64::from(val.0))?;
1477            }
1478            AttributeValue::Endianity(val) => {
1479                debug_assert_form!(constants::DW_FORM_udata);
1480                w.write_uleb128(u64::from(val.0))?;
1481            }
1482            AttributeValue::Accessibility(val) => {
1483                debug_assert_form!(constants::DW_FORM_udata);
1484                w.write_uleb128(u64::from(val.0))?;
1485            }
1486            AttributeValue::Visibility(val) => {
1487                debug_assert_form!(constants::DW_FORM_udata);
1488                w.write_uleb128(u64::from(val.0))?;
1489            }
1490            AttributeValue::Virtuality(val) => {
1491                debug_assert_form!(constants::DW_FORM_udata);
1492                w.write_uleb128(u64::from(val.0))?;
1493            }
1494            AttributeValue::Language(val) => {
1495                debug_assert_form!(constants::DW_FORM_udata);
1496                w.write_uleb128(u64::from(val.0))?;
1497            }
1498            AttributeValue::AddressClass(val) => {
1499                debug_assert_form!(constants::DW_FORM_udata);
1500                w.write_uleb128(val.0)?;
1501            }
1502            AttributeValue::IdentifierCase(val) => {
1503                debug_assert_form!(constants::DW_FORM_udata);
1504                w.write_uleb128(u64::from(val.0))?;
1505            }
1506            AttributeValue::CallingConvention(val) => {
1507                debug_assert_form!(constants::DW_FORM_udata);
1508                w.write_uleb128(u64::from(val.0))?;
1509            }
1510            AttributeValue::Inline(val) => {
1511                debug_assert_form!(constants::DW_FORM_udata);
1512                w.write_uleb128(u64::from(val.0))?;
1513            }
1514            AttributeValue::Ordering(val) => {
1515                debug_assert_form!(constants::DW_FORM_udata);
1516                w.write_uleb128(u64::from(val.0))?;
1517            }
1518            AttributeValue::FileIndex(val) => {
1519                debug_assert_form!(constants::DW_FORM_udata);
1520                w.write_uleb128(val.map(|id| id.raw(unit.version())).unwrap_or(0))?;
1521            }
1522        }
1523        Ok(())
1524    }
1525}
1526
1527define_section!(
1528    DebugInfo,
1529    DebugInfoOffset,
1530    "A writable `.debug_info` section."
1531);
1532
1533/// The section offsets of all elements of a unit within a `.debug_info` section.
1534#[derive(Debug)]
1535pub(crate) struct UnitOffsets {
1536    base_id: BaseId,
1537    unit: DebugInfoOffset,
1538    entries: Vec<DebugInfoOffset>,
1539}
1540
1541impl UnitOffsets {
1542    /// Get the `.debug_info` offset for the given entry.
1543    ///
1544    /// Returns `None` if the offset has not been calculated yet.
1545    #[inline]
1546    fn debug_info_offset(&self, entry: UnitEntryId) -> Option<DebugInfoOffset> {
1547        debug_assert_eq!(self.base_id, entry.base_id);
1548        let offset = self.entries[entry.index];
1549        if offset.0 == 0 { None } else { Some(offset) }
1550    }
1551
1552    /// Get the unit offset for the given entry.
1553    ///
1554    /// Returns `None` if the offset has not been calculated yet.
1555    /// This may occur if the entry is orphaned or if a reference
1556    /// to the entry occurs before the entry itself is written.
1557    #[inline]
1558    pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> Option<u64> {
1559        self.debug_info_offset(entry)
1560            .map(|offset| (offset.0 - self.unit.0) as u64)
1561    }
1562}
1563
1564/// A reference to a `.debug_info` entry.
1565#[deprecated(note = "Renamed to DebugInfoRef")]
1566pub type Reference = DebugInfoRef;
1567
1568/// A reference to a `.debug_info` entry.
1569#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1570pub enum DebugInfoRef {
1571    /// An external symbol.
1572    ///
1573    /// The meaning of this value is decided by the writer, but
1574    /// will typically be an index into a symbol table.
1575    Symbol(usize),
1576    /// An entry in the same section.
1577    ///
1578    /// This only supports references in units that are emitted together.
1579    Entry(UnitId, UnitEntryId),
1580}
1581
1582/// A reference to a `.debug_info` entry that has yet to be resolved.
1583#[derive(Debug, Clone, Copy)]
1584pub(crate) struct DebugInfoFixup {
1585    /// The offset within the section where the reference should be written.
1586    pub offset: usize,
1587    /// The size of the reference.
1588    pub size: u8,
1589    /// The unit containing the entry.
1590    pub unit: UnitId,
1591    /// The entry being referenced.
1592    pub entry: UnitEntryId,
1593}
1594
1595#[cfg(feature = "read")]
1596pub use convert::*;
1597#[cfg(feature = "read")]
1598pub(crate) mod convert {
1599    use super::*;
1600    use crate::common::{
1601        DwoId, LineEncoding, LocationListsOffset, RangeListsOffset, UnitSectionOffset,
1602    };
1603    use crate::read::{self, Reader, ReaderOffset};
1604    use crate::write::{
1605        self, ConvertError, ConvertLineProgram, ConvertResult, Dwarf, LocationList, RangeList,
1606    };
1607
1608    type FnvHashMap<K, V> = hashbrown::HashMap<K, V, fnv::FnvBuildHasher>;
1609
1610    #[derive(Debug, Default)]
1611    struct FilterDependencies {
1612        edges: FnvHashMap<UnitSectionOffset, Vec<UnitSectionOffset>>,
1613        required: Vec<UnitSectionOffset>,
1614    }
1615
1616    impl FilterDependencies {
1617        /// Mark `entry` as a valid offset.
1618        ///
1619        /// This must be called before adding an edge from an entry.
1620        ///
1621        /// Also add edges from `entry` to `deps`.
1622        fn add_entry(&mut self, entry: UnitSectionOffset, deps: Vec<UnitSectionOffset>) {
1623            debug_assert!(!self.edges.contains_key(&entry));
1624            self.edges.insert(entry, deps);
1625        }
1626
1627        /// If `from` is reachable then `to` is also reachable.
1628        ///
1629        /// Must have already called `add_entry(from)`.
1630        ///
1631        /// The edge will be ignored if `add_entry` is never called for `to`
1632        /// (either before or after).
1633        fn add_edge(&mut self, from: UnitSectionOffset, to: UnitSectionOffset) {
1634            self.edges.get_mut(&from).unwrap().push(to);
1635        }
1636
1637        /// Mark `entry` as reachable.
1638        ///
1639        /// The entry will be ignored if `add_entry` is never called for `entry`
1640        /// (either before or after).
1641        fn require_entry(&mut self, entry: UnitSectionOffset) {
1642            self.required.push(entry);
1643        }
1644
1645        /// Return a sorted list of all reachable entries.
1646        fn get_reachable(mut self) -> Vec<UnitSectionOffset> {
1647            let mut reachable = Vec::new();
1648            let mut queue = vec![self.required];
1649            while let Some(entries) = queue.pop() {
1650                for entry in entries {
1651                    if let Some(deps) = self.edges.remove(&entry) {
1652                        reachable.push(entry);
1653                        queue.push(deps);
1654                    }
1655                }
1656            }
1657            reachable.sort_unstable();
1658            reachable
1659        }
1660    }
1661
1662    /// The state for identifying which DIEs in a `.debug_info` section
1663    /// need to be converted.
1664    ///
1665    /// This is used to prune unneeded DIEs, and reserve IDs so that
1666    /// DIE references can be converted.
1667    ///
1668    /// The user should call [`FilterUnitSection::read_unit`] and
1669    /// [`FilterUnit::read_entry`] to traverse all DIEs in the section. Once there are
1670    /// no more units, this state can be passed to [`Dwarf::convert_with_filter`] or
1671    /// [`ConvertUnit::convert_split_with_filter`].
1672    ///
1673    /// ## Example
1674    ///
1675    /// Create a filter for the DIEs in a DWARF section.
1676    ///
1677    /// ```rust,no_run
1678    /// # fn example() -> Result<(), gimli::write::ConvertError> {
1679    /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
1680    /// # let need_entry = &|entry: &gimli::write::FilterUnitEntry<_>| -> Result<bool, gimli::write::ConvertError> { Ok(false) };
1681    /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
1682    /// let mut filter = gimli::write::FilterUnitSection::new(&read_dwarf)?;
1683    /// while let Some(mut unit) = filter.read_unit()? {
1684    ///     let mut entry = unit.null_entry();
1685    ///     while unit.read_entry(&mut entry)? {
1686    ///         if need_entry(&entry)? {
1687    ///             unit.require_entry(entry.offset);
1688    ///         }
1689    ///     }
1690    /// }
1691    /// // `filter` can now be used to filter the DIEs during a conversion.
1692    /// # unreachable!()
1693    /// # }
1694    /// ```
1695    #[derive(Debug)]
1696    pub struct FilterUnitSection<'a, R: Reader<Offset = usize>> {
1697        dwarf: &'a read::Dwarf<R>,
1698        unit_headers: read::DebugInfoUnitHeadersIter<R>,
1699        skeleton_unit: Option<read::UnitRef<'a, R>>,
1700        units: Vec<read::Unit<R>>,
1701        deps: FilterDependencies,
1702    }
1703
1704    impl<'a, R: Reader<Offset = usize>> FilterUnitSection<'a, R> {
1705        /// Start parsing a `.debug_info` section.
1706        ///
1707        /// ## Example
1708        ///
1709        /// ```rust,no_run
1710        /// # fn example() -> Result<(), gimli::write::ConvertError> {
1711        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
1712        /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
1713        /// let mut filter = gimli::write::FilterUnitSection::new(&read_dwarf)?;
1714        /// # unreachable!()
1715        /// # }
1716        /// ```
1717        pub fn new(dwarf: &'a read::Dwarf<R>) -> ConvertResult<Self> {
1718            Ok(FilterUnitSection {
1719                dwarf,
1720                unit_headers: dwarf.units(),
1721                skeleton_unit: None,
1722                units: Vec::new(),
1723                deps: FilterDependencies::default(),
1724            })
1725        }
1726
1727        /// Start parsing the `.debug_info` section for a split DWARF unit.
1728        ///
1729        /// ## Example
1730        ///
1731        /// ```rust,no_run
1732        /// # fn example() -> Result<(), gimli::write::ConvertError> {
1733        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
1734        /// # let skeleton_unit: gimli::UnitRef<'static, gimli::EndianSlice<gimli::RunTimeEndian>> = unimplemented!();
1735        /// let dwp = gimli::read::DwarfPackage::load(loader, Default::default())?;
1736        /// let dwo_id = skeleton_unit.dwo_id.unwrap();
1737        /// let split_dwarf = dwp.find_cu(dwo_id, skeleton_unit.dwarf)?.unwrap();
1738        /// let mut filter = gimli::write::FilterUnitSection::new_split(&split_dwarf, skeleton_unit)?;
1739        /// # unreachable!()
1740        /// # }
1741        /// ```
1742        pub fn new_split(
1743            dwarf: &'a read::Dwarf<R>,
1744            skeleton_unit: read::UnitRef<'a, R>,
1745        ) -> ConvertResult<Self> {
1746            Ok(FilterUnitSection {
1747                dwarf,
1748                unit_headers: dwarf.units(),
1749                skeleton_unit: Some(skeleton_unit),
1750                units: Vec::new(),
1751                deps: FilterDependencies::default(),
1752            })
1753        }
1754
1755        /// Read the next unit header and prepare to parse its DIEs.
1756        pub fn read_unit(&'_ mut self) -> ConvertResult<Option<FilterUnit<'_, R>>> {
1757            let Some(header) = self.unit_headers.next()? else {
1758                return Ok(None);
1759            };
1760            let mut unit = self.dwarf.unit(header)?;
1761            if let Some(skeleton_unit) = self.skeleton_unit {
1762                unit.copy_relocated_attributes(&skeleton_unit);
1763            }
1764            self.units.push(unit);
1765            let unit = self.units.last().unwrap().unit_ref(self.dwarf);
1766
1767            FilterUnit::new(unit, self.skeleton_unit, &mut self.deps).map(Some)
1768        }
1769    }
1770
1771    /// The state for identifying which DIEs in a `.debug_info` unit
1772    /// need to be converted.
1773    ///
1774    /// This is created by [`FilterUnitSection::read_unit`].
1775    ///
1776    /// See [`FilterUnitSection`] for an example.
1777    #[derive(Debug)]
1778    pub struct FilterUnit<'a, R: Reader<Offset = usize>> {
1779        /// The unit being read.
1780        pub read_unit: read::UnitRef<'a, R>,
1781        /// The skeleton unit being read if `read_unit` is a split unit.
1782        pub read_skeleton_unit: Option<read::UnitRef<'a, R>>,
1783        entries: read::EntriesRaw<'a, R>,
1784        parents: Vec<FilterParent>,
1785        deps: &'a mut FilterDependencies,
1786    }
1787
1788    #[derive(Debug, Clone, Copy)]
1789    struct FilterParent {
1790        depth: isize,
1791        offset: read::UnitOffset,
1792        tag: constants::DwTag,
1793    }
1794
1795    impl<'a, R: Reader<Offset = usize>> FilterUnit<'a, R> {
1796        fn new(
1797            read_unit: read::UnitRef<'a, R>,
1798            read_skeleton_unit: Option<read::UnitRef<'a, R>>,
1799            deps: &'a mut FilterDependencies,
1800        ) -> ConvertResult<Self> {
1801            let mut entries = read_unit.entries_raw(None)?;
1802            let abbrev = entries
1803                .read_abbreviation()?
1804                .ok_or(read::Error::MissingUnitDie)?;
1805            entries.skip_attributes(abbrev.attributes())?;
1806            Ok(FilterUnit {
1807                read_unit,
1808                read_skeleton_unit,
1809                entries,
1810                parents: Vec::new(),
1811                deps,
1812            })
1813        }
1814
1815        /// Return a null DIE for use with [`FilterUnit::read_entry`].
1816        pub fn null_entry(&self) -> FilterUnitEntry<'a, R> {
1817            FilterUnitEntry::null(self.read_unit)
1818        }
1819
1820        /// Read the next DIE.
1821        ///
1822        /// Returns `false` if the unit has no more DIEs.
1823        ///
1824        /// This also records dependencies for the DIE:
1825        /// - the DIE always depends on its parent
1826        /// - the parent may depend on the DIE
1827        /// - the DIE depends on any DIEs that are referenced by its attributes
1828        ///
1829        /// The only task the user needs to perform is to call
1830        /// [`FilterUnit::require_entry`] if the DIE is always required to be
1831        /// converted. Typically, a DIE will be required if it has a valid address range.
1832        pub fn read_entry(&mut self, entry: &mut FilterUnitEntry<'a, R>) -> ConvertResult<bool> {
1833            loop {
1834                if self.entries.is_empty() {
1835                    return Ok(false);
1836                }
1837
1838                if !self.entries.read_entry(&mut entry.read_entry)? {
1839                    // Null entry.
1840                    continue;
1841                }
1842                entry.read_unit = self.read_unit;
1843                Self::filter_attributes(entry)?;
1844
1845                while let Some(parent) = self.parents.last() {
1846                    if parent.depth < entry.depth {
1847                        break;
1848                    }
1849                    self.parents.pop();
1850                }
1851                let parent = self.parents.last().copied();
1852                entry.parent = parent.map(|p| p.offset);
1853                entry.parent_tag = parent.map(|p| p.tag);
1854
1855                if entry.has_children() {
1856                    self.parents.push(FilterParent {
1857                        depth: entry.depth,
1858                        offset: entry.offset,
1859                        tag: entry.tag,
1860                    });
1861                }
1862
1863                let entry_offset = entry.offset.to_unit_section_offset(&self.read_unit);
1864                let mut deps = Vec::new();
1865                for attr in &entry.attrs {
1866                    self.add_attribute_refs(&mut deps, attr.value())?;
1867                }
1868                if let Some(parent) = parent {
1869                    let parent_offset = parent.offset.to_unit_section_offset(&self.read_unit);
1870                    deps.push(parent_offset);
1871                    if parent.tag != constants::DW_TAG_namespace && entry.has_die_back_edge() {
1872                        self.deps.add_edge(parent_offset, entry_offset);
1873                    }
1874                }
1875                self.deps.add_entry(entry_offset, deps);
1876
1877                return Ok(true);
1878            }
1879        }
1880
1881        fn filter_attributes(entry: &mut FilterUnitEntry<'a, R>) -> ConvertResult<()> {
1882            entry.read_entry.attrs.retain(|attr| {
1883                match attr.name() {
1884                    // Skip DWARF metadata attributes.
1885                    // TODO: should DWO attributes be conditionally kept?
1886                    constants::DW_AT_sibling
1887                    | constants::DW_AT_str_offsets_base
1888                    | constants::DW_AT_addr_base
1889                    | constants::DW_AT_rnglists_base
1890                    | constants::DW_AT_loclists_base
1891                    | constants::DW_AT_dwo_name
1892                    | constants::DW_AT_GNU_addr_base
1893                    | constants::DW_AT_GNU_ranges_base
1894                    | constants::DW_AT_GNU_dwo_name
1895                    | constants::DW_AT_GNU_dwo_id => false,
1896                    _ => true,
1897                }
1898            });
1899            Ok(())
1900        }
1901
1902        fn add_attribute_refs(
1903            &mut self,
1904            deps: &mut Vec<UnitSectionOffset>,
1905            value: read::AttributeValue<R>,
1906        ) -> ConvertResult<()> {
1907            match value {
1908                read::AttributeValue::UnitRef(val) => {
1909                    // This checks that the offset is within bounds, but not that it refers to a valid DIE.
1910                    if val.is_in_bounds(&self.read_unit) {
1911                        deps.push(val.to_unit_section_offset(&self.read_unit));
1912                    }
1913                }
1914                read::AttributeValue::DebugInfoRef(val) => {
1915                    let offset = val
1916                        .to_unit_section_offset(&self.read_unit)
1917                        .ok_or(ConvertError::InvalidDebugInfoRef)?;
1918                    deps.push(offset);
1919                }
1920                read::AttributeValue::Exprloc(expression) => {
1921                    self.add_expression_refs(deps, expression.clone())?;
1922                }
1923                read::AttributeValue::LocationListsRef(val) => {
1924                    self.add_location_refs(deps, val)?;
1925                }
1926                read::AttributeValue::DebugLocListsIndex(index) => {
1927                    self.add_location_refs(deps, self.read_unit.locations_offset(index)?)?;
1928                }
1929                _ => (),
1930            }
1931            Ok(())
1932        }
1933
1934        fn add_location_refs(
1935            &mut self,
1936            deps: &mut Vec<UnitSectionOffset>,
1937            offset: LocationListsOffset,
1938        ) -> ConvertResult<()> {
1939            let mut locations = self.read_unit.locations(offset)?;
1940            while let Some(location) = locations.next()? {
1941                self.add_expression_refs(deps, location.data)?;
1942            }
1943            Ok(())
1944        }
1945
1946        fn add_expression_refs(
1947            &mut self,
1948            deps: &mut Vec<UnitSectionOffset>,
1949            expression: read::Expression<R>,
1950        ) -> ConvertResult<()> {
1951            let mut ops = expression.operations(self.read_unit.encoding());
1952            // Ignore parsing errors. They can be handled in the conversion step.
1953            while let Ok(Some(op)) = ops.next() {
1954                match op {
1955                    read::Operation::Deref {
1956                        base_type: offset, ..
1957                    }
1958                    | read::Operation::RegisterOffset {
1959                        base_type: offset, ..
1960                    }
1961                    | read::Operation::TypedLiteral {
1962                        base_type: offset, ..
1963                    }
1964                    | read::Operation::Convert {
1965                        base_type: offset, ..
1966                    }
1967                    | read::Operation::Reinterpret {
1968                        base_type: offset, ..
1969                    }
1970                    | read::Operation::ParameterRef { offset, .. }
1971                    | read::Operation::Call {
1972                        offset: read::DieReference::UnitRef(offset),
1973                        ..
1974                    } => {
1975                        if offset.is_in_bounds(&self.read_unit) {
1976                            deps.push(offset.to_unit_section_offset(&self.read_unit));
1977                        }
1978                    }
1979                    read::Operation::Call {
1980                        offset: read::DieReference::DebugInfoRef(ref_offset),
1981                        ..
1982                    } => {
1983                        let offset = ref_offset
1984                            .to_unit_section_offset(&self.read_unit)
1985                            .ok_or(ConvertError::InvalidDebugInfoRef)?;
1986                        deps.push(offset);
1987                    }
1988                    _ => {}
1989                }
1990            }
1991            Ok(())
1992        }
1993
1994        /// Indicate that the DIE with the given offset is always required to be converted.
1995        ///
1996        /// Typically, this will be called if the DIE has a valid address range.
1997        ///
1998        /// This can only be called for offsets within the current unit.
1999        pub fn require_entry(&mut self, offset: read::UnitOffset) {
2000            debug_assert!(offset.is_in_bounds(&self.read_unit));
2001            self.deps
2002                .require_entry(offset.to_unit_section_offset(&self.read_unit));
2003        }
2004    }
2005
2006    /// A DIE read by [`FilterUnit::read_entry`].
2007    ///
2008    /// This is a simple wrapper that adds some extra information to
2009    /// [`read::DebuggingInformationEntry`]. The inner [`Self::read_entry`] is accessible
2010    /// via `Deref`.
2011    ///
2012    /// See [`FilterUnitSection`] for an example.
2013    #[derive(Debug)]
2014    #[non_exhaustive]
2015    pub struct FilterUnitEntry<'a, R: Reader<Offset = usize>> {
2016        /// The unit that this DIE was read from.
2017        ///
2018        /// This may be a skeleton unit.
2019        pub read_unit: read::UnitRef<'a, R>,
2020        /// The DIE that was read.
2021        pub read_entry: read::DebuggingInformationEntry<R>,
2022        /// The offset of this DIE's parent, if any.
2023        ///
2024        /// This is set to `None` if the parent is the root of the unit.
2025        pub parent: Option<read::UnitOffset>,
2026        /// The tag of this DIE's parent, if any.
2027        ///
2028        /// This is set to `None` if the parent is the root of the unit.
2029        pub parent_tag: Option<constants::DwTag>,
2030    }
2031
2032    impl<'a, R: Reader<Offset = usize>> Deref for FilterUnitEntry<'a, R> {
2033        type Target = read::DebuggingInformationEntry<R>;
2034
2035        fn deref(&self) -> &Self::Target {
2036            &self.read_entry
2037        }
2038    }
2039
2040    impl<'a, R: Reader<Offset = usize>> FilterUnitEntry<'a, R> {
2041        /// Return a null entry.
2042        ///
2043        /// This can be used with [`FilterUnit::read_entry`],
2044        pub fn null(read_unit: read::UnitRef<'a, R>) -> Self {
2045            FilterUnitEntry {
2046                read_unit,
2047                read_entry: read::DebuggingInformationEntry::null(),
2048                parent: None,
2049                parent_tag: None,
2050            }
2051        }
2052
2053        /// Return `true` if this DIE has a back-edge to its parent.
2054        // DIEs can be broadly divided into three categories:
2055        // 1. Extensions of their parents; effectively attributes: DW_TAG_variable, DW_TAG_member, etc.
2056        // 2. Standalone entities referred to by other DIEs via 'reference' class attributes: types.
2057        // 3. Structural entities that organize how the above relate to each other: namespaces.
2058        // Here, we must make sure to return 'true' for DIEs in the first category since stripping them,
2059        // provided their parent is alive, is always wrong. To be conservatively correct in the face
2060        // of new/vendor tags, we maintain a "(mostly) known good" list of tags of the latter categories.
2061        fn has_die_back_edge(&self) -> bool {
2062            match self.tag {
2063                constants::DW_TAG_array_type
2064                | constants::DW_TAG_atomic_type
2065                | constants::DW_TAG_base_type
2066                | constants::DW_TAG_class_type
2067                | constants::DW_TAG_const_type
2068                | constants::DW_TAG_dwarf_procedure
2069                | constants::DW_TAG_entry_point
2070                | constants::DW_TAG_enumeration_type
2071                | constants::DW_TAG_pointer_type
2072                | constants::DW_TAG_ptr_to_member_type
2073                | constants::DW_TAG_reference_type
2074                | constants::DW_TAG_restrict_type
2075                | constants::DW_TAG_rvalue_reference_type
2076                | constants::DW_TAG_string_type
2077                | constants::DW_TAG_structure_type
2078                | constants::DW_TAG_typedef
2079                | constants::DW_TAG_union_type
2080                | constants::DW_TAG_unspecified_type
2081                | constants::DW_TAG_volatile_type
2082                | constants::DW_TAG_coarray_type
2083                | constants::DW_TAG_common_block
2084                | constants::DW_TAG_dynamic_type
2085                | constants::DW_TAG_file_type
2086                | constants::DW_TAG_immutable_type
2087                | constants::DW_TAG_interface_type
2088                | constants::DW_TAG_set_type
2089                | constants::DW_TAG_shared_type
2090                | constants::DW_TAG_subroutine_type
2091                | constants::DW_TAG_packed_type
2092                | constants::DW_TAG_template_alias
2093                | constants::DW_TAG_namelist
2094                | constants::DW_TAG_namespace
2095                | constants::DW_TAG_imported_unit
2096                | constants::DW_TAG_imported_declaration
2097                | constants::DW_TAG_imported_module
2098                | constants::DW_TAG_module => false,
2099                constants::DW_TAG_subprogram => self.has_attr(constants::DW_AT_declaration),
2100                _ => true,
2101            }
2102        }
2103    }
2104
2105    /// The state for the conversion of a `.debug_info` section.
2106    ///
2107    /// Created by [`Dwarf::convert`] or [`Dwarf::convert_with_filter`].
2108    #[derive(Debug)]
2109    pub struct ConvertUnitSection<'a, R: Reader<Offset = usize>> {
2110        read_dwarf: &'a read::Dwarf<R>,
2111        read_units: Vec<(read::Unit<R>, UnitId)>,
2112        /// The next unit in `read_units` to return from `read_unit`.
2113        read_unit_index: usize,
2114        /// The associated skeleton unit if this is a split DWARF section.
2115        ///
2116        /// If this is set then `read_units` will contain exactly one unit.
2117        read_skeleton_unit: Option<read::UnitRef<'a, R>>,
2118        entry_ids: FnvHashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
2119        dwarf: &'a mut Dwarf,
2120    }
2121
2122    impl<'a, R: Reader<Offset = usize>> ConvertUnitSection<'a, R> {
2123        /// Create a converter for the `.debug_info` section of the given DWARF object.
2124        pub(crate) fn new(
2125            read_dwarf: &'a read::Dwarf<R>,
2126            dwarf: &'a mut Dwarf,
2127        ) -> ConvertResult<Self> {
2128            let mut convert = ConvertUnitSection {
2129                read_dwarf,
2130                read_units: Vec::new(),
2131                read_unit_index: 0,
2132                read_skeleton_unit: None,
2133                entry_ids: FnvHashMap::default(),
2134                dwarf,
2135            };
2136
2137            // Assigns ids to all units and entries, so that we can convert
2138            // references in attributes.
2139            let mut offsets = Vec::new();
2140            let mut read_units = read_dwarf.units();
2141            while let Some(read_unit) = read_units.next()? {
2142                let read_unit = read_dwarf.unit(read_unit)?;
2143                read_entry_offsets(&read_unit, &mut offsets)?;
2144                convert.reserve_unit(read_unit, &offsets);
2145            }
2146
2147            Ok(convert)
2148        }
2149
2150        /// Create a converter for the `.debug_info` section of the given DWARF object.
2151        ///
2152        /// Only reachable entries identified by `filter` will be reserved.
2153        ///
2154        /// Units with no reachable entries will be skipped.
2155        pub(crate) fn new_with_filter(
2156            dwarf: &'a mut Dwarf,
2157            filter: FilterUnitSection<'a, R>,
2158        ) -> ConvertResult<Self> {
2159            let mut convert = ConvertUnitSection {
2160                read_dwarf: filter.dwarf,
2161                read_units: Vec::new(),
2162                read_unit_index: 0,
2163                read_skeleton_unit: filter.skeleton_unit,
2164                entry_ids: FnvHashMap::default(),
2165                dwarf,
2166            };
2167
2168            let offsets = filter.deps.get_reachable();
2169
2170            // Reserve all filtered entries.
2171            let mut start;
2172            let mut end = 0;
2173            for unit in filter.units {
2174                start = end;
2175                while let Some(offset) = offsets.get(end) {
2176                    if offset.to_unit_offset(&unit).is_none() {
2177                        break;
2178                    }
2179                    end += 1;
2180                }
2181                convert.reserve_unit(unit, &offsets[start..end]);
2182            }
2183            debug_assert_eq!(end, offsets.len());
2184
2185            Ok(convert)
2186        }
2187
2188        /// Create a placeholder for each entry in a unit.
2189        ///
2190        /// This allows us to assign IDs to entries before they are created.
2191        fn reserve_unit(&mut self, unit: read::Unit<R>, offsets: &[UnitSectionOffset]) {
2192            let root_offset = unit.header.root_offset().to_unit_section_offset(&unit);
2193
2194            let unit_id = self
2195                .dwarf
2196                .units
2197                .add(Unit::new(unit.encoding(), LineProgram::none()));
2198            self.read_units.push((unit, unit_id));
2199            let unit = self.dwarf.units.get_mut(unit_id);
2200
2201            self.entry_ids.insert(root_offset, (unit_id, unit.root()));
2202            for offset in offsets {
2203                self.entry_ids.insert(*offset, (unit_id, unit.reserve()));
2204            }
2205        }
2206
2207        /// Read the next unit header and prepare to convert it.
2208        ///
2209        /// Returns a `ConvertUnit` for the unit, and a `ConvertUnitEntry` for the root
2210        /// DIE.
2211        ///
2212        /// See [`ConvertUnit`] for an example of the unit conversion.
2213        pub fn read_unit(
2214            &mut self,
2215        ) -> ConvertResult<Option<(ConvertUnit<'_, R>, ConvertUnitEntry<'_, R>)>> {
2216            let Some((read_unit, unit_id)) = self.read_units.get(self.read_unit_index) else {
2217                return Ok(None);
2218            };
2219            self.read_unit_index += 1;
2220
2221            let read_unit = read_unit.unit_ref(self.read_dwarf);
2222
2223            let mut unit = ConvertUnit {
2224                read_unit,
2225                read_skeleton_unit: self.read_skeleton_unit,
2226                unit_id: *unit_id,
2227                unit: self.dwarf.units.get_mut(*unit_id),
2228                entry_ids: &self.entry_ids,
2229                line_strings: &mut self.dwarf.line_strings,
2230                strings: &mut self.dwarf.strings,
2231                line_program_files: Vec::new(),
2232                read_entries: read_unit.entries_raw(None)?,
2233                parents: Vec::new(),
2234            };
2235            let mut root_entry = unit.null_entry();
2236            unit.read_entry(&mut root_entry)?
2237                .ok_or(read::Error::MissingUnitDie)?;
2238            Ok(Some((unit, root_entry)))
2239        }
2240    }
2241
2242    /// The state for the conversion of a split `.debug_info` section.
2243    ///
2244    /// Created by [`ConvertUnit::convert_split`] or
2245    /// [`ConvertUnit::convert_split_with_filter`].
2246    #[derive(Debug)]
2247    pub struct ConvertSplitUnitSection<'a, R: Reader<Offset = usize>> {
2248        read_dwarf: &'a read::Dwarf<R>,
2249        read_unit: read::Unit<R>,
2250        read_skeleton_unit: read::UnitRef<'a, R>,
2251        entry_ids: FnvHashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
2252        unit_id: UnitId,
2253        unit: &'a mut write::Unit,
2254        line_strings: &'a mut write::LineStringTable,
2255        strings: &'a mut write::StringTable,
2256    }
2257
2258    impl<'a, R: Reader<Offset = usize>> ConvertSplitUnitSection<'a, R> {
2259        fn new(
2260            skeleton: &'a mut ConvertUnit<'a, R>,
2261            split_dwarf: &'a read::Dwarf<R>,
2262        ) -> ConvertResult<Self> {
2263            debug_assert!(skeleton.read_skeleton_unit.is_none());
2264
2265            let split_unit_header = split_dwarf
2266                .units()
2267                .next()?
2268                .ok_or(read::Error::MissingSplitUnit)?;
2269            let mut split_unit = split_dwarf.unit(split_unit_header)?;
2270            split_unit.copy_relocated_attributes(&skeleton.read_unit);
2271
2272            let mut offsets = Vec::new();
2273            read_entry_offsets(&split_unit, &mut offsets)?;
2274
2275            Self::new_with_offsets(skeleton, split_dwarf, split_unit, offsets)
2276        }
2277
2278        fn new_with_filter(
2279            skeleton: &'a mut ConvertUnit<'a, R>,
2280            filter: FilterUnitSection<'a, R>,
2281        ) -> ConvertResult<Self> {
2282            debug_assert!(skeleton.read_skeleton_unit.is_none());
2283
2284            let split_unit = filter
2285                .units
2286                .into_iter()
2287                .next()
2288                .ok_or(read::Error::MissingSplitUnit)?;
2289
2290            let offsets = filter.deps.get_reachable();
2291
2292            Self::new_with_offsets(skeleton, filter.dwarf, split_unit, offsets)
2293        }
2294
2295        fn new_with_offsets(
2296            skeleton: &'a mut ConvertUnit<'a, R>,
2297            split_dwarf: &'a read::Dwarf<R>,
2298            split_unit: read::Unit<R>,
2299            offsets: Vec<UnitSectionOffset>,
2300        ) -> ConvertResult<Self> {
2301            let root_offset = split_unit
2302                .header
2303                .root_offset()
2304                .to_unit_section_offset(&split_unit);
2305
2306            // Replace the unit that was reserved for the skeleton unit.
2307            let unit_id = skeleton.unit_id;
2308            let unit = &mut *skeleton.unit;
2309
2310            let mut entry_ids = FnvHashMap::default();
2311            entry_ids.insert(root_offset, (unit_id, unit.root()));
2312            for offset in offsets {
2313                entry_ids.insert(offset, (unit_id, unit.reserve()));
2314            }
2315
2316            Ok(ConvertSplitUnitSection {
2317                read_dwarf: split_dwarf,
2318                read_unit: split_unit,
2319                read_skeleton_unit: skeleton.read_unit,
2320                entry_ids,
2321                unit_id,
2322                unit,
2323                line_strings: skeleton.line_strings,
2324                strings: skeleton.strings,
2325            })
2326        }
2327
2328        /// Read the split unit header and prepare to convert it.
2329        ///
2330        /// Returns a `ConvertUnit` for the unit, and a `ConvertUnitEntry` for the root
2331        /// DIE.
2332        ///
2333        /// See [`ConvertUnit`] for an example of the unit conversion.
2334        pub fn read_unit(
2335            &'_ mut self,
2336        ) -> ConvertResult<(ConvertUnit<'_, R>, ConvertUnitEntry<'_, R>)> {
2337            let read_unit = self.read_unit.unit_ref(self.read_dwarf);
2338
2339            let mut unit = ConvertUnit {
2340                read_unit,
2341                read_skeleton_unit: Some(self.read_skeleton_unit),
2342                unit_id: self.unit_id,
2343                unit: self.unit,
2344                entry_ids: &self.entry_ids,
2345                line_strings: self.line_strings,
2346                strings: self.strings,
2347                line_program_files: Vec::new(),
2348                read_entries: read_unit.entries_raw(None)?,
2349                parents: Vec::new(),
2350            };
2351            let mut root_entry = unit.null_entry();
2352            unit.read_entry(&mut root_entry)?
2353                .ok_or(read::Error::MissingUnitDie)?;
2354            Ok((unit, root_entry))
2355        }
2356    }
2357
2358    /// Read entry offsets for a unit.
2359    ///
2360    /// `offsets` is cleared first, allowing reuse of the allocation.
2361    ///
2362    /// Does not include the root entry.
2363    fn read_entry_offsets<R: Reader<Offset = usize>>(
2364        unit: &read::Unit<R>,
2365        offsets: &mut Vec<UnitSectionOffset>,
2366    ) -> ConvertResult<()> {
2367        let mut read_entries = unit.entries_raw(None)?;
2368
2369        // The root entry is skipped because write::Unit always creates a root entry.
2370        let abbrev = read_entries
2371            .read_abbreviation()?
2372            .ok_or(read::Error::MissingUnitDie)?;
2373        read_entries.skip_attributes(abbrev.attributes())?;
2374
2375        offsets.clear();
2376        while !read_entries.is_empty() {
2377            let offset = read_entries.next_offset();
2378            let Some(abbrev) = read_entries.read_abbreviation()? else {
2379                continue;
2380            };
2381            read_entries.skip_attributes(abbrev.attributes())?;
2382            offsets.push(offset.to_unit_section_offset(unit));
2383        }
2384
2385        Ok(())
2386    }
2387
2388    /// The state for the conversion of a `.debug_info` unit.
2389    ///
2390    /// This is created by [`ConvertUnitSection::read_unit`] or
2391    /// [`ConvertSplitUnitSection::read_unit`].
2392    ///
2393    /// ## Example
2394    ///
2395    /// Convert a unit.
2396    ///
2397    /// ```rust,no_run
2398    /// # fn example() -> Result<(), gimli::write::ConvertError> {
2399    /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
2400    /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
2401    /// let mut write_dwarf = gimli::write::Dwarf::new();
2402    /// let mut convert = write_dwarf.convert(&read_dwarf)?;
2403    /// while let Some((mut unit, root_entry)) = convert.read_unit()? {
2404    ///     if let Some(convert_program) = unit.read_line_program(None, None)? {
2405    ///         let (program, files) = convert_program.convert(
2406    ///             &|address| Some(gimli::write::Address::Constant(address)),
2407    ///         )?;
2408    ///         unit.set_line_program(program, files);
2409    ///     }
2410    ///     let root_id = unit.unit.root();
2411    ///     convert_attributes(&mut unit, root_id, &root_entry)?;
2412    ///     let mut entry = root_entry;
2413    ///     while let Some(id) = unit.read_entry(&mut entry)? {
2414    ///         // `id` is `None` for DIEs that weren't reserved and thus don't need converting.
2415    ///         // This only happens when `FilterUnitSection` is used.
2416    ///         if id.is_none() {
2417    ///             continue;
2418    ///         }
2419    ///         let id = unit.add_entry(id, &entry);
2420    ///         convert_attributes(&mut unit, id, &entry)?;
2421    ///     }
2422    /// }
2423    ///
2424    /// fn convert_attributes<R: gimli::Reader<Offset = usize>>(
2425    ///     unit: &mut gimli::write::ConvertUnit<'_, R>,
2426    ///     id: gimli::write::UnitEntryId,
2427    ///     entry: &gimli::write::ConvertUnitEntry<'_, R>,
2428    /// ) -> gimli::write::ConvertResult<()> {
2429    ///     for attr in &entry.attrs {
2430    ///         let value = unit.convert_attribute_value(
2431    ///             entry.read_unit,
2432    ///             attr,
2433    ///             &|address| Some(gimli::write::Address::Constant(address)),
2434    ///         )?;
2435    ///         unit.unit.get_mut(id).set(attr.name(), value);
2436    ///     }
2437    ///     Ok(())
2438    /// }
2439    /// # unreachable!()
2440    /// # }
2441    /// ```
2442    #[derive(Debug)]
2443    pub struct ConvertUnit<'a, R: Reader<Offset = usize>> {
2444        /// The unit being read from.
2445        pub read_unit: read::UnitRef<'a, R>,
2446        /// The skeleton unit being read from if `read_unit` is a split unit.
2447        pub read_skeleton_unit: Option<read::UnitRef<'a, R>>,
2448        unit_id: UnitId,
2449        /// The unit being written to.
2450        pub unit: &'a mut write::Unit,
2451        /// The table containing converted line strings.
2452        pub line_strings: &'a mut write::LineStringTable,
2453        /// The table containing converted strings.
2454        pub strings: &'a mut write::StringTable,
2455        line_program_files: Vec<FileId>,
2456        entry_ids: &'a FnvHashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
2457        read_entries: read::EntriesRaw<'a, R>,
2458        parents: Vec<(isize, UnitEntryId)>,
2459    }
2460
2461    impl<'a, R: Reader<Offset = usize>> ConvertUnit<'a, R> {
2462        /// Create a converter for all DIEs in a split DWARF unit and its skeleton unit.
2463        ///
2464        /// `split_dwarf` is the unit's contribution to the DWARF sections
2465        /// in a `DwarfPackage`, or the DWARF sections in a DWO file.
2466        ///
2467        /// ## Example
2468        ///
2469        /// Convert a split DWARF unit using `convert_split`.
2470        ///
2471        /// ```rust,no_run
2472        /// # fn example() -> Result<(), gimli::write::ConvertError> {
2473        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
2474        /// # let skeleton_unit: gimli::UnitRef<'static, gimli::EndianSlice<gimli::RunTimeEndian>> = unimplemented!();
2475        /// let dwp = gimli::read::DwarfPackage::load(loader, Default::default())?;
2476        /// let mut convert: gimli::write::ConvertUnitSection<_> = unimplemented!();
2477        /// while let Some((mut unit, root_entry)) = convert.read_unit()? {
2478        ///     let Some(dwo_id) = unit.read_unit.dwo_id else {
2479        ///         // Not a split unit. Handling omitted for this example.
2480        ///         continue;
2481        ///     };
2482        ///     let split_dwarf = dwp.find_cu(dwo_id, skeleton_unit.dwarf)?.unwrap();
2483        ///     let mut convert_split = unit.convert_split(&split_dwarf)?;
2484        ///     let (split_unit, split_root_entry) = convert_split.read_unit()?;
2485        ///     // Now you can convert the root entry attributes, and other entries.
2486        /// }
2487        /// # unreachable!()
2488        /// # }
2489        /// ```
2490        pub fn convert_split(
2491            &'a mut self,
2492            split_dwarf: &'a read::Dwarf<R>,
2493        ) -> ConvertResult<ConvertSplitUnitSection<'a, R>> {
2494            ConvertSplitUnitSection::new(self, split_dwarf)
2495        }
2496
2497        /// Create a converter for some of the  DIEs in a split DWARF unit and its skeleton unit.
2498        ///
2499        /// `filter` determines which DIEs are converted. This can be created using
2500        /// [`FilterUnitSection::new_split`].
2501        ///
2502        /// ## Example
2503        ///
2504        /// Convert a split DWARF unit using `convert_split_with_filter`.
2505        ///
2506        /// ```rust,no_run
2507        /// # fn example() -> Result<(), gimli::write::ConvertError> {
2508        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
2509        /// # let need_entry = &|entry: &gimli::write::FilterUnitEntry<_>| -> Result<bool, gimli::write::ConvertError> { Ok(false) };
2510        /// # let skeleton_unit: gimli::UnitRef<'static, gimli::EndianSlice<gimli::RunTimeEndian>> = unimplemented!();
2511        /// let dwp = gimli::read::DwarfPackage::load(loader, Default::default())?;
2512        /// let mut convert: gimli::write::ConvertUnitSection<_> = unimplemented!();
2513        /// while let Some((mut unit, root_entry)) = convert.read_unit()? {
2514        ///     let Some(dwo_id) = unit.read_unit.dwo_id else {
2515        ///         // Not a split unit. Handling omitted for this example.
2516        ///         continue;
2517        ///     };
2518        ///     let split_dwarf = dwp.find_cu(dwo_id, skeleton_unit.dwarf)?.unwrap();
2519        ///     let mut filter = gimli::write::FilterUnitSection::new_split(&split_dwarf, unit.read_unit)?;
2520        ///     while let Some(mut unit) = filter.read_unit()? {
2521        ///         let mut entry = unit.null_entry();
2522        ///         while unit.read_entry(&mut entry)? {
2523        ///             if need_entry(&entry)? {
2524        ///                 unit.require_entry(entry.offset);
2525        ///             }
2526        ///         }
2527        ///     }
2528        ///     let mut convert_split = unit.convert_split_with_filter(filter)?;
2529        ///     let (split_unit, split_root_entry) = convert_split.read_unit()?;
2530        ///     // Now you can convert the root entry attributes, and other entries.
2531        /// }
2532        /// # unreachable!()
2533        /// # }
2534        /// ```
2535        pub fn convert_split_with_filter(
2536            &'a mut self,
2537            filter: FilterUnitSection<'a, R>,
2538        ) -> ConvertResult<ConvertSplitUnitSection<'a, R>> {
2539            ConvertSplitUnitSection::new_with_filter(self, filter)
2540        }
2541
2542        /// Start converting the line number program for this unit.
2543        ///
2544        /// `encoding` and `line_encoding` apply to the converted program, and
2545        /// may be different from the source program. If `None`, the encoding from
2546        /// the source program is used.
2547        ///
2548        /// Returns `Ok(None)` if there is no line number program for this unit.
2549        ///
2550        /// See [`ConvertLineProgram`] for an example of converting the program.
2551        pub fn read_line_program(
2552            &'_ mut self,
2553            encoding: Option<Encoding>,
2554            line_encoding: Option<LineEncoding>,
2555        ) -> ConvertResult<Option<ConvertLineProgram<'_, R>>> {
2556            let read_unit = self.read_skeleton_unit.unwrap_or(self.read_unit);
2557            let Some(read_program) = &read_unit.line_program else {
2558                return Ok(None);
2559            };
2560            ConvertLineProgram::new(
2561                read_unit.dwarf,
2562                read_program.clone(),
2563                // If the program is in a skeleton unit, then pass the name from the split unit.
2564                self.read_skeleton_unit
2565                    .and_then(|_| self.read_unit.name.clone()),
2566                encoding,
2567                line_encoding,
2568                self.line_strings,
2569                self.strings,
2570            )
2571            .map(Some)
2572        }
2573
2574        /// Sets the converted line program for the unit, and the mapping for converting
2575        /// file index attributes.
2576        ///
2577        /// The parameters are from the result of [`ConvertLineProgram::program`].
2578        pub fn set_line_program(
2579            &mut self,
2580            line_program: LineProgram,
2581            line_program_files: Vec<FileId>,
2582        ) {
2583            self.unit.line_program = line_program;
2584            self.line_program_files = line_program_files;
2585        }
2586
2587        /// Return a null DIE for use with [`ConvertUnit::read_entry`].
2588        pub fn null_entry(&self) -> ConvertUnitEntry<'a, R> {
2589            ConvertUnitEntry::null(self.read_unit)
2590        }
2591
2592        /// Read the next DIE from the input.
2593        ///
2594        /// Returns the `UnitEntryId` that was reserved for the entry, if any. If you wish
2595        /// to use this ID, you must call [`Unit::add_reserved`] or [`ConvertUnit::add_entry`].
2596        ///
2597        /// Returns a [`ConvertUnitEntry`] containing information about the DIE and its
2598        /// attributes.
2599        ///
2600        /// Returns `Ok(None)` if there are no more entries.
2601        pub fn read_entry(
2602            &mut self,
2603            entry: &mut ConvertUnitEntry<'a, R>,
2604        ) -> ConvertResult<Option<Option<UnitEntryId>>> {
2605            loop {
2606                if self.read_entries.is_empty() {
2607                    return Ok(None);
2608                }
2609
2610                if !self.read_entries.read_entry(&mut entry.read_entry)? {
2611                    // Null entry.
2612                    continue;
2613                };
2614                entry.read_unit = self.read_unit;
2615                entry.filter_attributes();
2616
2617                let section_offset = entry.offset.to_unit_section_offset(&self.read_unit);
2618                let id = self.entry_ids.get(&section_offset).map(|entry| entry.1);
2619
2620                entry.parent = None;
2621                while let Some((parent_depth, parent_id)) = self.parents.last().copied() {
2622                    if parent_depth < entry.depth {
2623                        entry.parent = Some(parent_id);
2624                        break;
2625                    }
2626                    self.parents.pop();
2627                }
2628
2629                if let Some(id) = id
2630                    && entry.has_children()
2631                {
2632                    self.parents.push((entry.depth, id));
2633                }
2634
2635                return Ok(Some(id));
2636            }
2637        }
2638
2639        /// Add an entry to the converted unit.
2640        ///
2641        /// The tag, parent, and `DW_AT_sibling` attribute are set using the
2642        /// fields of `entry`. No other attributes are copied.
2643        ///
2644        /// `id` is the entry ID that was reserved, if any. This is usually the ID that
2645        /// was returned by [`ConvertUnit::read_entry`]. [`Unit::add_reserved`] will
2646        /// automatically be called for this ID. If not specified then a new ID is
2647        /// created.
2648        ///
2649        /// Returns the ID of the entry (either reserved or newly created).
2650        pub fn add_entry(
2651            &mut self,
2652            id: Option<UnitEntryId>,
2653            entry: &ConvertUnitEntry<'_, R>,
2654        ) -> UnitEntryId {
2655            let parent = entry.parent.unwrap_or(self.unit.root());
2656            let id = match id {
2657                Some(id) => {
2658                    self.unit.add_reserved(id, parent, entry.tag);
2659                    id
2660                }
2661                None => self.unit.add(parent, entry.tag),
2662            };
2663            let new_entry = self.unit.get_mut(id);
2664            new_entry.set_sibling(entry.sibling);
2665            new_entry.reserve(entry.attrs.len());
2666            id
2667        }
2668
2669        /// Write the unit to the given sections.
2670        ///
2671        /// This unit will be written immediately, instead of when [`Dwarf::write`] is called.
2672        /// Note that [`Dwarf::write`] must still be called after all units have been
2673        /// converted.
2674        ///
2675        /// This also frees memory associated with DIEs for this, which is useful for
2676        /// reducing total memory usage.
2677        pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
2678            let abbrev_offset = sections.debug_abbrev.offset();
2679            let mut abbrevs = AbbreviationTable::default();
2680            self.unit.write(
2681                sections,
2682                abbrev_offset,
2683                &mut abbrevs,
2684                self.line_strings,
2685                self.strings,
2686            )?;
2687            abbrevs.write(&mut sections.debug_abbrev)?;
2688            self.unit.free();
2689            Ok(())
2690        }
2691
2692        /// Mark this unit as unneeded.
2693        ///
2694        /// This unit will not be written, even when [`Dwarf::write`] is called.
2695        ///
2696        /// This also frees memory associated with DIEs for this unit, which is useful for
2697        /// reducing total memory usage.
2698        pub fn skip(&mut self) {
2699            self.unit.skip();
2700            self.unit.free();
2701        }
2702
2703        /// Convert everything in the unit.
2704        ///
2705        /// This will convert all DIEs, and the values referenced by the attributes
2706        /// such as strings, ranges, locations and line programs.
2707        /// The converted values will be stored in [`Self::unit`].
2708        ///
2709        /// `root_entry` must be the entry returned by [`ConvertUnitSection::read_unit`].
2710        ///
2711        /// See [`Dwarf::from`](crate::write::Dwarf::from) for the meaning of `convert_address`.
2712        pub fn convert(
2713            &mut self,
2714            root_entry: ConvertUnitEntry<'a, R>,
2715            convert_address: &dyn Fn(u64) -> Option<Address>,
2716        ) -> ConvertResult<()> {
2717            if let Some(convert_program) = self.read_line_program(None, None)? {
2718                let (program, files) = convert_program.convert(convert_address)?;
2719                self.set_line_program(program, files);
2720            }
2721            self.convert_attributes(self.unit.root(), &root_entry, convert_address)?;
2722            let mut entry = root_entry;
2723            while let Some(id) = self.read_entry(&mut entry)? {
2724                if id.is_none() {
2725                    continue;
2726                }
2727                let id = self.add_entry(id, &entry);
2728                self.convert_attributes(id, &entry, convert_address)?;
2729            }
2730            Ok(())
2731        }
2732
2733        pub(crate) fn convert_attributes(
2734            &mut self,
2735            id: UnitEntryId,
2736            entry: &ConvertUnitEntry<'_, R>,
2737            convert_address: &dyn Fn(u64) -> Option<Address>,
2738        ) -> ConvertResult<()> {
2739            for attr in &entry.attrs {
2740                if attr.name() == constants::DW_AT_GNU_locviews {
2741                    // This is a GNU extension that is not supported, and is safe to ignore.
2742                    // TODO: remove this when we support it.
2743                } else {
2744                    let value =
2745                        self.convert_attribute_value(entry.read_unit, attr, convert_address)?;
2746                    self.unit.get_mut(id).set(attr.name(), value);
2747                }
2748            }
2749            Ok(())
2750        }
2751
2752        /// Convert an attribute value.
2753        ///
2754        /// [`Self::set_line_program`] must be called before converting
2755        /// file index attributes.
2756        ///
2757        /// See [`Dwarf::from`](crate::write::Dwarf::from) for the meaning of `convert_address`.
2758        pub fn convert_attribute_value(
2759            &mut self,
2760            read_unit: read::UnitRef<'_, R>,
2761            attr: &read::Attribute<R>,
2762            convert_address: &dyn Fn(u64) -> Option<Address>,
2763        ) -> ConvertResult<AttributeValue> {
2764            if attr.form() == constants::DW_FORM_implicit_const {
2765                let implicit_const_value = match attr.raw_value() {
2766                    read::AttributeValue::Sdata(val) => val,
2767                    _ => return Err(ConvertError::InvalidAttributeValue),
2768                };
2769                // TODO: should we limit which names this is supported for?
2770                // For example, if it occurred for DW_AT_decl_file then we
2771                // wouldn't correct convert the file index.
2772                return Ok(AttributeValue::ImplicitConst(implicit_const_value));
2773            }
2774            Ok(match attr.value() {
2775                read::AttributeValue::Addr(val) => match (convert_address)(val) {
2776                    Some(val) => AttributeValue::Address(val),
2777                    None => return Err(ConvertError::InvalidAddress),
2778                },
2779                read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()),
2780                read::AttributeValue::Data1(val) => AttributeValue::Data1(val),
2781                read::AttributeValue::Data2(val) => AttributeValue::Data2(val),
2782                read::AttributeValue::Data4(val) => AttributeValue::Data4(val),
2783                read::AttributeValue::Data8(val) => AttributeValue::Data8(val),
2784                read::AttributeValue::Data16(val) => AttributeValue::Data16(val),
2785                read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val),
2786                read::AttributeValue::Udata(val) => AttributeValue::Udata(val),
2787                read::AttributeValue::Exprloc(expression) => {
2788                    if attr.name() == constants::DW_AT_vtable_elem_location {
2789                        let bytecode = expression.0.to_slice()?;
2790                        if bytecode.first().copied() == Some(constants::DW_OP_constu.0) {
2791                            // This is a vtable index. We must preserve the DW_OP_constu
2792                            // operation because gdb checks for it.
2793                            // `convert_expression` is unsuitable because it may convert
2794                            // to something like DW_OP_lit0.
2795                            return Ok(AttributeValue::Exprloc(Expression::raw(bytecode.to_vec())));
2796                        }
2797                    }
2798                    let expression =
2799                        self.convert_expression(read_unit, expression, convert_address)?;
2800                    AttributeValue::Exprloc(expression)
2801                }
2802                read::AttributeValue::Flag(val) => {
2803                    if attr.form() == constants::DW_FORM_flag_present {
2804                        AttributeValue::FlagPresent
2805                    } else {
2806                        AttributeValue::Flag(val)
2807                    }
2808                }
2809                read::AttributeValue::DebugAddrIndex(index) => {
2810                    let val = read_unit.address(index)?;
2811                    match convert_address(val) {
2812                        Some(val) => AttributeValue::Address(val),
2813                        None => return Err(ConvertError::InvalidAddress),
2814                    }
2815                }
2816                read::AttributeValue::UnitRef(val) => {
2817                    // TODO: must not be in the skeleton unit
2818                    AttributeValue::UnitRef(self.convert_unit_ref(val)?)
2819                }
2820                read::AttributeValue::DebugInfoRef(val) => {
2821                    // TODO: must not be in the skeleton unit
2822                    AttributeValue::DebugInfoRef(self.convert_debug_info_ref(val)?)
2823                }
2824                read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val),
2825                read::AttributeValue::DebugLineRef(val) => {
2826                    // There should only be a ref to the line program in the CU DIE.
2827                    if Some(val)
2828                        != read_unit
2829                            .line_program
2830                            .as_ref()
2831                            .map(|program| program.header().offset())
2832                    {
2833                        return Err(ConvertError::InvalidLineRef);
2834                    };
2835                    AttributeValue::LineProgramRef
2836                }
2837                read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val),
2838                read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val),
2839                read::AttributeValue::LocationListsRef(val) => {
2840                    let loc_list = self.convert_location_list(read_unit, val, convert_address)?;
2841                    let loc_id = self.unit.locations.add(loc_list);
2842                    AttributeValue::LocationListRef(loc_id)
2843                }
2844                read::AttributeValue::DebugLocListsIndex(index) => {
2845                    let offset = read_unit.locations_offset(index)?;
2846                    let loc_list =
2847                        self.convert_location_list(read_unit, offset, convert_address)?;
2848                    let loc_id = self.unit.locations.add(loc_list);
2849                    AttributeValue::LocationListRef(loc_id)
2850                }
2851                read::AttributeValue::RangeListsRef(offset) => {
2852                    let offset = read_unit.ranges_offset_from_raw(offset);
2853                    let range_list = self.convert_range_list(read_unit, offset, convert_address)?;
2854                    let range_id = self.unit.ranges.add(range_list);
2855                    AttributeValue::RangeListRef(range_id)
2856                }
2857                read::AttributeValue::DebugRngListsIndex(index) => {
2858                    let offset = read_unit.ranges_offset(index)?;
2859                    let range_list = self.convert_range_list(read_unit, offset, convert_address)?;
2860                    let range_id = self.unit.ranges.add(range_list);
2861                    AttributeValue::RangeListRef(range_id)
2862                }
2863                read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val),
2864                read::AttributeValue::DebugStrRef(offset) => {
2865                    let r = read_unit.string(offset)?;
2866                    let id = self.strings.add(r.to_slice()?);
2867                    AttributeValue::StringRef(id)
2868                }
2869                read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val),
2870                read::AttributeValue::DebugStrOffsetsIndex(index) => {
2871                    let offset = read_unit.string_offset(index)?;
2872                    let r = read_unit.string(offset)?;
2873                    let id = self.strings.add(r.to_slice()?);
2874                    AttributeValue::StringRef(id)
2875                }
2876                read::AttributeValue::DebugLineStrRef(offset) => {
2877                    let r = read_unit.line_string(offset)?;
2878                    let id = self.line_strings.add(r.to_slice()?);
2879                    AttributeValue::LineStringRef(id)
2880                }
2881                read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()),
2882                read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val),
2883                read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val),
2884                read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val),
2885                read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val),
2886                read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val),
2887                read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val),
2888                read::AttributeValue::Language(val) => AttributeValue::Language(val),
2889                read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val),
2890                read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val),
2891                read::AttributeValue::CallingConvention(val) => {
2892                    AttributeValue::CallingConvention(val)
2893                }
2894                read::AttributeValue::Inline(val) => AttributeValue::Inline(val),
2895                read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val),
2896                read::AttributeValue::FileIndex(val) => {
2897                    AttributeValue::FileIndex(self.convert_file_index(read_unit, val)?)
2898                }
2899                read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val),
2900                // Should always be a more specific section reference.
2901                read::AttributeValue::SecOffset(_) => {
2902                    return Err(ConvertError::InvalidAttributeValue);
2903                }
2904                // These are only used for metadata attributes, and should have
2905                // been skipped already.
2906                read::AttributeValue::DebugAddrBase(_)
2907                | read::AttributeValue::DebugLocListsBase(_)
2908                | read::AttributeValue::DebugRngListsBase(_)
2909                | read::AttributeValue::DebugStrOffsetsBase(_) => {
2910                    return Err(ConvertError::InvalidAttributeValue);
2911                }
2912            })
2913        }
2914
2915        /// Convert an expression.
2916        ///
2917        /// See [`Dwarf::from`](crate::write::Dwarf::from) for the meaning of `convert_address`.
2918        pub fn convert_expression(
2919            &self,
2920            read_unit: read::UnitRef<'_, R>,
2921            expression: read::Expression<R>,
2922            convert_address: &dyn Fn(u64) -> Option<Address>,
2923        ) -> ConvertResult<Expression> {
2924            Expression::from(
2925                expression,
2926                read_unit.encoding(),
2927                Some(read_unit),
2928                convert_address,
2929                self,
2930            )
2931        }
2932
2933        /// Convert a file index from a `DW_AT_decl_file` or similar attribute.
2934        ///
2935        /// [`Self::set_line_program`] must be called before converting
2936        /// file index attributes.
2937        pub fn convert_file_index(
2938            &self,
2939            read_unit: read::UnitRef<'_, R>,
2940            index: u64,
2941        ) -> ConvertResult<Option<FileId>> {
2942            if index == 0 && read_unit.encoding().version <= 4 {
2943                return Ok(None);
2944            }
2945            match self.line_program_files.get(index as usize) {
2946                Some(id) => Ok(Some(*id)),
2947                None => Err(ConvertError::InvalidFileIndex),
2948            }
2949        }
2950
2951        /// Convert a location list.
2952        ///
2953        /// See [`Dwarf::from`](crate::write::Dwarf::from) for the meaning of `convert_address`.
2954        pub fn convert_location_list(
2955            &self,
2956            read_unit: read::UnitRef<'_, R>,
2957            offset: LocationListsOffset,
2958            convert_address: &dyn Fn(u64) -> Option<Address>,
2959        ) -> ConvertResult<LocationList> {
2960            let iter = read_unit.raw_locations(offset)?;
2961            LocationList::from(iter, read_unit, convert_address, self)
2962        }
2963
2964        /// Convert a range list.
2965        ///
2966        /// See [`Dwarf::from`](crate::write::Dwarf::from) for the meaning of `convert_address`.
2967        pub fn convert_range_list(
2968            &self,
2969            read_unit: read::UnitRef<'_, R>,
2970            offset: RangeListsOffset,
2971            convert_address: &dyn Fn(u64) -> Option<Address>,
2972        ) -> ConvertResult<RangeList> {
2973            let iter = read_unit.raw_ranges(offset)?;
2974            RangeList::from(iter, read_unit, convert_address)
2975        }
2976
2977        /// Convert a reference to an entry in the same unit.
2978        ///
2979        /// This conversion doesn't work for references from a skeleton unit,
2980        /// but those shouldn't occur in practice.
2981        pub fn convert_unit_ref(&self, entry: read::UnitOffset) -> ConvertResult<UnitEntryId> {
2982            if !entry.is_in_bounds(&self.read_unit) {
2983                return Err(ConvertError::InvalidUnitRef);
2984            }
2985            let id = self
2986                .entry_ids
2987                .get(&entry.to_unit_section_offset(&self.read_unit))
2988                .ok_or(ConvertError::InvalidUnitRef)?;
2989            Ok(id.1)
2990        }
2991
2992        /// Convert a `.debug_info` reference.
2993        ///
2994        /// This conversion doesn't work for references from a skeleton unit,
2995        /// but those shouldn't occur in practice.
2996        pub fn convert_debug_info_ref(
2997            &self,
2998            entry: DebugInfoOffset,
2999        ) -> ConvertResult<DebugInfoRef> {
3000            // TODO: support relocation of this value
3001            let offset = entry
3002                .to_unit_section_offset(&self.read_unit)
3003                .ok_or(ConvertError::InvalidDebugInfoRef)?;
3004            let id = self
3005                .entry_ids
3006                .get(&offset)
3007                .ok_or(ConvertError::InvalidDebugInfoRef)?;
3008            Ok(DebugInfoRef::Entry(id.0, id.1))
3009        }
3010    }
3011
3012    /// A DIE read by [`ConvertUnit::read_entry`].
3013    ///
3014    /// This is a simple wrapper that adds some extra information to
3015    /// [`read::DebuggingInformationEntry`]. The inner [`Self::read_entry`] is accessible
3016    /// via `Deref`.
3017    #[derive(Debug)]
3018    #[non_exhaustive]
3019    pub struct ConvertUnitEntry<'a, R: Reader<Offset = usize>> {
3020        /// The unit that this DIE was read from.
3021        ///
3022        /// This may be a skeleton unit.
3023        pub read_unit: read::UnitRef<'a, R>,
3024        /// The DIE that was read.
3025        pub read_entry: read::DebuggingInformationEntry<R>,
3026        /// True if the `DW_AT_sibling` attribute was present.
3027        pub sibling: bool,
3028        /// The id of the entry that was reserved for this DIE's parent, if any.
3029        ///
3030        /// You may ignore this value if you wish to use a different parent.
3031        /// This is set to `None` if the parent is unknown or is the root DIE.
3032        pub parent: Option<UnitEntryId>,
3033    }
3034
3035    impl<'a, R: Reader<Offset = usize>> Deref for ConvertUnitEntry<'a, R> {
3036        type Target = read::DebuggingInformationEntry<R>;
3037
3038        fn deref(&self) -> &Self::Target {
3039            &self.read_entry
3040        }
3041    }
3042
3043    impl<'a, R: Reader<Offset = usize>> ConvertUnitEntry<'a, R> {
3044        /// Return a null entry.
3045        ///
3046        /// This can be used with [`ConvertUnit::read_entry`],
3047        pub fn null(read_unit: read::UnitRef<'a, R>) -> Self {
3048            ConvertUnitEntry {
3049                read_unit,
3050                read_entry: read::DebuggingInformationEntry::null(),
3051                sibling: false,
3052                parent: None,
3053            }
3054        }
3055
3056        /// Read the DIE at the given offset.
3057        ///
3058        /// This does not affect the state of the reader.
3059        /// The returned entry will not have a valid `depth` or `parent`.
3060        /// This may be used for entries that were not filtered or reserved.
3061        ///
3062        /// Returns an error if there is no entry at the given offset.
3063        pub fn read(
3064            read_unit: read::UnitRef<'a, R>,
3065            offset: read::UnitOffset,
3066        ) -> ConvertResult<ConvertUnitEntry<'a, R>> {
3067            let mut read_entries = read_unit.entries_raw(Some(offset))?;
3068            let mut read_entry = read::DebuggingInformationEntry::null();
3069            if !read_entries.read_entry(&mut read_entry)? {
3070                // Null entry.
3071                return Err(read::Error::NoEntryAtGivenOffset(offset.0.into_u64()).into());
3072            };
3073
3074            let mut entry = ConvertUnitEntry {
3075                read_unit,
3076                read_entry,
3077                sibling: false,
3078                parent: None,
3079            };
3080            entry.filter_attributes();
3081            Ok(entry)
3082        }
3083
3084        fn filter_attributes(&mut self) {
3085            self.sibling = false;
3086            self.read_entry.attrs.retain(|attr| {
3087                match attr.name() {
3088                    // This may point to a null entry, so we have to treat it differently.
3089                    constants::DW_AT_sibling => {
3090                        self.sibling = true;
3091                        false
3092                    }
3093                    // Skip DWARF metadata attributes.
3094                    // TODO: should DWO attributes be conditionally kept?
3095                    constants::DW_AT_str_offsets_base
3096                    | constants::DW_AT_addr_base
3097                    | constants::DW_AT_rnglists_base
3098                    | constants::DW_AT_loclists_base
3099                    | constants::DW_AT_dwo_name
3100                    | constants::DW_AT_GNU_addr_base
3101                    | constants::DW_AT_GNU_ranges_base
3102                    | constants::DW_AT_GNU_dwo_name
3103                    | constants::DW_AT_GNU_dwo_id => false,
3104                    _ => true,
3105                }
3106            });
3107        }
3108    }
3109
3110    pub(crate) trait ConvertDebugInfoRef {
3111        fn convert_unit_ref(&self, entry: read::UnitOffset) -> ConvertResult<UnitEntryId>;
3112        fn convert_debug_info_ref(&self, entry: DebugInfoOffset) -> ConvertResult<DebugInfoRef>;
3113    }
3114
3115    impl<'a, R: Reader<Offset = usize>> ConvertDebugInfoRef for ConvertUnit<'a, R> {
3116        fn convert_unit_ref(&self, entry: read::UnitOffset) -> ConvertResult<UnitEntryId> {
3117            ConvertUnit::convert_unit_ref(self, entry)
3118        }
3119
3120        fn convert_debug_info_ref(&self, entry: DebugInfoOffset) -> ConvertResult<DebugInfoRef> {
3121            ConvertUnit::convert_debug_info_ref(self, entry)
3122        }
3123    }
3124
3125    pub(crate) struct NoConvertDebugInfoRef;
3126
3127    impl ConvertDebugInfoRef for NoConvertDebugInfoRef {
3128        fn convert_unit_ref(&self, _entry: read::UnitOffset) -> ConvertResult<UnitEntryId> {
3129            Err(ConvertError::InvalidUnitRef)
3130        }
3131
3132        fn convert_debug_info_ref(&self, _entry: DebugInfoOffset) -> ConvertResult<DebugInfoRef> {
3133            Err(ConvertError::InvalidDebugInfoRef)
3134        }
3135    }
3136}
3137
3138#[cfg(test)]
3139#[cfg(feature = "read")]
3140mod tests {
3141    use super::*;
3142    use crate::LittleEndian;
3143    use crate::common::LineEncoding;
3144    use crate::constants;
3145    use crate::read;
3146    use crate::write::{
3147        Dwarf, DwarfUnit, EndianVec, LineString, Location, LocationList, Range, RangeList,
3148    };
3149    use core::mem;
3150
3151    #[test]
3152    fn test_unit_table() {
3153        let mut dwarf = Dwarf::new();
3154        let unit_id1 = dwarf.units.add(Unit::new(
3155            Encoding {
3156                version: 4,
3157                address_size: 8,
3158                format: Format::Dwarf32,
3159            },
3160            LineProgram::none(),
3161        ));
3162        let unit2 = dwarf.units.add(Unit::new(
3163            Encoding {
3164                version: 2,
3165                address_size: 4,
3166                format: Format::Dwarf64,
3167            },
3168            LineProgram::none(),
3169        ));
3170        let unit3 = dwarf.units.add(Unit::new(
3171            Encoding {
3172                version: 5,
3173                address_size: 4,
3174                format: Format::Dwarf32,
3175            },
3176            LineProgram::none(),
3177        ));
3178        assert_eq!(dwarf.units.count(), 3);
3179        {
3180            let unit1 = dwarf.units.get_mut(unit_id1);
3181            assert_eq!(unit1.version(), 4);
3182            assert_eq!(unit1.address_size(), 8);
3183            assert_eq!(unit1.format(), Format::Dwarf32);
3184            assert_eq!(unit1.count(), 1);
3185
3186            let root_id = unit1.root();
3187            assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0));
3188            {
3189                let root = unit1.get_mut(root_id);
3190                assert_eq!(root.id(), root_id);
3191                assert!(root.parent().is_none());
3192                assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
3193
3194                // Test get/get_mut
3195                assert!(root.get(constants::DW_AT_producer).is_none());
3196                assert!(root.get_mut(constants::DW_AT_producer).is_none());
3197                let mut producer = AttributeValue::String(b"root"[..].into());
3198                root.set(constants::DW_AT_producer, producer.clone());
3199                assert_eq!(root.get(constants::DW_AT_producer), Some(&producer));
3200                assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer));
3201
3202                // Test attrs
3203                let mut attrs = root.attrs();
3204                let attr = attrs.next().unwrap();
3205                assert_eq!(attr.name(), constants::DW_AT_producer);
3206                assert_eq!(attr.get(), &producer);
3207                assert!(attrs.next().is_none());
3208            }
3209
3210            let child1 = unit1.add(root_id, constants::DW_TAG_subprogram);
3211            assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1));
3212            {
3213                let child1 = unit1.get_mut(child1);
3214                assert_eq!(child1.parent(), Some(root_id));
3215
3216                let tmp = AttributeValue::String(b"tmp"[..].into());
3217                child1.set(constants::DW_AT_name, tmp.clone());
3218                assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp));
3219
3220                // Test attrs_mut
3221                let name = AttributeValue::StringRef(dwarf.strings.add(&b"child1"[..]));
3222                {
3223                    let attr = child1.attrs_mut().next().unwrap();
3224                    assert_eq!(attr.name(), constants::DW_AT_name);
3225                    attr.set(name.clone());
3226                }
3227                assert_eq!(child1.get(constants::DW_AT_name), Some(&name));
3228            }
3229
3230            let child2 = unit1.add(root_id, constants::DW_TAG_subprogram);
3231            assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2));
3232            {
3233                let child2 = unit1.get_mut(child2);
3234                assert_eq!(child2.parent(), Some(root_id));
3235
3236                let tmp = AttributeValue::String(b"tmp"[..].into());
3237                child2.set(constants::DW_AT_name, tmp.clone());
3238                assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp));
3239
3240                // Test replace
3241                let name = AttributeValue::StringRef(dwarf.strings.add(&b"child2"[..]));
3242                child2.set(constants::DW_AT_name, name.clone());
3243                assert_eq!(child2.get(constants::DW_AT_name), Some(&name));
3244            }
3245
3246            {
3247                let root = unit1.get(root_id);
3248                assert_eq!(
3249                    root.children().cloned().collect::<Vec<_>>(),
3250                    vec![child1, child2]
3251                );
3252            }
3253        }
3254        {
3255            let unit2 = dwarf.units.get(unit2);
3256            assert_eq!(unit2.version(), 2);
3257            assert_eq!(unit2.address_size(), 4);
3258            assert_eq!(unit2.format(), Format::Dwarf64);
3259            assert_eq!(unit2.count(), 1);
3260
3261            let root = unit2.root();
3262            assert_eq!(root, UnitEntryId::new(unit2.base_id, 0));
3263            let root = unit2.get(root);
3264            assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0));
3265            assert!(root.parent().is_none());
3266            assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
3267        }
3268
3269        let mut sections = Sections::new(EndianVec::new(LittleEndian));
3270        dwarf.write(&mut sections).unwrap();
3271
3272        let read_dwarf = sections.read(LittleEndian);
3273        let mut read_units = read_dwarf.units();
3274
3275        {
3276            let read_unit1 = read_units.next().unwrap().unwrap();
3277            let unit1 = dwarf.units.get(unit_id1);
3278            assert_eq!(unit1.version(), read_unit1.version());
3279            assert_eq!(unit1.address_size(), read_unit1.address_size());
3280            assert_eq!(unit1.format(), read_unit1.format());
3281
3282            let read_unit1 = read_dwarf.unit(read_unit1).unwrap();
3283            let mut read_entries = read_unit1.entries();
3284
3285            let root = unit1.get(unit1.root());
3286            {
3287                let read_root = read_entries.next_dfs().unwrap().unwrap();
3288                assert_eq!(read_root.depth(), 0);
3289                assert_eq!(root.tag(), read_root.tag());
3290                assert!(read_root.has_children());
3291
3292                let producer = match root.get(constants::DW_AT_producer).unwrap() {
3293                    AttributeValue::String(producer) => &**producer,
3294                    otherwise => panic!("unexpected {:?}", otherwise),
3295                };
3296                assert_eq!(producer, b"root");
3297                let read_producer = read_root.attr_value(constants::DW_AT_producer).unwrap();
3298                assert_eq!(
3299                    read_dwarf
3300                        .attr_string(&read_unit1, read_producer)
3301                        .unwrap()
3302                        .slice(),
3303                    producer
3304                );
3305            }
3306
3307            let mut children = root.children().cloned();
3308
3309            {
3310                let child = children.next().unwrap();
3311                assert_eq!(child, UnitEntryId::new(unit1.base_id, 1));
3312                let child = unit1.get(child);
3313                let read_child = read_entries.next_dfs().unwrap().unwrap();
3314                assert_eq!(read_child.depth(), 1);
3315                assert_eq!(child.tag(), read_child.tag());
3316                assert!(!read_child.has_children());
3317
3318                let name = match child.get(constants::DW_AT_name).unwrap() {
3319                    AttributeValue::StringRef(name) => *name,
3320                    otherwise => panic!("unexpected {:?}", otherwise),
3321                };
3322                let name = dwarf.strings.get(name);
3323                assert_eq!(name, b"child1");
3324                let read_name = read_child.attr_value(constants::DW_AT_name).unwrap();
3325                assert_eq!(
3326                    read_dwarf
3327                        .attr_string(&read_unit1, read_name)
3328                        .unwrap()
3329                        .slice(),
3330                    name
3331                );
3332            }
3333
3334            {
3335                let child = children.next().unwrap();
3336                assert_eq!(child, UnitEntryId::new(unit1.base_id, 2));
3337                let child = unit1.get(child);
3338                let read_child = read_entries.next_dfs().unwrap().unwrap();
3339                assert_eq!(read_child.depth(), 1);
3340                assert_eq!(child.tag(), read_child.tag());
3341                assert!(!read_child.has_children());
3342
3343                let name = match child.get(constants::DW_AT_name).unwrap() {
3344                    AttributeValue::StringRef(name) => *name,
3345                    otherwise => panic!("unexpected {:?}", otherwise),
3346                };
3347                let name = dwarf.strings.get(name);
3348                assert_eq!(name, b"child2");
3349                let read_name = read_child.attr_value(constants::DW_AT_name).unwrap();
3350                assert_eq!(
3351                    read_dwarf
3352                        .attr_string(&read_unit1, read_name)
3353                        .unwrap()
3354                        .slice(),
3355                    name
3356                );
3357            }
3358
3359            assert!(read_entries.next_dfs().unwrap().is_none());
3360        }
3361
3362        {
3363            let read_unit2 = read_units.next().unwrap().unwrap();
3364            let unit2 = dwarf.units.get(unit2);
3365            assert_eq!(unit2.version(), read_unit2.version());
3366            assert_eq!(unit2.address_size(), read_unit2.address_size());
3367            assert_eq!(unit2.format(), read_unit2.format());
3368
3369            let abbrevs = read_dwarf.abbreviations(&read_unit2).unwrap();
3370            let mut read_entries = read_unit2.entries(&abbrevs);
3371
3372            {
3373                let root = unit2.get(unit2.root());
3374                let read_root = read_entries.next_dfs().unwrap().unwrap();
3375                assert_eq!(read_root.depth(), 0);
3376                assert_eq!(root.tag(), read_root.tag());
3377                assert!(!read_root.has_children());
3378            }
3379
3380            assert!(read_entries.next_dfs().unwrap().is_none());
3381        }
3382
3383        {
3384            let read_unit3 = read_units.next().unwrap().unwrap();
3385            let unit3 = dwarf.units.get(unit3);
3386            assert_eq!(unit3.version(), read_unit3.version());
3387            assert_eq!(unit3.address_size(), read_unit3.address_size());
3388            assert_eq!(unit3.format(), read_unit3.format());
3389
3390            let abbrevs = read_dwarf.abbreviations(&read_unit3).unwrap();
3391            let mut read_entries = read_unit3.entries(&abbrevs);
3392
3393            {
3394                let root = unit3.get(unit3.root());
3395                let read_root = read_entries.next_dfs().unwrap().unwrap();
3396                assert_eq!(read_root.depth(), 0);
3397                assert_eq!(root.tag(), read_root.tag());
3398                assert!(!read_root.has_children());
3399            }
3400
3401            assert!(read_entries.next_dfs().unwrap().is_none());
3402        }
3403
3404        assert!(read_units.next().unwrap().is_none());
3405
3406        let convert_dwarf =
3407            Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))).unwrap();
3408        assert_eq!(convert_dwarf.units.count(), dwarf.units.count());
3409
3410        for i in 0..convert_dwarf.units.count() {
3411            let unit_id = dwarf.units.id(i);
3412            let unit = dwarf.units.get(unit_id);
3413            let convert_unit_id = convert_dwarf.units.id(i);
3414            let convert_unit = convert_dwarf.units.get(convert_unit_id);
3415            assert_eq!(convert_unit.version(), unit.version());
3416            assert_eq!(convert_unit.address_size(), unit.address_size());
3417            assert_eq!(convert_unit.format(), unit.format());
3418            assert_eq!(convert_unit.count(), unit.count());
3419
3420            let root = unit.get(unit.root());
3421            let convert_root = convert_unit.get(convert_unit.root());
3422            assert_eq!(convert_root.tag(), root.tag());
3423            for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
3424                assert_eq!(convert_attr, attr);
3425            }
3426        }
3427    }
3428
3429    #[test]
3430    fn test_attribute_value() {
3431        let string_data = "string data";
3432        let line_string_data = "line string data";
3433
3434        let data = vec![1, 2, 3, 4];
3435        let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian);
3436
3437        let mut expression = Expression::new();
3438        expression.op_constu(57);
3439        let read_expression = read::Expression(read::EndianSlice::new(
3440            &[constants::DW_OP_constu.0, 57],
3441            LittleEndian,
3442        ));
3443
3444        let range = RangeList(vec![Range::StartEnd {
3445            begin: Address::Constant(0x1234),
3446            end: Address::Constant(0x2345),
3447        }]);
3448
3449        let location = LocationList(vec![Location::StartEnd {
3450            begin: Address::Constant(0x1234),
3451            end: Address::Constant(0x2345),
3452            data: expression.clone(),
3453        }]);
3454
3455        for &version in &[2, 3, 4, 5] {
3456            for &address_size in &[4, 8] {
3457                for &format in &[Format::Dwarf32, Format::Dwarf64] {
3458                    let encoding = Encoding {
3459                        format,
3460                        version,
3461                        address_size,
3462                    };
3463
3464                    let mut dwarf = Dwarf::new();
3465                    let unit = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
3466                    let unit = dwarf.units.get_mut(unit);
3467                    let loc_id = unit.locations.add(location.clone());
3468                    let range_id = unit.ranges.add(range.clone());
3469                    // Create a string with a non-zero id/offset.
3470                    dwarf.strings.add("dummy string");
3471                    let string_id = dwarf.strings.add(string_data);
3472                    dwarf.line_strings.add("dummy line string");
3473                    let line_string_id = dwarf.line_strings.add(line_string_data);
3474
3475                    let mut attributes = vec![
3476                        (
3477                            constants::DW_AT_name,
3478                            AttributeValue::Address(Address::Constant(0x1234)),
3479                            read::AttributeValue::Addr(0x1234),
3480                        ),
3481                        (
3482                            constants::DW_AT_name,
3483                            AttributeValue::Block(data.clone()),
3484                            read::AttributeValue::Block(read_data),
3485                        ),
3486                        (
3487                            constants::DW_AT_name,
3488                            AttributeValue::Data1(0x12),
3489                            read::AttributeValue::Data1(0x12),
3490                        ),
3491                        (
3492                            constants::DW_AT_name,
3493                            AttributeValue::Data2(0x1234),
3494                            read::AttributeValue::Data2(0x1234),
3495                        ),
3496                        (
3497                            constants::DW_AT_name,
3498                            AttributeValue::Data4(0x1234),
3499                            read::AttributeValue::Data4(0x1234),
3500                        ),
3501                        (
3502                            constants::DW_AT_name,
3503                            AttributeValue::Data8(0x1234),
3504                            read::AttributeValue::Data8(0x1234),
3505                        ),
3506                        (
3507                            constants::DW_AT_name,
3508                            AttributeValue::Data16(0x1234),
3509                            read::AttributeValue::Data16(0x1234),
3510                        ),
3511                        (
3512                            constants::DW_AT_name,
3513                            AttributeValue::Sdata(0x1234),
3514                            read::AttributeValue::Sdata(0x1234),
3515                        ),
3516                        (
3517                            constants::DW_AT_name,
3518                            AttributeValue::Udata(0x1234),
3519                            read::AttributeValue::Udata(0x1234),
3520                        ),
3521                        (
3522                            constants::DW_AT_name,
3523                            AttributeValue::Flag(false),
3524                            read::AttributeValue::Flag(false),
3525                        ),
3526                        (
3527                            constants::DW_AT_name,
3528                            AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
3529                            read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
3530                        ),
3531                        (
3532                            constants::DW_AT_macro_info,
3533                            AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)),
3534                            read::AttributeValue::SecOffset(0x1234),
3535                        ),
3536                        (
3537                            constants::DW_AT_macros,
3538                            AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)),
3539                            read::AttributeValue::SecOffset(0x1234),
3540                        ),
3541                        (
3542                            constants::DW_AT_name,
3543                            AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
3544                            read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
3545                        ),
3546                        (
3547                            constants::DW_AT_name,
3548                            AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
3549                            read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
3550                        ),
3551                        (
3552                            constants::DW_AT_name,
3553                            AttributeValue::String(data.clone()),
3554                            read::AttributeValue::String(read_data),
3555                        ),
3556                        (
3557                            constants::DW_AT_encoding,
3558                            AttributeValue::Encoding(constants::DwAte(0x12)),
3559                            read::AttributeValue::Udata(0x12),
3560                        ),
3561                        (
3562                            constants::DW_AT_decimal_sign,
3563                            AttributeValue::DecimalSign(constants::DwDs(0x12)),
3564                            read::AttributeValue::Udata(0x12),
3565                        ),
3566                        (
3567                            constants::DW_AT_endianity,
3568                            AttributeValue::Endianity(constants::DwEnd(0x12)),
3569                            read::AttributeValue::Udata(0x12),
3570                        ),
3571                        (
3572                            constants::DW_AT_accessibility,
3573                            AttributeValue::Accessibility(constants::DwAccess(0x12)),
3574                            read::AttributeValue::Udata(0x12),
3575                        ),
3576                        (
3577                            constants::DW_AT_visibility,
3578                            AttributeValue::Visibility(constants::DwVis(0x12)),
3579                            read::AttributeValue::Udata(0x12),
3580                        ),
3581                        (
3582                            constants::DW_AT_virtuality,
3583                            AttributeValue::Virtuality(constants::DwVirtuality(0x12)),
3584                            read::AttributeValue::Udata(0x12),
3585                        ),
3586                        (
3587                            constants::DW_AT_language,
3588                            AttributeValue::Language(constants::DwLang(0x12)),
3589                            read::AttributeValue::Udata(0x12),
3590                        ),
3591                        (
3592                            constants::DW_AT_address_class,
3593                            AttributeValue::AddressClass(constants::DwAddr(0x12)),
3594                            read::AttributeValue::Udata(0x12),
3595                        ),
3596                        (
3597                            constants::DW_AT_identifier_case,
3598                            AttributeValue::IdentifierCase(constants::DwId(0x12)),
3599                            read::AttributeValue::Udata(0x12),
3600                        ),
3601                        (
3602                            constants::DW_AT_calling_convention,
3603                            AttributeValue::CallingConvention(constants::DwCc(0x12)),
3604                            read::AttributeValue::Udata(0x12),
3605                        ),
3606                        (
3607                            constants::DW_AT_ordering,
3608                            AttributeValue::Ordering(constants::DwOrd(0x12)),
3609                            read::AttributeValue::Udata(0x12),
3610                        ),
3611                        (
3612                            constants::DW_AT_inline,
3613                            AttributeValue::Inline(constants::DwInl(0x12)),
3614                            read::AttributeValue::Udata(0x12),
3615                        ),
3616                    ];
3617                    let mut attributes2 = Vec::new();
3618                    if version >= 4 {
3619                        attributes.push((
3620                            constants::DW_AT_location,
3621                            AttributeValue::Exprloc(expression.clone()),
3622                            read::AttributeValue::Exprloc(read_expression),
3623                        ));
3624                    } else {
3625                        attributes.push((
3626                            constants::DW_AT_location,
3627                            AttributeValue::Exprloc(expression.clone()),
3628                            read::AttributeValue::Block(read_expression.0),
3629                        ));
3630                    }
3631                    if version >= 4 {
3632                        attributes.push((
3633                            constants::DW_AT_name,
3634                            AttributeValue::FlagPresent,
3635                            read::AttributeValue::Flag(true),
3636                        ));
3637                    } else {
3638                        attributes2.push((
3639                            constants::DW_AT_name,
3640                            AttributeValue::FlagPresent,
3641                            read::AttributeValue::Flag(true),
3642                            AttributeValue::Flag(true),
3643                        ));
3644                    };
3645                    if version >= 5 {
3646                        attributes.push((
3647                            constants::DW_AT_language,
3648                            AttributeValue::ImplicitConst(0x12),
3649                            read::AttributeValue::Sdata(0x12),
3650                        ));
3651                    } else {
3652                        attributes2.push((
3653                            constants::DW_AT_language,
3654                            AttributeValue::ImplicitConst(0x12),
3655                            read::AttributeValue::Sdata(0x12),
3656                            AttributeValue::Language(constants::DwLang(0x12)),
3657                        ));
3658                    }
3659
3660                    let mut add_attribute = |name, value| {
3661                        let entry_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
3662                        let entry = unit.get_mut(entry_id);
3663                        entry.set(name, value);
3664                    };
3665                    for (name, value, _) in &attributes {
3666                        add_attribute(*name, value.clone());
3667                    }
3668                    for (name, value, _, _) in &attributes2 {
3669                        add_attribute(*name, value.clone());
3670                    }
3671                    add_attribute(
3672                        constants::DW_AT_location,
3673                        AttributeValue::LocationListRef(loc_id),
3674                    );
3675                    add_attribute(
3676                        constants::DW_AT_ranges,
3677                        AttributeValue::RangeListRef(range_id),
3678                    );
3679                    add_attribute(constants::DW_AT_name, AttributeValue::StringRef(string_id));
3680                    add_attribute(
3681                        constants::DW_AT_name,
3682                        AttributeValue::LineStringRef(line_string_id),
3683                    );
3684
3685                    let mut sections = Sections::new(EndianVec::new(LittleEndian));
3686                    dwarf.write(&mut sections).unwrap();
3687
3688                    let read_dwarf = sections.read(LittleEndian);
3689                    let mut read_units = read_dwarf.units();
3690                    let read_unit = read_units.next().unwrap().unwrap();
3691                    let read_unit = read_dwarf.unit(read_unit).unwrap();
3692                    let read_unit = read_unit.unit_ref(&read_dwarf);
3693                    let mut read_entries = read_unit.entries();
3694                    let _root = read_entries.next_dfs().unwrap().unwrap();
3695
3696                    let mut get_attribute = |name| {
3697                        let entry = read_entries.next_dfs().unwrap().unwrap();
3698                        *entry.attr(name).unwrap()
3699                    };
3700                    for (name, _, expect_value) in &attributes {
3701                        let read_value = &get_attribute(*name).raw_value();
3702                        // read::AttributeValue is invariant in the lifetime of R.
3703                        // The lifetimes here are all okay, so transmute it.
3704                        let read_value = unsafe {
3705                            mem::transmute::<
3706                                &read::AttributeValue<read::EndianSlice<'_, LittleEndian>>,
3707                                &read::AttributeValue<read::EndianSlice<'_, LittleEndian>>,
3708                            >(read_value)
3709                        };
3710                        assert_eq!(read_value, expect_value);
3711                    }
3712                    for (name, _, expect_value, _) in &attributes2 {
3713                        let read_value = &get_attribute(*name).raw_value();
3714                        // read::AttributeValue is invariant in the lifetime of R.
3715                        // The lifetimes here are all okay, so transmute it.
3716                        let read_value = unsafe {
3717                            mem::transmute::<
3718                                &read::AttributeValue<read::EndianSlice<'_, LittleEndian>>,
3719                                &read::AttributeValue<read::EndianSlice<'_, LittleEndian>>,
3720                            >(read_value)
3721                        };
3722                        assert_eq!(read_value, expect_value);
3723                    }
3724
3725                    let read_attr = get_attribute(constants::DW_AT_location).value();
3726                    let read::AttributeValue::LocationListsRef(read_loc_offset) = read_attr else {
3727                        panic!("unexpected {:?}", read_attr);
3728                    };
3729                    let mut read_locations = read_unit.locations(read_loc_offset).unwrap();
3730                    let read_location = read_locations.next().unwrap().unwrap();
3731                    assert_eq!(read_location.range.begin, 0x1234);
3732                    assert_eq!(read_location.range.end, 0x2345);
3733                    assert_eq!(read_location.data, read_expression);
3734
3735                    let read_attr = get_attribute(constants::DW_AT_ranges).value();
3736                    let read::AttributeValue::RangeListsRef(read_range_offset) = read_attr else {
3737                        panic!("unexpected {:?}", read_attr);
3738                    };
3739                    let read_range_offset = read_unit.ranges_offset_from_raw(read_range_offset);
3740                    let mut read_ranges = read_unit.ranges(read_range_offset).unwrap();
3741                    let read_range = read_ranges.next().unwrap().unwrap();
3742                    assert_eq!(read_range.begin, 0x1234);
3743                    assert_eq!(read_range.end, 0x2345);
3744
3745                    let read_string = get_attribute(constants::DW_AT_name).raw_value();
3746                    let read::AttributeValue::DebugStrRef(read_string_offset) = read_string else {
3747                        panic!("unexpected {:?}", read_string);
3748                    };
3749                    assert_eq!(
3750                        read_dwarf.string(read_string_offset).unwrap().slice(),
3751                        string_data.as_bytes()
3752                    );
3753
3754                    let read_line_string = get_attribute(constants::DW_AT_name).raw_value();
3755                    let read::AttributeValue::DebugLineStrRef(read_line_string_offset) =
3756                        read_line_string
3757                    else {
3758                        panic!("unexpected {:?}", read_line_string);
3759                    };
3760                    assert_eq!(
3761                        read_dwarf
3762                            .line_string(read_line_string_offset)
3763                            .unwrap()
3764                            .slice(),
3765                        line_string_data.as_bytes()
3766                    );
3767
3768                    let convert_dwarf =
3769                        Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address)))
3770                            .unwrap();
3771                    let convert_unit = convert_dwarf.units.get(convert_dwarf.units.id(0));
3772                    let convert_root = convert_unit.get(convert_unit.root());
3773                    let mut convert_entries = convert_root.children();
3774
3775                    let mut get_convert_attr = |name| {
3776                        let convert_entry = convert_unit.get(*convert_entries.next().unwrap());
3777                        convert_entry.get(name).unwrap()
3778                    };
3779                    for (name, attr, _) in &attributes {
3780                        let convert_attr = get_convert_attr(*name);
3781                        assert_eq!(convert_attr, attr);
3782                    }
3783                    for (name, _, _, attr) in &attributes2 {
3784                        let convert_attr = get_convert_attr(*name);
3785                        assert_eq!(convert_attr, attr);
3786                    }
3787
3788                    let convert_attr = get_convert_attr(constants::DW_AT_location);
3789                    let AttributeValue::LocationListRef(convert_loc_id) = convert_attr else {
3790                        panic!("unexpected {:?}", convert_attr);
3791                    };
3792                    let convert_location = convert_unit.locations.get(*convert_loc_id);
3793                    assert_eq!(*convert_location, location);
3794
3795                    let convert_attr = get_convert_attr(constants::DW_AT_ranges);
3796                    let AttributeValue::RangeListRef(convert_range_id) = convert_attr else {
3797                        panic!("unexpected {:?}", convert_attr);
3798                    };
3799                    let convert_range = convert_unit.ranges.get(*convert_range_id);
3800                    assert_eq!(*convert_range, range);
3801
3802                    let convert_attr = get_convert_attr(constants::DW_AT_name);
3803                    let AttributeValue::StringRef(convert_string_id) = convert_attr else {
3804                        panic!("unexpected {:?}", convert_attr);
3805                    };
3806                    let convert_string = convert_dwarf.strings.get(*convert_string_id);
3807                    assert_eq!(convert_string, string_data.as_bytes());
3808
3809                    let convert_attr = get_convert_attr(constants::DW_AT_name);
3810                    let AttributeValue::LineStringRef(convert_line_string_id) = convert_attr else {
3811                        panic!("unexpected {:?}", convert_attr);
3812                    };
3813                    let convert_line_string =
3814                        convert_dwarf.line_strings.get(*convert_line_string_id);
3815                    assert_eq!(convert_line_string, line_string_data.as_bytes());
3816                }
3817            }
3818        }
3819    }
3820
3821    #[test]
3822    fn test_unit_ref() {
3823        let mut dwarf = Dwarf::new();
3824        let unit_id1 = dwarf.units.add(Unit::new(
3825            Encoding {
3826                version: 4,
3827                address_size: 8,
3828                format: Format::Dwarf32,
3829            },
3830            LineProgram::none(),
3831        ));
3832        assert_eq!(unit_id1, dwarf.units.id(0));
3833        let unit_id2 = dwarf.units.add(Unit::new(
3834            Encoding {
3835                version: 2,
3836                address_size: 4,
3837                format: Format::Dwarf64,
3838            },
3839            LineProgram::none(),
3840        ));
3841        assert_eq!(unit_id2, dwarf.units.id(1));
3842        let unit1_child1 = UnitEntryId::new(dwarf.units.get(unit_id1).base_id, 1);
3843        let unit1_child2 = UnitEntryId::new(dwarf.units.get(unit_id1).base_id, 2);
3844        let unit2_child1 = UnitEntryId::new(dwarf.units.get(unit_id2).base_id, 1);
3845        let unit2_child2 = UnitEntryId::new(dwarf.units.get(unit_id2).base_id, 2);
3846        {
3847            let unit1 = dwarf.units.get_mut(unit_id1);
3848            let root = unit1.root();
3849            let child_id1 = unit1.add(root, constants::DW_TAG_subprogram);
3850            assert_eq!(child_id1, unit1_child1);
3851            let child_id2 = unit1.add(root, constants::DW_TAG_subprogram);
3852            assert_eq!(child_id2, unit1_child2);
3853            {
3854                let child1 = unit1.get_mut(child_id1);
3855                child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
3856            }
3857            {
3858                let child2 = unit1.get_mut(child_id2);
3859                child2.set(
3860                    constants::DW_AT_type,
3861                    AttributeValue::DebugInfoRef(DebugInfoRef::Entry(unit_id2, unit2_child1)),
3862                );
3863            }
3864        }
3865        {
3866            let unit2 = dwarf.units.get_mut(unit_id2);
3867            let root = unit2.root();
3868            let child_id1 = unit2.add(root, constants::DW_TAG_subprogram);
3869            assert_eq!(child_id1, unit2_child1);
3870            let child_id2 = unit2.add(root, constants::DW_TAG_subprogram);
3871            assert_eq!(child_id2, unit2_child2);
3872            {
3873                let child1 = unit2.get_mut(child_id1);
3874                child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
3875            }
3876            {
3877                let child2 = unit2.get_mut(child_id2);
3878                child2.set(
3879                    constants::DW_AT_type,
3880                    AttributeValue::DebugInfoRef(DebugInfoRef::Entry(unit_id1, unit1_child1)),
3881                );
3882            }
3883        }
3884
3885        let mut sections = Sections::new(EndianVec::new(LittleEndian));
3886        dwarf.write(&mut sections).unwrap();
3887
3888        let read_dwarf = sections.read(LittleEndian);
3889        let mut read_units = read_dwarf.units();
3890
3891        let read_unit = read_units.next().unwrap().unwrap();
3892        let abbrevs = read_dwarf.abbreviations(&read_unit).unwrap();
3893        let mut read_entries = read_unit.entries(&abbrevs);
3894        let _root = read_entries.next_dfs().unwrap().unwrap();
3895        let entry = read_entries.next_dfs().unwrap().unwrap();
3896        let read_unit1_child1_attr = entry.attr_value(constants::DW_AT_type);
3897        let read_unit1_child1_section_offset =
3898            entry.offset().to_debug_info_offset(&read_unit).unwrap();
3899        let entry = read_entries.next_dfs().unwrap().unwrap();
3900        let read_unit1_child2_attr = entry.attr_value(constants::DW_AT_type);
3901        let read_unit1_child2_offset = entry.offset();
3902
3903        let read_unit = read_units.next().unwrap().unwrap();
3904        let abbrevs = read_dwarf.abbreviations(&read_unit).unwrap();
3905        let mut read_entries = read_unit.entries(&abbrevs);
3906        let _root = read_entries.next_dfs().unwrap().unwrap();
3907        let entry = read_entries.next_dfs().unwrap().unwrap();
3908        let read_unit2_child1_attr = entry.attr_value(constants::DW_AT_type);
3909        let read_unit2_child1_section_offset =
3910            entry.offset().to_debug_info_offset(&read_unit).unwrap();
3911        let entry = read_entries.next_dfs().unwrap().unwrap();
3912        let read_unit2_child2_attr = entry.attr_value(constants::DW_AT_type);
3913        let read_unit2_child2_offset = entry.offset();
3914
3915        assert_eq!(
3916            read_unit1_child1_attr,
3917            Some(read::AttributeValue::UnitRef(read_unit1_child2_offset))
3918        );
3919        assert_eq!(
3920            read_unit1_child2_attr,
3921            Some(read::AttributeValue::DebugInfoRef(
3922                read_unit2_child1_section_offset
3923            ))
3924        );
3925        assert_eq!(
3926            read_unit2_child1_attr,
3927            Some(read::AttributeValue::UnitRef(read_unit2_child2_offset))
3928        );
3929        assert_eq!(
3930            read_unit2_child2_attr,
3931            Some(read::AttributeValue::DebugInfoRef(
3932                read_unit1_child1_section_offset
3933            ))
3934        );
3935
3936        let convert_dwarf =
3937            Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address))).unwrap();
3938        let convert_units = &convert_dwarf.units;
3939        assert_eq!(convert_units.count(), dwarf.units.count());
3940
3941        for i in 0..convert_units.count() {
3942            let unit = dwarf.units.get(dwarf.units.id(i));
3943            let convert_unit = convert_units.get(convert_units.id(i));
3944            assert_eq!(convert_unit.version(), unit.version());
3945            assert_eq!(convert_unit.address_size(), unit.address_size());
3946            assert_eq!(convert_unit.format(), unit.format());
3947            assert_eq!(convert_unit.count(), unit.count());
3948
3949            let root = unit.get(unit.root());
3950            let convert_root = convert_unit.get(convert_unit.root());
3951            assert_eq!(convert_root.tag(), root.tag());
3952            for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
3953                assert_eq!(convert_attr, attr);
3954            }
3955
3956            let child1 = unit.get(UnitEntryId::new(unit.base_id, 1));
3957            let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1));
3958            assert_eq!(convert_child1.tag(), child1.tag());
3959            for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) {
3960                assert_eq!(convert_attr.name, attr.name);
3961                match (convert_attr.value.clone(), attr.value.clone()) {
3962                    (
3963                        AttributeValue::DebugInfoRef(DebugInfoRef::Entry(
3964                            convert_unit,
3965                            convert_entry,
3966                        )),
3967                        AttributeValue::DebugInfoRef(DebugInfoRef::Entry(unit, entry)),
3968                    ) => {
3969                        assert_eq!(convert_unit.index, unit.index);
3970                        assert_eq!(convert_entry.index, entry.index);
3971                    }
3972                    (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
3973                        assert_eq!(convert_id.index, id.index);
3974                    }
3975                    (convert_value, value) => assert_eq!(convert_value, value),
3976                }
3977            }
3978
3979            let child2 = unit.get(UnitEntryId::new(unit.base_id, 2));
3980            let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2));
3981            assert_eq!(convert_child2.tag(), child2.tag());
3982            for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) {
3983                assert_eq!(convert_attr.name, attr.name);
3984                match (convert_attr.value.clone(), attr.value.clone()) {
3985                    (
3986                        AttributeValue::DebugInfoRef(DebugInfoRef::Entry(
3987                            convert_unit,
3988                            convert_entry,
3989                        )),
3990                        AttributeValue::DebugInfoRef(DebugInfoRef::Entry(unit, entry)),
3991                    ) => {
3992                        assert_eq!(convert_unit.index, unit.index);
3993                        assert_eq!(convert_entry.index, entry.index);
3994                    }
3995                    (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
3996                        assert_eq!(convert_id.index, id.index);
3997                    }
3998                    (convert_value, value) => assert_eq!(convert_value, value),
3999                }
4000            }
4001        }
4002    }
4003
4004    #[test]
4005    fn test_sibling() {
4006        fn add_child(
4007            unit: &mut Unit,
4008            parent: UnitEntryId,
4009            tag: constants::DwTag,
4010            name: &str,
4011        ) -> UnitEntryId {
4012            let id = unit.add(parent, tag);
4013            let child = unit.get_mut(id);
4014            child.set(constants::DW_AT_name, AttributeValue::String(name.into()));
4015            child.set_sibling(true);
4016            id
4017        }
4018
4019        fn add_children(unit: &mut Unit) {
4020            let root = unit.root();
4021            let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1");
4022            add_child(unit, child1, constants::DW_TAG_variable, "grandchild1");
4023            add_child(unit, root, constants::DW_TAG_subprogram, "child2");
4024            add_child(unit, root, constants::DW_TAG_subprogram, "child3");
4025        }
4026
4027        fn next_child<R: read::Reader<Offset = usize>>(
4028            entries: &mut read::EntriesCursor<'_, R>,
4029        ) -> (read::UnitOffset, Option<read::UnitOffset>) {
4030            let entry = entries.next_dfs().unwrap().unwrap();
4031            let offset = entry.offset();
4032            let sibling = entry
4033                .attr_value(constants::DW_AT_sibling)
4034                .map(|attr| match attr {
4035                    read::AttributeValue::UnitRef(offset) => offset,
4036                    _ => panic!("bad sibling value"),
4037                });
4038            (offset, sibling)
4039        }
4040
4041        fn check_sibling<R: read::Reader<Offset = usize>>(
4042            unit: read::UnitHeader<R>,
4043            dwarf: &read::Dwarf<R>,
4044        ) {
4045            let unit = dwarf.unit(unit).unwrap();
4046            let mut entries = unit.entries();
4047            // root
4048            entries.next_dfs().unwrap().unwrap();
4049            // child1
4050            let (_, sibling1) = next_child(&mut entries);
4051            // grandchild1
4052            entries.next_dfs().unwrap().unwrap();
4053            // child2
4054            let (offset2, sibling2) = next_child(&mut entries);
4055            // child3
4056            let (_, _) = next_child(&mut entries);
4057            assert_eq!(sibling1, Some(offset2));
4058            assert_eq!(sibling2, None);
4059        }
4060
4061        let encoding = Encoding {
4062            format: Format::Dwarf32,
4063            version: 4,
4064            address_size: 8,
4065        };
4066        let mut dwarf = Dwarf::new();
4067        let unit_id1 = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
4068        add_children(dwarf.units.get_mut(unit_id1));
4069        let unit_id2 = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
4070        add_children(dwarf.units.get_mut(unit_id2));
4071
4072        let mut sections = Sections::new(EndianVec::new(LittleEndian));
4073        dwarf.write(&mut sections).unwrap();
4074
4075        let read_dwarf = sections.read(LittleEndian);
4076        let mut read_units = read_dwarf.units();
4077        check_sibling(read_units.next().unwrap().unwrap(), &read_dwarf);
4078        check_sibling(read_units.next().unwrap().unwrap(), &read_dwarf);
4079    }
4080
4081    #[test]
4082    fn test_line_ref() {
4083        let dir_bytes = b"dir";
4084        let file_bytes1 = b"file1";
4085        let file_bytes2 = b"file2";
4086        let file_string1 = LineString::String(file_bytes1.to_vec());
4087        let file_string2 = LineString::String(file_bytes2.to_vec());
4088
4089        for &version in &[2, 3, 4, 5] {
4090            for &address_size in &[4, 8] {
4091                for &format in &[Format::Dwarf32, Format::Dwarf64] {
4092                    let encoding = Encoding {
4093                        format,
4094                        version,
4095                        address_size,
4096                    };
4097
4098                    // The line program we'll be referencing.
4099                    let mut line_program = LineProgram::new(
4100                        encoding,
4101                        LineEncoding::default(),
4102                        LineString::String(dir_bytes.to_vec()),
4103                        None,
4104                        file_string1.clone(),
4105                        None,
4106                    );
4107                    let dir = line_program.default_directory();
4108                    // For version >= 5, this will reuse the existing file at index 0.
4109                    let file1 = line_program.add_file(file_string1.clone(), dir, None);
4110                    let file2 = line_program.add_file(file_string2.clone(), dir, None);
4111
4112                    let mut unit = Unit::new(encoding, line_program);
4113                    let root = unit.get_mut(unit.root());
4114                    root.set(
4115                        constants::DW_AT_name,
4116                        AttributeValue::String(file_bytes1.to_vec()),
4117                    );
4118                    root.set(
4119                        constants::DW_AT_comp_dir,
4120                        AttributeValue::String(dir_bytes.to_vec()),
4121                    );
4122                    root.set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef);
4123
4124                    let child = unit.add(unit.root(), constants::DW_TAG_subprogram);
4125                    unit.get_mut(child).set(
4126                        constants::DW_AT_decl_file,
4127                        AttributeValue::FileIndex(Some(file1)),
4128                    );
4129
4130                    let child = unit.add(unit.root(), constants::DW_TAG_subprogram);
4131                    unit.get_mut(child).set(
4132                        constants::DW_AT_call_file,
4133                        AttributeValue::FileIndex(Some(file2)),
4134                    );
4135
4136                    let mut dwarf = Dwarf::new();
4137                    dwarf.units.add(unit);
4138
4139                    let mut sections = Sections::new(EndianVec::new(LittleEndian));
4140                    dwarf.write(&mut sections).unwrap();
4141
4142                    let read_dwarf = sections.read(LittleEndian);
4143                    let mut read_units = read_dwarf.units();
4144                    let read_unit = read_units.next().unwrap().unwrap();
4145                    let read_unit = read_dwarf.unit(read_unit).unwrap();
4146                    let read_unit = read_unit.unit_ref(&read_dwarf);
4147                    let read_line_program = read_unit.line_program.as_ref().unwrap().header();
4148                    let mut read_entries = read_unit.entries();
4149                    let _root = read_entries.next_dfs().unwrap().unwrap();
4150
4151                    let mut get_path = |name| {
4152                        let entry = read_entries.next_dfs().unwrap().unwrap();
4153                        let read_attr = entry.attr(name).unwrap();
4154                        let read::AttributeValue::FileIndex(read_file_index) = read_attr.value()
4155                        else {
4156                            panic!("unexpected {:?}", read_attr);
4157                        };
4158                        let read_file = read_line_program.file(read_file_index).unwrap();
4159                        let read_path = read_unit
4160                            .attr_string(read_file.path_name())
4161                            .unwrap()
4162                            .slice();
4163                        (read_file_index, read_path)
4164                    };
4165
4166                    let (read_index, read_path) = get_path(constants::DW_AT_decl_file);
4167                    assert_eq!(read_index, if version >= 5 { 0 } else { 1 });
4168                    assert_eq!(read_path, file_bytes1);
4169
4170                    let (read_index, read_path) = get_path(constants::DW_AT_call_file);
4171                    assert_eq!(read_index, if version >= 5 { 1 } else { 2 });
4172                    assert_eq!(read_path, file_bytes2);
4173
4174                    let convert_dwarf =
4175                        Dwarf::from(&read_dwarf, &|address| Some(Address::Constant(address)))
4176                            .unwrap();
4177                    let convert_unit = convert_dwarf.units.get(convert_dwarf.units.id(0));
4178                    let convert_root = convert_unit.get(convert_unit.root());
4179                    let mut convert_entries = convert_root.children();
4180
4181                    let mut get_convert_path = |name| {
4182                        let convert_entry = convert_unit.get(*convert_entries.next().unwrap());
4183                        let convert_attr = convert_entry.get(name).unwrap();
4184                        let AttributeValue::FileIndex(Some(convert_file_index)) = convert_attr
4185                        else {
4186                            panic!("unexpected {:?}", convert_attr);
4187                        };
4188                        convert_unit.line_program.get_file(*convert_file_index).0
4189                    };
4190
4191                    let convert_path = get_convert_path(constants::DW_AT_decl_file);
4192                    assert_eq!(convert_dwarf.get_line_string(convert_path), file_bytes1);
4193
4194                    let convert_path = get_convert_path(constants::DW_AT_call_file);
4195                    assert_eq!(convert_dwarf.get_line_string(convert_path), file_bytes2);
4196                }
4197            }
4198        }
4199    }
4200
4201    #[test]
4202    fn test_line_program_used() {
4203        for used in [false, true] {
4204            let encoding = Encoding {
4205                format: Format::Dwarf32,
4206                version: 5,
4207                address_size: 8,
4208            };
4209
4210            let line_program = LineProgram::new(
4211                encoding,
4212                LineEncoding::default(),
4213                LineString::String(b"comp_dir".to_vec()),
4214                None,
4215                LineString::String(b"comp_name".to_vec()),
4216                None,
4217            );
4218
4219            let mut unit = Unit::new(encoding, line_program);
4220            let file_id = if used { Some(FileId::new(0)) } else { None };
4221            let root = unit.root();
4222            unit.get_mut(root).set(
4223                constants::DW_AT_decl_file,
4224                AttributeValue::FileIndex(file_id),
4225            );
4226
4227            let mut dwarf = Dwarf::new();
4228            dwarf.units.add(unit);
4229
4230            let mut sections = Sections::new(EndianVec::new(LittleEndian));
4231            dwarf.write(&mut sections).unwrap();
4232            assert_eq!(!used, sections.debug_line.slice().is_empty());
4233        }
4234    }
4235
4236    #[test]
4237    fn test_delete_child() {
4238        fn set_name(unit: &mut Unit, id: UnitEntryId, name: &str) {
4239            let entry = unit.get_mut(id);
4240            entry.set(constants::DW_AT_name, AttributeValue::String(name.into()));
4241        }
4242        fn check_name<R: read::Reader>(
4243            entry: &read::DebuggingInformationEntry<R>,
4244            unit: read::UnitRef<'_, R>,
4245            name: &str,
4246        ) {
4247            let name_attr = entry.attr(constants::DW_AT_name).unwrap();
4248            let entry_name = unit.attr_string(name_attr.value()).unwrap();
4249            let entry_name_str = entry_name.to_string().unwrap();
4250            assert_eq!(entry_name_str, name);
4251        }
4252        let encoding = Encoding {
4253            format: Format::Dwarf32,
4254            version: 4,
4255            address_size: 8,
4256        };
4257        let mut dwarf = DwarfUnit::new(encoding);
4258        let root = dwarf.unit.root();
4259
4260        // Add and delete entries in the root unit
4261        let child1 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
4262        set_name(&mut dwarf.unit, child1, "child1");
4263        let grandchild1 = dwarf.unit.add(child1, constants::DW_TAG_variable);
4264        set_name(&mut dwarf.unit, grandchild1, "grandchild1");
4265        let child2 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
4266        set_name(&mut dwarf.unit, child2, "child2");
4267        // This deletes both `child1` and its child `grandchild1`
4268        dwarf.unit.get_mut(root).delete_child(child1);
4269        let child3 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
4270        set_name(&mut dwarf.unit, child3, "child3");
4271        let child4 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
4272        set_name(&mut dwarf.unit, child4, "child4");
4273        let grandchild4 = dwarf.unit.add(child4, constants::DW_TAG_variable);
4274        set_name(&mut dwarf.unit, grandchild4, "grandchild4");
4275        dwarf.unit.get_mut(child4).delete_child(grandchild4);
4276
4277        let mut sections = Sections::new(EndianVec::new(LittleEndian));
4278
4279        // Write DWARF data which should only include `child2`, `child3` and `child4`
4280        dwarf.write(&mut sections).unwrap();
4281
4282        let read_dwarf = sections.read(LittleEndian);
4283        let read_unit = read_dwarf.units().next().unwrap().unwrap();
4284        let read_unit = read_dwarf.unit(read_unit).unwrap();
4285        let read_unit = read_unit.unit_ref(&read_dwarf);
4286        let mut entries = read_unit.entries();
4287        // root
4288        entries.next_dfs().unwrap().unwrap();
4289        // child2
4290        let read_child2 = entries.next_dfs().unwrap().unwrap();
4291        check_name(read_child2, read_unit, "child2");
4292        // child3
4293        let read_child3 = entries.next_dfs().unwrap().unwrap();
4294        check_name(read_child3, read_unit, "child3");
4295        // child4
4296        let read_child4 = entries.next_dfs().unwrap().unwrap();
4297        check_name(read_child4, read_unit, "child4");
4298        // There should be no more entries
4299        assert!(entries.next_dfs().unwrap().is_none());
4300    }
4301
4302    #[test]
4303    fn test_missing_unit_ref() {
4304        let encoding = Encoding {
4305            format: Format::Dwarf32,
4306            version: 5,
4307            address_size: 8,
4308        };
4309
4310        let mut dwarf = Dwarf::new();
4311        let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
4312        let unit = dwarf.units.get_mut(unit_id);
4313
4314        // Create the entry to be referenced.
4315        let entry_id = unit.add(unit.root(), constants::DW_TAG_const_type);
4316        // And delete it so that it is not available when writing.
4317        unit.get_mut(unit.root()).delete_child(entry_id);
4318
4319        // Create a reference to the deleted entry.
4320        let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
4321        unit.get_mut(subprogram_id)
4322            .set(constants::DW_AT_type, AttributeValue::UnitRef(entry_id));
4323
4324        // Writing the DWARF should fail.
4325        let mut sections = Sections::new(EndianVec::new(LittleEndian));
4326        assert_eq!(dwarf.write(&mut sections), Err(Error::InvalidReference));
4327    }
4328
4329    #[test]
4330    fn test_missing_debuginfo_ref() {
4331        let encoding = Encoding {
4332            format: Format::Dwarf32,
4333            version: 5,
4334            address_size: 8,
4335        };
4336
4337        let mut dwarf = Dwarf::new();
4338        let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
4339        let unit = dwarf.units.get_mut(unit_id);
4340
4341        // Create the entry to be referenced.
4342        let entry_id = unit.add(unit.root(), constants::DW_TAG_const_type);
4343        // And delete it so that it is not available when writing.
4344        unit.get_mut(unit.root()).delete_child(entry_id);
4345
4346        // Create a reference to the deleted entry.
4347        let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
4348        unit.get_mut(subprogram_id).set(
4349            constants::DW_AT_type,
4350            AttributeValue::DebugInfoRef(DebugInfoRef::Entry(unit_id, entry_id)),
4351        );
4352
4353        // Writing the DWARF should fail.
4354        let mut sections = Sections::new(EndianVec::new(LittleEndian));
4355        assert_eq!(dwarf.write(&mut sections), Err(Error::InvalidReference));
4356    }
4357}