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