1 use alloc::vec::Vec;
2 use std::ops::{Deref, DerefMut};
3 use std::{slice, usize};
4 
5 use crate::common::{
6     DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset,
7     DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId,
8 };
9 use crate::constants;
10 use crate::leb128::write::{sleb128_size, uleb128_size};
11 use crate::write::{
12     Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets,
13     DebugStrOffsets, Error, Expression, FileId, LineProgram, LineStringId, LocationListId,
14     LocationListOffsets, LocationListTable, RangeListId, RangeListOffsets, RangeListTable,
15     Reference, Result, Section, Sections, StringId, Writer,
16 };
17 
18 define_id!(UnitId, "An identifier for a unit in a `UnitTable`.");
19 
20 define_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)]
24 pub struct UnitTable {
25     base_id: BaseId,
26     units: Vec<Unit>,
27 }
28 
29 impl 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]
add(&mut self, unit: Unit) -> UnitId36     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]
count(&self) -> usize44     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]
id(&self, index: usize) -> UnitId54     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]
get(&self, id: UnitId) -> &Unit65     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]
get_mut(&mut self, id: UnitId) -> &mut Unit76     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     /// Write the units to the given sections.
82     ///
83     /// `strings` must contain the `.debug_str` offsets of the corresponding
84     /// `StringTable`.
write<W: Writer>( &mut self, sections: &mut Sections<W>, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, ) -> Result<DebugInfoOffsets>85     pub fn write<W: Writer>(
86         &mut self,
87         sections: &mut Sections<W>,
88         line_strings: &DebugLineStrOffsets,
89         strings: &DebugStrOffsets,
90     ) -> Result<DebugInfoOffsets> {
91         let mut offsets = DebugInfoOffsets {
92             base_id: self.base_id,
93             units: Vec::new(),
94         };
95         for unit in &mut self.units {
96             // TODO: maybe share abbreviation tables
97             let abbrev_offset = sections.debug_abbrev.offset();
98             let mut abbrevs = AbbreviationTable::default();
99 
100             offsets.units.push(unit.write(
101                 sections,
102                 abbrev_offset,
103                 &mut abbrevs,
104                 line_strings,
105                 strings,
106             )?);
107 
108             abbrevs.write(&mut sections.debug_abbrev)?;
109         }
110 
111         write_section_refs(
112             &mut sections.debug_info_refs,
113             &mut sections.debug_info.0,
114             &offsets,
115         )?;
116         write_section_refs(
117             &mut sections.debug_loc_refs,
118             &mut sections.debug_loc.0,
119             &offsets,
120         )?;
121         write_section_refs(
122             &mut sections.debug_loclists_refs,
123             &mut sections.debug_loclists.0,
124             &offsets,
125         )?;
126 
127         Ok(offsets)
128     }
129 }
130 
write_section_refs<W: Writer>( references: &mut Vec<DebugInfoReference>, w: &mut W, offsets: &DebugInfoOffsets, ) -> Result<()>131 fn write_section_refs<W: Writer>(
132     references: &mut Vec<DebugInfoReference>,
133     w: &mut W,
134     offsets: &DebugInfoOffsets,
135 ) -> Result<()> {
136     for r in references.drain(..) {
137         let entry_offset = offsets.entry(r.unit, r.entry).0;
138         debug_assert_ne!(entry_offset, 0);
139         w.write_offset_at(r.offset, entry_offset, SectionId::DebugInfo, r.size)?;
140     }
141     Ok(())
142 }
143 
144 /// A unit's debugging information.
145 #[derive(Debug)]
146 pub struct Unit {
147     base_id: BaseId,
148     /// The encoding parameters for this unit.
149     encoding: Encoding,
150     /// The line number program for this unit.
151     pub line_program: LineProgram,
152     /// A table of range lists used by this unit.
153     pub ranges: RangeListTable,
154     /// A table of location lists used by this unit.
155     pub locations: LocationListTable,
156     /// All entries in this unit. The order is unrelated to the tree order.
157     // Requirements:
158     // - entries form a tree
159     // - entries can be added in any order
160     // - entries have a fixed id
161     // - able to quickly lookup an entry from its id
162     // Limitations of current implemention:
163     // - mutable iteration of children is messy due to borrow checker
164     entries: Vec<DebuggingInformationEntry>,
165     /// The index of the root entry in entries.
166     root: UnitEntryId,
167 }
168 
169 impl Unit {
170     /// Create a new `Unit`.
new(encoding: Encoding, line_program: LineProgram) -> Self171     pub fn new(encoding: Encoding, line_program: LineProgram) -> Self {
172         let base_id = BaseId::default();
173         let ranges = RangeListTable::default();
174         let locations = LocationListTable::default();
175         let mut entries = Vec::new();
176         let root = DebuggingInformationEntry::new(
177             base_id,
178             &mut entries,
179             None,
180             constants::DW_TAG_compile_unit,
181         );
182         Unit {
183             base_id,
184             encoding,
185             line_program,
186             ranges,
187             locations,
188             entries,
189             root,
190         }
191     }
192 
193     /// Return the encoding parameters for this unit.
194     #[inline]
encoding(&self) -> Encoding195     pub fn encoding(&self) -> Encoding {
196         self.encoding
197     }
198 
199     /// Return the DWARF version for this unit.
200     #[inline]
version(&self) -> u16201     pub fn version(&self) -> u16 {
202         self.encoding.version
203     }
204 
205     /// Return the address size in bytes for this unit.
206     #[inline]
address_size(&self) -> u8207     pub fn address_size(&self) -> u8 {
208         self.encoding.address_size
209     }
210 
211     /// Return the DWARF format for this unit.
212     #[inline]
format(&self) -> Format213     pub fn format(&self) -> Format {
214         self.encoding.format
215     }
216 
217     /// Return the number of `DebuggingInformationEntry`s created for this unit.
218     ///
219     /// This includes entries that no longer have a parent.
220     #[inline]
count(&self) -> usize221     pub fn count(&self) -> usize {
222         self.entries.len()
223     }
224 
225     /// Return the id of the root entry.
226     #[inline]
root(&self) -> UnitEntryId227     pub fn root(&self) -> UnitEntryId {
228         self.root
229     }
230 
231     /// Add a new `DebuggingInformationEntry` to this unit and return its id.
232     ///
233     /// The `parent` must be within the same unit.
234     ///
235     /// # Panics
236     ///
237     /// Panics if `parent` is invalid.
238     #[inline]
add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId239     pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId {
240         debug_assert_eq!(self.base_id, parent.base_id);
241         DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag)
242     }
243 
244     /// Get a reference to an entry.
245     ///
246     /// # Panics
247     ///
248     /// Panics if `id` is invalid.
249     #[inline]
get(&self, id: UnitEntryId) -> &DebuggingInformationEntry250     pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry {
251         debug_assert_eq!(self.base_id, id.base_id);
252         &self.entries[id.index]
253     }
254 
255     /// Get a mutable reference to an entry.
256     ///
257     /// # Panics
258     ///
259     /// Panics if `id` is invalid.
260     #[inline]
get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry261     pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry {
262         debug_assert_eq!(self.base_id, id.base_id);
263         &mut self.entries[id.index]
264     }
265 
266     /// Return true if `self.line_program` is used by a DIE.
line_program_in_use(&self) -> bool267     fn line_program_in_use(&self) -> bool {
268         if self.line_program.is_none() {
269             return false;
270         }
271         if !self.line_program.is_empty() {
272             return true;
273         }
274 
275         for entry in &self.entries {
276             for attr in &entry.attrs {
277                 if let AttributeValue::FileIndex(Some(_)) = attr.value {
278                     return true;
279                 }
280             }
281         }
282 
283         false
284     }
285 
286     /// Write the unit to the given sections.
write<W: Writer>( &mut self, sections: &mut Sections<W>, abbrev_offset: DebugAbbrevOffset, abbrevs: &mut AbbreviationTable, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, ) -> Result<UnitOffsets>287     pub(crate) fn write<W: Writer>(
288         &mut self,
289         sections: &mut Sections<W>,
290         abbrev_offset: DebugAbbrevOffset,
291         abbrevs: &mut AbbreviationTable,
292         line_strings: &DebugLineStrOffsets,
293         strings: &DebugStrOffsets,
294     ) -> Result<UnitOffsets> {
295         let line_program = if self.line_program_in_use() {
296             self.entries[self.root.index]
297                 .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef);
298             Some(self.line_program.write(
299                 &mut sections.debug_line,
300                 self.encoding,
301                 line_strings,
302                 strings,
303             )?)
304         } else {
305             self.entries[self.root.index].delete(constants::DW_AT_stmt_list);
306             None
307         };
308 
309         // TODO: use .debug_types for type units in DWARF v4.
310         let w = &mut sections.debug_info;
311 
312         let mut offsets = UnitOffsets {
313             base_id: self.base_id,
314             unit: w.offset(),
315             // Entries can be written in any order, so create the complete vec now.
316             entries: vec![EntryOffset::none(); self.entries.len()],
317         };
318 
319         let length_offset = w.write_initial_length(self.format())?;
320         let length_base = w.len();
321 
322         w.write_u16(self.version())?;
323         if 2 <= self.version() && self.version() <= 4 {
324             w.write_offset(
325                 abbrev_offset.0,
326                 SectionId::DebugAbbrev,
327                 self.format().word_size(),
328             )?;
329             w.write_u8(self.address_size())?;
330         } else if self.version() == 5 {
331             w.write_u8(constants::DW_UT_compile.0)?;
332             w.write_u8(self.address_size())?;
333             w.write_offset(
334                 abbrev_offset.0,
335                 SectionId::DebugAbbrev,
336                 self.format().word_size(),
337             )?;
338         } else {
339             return Err(Error::UnsupportedVersion(self.version()));
340         }
341 
342         // Calculate all DIE offsets, so that we are able to output references to them.
343         // However, references to base types in expressions use ULEB128, so base types
344         // must be moved to the front before we can calculate offsets.
345         self.reorder_base_types();
346         let mut offset = w.len();
347         self.entries[self.root.index].calculate_offsets(
348             self,
349             &mut offset,
350             &mut offsets,
351             abbrevs,
352         )?;
353 
354         let range_lists = self.ranges.write(sections, self.encoding)?;
355         // Location lists can't be written until we have DIE offsets.
356         let loc_lists = self
357             .locations
358             .write(sections, self.encoding, Some(&offsets))?;
359 
360         let w = &mut sections.debug_info;
361         let mut unit_refs = Vec::new();
362         self.entries[self.root.index].write(
363             w,
364             &mut sections.debug_info_refs,
365             &mut unit_refs,
366             self,
367             &mut offsets,
368             abbrevs,
369             line_program,
370             line_strings,
371             strings,
372             &range_lists,
373             &loc_lists,
374         )?;
375 
376         let length = (w.len() - length_base) as u64;
377         w.write_initial_length_at(length_offset, length, self.format())?;
378 
379         for (offset, entry) in unit_refs {
380             // This does not need relocation.
381             w.write_udata_at(
382                 offset.0,
383                 offsets.unit_offset(entry),
384                 self.format().word_size(),
385             )?;
386         }
387 
388         Ok(offsets)
389     }
390 
391     /// Reorder base types to come first so that typed stack operations
392     /// can get their offset.
reorder_base_types(&mut self)393     fn reorder_base_types(&mut self) {
394         let root = &self.entries[self.root.index];
395         let mut root_children = Vec::with_capacity(root.children.len());
396         for entry in &root.children {
397             if self.entries[entry.index].tag == constants::DW_TAG_base_type {
398                 root_children.push(*entry);
399             }
400         }
401         for entry in &root.children {
402             if self.entries[entry.index].tag != constants::DW_TAG_base_type {
403                 root_children.push(*entry);
404             }
405         }
406         self.entries[self.root.index].children = root_children;
407     }
408 }
409 
410 /// A Debugging Information Entry (DIE).
411 ///
412 /// DIEs have a set of attributes and optionally have children DIEs as well.
413 ///
414 /// DIEs form a tree without any cycles. This is enforced by specifying the
415 /// parent when creating a DIE, and disallowing changes of parent.
416 #[derive(Debug)]
417 pub struct DebuggingInformationEntry {
418     id: UnitEntryId,
419     parent: Option<UnitEntryId>,
420     tag: constants::DwTag,
421     /// Whether to emit `DW_AT_sibling`.
422     sibling: bool,
423     attrs: Vec<Attribute>,
424     children: Vec<UnitEntryId>,
425 }
426 
427 impl DebuggingInformationEntry {
428     /// Create a new `DebuggingInformationEntry`.
429     ///
430     /// # Panics
431     ///
432     /// Panics if `parent` is invalid.
433     #[allow(clippy::new_ret_no_self)]
new( base_id: BaseId, entries: &mut Vec<DebuggingInformationEntry>, parent: Option<UnitEntryId>, tag: constants::DwTag, ) -> UnitEntryId434     fn new(
435         base_id: BaseId,
436         entries: &mut Vec<DebuggingInformationEntry>,
437         parent: Option<UnitEntryId>,
438         tag: constants::DwTag,
439     ) -> UnitEntryId {
440         let id = UnitEntryId::new(base_id, entries.len());
441         entries.push(DebuggingInformationEntry {
442             id,
443             parent,
444             tag,
445             sibling: false,
446             attrs: Vec::new(),
447             children: Vec::new(),
448         });
449         if let Some(parent) = parent {
450             debug_assert_eq!(base_id, parent.base_id);
451             assert_ne!(parent, id);
452             entries[parent.index].children.push(id);
453         }
454         id
455     }
456 
457     /// Return the id of this entry.
458     #[inline]
id(&self) -> UnitEntryId459     pub fn id(&self) -> UnitEntryId {
460         self.id
461     }
462 
463     /// Return the parent of this entry.
464     #[inline]
parent(&self) -> Option<UnitEntryId>465     pub fn parent(&self) -> Option<UnitEntryId> {
466         self.parent
467     }
468 
469     /// Return the tag of this entry.
470     #[inline]
tag(&self) -> constants::DwTag471     pub fn tag(&self) -> constants::DwTag {
472         self.tag
473     }
474 
475     /// Return `true` if a `DW_AT_sibling` attribute will be emitted.
476     #[inline]
sibling(&self) -> bool477     pub fn sibling(&self) -> bool {
478         self.sibling
479     }
480 
481     /// Set whether a `DW_AT_sibling` attribute will be emitted.
482     ///
483     /// The attribute will only be emitted if the DIE has children.
484     #[inline]
set_sibling(&mut self, sibling: bool)485     pub fn set_sibling(&mut self, sibling: bool) {
486         self.sibling = sibling;
487     }
488 
489     /// Iterate over the attributes of this entry.
490     #[inline]
attrs(&self) -> slice::Iter<Attribute>491     pub fn attrs(&self) -> slice::Iter<Attribute> {
492         self.attrs.iter()
493     }
494 
495     /// Iterate over the attributes of this entry for modification.
496     #[inline]
attrs_mut(&mut self) -> slice::IterMut<Attribute>497     pub fn attrs_mut(&mut self) -> slice::IterMut<Attribute> {
498         self.attrs.iter_mut()
499     }
500 
501     /// Get an attribute.
get(&self, name: constants::DwAt) -> Option<&AttributeValue>502     pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> {
503         self.attrs
504             .iter()
505             .find(|attr| attr.name == name)
506             .map(|attr| &attr.value)
507     }
508 
509     /// Get an attribute for modification.
get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue>510     pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> {
511         self.attrs
512             .iter_mut()
513             .find(|attr| attr.name == name)
514             .map(|attr| &mut attr.value)
515     }
516 
517     /// Set an attribute.
518     ///
519     /// Replaces any existing attribute with the same name.
520     ///
521     /// # Panics
522     ///
523     /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead.
set(&mut self, name: constants::DwAt, value: AttributeValue)524     pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) {
525         assert_ne!(name, constants::DW_AT_sibling);
526         if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) {
527             attr.value = value;
528             return;
529         }
530         self.attrs.push(Attribute { name, value });
531     }
532 
533     /// Delete an attribute.
534     ///
535     /// Replaces any existing attribute with the same name.
delete(&mut self, name: constants::DwAt)536     pub fn delete(&mut self, name: constants::DwAt) {
537         self.attrs.retain(|x| x.name != name);
538     }
539 
540     /// Iterate over the children of this entry.
541     ///
542     /// Note: use `Unit::add` to add a new child to this entry.
543     #[inline]
children(&self) -> slice::Iter<UnitEntryId>544     pub fn children(&self) -> slice::Iter<UnitEntryId> {
545         self.children.iter()
546     }
547 
548     /// Return the type abbreviation for this DIE.
abbreviation(&self, encoding: Encoding) -> Result<Abbreviation>549     fn abbreviation(&self, encoding: Encoding) -> Result<Abbreviation> {
550         let mut attrs = Vec::new();
551 
552         if self.sibling && !self.children.is_empty() {
553             let form = match encoding.format {
554                 Format::Dwarf32 => constants::DW_FORM_ref4,
555                 Format::Dwarf64 => constants::DW_FORM_ref8,
556             };
557             attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form));
558         }
559 
560         for attr in &self.attrs {
561             attrs.push(attr.specification(encoding)?);
562         }
563 
564         Ok(Abbreviation::new(
565             self.tag,
566             !self.children.is_empty(),
567             attrs,
568         ))
569     }
570 
calculate_offsets( &self, unit: &Unit, offset: &mut usize, offsets: &mut UnitOffsets, abbrevs: &mut AbbreviationTable, ) -> Result<()>571     fn calculate_offsets(
572         &self,
573         unit: &Unit,
574         offset: &mut usize,
575         offsets: &mut UnitOffsets,
576         abbrevs: &mut AbbreviationTable,
577     ) -> Result<()> {
578         offsets.entries[self.id.index].offset = DebugInfoOffset(*offset);
579         offsets.entries[self.id.index].abbrev = abbrevs.add(self.abbreviation(unit.encoding())?);
580         *offset += self.size(unit, offsets);
581         if !self.children.is_empty() {
582             for child in &self.children {
583                 unit.entries[child.index].calculate_offsets(unit, offset, offsets, abbrevs)?;
584             }
585             // Null child
586             *offset += 1;
587         }
588         Ok(())
589     }
590 
size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize591     fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize {
592         let mut size = uleb128_size(offsets.abbrev(self.id));
593         if self.sibling && !self.children.is_empty() {
594             size += unit.format().word_size() as usize;
595         }
596         for attr in &self.attrs {
597             size += attr.value.size(unit, offsets);
598         }
599         size
600     }
601 
602     /// Write the entry to the given sections.
603     #[allow(clippy::too_many_arguments)]
write<W: Writer>( &self, w: &mut DebugInfo<W>, debug_info_refs: &mut Vec<DebugInfoReference>, unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, unit: &Unit, offsets: &mut UnitOffsets, abbrevs: &mut AbbreviationTable, line_program: Option<DebugLineOffset>, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, range_lists: &RangeListOffsets, loc_lists: &LocationListOffsets, ) -> Result<()>604     fn write<W: Writer>(
605         &self,
606         w: &mut DebugInfo<W>,
607         debug_info_refs: &mut Vec<DebugInfoReference>,
608         unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
609         unit: &Unit,
610         offsets: &mut UnitOffsets,
611         abbrevs: &mut AbbreviationTable,
612         line_program: Option<DebugLineOffset>,
613         line_strings: &DebugLineStrOffsets,
614         strings: &DebugStrOffsets,
615         range_lists: &RangeListOffsets,
616         loc_lists: &LocationListOffsets,
617     ) -> Result<()> {
618         debug_assert_eq!(offsets.debug_info_offset(self.id), w.offset());
619         w.write_uleb128(offsets.abbrev(self.id))?;
620 
621         let sibling_offset = if self.sibling && !self.children.is_empty() {
622             let offset = w.offset();
623             w.write_udata(0, unit.format().word_size())?;
624             Some(offset)
625         } else {
626             None
627         };
628 
629         for attr in &self.attrs {
630             attr.value.write(
631                 w,
632                 debug_info_refs,
633                 unit_refs,
634                 unit,
635                 offsets,
636                 line_program,
637                 line_strings,
638                 strings,
639                 range_lists,
640                 loc_lists,
641             )?;
642         }
643 
644         if !self.children.is_empty() {
645             for child in &self.children {
646                 unit.entries[child.index].write(
647                     w,
648                     debug_info_refs,
649                     unit_refs,
650                     unit,
651                     offsets,
652                     abbrevs,
653                     line_program,
654                     line_strings,
655                     strings,
656                     range_lists,
657                     loc_lists,
658                 )?;
659             }
660             // Null child
661             w.write_u8(0)?;
662         }
663 
664         if let Some(offset) = sibling_offset {
665             let next_offset = (w.offset().0 - offsets.unit.0) as u64;
666             // This does not need relocation.
667             w.write_udata_at(offset.0, next_offset, unit.format().word_size())?;
668         }
669         Ok(())
670     }
671 }
672 
673 /// An attribute in a `DebuggingInformationEntry`, consisting of a name and
674 /// associated value.
675 #[derive(Debug, Clone, PartialEq, Eq)]
676 pub struct Attribute {
677     name: constants::DwAt,
678     value: AttributeValue,
679 }
680 
681 impl Attribute {
682     /// Get the name of this attribute.
683     #[inline]
name(&self) -> constants::DwAt684     pub fn name(&self) -> constants::DwAt {
685         self.name
686     }
687 
688     /// Get the value of this attribute.
689     #[inline]
get(&self) -> &AttributeValue690     pub fn get(&self) -> &AttributeValue {
691         &self.value
692     }
693 
694     /// Set the value of this attribute.
695     #[inline]
set(&mut self, value: AttributeValue)696     pub fn set(&mut self, value: AttributeValue) {
697         self.value = value;
698     }
699 
700     /// Return the type specification for this attribute.
specification(&self, encoding: Encoding) -> Result<AttributeSpecification>701     fn specification(&self, encoding: Encoding) -> Result<AttributeSpecification> {
702         Ok(AttributeSpecification::new(
703             self.name,
704             self.value.form(encoding)?,
705         ))
706     }
707 }
708 
709 /// The value of an attribute in a `DebuggingInformationEntry`.
710 #[derive(Debug, Clone, PartialEq, Eq)]
711 pub enum AttributeValue {
712     /// "Refers to some location in the address space of the described program."
713     Address(Address),
714 
715     /// A slice of an arbitrary number of bytes.
716     Block(Vec<u8>),
717 
718     /// A one byte constant data value. How to interpret the byte depends on context.
719     ///
720     /// From section 7 of the standard: "Depending on context, it may be a
721     /// signed integer, an unsigned integer, a floating-point constant, or
722     /// anything else."
723     Data1(u8),
724 
725     /// A two byte constant data value. How to interpret the bytes depends on context.
726     ///
727     /// This value will be converted to the target endian before writing.
728     ///
729     /// From section 7 of the standard: "Depending on context, it may be a
730     /// signed integer, an unsigned integer, a floating-point constant, or
731     /// anything else."
732     Data2(u16),
733 
734     /// A four byte constant data value. How to interpret the bytes depends on context.
735     ///
736     /// This value will be converted to the target endian before writing.
737     ///
738     /// From section 7 of the standard: "Depending on context, it may be a
739     /// signed integer, an unsigned integer, a floating-point constant, or
740     /// anything else."
741     Data4(u32),
742 
743     /// An eight byte constant data value. How to interpret the bytes depends on context.
744     ///
745     /// This value will be converted to the target endian before writing.
746     ///
747     /// From section 7 of the standard: "Depending on context, it may be a
748     /// signed integer, an unsigned integer, a floating-point constant, or
749     /// anything else."
750     Data8(u64),
751 
752     /// A signed integer constant.
753     Sdata(i64),
754 
755     /// An unsigned integer constant.
756     Udata(u64),
757 
758     /// "The information bytes contain a DWARF expression (see Section 2.5) or
759     /// location description (see Section 2.6)."
760     Exprloc(Expression),
761 
762     /// A boolean that indicates presence or absence of the attribute.
763     Flag(bool),
764 
765     /// An attribute that is always present.
766     FlagPresent,
767 
768     /// A reference to a `DebuggingInformationEntry` in this unit.
769     UnitRef(UnitEntryId),
770 
771     /// A reference to a `DebuggingInformationEntry` in a potentially different unit.
772     DebugInfoRef(Reference),
773 
774     /// An offset into the `.debug_info` section of the supplementary object file.
775     ///
776     /// The API does not currently assist with generating this offset.
777     /// This variant will be removed from the API once support for writing
778     /// supplementary object files is implemented.
779     DebugInfoRefSup(DebugInfoOffset),
780 
781     /// A reference to a line number program.
782     LineProgramRef,
783 
784     /// A reference to a location list.
785     LocationListRef(LocationListId),
786 
787     /// An offset into the `.debug_macinfo` section.
788     ///
789     /// The API does not currently assist with generating this offset.
790     /// This variant will be removed from the API once support for writing
791     /// `.debug_macinfo` sections is implemented.
792     DebugMacinfoRef(DebugMacinfoOffset),
793 
794     /// An offset into the `.debug_macro` section.
795     ///
796     /// The API does not currently assist with generating this offset.
797     /// This variant will be removed from the API once support for writing
798     /// `.debug_macro` sections is implemented.
799     DebugMacroRef(DebugMacroOffset),
800 
801     /// A reference to a range list.
802     RangeListRef(RangeListId),
803 
804     /// A type signature.
805     ///
806     /// The API does not currently assist with generating this signature.
807     /// This variant will be removed from the API once support for writing
808     /// `.debug_types` sections is implemented.
809     DebugTypesRef(DebugTypeSignature),
810 
811     /// A reference to a string in the `.debug_str` section.
812     StringRef(StringId),
813 
814     /// An offset into the `.debug_str` section of the supplementary object file.
815     ///
816     /// The API does not currently assist with generating this offset.
817     /// This variant will be removed from the API once support for writing
818     /// supplementary object files is implemented.
819     DebugStrRefSup(DebugStrOffset),
820 
821     /// A reference to a string in the `.debug_line_str` section.
822     LineStringRef(LineStringId),
823 
824     /// A slice of bytes representing a string. Must not include null bytes.
825     /// Not guaranteed to be UTF-8 or anything like that.
826     String(Vec<u8>),
827 
828     /// The value of a `DW_AT_encoding` attribute.
829     Encoding(constants::DwAte),
830 
831     /// The value of a `DW_AT_decimal_sign` attribute.
832     DecimalSign(constants::DwDs),
833 
834     /// The value of a `DW_AT_endianity` attribute.
835     Endianity(constants::DwEnd),
836 
837     /// The value of a `DW_AT_accessibility` attribute.
838     Accessibility(constants::DwAccess),
839 
840     /// The value of a `DW_AT_visibility` attribute.
841     Visibility(constants::DwVis),
842 
843     /// The value of a `DW_AT_virtuality` attribute.
844     Virtuality(constants::DwVirtuality),
845 
846     /// The value of a `DW_AT_language` attribute.
847     Language(constants::DwLang),
848 
849     /// The value of a `DW_AT_address_class` attribute.
850     AddressClass(constants::DwAddr),
851 
852     /// The value of a `DW_AT_identifier_case` attribute.
853     IdentifierCase(constants::DwId),
854 
855     /// The value of a `DW_AT_calling_convention` attribute.
856     CallingConvention(constants::DwCc),
857 
858     /// The value of a `DW_AT_inline` attribute.
859     Inline(constants::DwInl),
860 
861     /// The value of a `DW_AT_ordering` attribute.
862     Ordering(constants::DwOrd),
863 
864     /// An index into the filename entries from the line number information
865     /// table for the unit containing this value.
866     FileIndex(Option<FileId>),
867 }
868 
869 impl AttributeValue {
870     /// Return the form that will be used to encode this value.
form(&self, encoding: Encoding) -> Result<constants::DwForm>871     pub fn form(&self, encoding: Encoding) -> Result<constants::DwForm> {
872         // TODO: missing forms:
873         // - DW_FORM_indirect
874         // - DW_FORM_implicit_const
875         // - FW_FORM_block1/block2/block4
876         // - DW_FORM_str/strx1/strx2/strx3/strx4
877         // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4
878         // - DW_FORM_data16
879         // - DW_FORM_line_strp
880         // - DW_FORM_loclistx
881         // - DW_FORM_rnglistx
882         let form = match *self {
883             AttributeValue::Address(_) => constants::DW_FORM_addr,
884             AttributeValue::Block(_) => constants::DW_FORM_block,
885             AttributeValue::Data1(_) => constants::DW_FORM_data1,
886             AttributeValue::Data2(_) => constants::DW_FORM_data2,
887             AttributeValue::Data4(_) => constants::DW_FORM_data4,
888             AttributeValue::Data8(_) => constants::DW_FORM_data8,
889             AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc,
890             AttributeValue::Flag(_) => constants::DW_FORM_flag,
891             AttributeValue::FlagPresent => constants::DW_FORM_flag_present,
892             AttributeValue::UnitRef(_) => {
893                 // Using a fixed size format lets us write a placeholder before we know
894                 // the value.
895                 match encoding.format {
896                     Format::Dwarf32 => constants::DW_FORM_ref4,
897                     Format::Dwarf64 => constants::DW_FORM_ref8,
898                 }
899             }
900             AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr,
901             AttributeValue::DebugInfoRefSup(_) => {
902                 // TODO: should this depend on the size of supplementary section?
903                 match encoding.format {
904                     Format::Dwarf32 => constants::DW_FORM_ref_sup4,
905                     Format::Dwarf64 => constants::DW_FORM_ref_sup8,
906                 }
907             }
908             AttributeValue::LineProgramRef
909             | AttributeValue::LocationListRef(_)
910             | AttributeValue::DebugMacinfoRef(_)
911             | AttributeValue::DebugMacroRef(_)
912             | AttributeValue::RangeListRef(_) => {
913                 if encoding.version == 2 || encoding.version == 3 {
914                     match encoding.format {
915                         Format::Dwarf32 => constants::DW_FORM_data4,
916                         Format::Dwarf64 => constants::DW_FORM_data8,
917                     }
918                 } else {
919                     constants::DW_FORM_sec_offset
920                 }
921             }
922             AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8,
923             AttributeValue::StringRef(_) => constants::DW_FORM_strp,
924             AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup,
925             AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp,
926             AttributeValue::String(_) => constants::DW_FORM_string,
927             AttributeValue::Encoding(_)
928             | AttributeValue::DecimalSign(_)
929             | AttributeValue::Endianity(_)
930             | AttributeValue::Accessibility(_)
931             | AttributeValue::Visibility(_)
932             | AttributeValue::Virtuality(_)
933             | AttributeValue::Language(_)
934             | AttributeValue::AddressClass(_)
935             | AttributeValue::IdentifierCase(_)
936             | AttributeValue::CallingConvention(_)
937             | AttributeValue::Inline(_)
938             | AttributeValue::Ordering(_)
939             | AttributeValue::FileIndex(_)
940             | AttributeValue::Udata(_) => constants::DW_FORM_udata,
941             AttributeValue::Sdata(_) => constants::DW_FORM_sdata,
942         };
943         Ok(form)
944     }
945 
size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize946     fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize {
947         macro_rules! debug_assert_form {
948             ($form:expr) => {
949                 debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form)
950             };
951         }
952         match *self {
953             AttributeValue::Address(_) => {
954                 debug_assert_form!(constants::DW_FORM_addr);
955                 unit.address_size() as usize
956             }
957             AttributeValue::Block(ref val) => {
958                 debug_assert_form!(constants::DW_FORM_block);
959                 uleb128_size(val.len() as u64) + val.len()
960             }
961             AttributeValue::Data1(_) => {
962                 debug_assert_form!(constants::DW_FORM_data1);
963                 1
964             }
965             AttributeValue::Data2(_) => {
966                 debug_assert_form!(constants::DW_FORM_data2);
967                 2
968             }
969             AttributeValue::Data4(_) => {
970                 debug_assert_form!(constants::DW_FORM_data4);
971                 4
972             }
973             AttributeValue::Data8(_) => {
974                 debug_assert_form!(constants::DW_FORM_data8);
975                 8
976             }
977             AttributeValue::Sdata(val) => {
978                 debug_assert_form!(constants::DW_FORM_sdata);
979                 sleb128_size(val)
980             }
981             AttributeValue::Udata(val) => {
982                 debug_assert_form!(constants::DW_FORM_udata);
983                 uleb128_size(val)
984             }
985             AttributeValue::Exprloc(ref val) => {
986                 debug_assert_form!(constants::DW_FORM_exprloc);
987                 let size = val.size(unit.encoding(), Some(offsets));
988                 uleb128_size(size as u64) + size
989             }
990             AttributeValue::Flag(_) => {
991                 debug_assert_form!(constants::DW_FORM_flag);
992                 1
993             }
994             AttributeValue::FlagPresent => {
995                 debug_assert_form!(constants::DW_FORM_flag_present);
996                 0
997             }
998             AttributeValue::UnitRef(_) => {
999                 match unit.format() {
1000                     Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
1001                     Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
1002                 }
1003                 unit.format().word_size() as usize
1004             }
1005             AttributeValue::DebugInfoRef(_) => {
1006                 debug_assert_form!(constants::DW_FORM_ref_addr);
1007                 if unit.version() == 2 {
1008                     unit.address_size() as usize
1009                 } else {
1010                     unit.format().word_size() as usize
1011                 }
1012             }
1013             AttributeValue::DebugInfoRefSup(_) => {
1014                 match unit.format() {
1015                     Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
1016                     Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
1017                 }
1018                 unit.format().word_size() as usize
1019             }
1020             AttributeValue::LineProgramRef => {
1021                 if unit.version() >= 4 {
1022                     debug_assert_form!(constants::DW_FORM_sec_offset);
1023                 }
1024                 unit.format().word_size() as usize
1025             }
1026             AttributeValue::LocationListRef(_) => {
1027                 if unit.version() >= 4 {
1028                     debug_assert_form!(constants::DW_FORM_sec_offset);
1029                 }
1030                 unit.format().word_size() as usize
1031             }
1032             AttributeValue::DebugMacinfoRef(_) => {
1033                 if unit.version() >= 4 {
1034                     debug_assert_form!(constants::DW_FORM_sec_offset);
1035                 }
1036                 unit.format().word_size() as usize
1037             }
1038             AttributeValue::DebugMacroRef(_) => {
1039                 if unit.version() >= 4 {
1040                     debug_assert_form!(constants::DW_FORM_sec_offset);
1041                 }
1042                 unit.format().word_size() as usize
1043             }
1044             AttributeValue::RangeListRef(_) => {
1045                 if unit.version() >= 4 {
1046                     debug_assert_form!(constants::DW_FORM_sec_offset);
1047                 }
1048                 unit.format().word_size() as usize
1049             }
1050             AttributeValue::DebugTypesRef(_) => {
1051                 debug_assert_form!(constants::DW_FORM_ref_sig8);
1052                 8
1053             }
1054             AttributeValue::StringRef(_) => {
1055                 debug_assert_form!(constants::DW_FORM_strp);
1056                 unit.format().word_size() as usize
1057             }
1058             AttributeValue::DebugStrRefSup(_) => {
1059                 debug_assert_form!(constants::DW_FORM_strp_sup);
1060                 unit.format().word_size() as usize
1061             }
1062             AttributeValue::LineStringRef(_) => {
1063                 debug_assert_form!(constants::DW_FORM_line_strp);
1064                 unit.format().word_size() as usize
1065             }
1066             AttributeValue::String(ref val) => {
1067                 debug_assert_form!(constants::DW_FORM_string);
1068                 val.len() + 1
1069             }
1070             AttributeValue::Encoding(val) => {
1071                 debug_assert_form!(constants::DW_FORM_udata);
1072                 uleb128_size(val.0 as u64)
1073             }
1074             AttributeValue::DecimalSign(val) => {
1075                 debug_assert_form!(constants::DW_FORM_udata);
1076                 uleb128_size(val.0 as u64)
1077             }
1078             AttributeValue::Endianity(val) => {
1079                 debug_assert_form!(constants::DW_FORM_udata);
1080                 uleb128_size(val.0 as u64)
1081             }
1082             AttributeValue::Accessibility(val) => {
1083                 debug_assert_form!(constants::DW_FORM_udata);
1084                 uleb128_size(val.0 as u64)
1085             }
1086             AttributeValue::Visibility(val) => {
1087                 debug_assert_form!(constants::DW_FORM_udata);
1088                 uleb128_size(val.0 as u64)
1089             }
1090             AttributeValue::Virtuality(val) => {
1091                 debug_assert_form!(constants::DW_FORM_udata);
1092                 uleb128_size(val.0 as u64)
1093             }
1094             AttributeValue::Language(val) => {
1095                 debug_assert_form!(constants::DW_FORM_udata);
1096                 uleb128_size(val.0 as u64)
1097             }
1098             AttributeValue::AddressClass(val) => {
1099                 debug_assert_form!(constants::DW_FORM_udata);
1100                 uleb128_size(val.0 as u64)
1101             }
1102             AttributeValue::IdentifierCase(val) => {
1103                 debug_assert_form!(constants::DW_FORM_udata);
1104                 uleb128_size(val.0 as u64)
1105             }
1106             AttributeValue::CallingConvention(val) => {
1107                 debug_assert_form!(constants::DW_FORM_udata);
1108                 uleb128_size(val.0 as u64)
1109             }
1110             AttributeValue::Inline(val) => {
1111                 debug_assert_form!(constants::DW_FORM_udata);
1112                 uleb128_size(val.0 as u64)
1113             }
1114             AttributeValue::Ordering(val) => {
1115                 debug_assert_form!(constants::DW_FORM_udata);
1116                 uleb128_size(val.0 as u64)
1117             }
1118             AttributeValue::FileIndex(val) => {
1119                 debug_assert_form!(constants::DW_FORM_udata);
1120                 uleb128_size(val.map(FileId::raw).unwrap_or(0))
1121             }
1122         }
1123     }
1124 
1125     /// Write the attribute value to the given sections.
1126     #[allow(clippy::cyclomatic_complexity, clippy::too_many_arguments)]
write<W: Writer>( &self, w: &mut DebugInfo<W>, debug_info_refs: &mut Vec<DebugInfoReference>, unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, unit: &Unit, offsets: &UnitOffsets, line_program: Option<DebugLineOffset>, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, range_lists: &RangeListOffsets, loc_lists: &LocationListOffsets, ) -> Result<()>1127     fn write<W: Writer>(
1128         &self,
1129         w: &mut DebugInfo<W>,
1130         debug_info_refs: &mut Vec<DebugInfoReference>,
1131         unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
1132         unit: &Unit,
1133         offsets: &UnitOffsets,
1134         line_program: Option<DebugLineOffset>,
1135         line_strings: &DebugLineStrOffsets,
1136         strings: &DebugStrOffsets,
1137         range_lists: &RangeListOffsets,
1138         loc_lists: &LocationListOffsets,
1139     ) -> Result<()> {
1140         macro_rules! debug_assert_form {
1141             ($form:expr) => {
1142                 debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form)
1143             };
1144         }
1145         match *self {
1146             AttributeValue::Address(val) => {
1147                 debug_assert_form!(constants::DW_FORM_addr);
1148                 w.write_address(val, unit.address_size())?;
1149             }
1150             AttributeValue::Block(ref val) => {
1151                 debug_assert_form!(constants::DW_FORM_block);
1152                 w.write_uleb128(val.len() as u64)?;
1153                 w.write(&val)?;
1154             }
1155             AttributeValue::Data1(val) => {
1156                 debug_assert_form!(constants::DW_FORM_data1);
1157                 w.write_u8(val)?;
1158             }
1159             AttributeValue::Data2(val) => {
1160                 debug_assert_form!(constants::DW_FORM_data2);
1161                 w.write_u16(val)?;
1162             }
1163             AttributeValue::Data4(val) => {
1164                 debug_assert_form!(constants::DW_FORM_data4);
1165                 w.write_u32(val)?;
1166             }
1167             AttributeValue::Data8(val) => {
1168                 debug_assert_form!(constants::DW_FORM_data8);
1169                 w.write_u64(val)?;
1170             }
1171             AttributeValue::Sdata(val) => {
1172                 debug_assert_form!(constants::DW_FORM_sdata);
1173                 w.write_sleb128(val)?;
1174             }
1175             AttributeValue::Udata(val) => {
1176                 debug_assert_form!(constants::DW_FORM_udata);
1177                 w.write_uleb128(val)?;
1178             }
1179             AttributeValue::Exprloc(ref val) => {
1180                 debug_assert_form!(constants::DW_FORM_exprloc);
1181                 w.write_uleb128(val.size(unit.encoding(), Some(offsets)) as u64)?;
1182                 val.write(
1183                     &mut w.0,
1184                     Some(debug_info_refs),
1185                     unit.encoding(),
1186                     Some(offsets),
1187                 )?;
1188             }
1189             AttributeValue::Flag(val) => {
1190                 debug_assert_form!(constants::DW_FORM_flag);
1191                 w.write_u8(val as u8)?;
1192             }
1193             AttributeValue::FlagPresent => {
1194                 debug_assert_form!(constants::DW_FORM_flag_present);
1195             }
1196             AttributeValue::UnitRef(id) => {
1197                 match unit.format() {
1198                     Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
1199                     Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
1200                 }
1201                 unit_refs.push((w.offset(), id));
1202                 w.write_udata(0, unit.format().word_size())?;
1203             }
1204             AttributeValue::DebugInfoRef(reference) => {
1205                 debug_assert_form!(constants::DW_FORM_ref_addr);
1206                 let size = if unit.version() == 2 {
1207                     unit.address_size()
1208                 } else {
1209                     unit.format().word_size()
1210                 };
1211                 match reference {
1212                     Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
1213                     Reference::Entry(unit, entry) => {
1214                         debug_info_refs.push(DebugInfoReference {
1215                             offset: w.len(),
1216                             unit,
1217                             entry,
1218                             size,
1219                         });
1220                         w.write_udata(0, size)?;
1221                     }
1222                 }
1223             }
1224             AttributeValue::DebugInfoRefSup(val) => {
1225                 match unit.format() {
1226                     Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
1227                     Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
1228                 }
1229                 w.write_udata(val.0 as u64, unit.format().word_size())?;
1230             }
1231             AttributeValue::LineProgramRef => {
1232                 if unit.version() >= 4 {
1233                     debug_assert_form!(constants::DW_FORM_sec_offset);
1234                 }
1235                 match line_program {
1236                     Some(line_program) => {
1237                         w.write_offset(
1238                             line_program.0,
1239                             SectionId::DebugLine,
1240                             unit.format().word_size(),
1241                         )?;
1242                     }
1243                     None => return Err(Error::InvalidAttributeValue),
1244                 }
1245             }
1246             AttributeValue::LocationListRef(val) => {
1247                 if unit.version() >= 4 {
1248                     debug_assert_form!(constants::DW_FORM_sec_offset);
1249                 }
1250                 let section = if unit.version() <= 4 {
1251                     SectionId::DebugLoc
1252                 } else {
1253                     SectionId::DebugLocLists
1254                 };
1255                 w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?;
1256             }
1257             AttributeValue::DebugMacinfoRef(val) => {
1258                 if unit.version() >= 4 {
1259                     debug_assert_form!(constants::DW_FORM_sec_offset);
1260                 }
1261                 w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?;
1262             }
1263             AttributeValue::DebugMacroRef(val) => {
1264                 if unit.version() >= 4 {
1265                     debug_assert_form!(constants::DW_FORM_sec_offset);
1266                 }
1267                 w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?;
1268             }
1269             AttributeValue::RangeListRef(val) => {
1270                 if unit.version() >= 4 {
1271                     debug_assert_form!(constants::DW_FORM_sec_offset);
1272                 }
1273                 let section = if unit.version() <= 4 {
1274                     SectionId::DebugRanges
1275                 } else {
1276                     SectionId::DebugRngLists
1277                 };
1278                 w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?;
1279             }
1280             AttributeValue::DebugTypesRef(val) => {
1281                 debug_assert_form!(constants::DW_FORM_ref_sig8);
1282                 w.write_u64(val.0)?;
1283             }
1284             AttributeValue::StringRef(val) => {
1285                 debug_assert_form!(constants::DW_FORM_strp);
1286                 w.write_offset(
1287                     strings.get(val).0,
1288                     SectionId::DebugStr,
1289                     unit.format().word_size(),
1290                 )?;
1291             }
1292             AttributeValue::DebugStrRefSup(val) => {
1293                 debug_assert_form!(constants::DW_FORM_strp_sup);
1294                 w.write_udata(val.0 as u64, unit.format().word_size())?;
1295             }
1296             AttributeValue::LineStringRef(val) => {
1297                 debug_assert_form!(constants::DW_FORM_line_strp);
1298                 w.write_offset(
1299                     line_strings.get(val).0,
1300                     SectionId::DebugLineStr,
1301                     unit.format().word_size(),
1302                 )?;
1303             }
1304             AttributeValue::String(ref val) => {
1305                 debug_assert_form!(constants::DW_FORM_string);
1306                 w.write(&val)?;
1307                 w.write_u8(0)?;
1308             }
1309             AttributeValue::Encoding(val) => {
1310                 debug_assert_form!(constants::DW_FORM_udata);
1311                 w.write_uleb128(u64::from(val.0))?;
1312             }
1313             AttributeValue::DecimalSign(val) => {
1314                 debug_assert_form!(constants::DW_FORM_udata);
1315                 w.write_uleb128(u64::from(val.0))?;
1316             }
1317             AttributeValue::Endianity(val) => {
1318                 debug_assert_form!(constants::DW_FORM_udata);
1319                 w.write_uleb128(u64::from(val.0))?;
1320             }
1321             AttributeValue::Accessibility(val) => {
1322                 debug_assert_form!(constants::DW_FORM_udata);
1323                 w.write_uleb128(u64::from(val.0))?;
1324             }
1325             AttributeValue::Visibility(val) => {
1326                 debug_assert_form!(constants::DW_FORM_udata);
1327                 w.write_uleb128(u64::from(val.0))?;
1328             }
1329             AttributeValue::Virtuality(val) => {
1330                 debug_assert_form!(constants::DW_FORM_udata);
1331                 w.write_uleb128(u64::from(val.0))?;
1332             }
1333             AttributeValue::Language(val) => {
1334                 debug_assert_form!(constants::DW_FORM_udata);
1335                 w.write_uleb128(u64::from(val.0))?;
1336             }
1337             AttributeValue::AddressClass(val) => {
1338                 debug_assert_form!(constants::DW_FORM_udata);
1339                 w.write_uleb128(val.0)?;
1340             }
1341             AttributeValue::IdentifierCase(val) => {
1342                 debug_assert_form!(constants::DW_FORM_udata);
1343                 w.write_uleb128(u64::from(val.0))?;
1344             }
1345             AttributeValue::CallingConvention(val) => {
1346                 debug_assert_form!(constants::DW_FORM_udata);
1347                 w.write_uleb128(u64::from(val.0))?;
1348             }
1349             AttributeValue::Inline(val) => {
1350                 debug_assert_form!(constants::DW_FORM_udata);
1351                 w.write_uleb128(u64::from(val.0))?;
1352             }
1353             AttributeValue::Ordering(val) => {
1354                 debug_assert_form!(constants::DW_FORM_udata);
1355                 w.write_uleb128(u64::from(val.0))?;
1356             }
1357             AttributeValue::FileIndex(val) => {
1358                 debug_assert_form!(constants::DW_FORM_udata);
1359                 w.write_uleb128(val.map(FileId::raw).unwrap_or(0))?;
1360             }
1361         }
1362         Ok(())
1363     }
1364 }
1365 
1366 define_section!(
1367     DebugInfo,
1368     DebugInfoOffset,
1369     "A writable `.debug_info` section."
1370 );
1371 
1372 /// The section offsets of all elements within a `.debug_info` section.
1373 #[derive(Debug, Default)]
1374 pub struct DebugInfoOffsets {
1375     base_id: BaseId,
1376     units: Vec<UnitOffsets>,
1377 }
1378 
1379 impl DebugInfoOffsets {
1380     #[cfg(test)]
unit_offsets(&self, unit: UnitId) -> &UnitOffsets1381     pub(crate) fn unit_offsets(&self, unit: UnitId) -> &UnitOffsets {
1382         debug_assert_eq!(self.base_id, unit.base_id);
1383         &self.units[unit.index]
1384     }
1385 
1386     /// Get the `.debug_info` section offset for the given unit.
1387     #[inline]
unit(&self, unit: UnitId) -> DebugInfoOffset1388     pub fn unit(&self, unit: UnitId) -> DebugInfoOffset {
1389         debug_assert_eq!(self.base_id, unit.base_id);
1390         self.units[unit.index].unit
1391     }
1392 
1393     /// Get the `.debug_info` section offset for the given entry.
1394     #[inline]
entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset1395     pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset {
1396         debug_assert_eq!(self.base_id, unit.base_id);
1397         self.units[unit.index].debug_info_offset(entry)
1398     }
1399 }
1400 
1401 /// The section offsets of all elements of a unit within a `.debug_info` section.
1402 #[derive(Debug)]
1403 pub(crate) struct UnitOffsets {
1404     base_id: BaseId,
1405     unit: DebugInfoOffset,
1406     entries: Vec<EntryOffset>,
1407 }
1408 
1409 impl UnitOffsets {
1410     #[cfg(test)]
none() -> Self1411     fn none() -> Self {
1412         UnitOffsets {
1413             base_id: BaseId::default(),
1414             unit: DebugInfoOffset(0),
1415             entries: Vec::new(),
1416         }
1417     }
1418 
1419     /// Get the .debug_info offset for the given entry.
1420     #[inline]
debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset1421     pub(crate) fn debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset {
1422         debug_assert_eq!(self.base_id, entry.base_id);
1423         let offset = self.entries[entry.index].offset;
1424         debug_assert_ne!(offset.0, 0);
1425         offset
1426     }
1427 
1428     /// Get the unit offset for the given entry.
1429     #[inline]
unit_offset(&self, entry: UnitEntryId) -> u641430     pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> u64 {
1431         let offset = self.debug_info_offset(entry);
1432         (offset.0 - self.unit.0) as u64
1433     }
1434 
1435     /// Get the abbreviation code for the given entry.
1436     #[inline]
abbrev(&self, entry: UnitEntryId) -> u641437     pub(crate) fn abbrev(&self, entry: UnitEntryId) -> u64 {
1438         debug_assert_eq!(self.base_id, entry.base_id);
1439         self.entries[entry.index].abbrev
1440     }
1441 }
1442 
1443 #[derive(Debug, Clone, Copy)]
1444 pub(crate) struct EntryOffset {
1445     offset: DebugInfoOffset,
1446     abbrev: u64,
1447 }
1448 
1449 impl EntryOffset {
none() -> Self1450     fn none() -> Self {
1451         EntryOffset {
1452             offset: DebugInfoOffset(0),
1453             abbrev: 0,
1454         }
1455     }
1456 }
1457 
1458 /// A reference to a `.debug_info` entry that has yet to be resolved.
1459 #[derive(Debug, Clone, Copy)]
1460 pub(crate) struct DebugInfoReference {
1461     /// The offset within the section of the reference.
1462     pub offset: usize,
1463     /// The size of the reference.
1464     pub size: u8,
1465     /// The unit containing the entry.
1466     pub unit: UnitId,
1467     /// The entry being referenced.
1468     pub entry: UnitEntryId,
1469 }
1470 
1471 #[cfg(feature = "read")]
1472 pub(crate) mod convert {
1473     use super::*;
1474     use crate::common::UnitSectionOffset;
1475     use crate::read::{self, Reader};
1476     use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList};
1477     use std::collections::HashMap;
1478 
1479     pub(crate) struct ConvertUnit<R: Reader<Offset = usize>> {
1480         from_unit: read::Unit<R>,
1481         base_id: BaseId,
1482         encoding: Encoding,
1483         entries: Vec<DebuggingInformationEntry>,
1484         entry_offsets: Vec<read::UnitOffset>,
1485         root: UnitEntryId,
1486     }
1487 
1488     pub(crate) struct ConvertUnitContext<'a, R: Reader<Offset = usize>> {
1489         pub dwarf: &'a read::Dwarf<R>,
1490         pub unit: &'a read::Unit<R>,
1491         pub line_strings: &'a mut write::LineStringTable,
1492         pub strings: &'a mut write::StringTable,
1493         pub ranges: &'a mut write::RangeListTable,
1494         pub locations: &'a mut write::LocationListTable,
1495         pub convert_address: &'a dyn Fn(u64) -> Option<Address>,
1496         pub base_address: Address,
1497         pub line_program_offset: Option<DebugLineOffset>,
1498         pub line_program_files: Vec<FileId>,
1499         pub entry_ids: &'a HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1500     }
1501 
1502     impl UnitTable {
1503         /// Create a unit table by reading the data in the given sections.
1504         ///
1505         /// This also updates the given tables with the values that are referenced from
1506         /// attributes in this section.
1507         ///
1508         /// `convert_address` is a function to convert read addresses into the `Address`
1509         /// type. For non-relocatable addresses, this function may simply return
1510         /// `Address::Constant(address)`. For relocatable addresses, it is the caller's
1511         /// responsibility to determine the symbol and addend corresponding to the address
1512         /// and return `Address::Symbol { symbol, addend }`.
from<R: Reader<Offset = usize>>( dwarf: &read::Dwarf<R>, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, convert_address: &dyn Fn(u64) -> Option<Address>, ) -> ConvertResult<UnitTable>1513         pub fn from<R: Reader<Offset = usize>>(
1514             dwarf: &read::Dwarf<R>,
1515             line_strings: &mut write::LineStringTable,
1516             strings: &mut write::StringTable,
1517             convert_address: &dyn Fn(u64) -> Option<Address>,
1518         ) -> ConvertResult<UnitTable> {
1519             let base_id = BaseId::default();
1520             let mut unit_entries = Vec::new();
1521             let mut entry_ids = HashMap::new();
1522 
1523             let mut from_units = dwarf.units();
1524             while let Some(from_unit) = from_units.next()? {
1525                 let unit_id = UnitId::new(base_id, unit_entries.len());
1526                 unit_entries.push(Unit::convert_entries(
1527                     from_unit,
1528                     unit_id,
1529                     &mut entry_ids,
1530                     dwarf,
1531                 )?);
1532             }
1533 
1534             // Attributes must be converted in a separate pass so that we can handle
1535             // references to other compilation units.
1536             let mut units = Vec::new();
1537             for unit_entries in unit_entries.drain(..) {
1538                 units.push(Unit::convert_attributes(
1539                     unit_entries,
1540                     &entry_ids,
1541                     dwarf,
1542                     line_strings,
1543                     strings,
1544                     convert_address,
1545                 )?);
1546             }
1547 
1548             Ok(UnitTable { base_id, units })
1549         }
1550     }
1551 
1552     impl Unit {
1553         /// Create a unit by reading the data in the input sections.
1554         ///
1555         /// Does not add entry attributes.
1556         #[allow(clippy::too_many_arguments)]
convert_entries<R: Reader<Offset = usize>>( from_header: read::CompilationUnitHeader<R>, unit_id: UnitId, entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, dwarf: &read::Dwarf<R>, ) -> ConvertResult<ConvertUnit<R>>1557         pub(crate) fn convert_entries<R: Reader<Offset = usize>>(
1558             from_header: read::CompilationUnitHeader<R>,
1559             unit_id: UnitId,
1560             entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1561             dwarf: &read::Dwarf<R>,
1562         ) -> ConvertResult<ConvertUnit<R>> {
1563             let base_id = BaseId::default();
1564 
1565             let from_unit = dwarf.unit(from_header)?;
1566             let encoding = from_unit.encoding();
1567 
1568             let mut entries = Vec::new();
1569             let mut entry_offsets = Vec::new();
1570 
1571             let mut from_tree = from_unit.entries_tree(None)?;
1572             let from_root = from_tree.root()?;
1573             let root = DebuggingInformationEntry::convert_entry(
1574                 from_root,
1575                 &from_unit,
1576                 base_id,
1577                 &mut entries,
1578                 &mut entry_offsets,
1579                 entry_ids,
1580                 None,
1581                 unit_id,
1582             )?;
1583 
1584             Ok(ConvertUnit {
1585                 from_unit,
1586                 base_id,
1587                 encoding,
1588                 entries,
1589                 entry_offsets,
1590                 root,
1591             })
1592         }
1593 
1594         /// Create entry attributes by reading the data in the input sections.
convert_attributes<R: Reader<Offset = usize>>( unit: ConvertUnit<R>, entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, dwarf: &read::Dwarf<R>, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, convert_address: &dyn Fn(u64) -> Option<Address>, ) -> ConvertResult<Unit>1595         fn convert_attributes<R: Reader<Offset = usize>>(
1596             unit: ConvertUnit<R>,
1597             entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1598             dwarf: &read::Dwarf<R>,
1599             line_strings: &mut write::LineStringTable,
1600             strings: &mut write::StringTable,
1601             convert_address: &dyn Fn(u64) -> Option<Address>,
1602         ) -> ConvertResult<Unit> {
1603             let from_unit = unit.from_unit;
1604             let base_address =
1605                 convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?;
1606 
1607             let (line_program_offset, line_program, line_program_files) =
1608                 match from_unit.line_program {
1609                     Some(ref from_program) => {
1610                         let from_program = from_program.clone();
1611                         let line_program_offset = from_program.header().offset();
1612                         let (line_program, line_program_files) = LineProgram::from(
1613                             from_program,
1614                             dwarf,
1615                             line_strings,
1616                             strings,
1617                             convert_address,
1618                         )?;
1619                         (Some(line_program_offset), line_program, line_program_files)
1620                     }
1621                     None => (None, LineProgram::none(), Vec::new()),
1622                 };
1623 
1624             let mut ranges = RangeListTable::default();
1625             let mut locations = LocationListTable::default();
1626 
1627             let mut context = ConvertUnitContext {
1628                 entry_ids,
1629                 dwarf,
1630                 unit: &from_unit,
1631                 line_strings,
1632                 strings,
1633                 ranges: &mut ranges,
1634                 locations: &mut locations,
1635                 convert_address,
1636                 base_address,
1637                 line_program_offset,
1638                 line_program_files,
1639             };
1640 
1641             let mut entries = unit.entries;
1642             for entry in &mut entries {
1643                 entry.convert_attributes(&mut context, &unit.entry_offsets)?;
1644             }
1645 
1646             Ok(Unit {
1647                 base_id: unit.base_id,
1648                 encoding: unit.encoding,
1649                 line_program,
1650                 ranges,
1651                 locations,
1652                 entries,
1653                 root: unit.root,
1654             })
1655         }
1656     }
1657 
1658     impl DebuggingInformationEntry {
1659         /// Create an entry by reading the data in the input sections.
1660         ///
1661         /// Does not add the entry attributes.
convert_entry<R: Reader<Offset = usize>>( from: read::EntriesTreeNode<R>, from_unit: &read::Unit<R>, base_id: BaseId, entries: &mut Vec<DebuggingInformationEntry>, entry_offsets: &mut Vec<read::UnitOffset>, entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, parent: Option<UnitEntryId>, unit_id: UnitId, ) -> ConvertResult<UnitEntryId>1662         fn convert_entry<R: Reader<Offset = usize>>(
1663             from: read::EntriesTreeNode<R>,
1664             from_unit: &read::Unit<R>,
1665             base_id: BaseId,
1666             entries: &mut Vec<DebuggingInformationEntry>,
1667             entry_offsets: &mut Vec<read::UnitOffset>,
1668             entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1669             parent: Option<UnitEntryId>,
1670             unit_id: UnitId,
1671         ) -> ConvertResult<UnitEntryId> {
1672             let from_entry = from.entry();
1673             let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag());
1674             let offset = from_entry.offset();
1675             entry_offsets.push(offset);
1676             entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id));
1677 
1678             let mut from_children = from.children();
1679             while let Some(from_child) = from_children.next()? {
1680                 DebuggingInformationEntry::convert_entry(
1681                     from_child,
1682                     from_unit,
1683                     base_id,
1684                     entries,
1685                     entry_offsets,
1686                     entry_ids,
1687                     Some(id),
1688                     unit_id,
1689                 )?;
1690             }
1691             Ok(id)
1692         }
1693 
1694         /// Create an entry's attributes by reading the data in the input sections.
convert_attributes<R: Reader<Offset = usize>>( &mut self, context: &mut ConvertUnitContext<R>, entry_offsets: &[read::UnitOffset], ) -> ConvertResult<()>1695         fn convert_attributes<R: Reader<Offset = usize>>(
1696             &mut self,
1697             context: &mut ConvertUnitContext<R>,
1698             entry_offsets: &[read::UnitOffset],
1699         ) -> ConvertResult<()> {
1700             let offset = entry_offsets[self.id.index];
1701             let from = context.unit.entry(offset)?;
1702             let mut from_attrs = from.attrs();
1703             while let Some(from_attr) = from_attrs.next()? {
1704                 if from_attr.name() == constants::DW_AT_sibling {
1705                     // This may point to a null entry, so we have to treat it differently.
1706                     self.set_sibling(true);
1707                 } else if let Some(attr) = Attribute::from(context, &from_attr)? {
1708                     self.set(attr.name, attr.value);
1709                 }
1710             }
1711             Ok(())
1712         }
1713     }
1714 
1715     impl Attribute {
1716         /// Create an attribute by reading the data in the given sections.
from<R: Reader<Offset = usize>>( context: &mut ConvertUnitContext<R>, from: &read::Attribute<R>, ) -> ConvertResult<Option<Attribute>>1717         pub(crate) fn from<R: Reader<Offset = usize>>(
1718             context: &mut ConvertUnitContext<R>,
1719             from: &read::Attribute<R>,
1720         ) -> ConvertResult<Option<Attribute>> {
1721             let value = AttributeValue::from(context, from.value())?;
1722             Ok(value.map(|value| Attribute {
1723                 name: from.name(),
1724                 value,
1725             }))
1726         }
1727     }
1728 
1729     impl AttributeValue {
1730         /// Create an attribute value by reading the data in the given sections.
from<R: Reader<Offset = usize>>( context: &mut ConvertUnitContext<R>, from: read::AttributeValue<R>, ) -> ConvertResult<Option<AttributeValue>>1731         pub(crate) fn from<R: Reader<Offset = usize>>(
1732             context: &mut ConvertUnitContext<R>,
1733             from: read::AttributeValue<R>,
1734         ) -> ConvertResult<Option<AttributeValue>> {
1735             let to = match from {
1736                 read::AttributeValue::Addr(val) => match (context.convert_address)(val) {
1737                     Some(val) => AttributeValue::Address(val),
1738                     None => return Err(ConvertError::InvalidAddress),
1739                 },
1740                 read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()),
1741                 read::AttributeValue::Data1(val) => AttributeValue::Data1(val),
1742                 read::AttributeValue::Data2(val) => AttributeValue::Data2(val),
1743                 read::AttributeValue::Data4(val) => AttributeValue::Data4(val),
1744                 read::AttributeValue::Data8(val) => AttributeValue::Data8(val),
1745                 read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val),
1746                 read::AttributeValue::Udata(val) => AttributeValue::Udata(val),
1747                 read::AttributeValue::Exprloc(expression) => {
1748                     let expression = Expression::from(
1749                         expression,
1750                         context.unit.encoding(),
1751                         Some(context.dwarf),
1752                         Some(context.unit),
1753                         Some(context.entry_ids),
1754                         context.convert_address,
1755                     )?;
1756                     AttributeValue::Exprloc(expression)
1757                 }
1758                 // TODO: it would be nice to preserve the flag form.
1759                 read::AttributeValue::Flag(val) => AttributeValue::Flag(val),
1760                 read::AttributeValue::DebugAddrBase(_base) => {
1761                     // We convert all address indices to addresses,
1762                     // so this is unneeded.
1763                     return Ok(None);
1764                 }
1765                 read::AttributeValue::DebugAddrIndex(index) => {
1766                     let val = context.dwarf.address(context.unit, index)?;
1767                     match (context.convert_address)(val) {
1768                         Some(val) => AttributeValue::Address(val),
1769                         None => return Err(ConvertError::InvalidAddress),
1770                     }
1771                 }
1772                 read::AttributeValue::UnitRef(val) => {
1773                     if !context.unit.header.is_valid_offset(val) {
1774                         return Err(ConvertError::InvalidUnitRef);
1775                     }
1776                     let id = context
1777                         .entry_ids
1778                         .get(&val.to_unit_section_offset(context.unit))
1779                         .ok_or(ConvertError::InvalidUnitRef)?;
1780                     AttributeValue::UnitRef(id.1)
1781                 }
1782                 read::AttributeValue::DebugInfoRef(val) => {
1783                     // TODO: support relocation of this value
1784                     let id = context
1785                         .entry_ids
1786                         .get(&UnitSectionOffset::DebugInfoOffset(val))
1787                         .ok_or(ConvertError::InvalidDebugInfoRef)?;
1788                     AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1))
1789                 }
1790                 read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val),
1791                 read::AttributeValue::DebugLineRef(val) => {
1792                     // There should only be the line program in the CU DIE which we've already
1793                     // converted, so check if it matches that.
1794                     if Some(val) == context.line_program_offset {
1795                         AttributeValue::LineProgramRef
1796                     } else {
1797                         return Err(ConvertError::InvalidLineRef);
1798                     }
1799                 }
1800                 read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val),
1801                 read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val),
1802                 read::AttributeValue::LocationListsRef(val) => {
1803                     let iter = context
1804                         .dwarf
1805                         .locations
1806                         .raw_locations(val, context.unit.encoding())?;
1807                     let loc_list = LocationList::from(iter, context)?;
1808                     let loc_id = context.locations.add(loc_list);
1809                     AttributeValue::LocationListRef(loc_id)
1810                 }
1811                 read::AttributeValue::DebugLocListsBase(_base) => {
1812                     // We convert all location list indices to offsets,
1813                     // so this is unneeded.
1814                     return Ok(None);
1815                 }
1816                 read::AttributeValue::DebugLocListsIndex(index) => {
1817                     let offset = context.dwarf.locations_offset(context.unit, index)?;
1818                     let iter = context
1819                         .dwarf
1820                         .locations
1821                         .raw_locations(offset, context.unit.encoding())?;
1822                     let loc_list = LocationList::from(iter, context)?;
1823                     let loc_id = context.locations.add(loc_list);
1824                     AttributeValue::LocationListRef(loc_id)
1825                 }
1826                 read::AttributeValue::RangeListsRef(val) => {
1827                     let iter = context
1828                         .dwarf
1829                         .ranges
1830                         .raw_ranges(val, context.unit.encoding())?;
1831                     let range_list = RangeList::from(iter, context)?;
1832                     let range_id = context.ranges.add(range_list);
1833                     AttributeValue::RangeListRef(range_id)
1834                 }
1835                 read::AttributeValue::DebugRngListsBase(_base) => {
1836                     // We convert all range list indices to offsets,
1837                     // so this is unneeded.
1838                     return Ok(None);
1839                 }
1840                 read::AttributeValue::DebugRngListsIndex(index) => {
1841                     let offset = context.dwarf.ranges_offset(context.unit, index)?;
1842                     let iter = context
1843                         .dwarf
1844                         .ranges
1845                         .raw_ranges(offset, context.unit.encoding())?;
1846                     let range_list = RangeList::from(iter, context)?;
1847                     let range_id = context.ranges.add(range_list);
1848                     AttributeValue::RangeListRef(range_id)
1849                 }
1850                 read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val),
1851                 read::AttributeValue::DebugStrRef(offset) => {
1852                     let r = context.dwarf.string(offset)?;
1853                     let id = context.strings.add(r.to_slice()?);
1854                     AttributeValue::StringRef(id)
1855                 }
1856                 read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val),
1857                 read::AttributeValue::DebugStrOffsetsBase(_base) => {
1858                     // We convert all string offsets to `.debug_str` references,
1859                     // so this is unneeded.
1860                     return Ok(None);
1861                 }
1862                 read::AttributeValue::DebugStrOffsetsIndex(index) => {
1863                     let offset = context.dwarf.string_offset(context.unit, index)?;
1864                     let r = context.dwarf.string(offset)?;
1865                     let id = context.strings.add(r.to_slice()?);
1866                     AttributeValue::StringRef(id)
1867                 }
1868                 read::AttributeValue::DebugLineStrRef(offset) => {
1869                     let r = context.dwarf.line_string(offset)?;
1870                     let id = context.line_strings.add(r.to_slice()?);
1871                     AttributeValue::LineStringRef(id)
1872                 }
1873                 read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()),
1874                 read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val),
1875                 read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val),
1876                 read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val),
1877                 read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val),
1878                 read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val),
1879                 read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val),
1880                 read::AttributeValue::Language(val) => AttributeValue::Language(val),
1881                 read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val),
1882                 read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val),
1883                 read::AttributeValue::CallingConvention(val) => {
1884                     AttributeValue::CallingConvention(val)
1885                 }
1886                 read::AttributeValue::Inline(val) => AttributeValue::Inline(val),
1887                 read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val),
1888                 read::AttributeValue::FileIndex(val) => {
1889                     if val == 0 {
1890                         // 0 means not specified, even for version 5.
1891                         AttributeValue::FileIndex(None)
1892                     } else {
1893                         match context.line_program_files.get(val as usize) {
1894                             Some(id) => AttributeValue::FileIndex(Some(*id)),
1895                             None => return Err(ConvertError::InvalidFileIndex),
1896                         }
1897                     }
1898                 }
1899                 // Should always be a more specific section reference.
1900                 read::AttributeValue::SecOffset(_) => {
1901                     return Err(ConvertError::InvalidAttributeValue);
1902                 }
1903             };
1904             Ok(Some(to))
1905         }
1906     }
1907 }
1908 
1909 #[cfg(test)]
1910 #[cfg(feature = "read")]
1911 mod tests {
1912     use super::*;
1913     use crate::common::{
1914         DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding,
1915         UnitSectionOffset,
1916     };
1917     use crate::constants;
1918     use crate::read;
1919     use crate::write::{
1920         DebugLine, DebugLineStr, DebugStr, EndianVec, LineString, LineStringTable, Location,
1921         LocationList, LocationListTable, Range, RangeList, RangeListOffsets, RangeListTable,
1922         StringTable,
1923     };
1924     use crate::LittleEndian;
1925     use std::collections::HashMap;
1926     use std::mem;
1927 
1928     #[test]
1929     #[allow(clippy::cyclomatic_complexity)]
test_unit_table()1930     fn test_unit_table() {
1931         let mut strings = StringTable::default();
1932 
1933         let mut units = UnitTable::default();
1934         let unit_id1 = units.add(Unit::new(
1935             Encoding {
1936                 version: 4,
1937                 address_size: 8,
1938                 format: Format::Dwarf32,
1939             },
1940             LineProgram::none(),
1941         ));
1942         let unit2 = units.add(Unit::new(
1943             Encoding {
1944                 version: 2,
1945                 address_size: 4,
1946                 format: Format::Dwarf64,
1947             },
1948             LineProgram::none(),
1949         ));
1950         let unit3 = units.add(Unit::new(
1951             Encoding {
1952                 version: 5,
1953                 address_size: 4,
1954                 format: Format::Dwarf32,
1955             },
1956             LineProgram::none(),
1957         ));
1958         assert_eq!(units.count(), 3);
1959         {
1960             let unit1 = units.get_mut(unit_id1);
1961             assert_eq!(unit1.version(), 4);
1962             assert_eq!(unit1.address_size(), 8);
1963             assert_eq!(unit1.format(), Format::Dwarf32);
1964             assert_eq!(unit1.count(), 1);
1965 
1966             let root_id = unit1.root();
1967             assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0));
1968             {
1969                 let root = unit1.get_mut(root_id);
1970                 assert_eq!(root.id(), root_id);
1971                 assert!(root.parent().is_none());
1972                 assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
1973 
1974                 // Test get/get_mut
1975                 assert!(root.get(constants::DW_AT_producer).is_none());
1976                 assert!(root.get_mut(constants::DW_AT_producer).is_none());
1977                 let mut producer = AttributeValue::String(b"root"[..].into());
1978                 root.set(constants::DW_AT_producer, producer.clone());
1979                 assert_eq!(root.get(constants::DW_AT_producer), Some(&producer));
1980                 assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer));
1981 
1982                 // Test attrs
1983                 let mut attrs = root.attrs();
1984                 let attr = attrs.next().unwrap();
1985                 assert_eq!(attr.name(), constants::DW_AT_producer);
1986                 assert_eq!(attr.get(), &producer);
1987                 assert!(attrs.next().is_none());
1988             }
1989 
1990             let child1 = unit1.add(root_id, constants::DW_TAG_subprogram);
1991             assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1));
1992             {
1993                 let child1 = unit1.get_mut(child1);
1994                 assert_eq!(child1.parent(), Some(root_id));
1995 
1996                 let tmp = AttributeValue::String(b"tmp"[..].into());
1997                 child1.set(constants::DW_AT_name, tmp.clone());
1998                 assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp));
1999 
2000                 // Test attrs_mut
2001                 let name = AttributeValue::StringRef(strings.add(&b"child1"[..]));
2002                 {
2003                     let attr = child1.attrs_mut().next().unwrap();
2004                     assert_eq!(attr.name(), constants::DW_AT_name);
2005                     attr.set(name.clone());
2006                 }
2007                 assert_eq!(child1.get(constants::DW_AT_name), Some(&name));
2008             }
2009 
2010             let child2 = unit1.add(root_id, constants::DW_TAG_subprogram);
2011             assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2));
2012             {
2013                 let child2 = unit1.get_mut(child2);
2014                 assert_eq!(child2.parent(), Some(root_id));
2015 
2016                 let tmp = AttributeValue::String(b"tmp"[..].into());
2017                 child2.set(constants::DW_AT_name, tmp.clone());
2018                 assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp));
2019 
2020                 // Test replace
2021                 let name = AttributeValue::StringRef(strings.add(&b"child2"[..]));
2022                 child2.set(constants::DW_AT_name, name.clone());
2023                 assert_eq!(child2.get(constants::DW_AT_name), Some(&name));
2024             }
2025 
2026             {
2027                 let root = unit1.get(root_id);
2028                 assert_eq!(
2029                     root.children().cloned().collect::<Vec<_>>(),
2030                     vec![child1, child2]
2031                 );
2032             }
2033         }
2034         {
2035             let unit2 = units.get(unit2);
2036             assert_eq!(unit2.version(), 2);
2037             assert_eq!(unit2.address_size(), 4);
2038             assert_eq!(unit2.format(), Format::Dwarf64);
2039             assert_eq!(unit2.count(), 1);
2040 
2041             let root = unit2.root();
2042             assert_eq!(root, UnitEntryId::new(unit2.base_id, 0));
2043             let root = unit2.get(root);
2044             assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0));
2045             assert!(root.parent().is_none());
2046             assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
2047         }
2048 
2049         let mut sections = Sections::new(EndianVec::new(LittleEndian));
2050         let debug_line_str_offsets = DebugLineStrOffsets::none();
2051         let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap();
2052         units
2053             .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2054             .unwrap();
2055 
2056         println!("{:?}", sections.debug_str);
2057         println!("{:?}", sections.debug_info);
2058         println!("{:?}", sections.debug_abbrev);
2059 
2060         let dwarf = read::Dwarf {
2061             debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
2062             debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
2063             debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian),
2064             ..Default::default()
2065         };
2066         let mut read_units = dwarf.units();
2067 
2068         {
2069             let read_unit1 = read_units.next().unwrap().unwrap();
2070             let unit1 = units.get(unit_id1);
2071             assert_eq!(unit1.version(), read_unit1.version());
2072             assert_eq!(unit1.address_size(), read_unit1.address_size());
2073             assert_eq!(unit1.format(), read_unit1.format());
2074 
2075             let read_unit1 = dwarf.unit(read_unit1).unwrap();
2076             let mut read_entries = read_unit1.entries();
2077 
2078             let root = unit1.get(unit1.root());
2079             {
2080                 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2081                 assert_eq!(depth, 0);
2082                 assert_eq!(root.tag(), read_root.tag());
2083                 assert!(read_root.has_children());
2084 
2085                 let producer = match root.get(constants::DW_AT_producer).unwrap() {
2086                     AttributeValue::String(ref producer) => &**producer,
2087                     otherwise => panic!("unexpected {:?}", otherwise),
2088                 };
2089                 assert_eq!(producer, b"root");
2090                 let read_producer = read_root
2091                     .attr_value(constants::DW_AT_producer)
2092                     .unwrap()
2093                     .unwrap();
2094                 assert_eq!(
2095                     dwarf
2096                         .attr_string(&read_unit1, read_producer)
2097                         .unwrap()
2098                         .slice(),
2099                     producer
2100                 );
2101             }
2102 
2103             let mut children = root.children().cloned();
2104 
2105             {
2106                 let child = children.next().unwrap();
2107                 assert_eq!(child, UnitEntryId::new(unit1.base_id, 1));
2108                 let child = unit1.get(child);
2109                 let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
2110                 assert_eq!(depth, 1);
2111                 assert_eq!(child.tag(), read_child.tag());
2112                 assert!(!read_child.has_children());
2113 
2114                 let name = match child.get(constants::DW_AT_name).unwrap() {
2115                     AttributeValue::StringRef(name) => *name,
2116                     otherwise => panic!("unexpected {:?}", otherwise),
2117                 };
2118                 let name = strings.get(name);
2119                 assert_eq!(name, b"child1");
2120                 let read_name = read_child
2121                     .attr_value(constants::DW_AT_name)
2122                     .unwrap()
2123                     .unwrap();
2124                 assert_eq!(
2125                     dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
2126                     name
2127                 );
2128             }
2129 
2130             {
2131                 let child = children.next().unwrap();
2132                 assert_eq!(child, UnitEntryId::new(unit1.base_id, 2));
2133                 let child = unit1.get(child);
2134                 let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
2135                 assert_eq!(depth, 0);
2136                 assert_eq!(child.tag(), read_child.tag());
2137                 assert!(!read_child.has_children());
2138 
2139                 let name = match child.get(constants::DW_AT_name).unwrap() {
2140                     AttributeValue::StringRef(name) => *name,
2141                     otherwise => panic!("unexpected {:?}", otherwise),
2142                 };
2143                 let name = strings.get(name);
2144                 assert_eq!(name, b"child2");
2145                 let read_name = read_child
2146                     .attr_value(constants::DW_AT_name)
2147                     .unwrap()
2148                     .unwrap();
2149                 assert_eq!(
2150                     dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
2151                     name
2152                 );
2153             }
2154 
2155             assert!(read_entries.next_dfs().unwrap().is_none());
2156         }
2157 
2158         {
2159             let read_unit2 = read_units.next().unwrap().unwrap();
2160             let unit2 = units.get(unit2);
2161             assert_eq!(unit2.version(), read_unit2.version());
2162             assert_eq!(unit2.address_size(), read_unit2.address_size());
2163             assert_eq!(unit2.format(), read_unit2.format());
2164 
2165             let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
2166             let mut read_entries = read_unit2.entries(&abbrevs);
2167 
2168             {
2169                 let root = unit2.get(unit2.root());
2170                 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2171                 assert_eq!(depth, 0);
2172                 assert_eq!(root.tag(), read_root.tag());
2173                 assert!(!read_root.has_children());
2174             }
2175 
2176             assert!(read_entries.next_dfs().unwrap().is_none());
2177         }
2178 
2179         {
2180             let read_unit3 = read_units.next().unwrap().unwrap();
2181             let unit3 = units.get(unit3);
2182             assert_eq!(unit3.version(), read_unit3.version());
2183             assert_eq!(unit3.address_size(), read_unit3.address_size());
2184             assert_eq!(unit3.format(), read_unit3.format());
2185 
2186             let abbrevs = dwarf.abbreviations(&read_unit3).unwrap();
2187             let mut read_entries = read_unit3.entries(&abbrevs);
2188 
2189             {
2190                 let root = unit3.get(unit3.root());
2191                 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2192                 assert_eq!(depth, 0);
2193                 assert_eq!(root.tag(), read_root.tag());
2194                 assert!(!read_root.has_children());
2195             }
2196 
2197             assert!(read_entries.next_dfs().unwrap().is_none());
2198         }
2199 
2200         assert!(read_units.next().unwrap().is_none());
2201 
2202         let mut convert_line_strings = LineStringTable::default();
2203         let mut convert_strings = StringTable::default();
2204         let convert_units = UnitTable::from(
2205             &dwarf,
2206             &mut convert_line_strings,
2207             &mut convert_strings,
2208             &|address| Some(Address::Constant(address)),
2209         )
2210         .unwrap();
2211         assert_eq!(convert_units.count(), units.count());
2212 
2213         for i in 0..convert_units.count() {
2214             let unit_id = units.id(i);
2215             let unit = units.get(unit_id);
2216             let convert_unit_id = convert_units.id(i);
2217             let convert_unit = convert_units.get(convert_unit_id);
2218             assert_eq!(convert_unit.version(), unit.version());
2219             assert_eq!(convert_unit.address_size(), unit.address_size());
2220             assert_eq!(convert_unit.format(), unit.format());
2221             assert_eq!(convert_unit.count(), unit.count());
2222 
2223             let root = unit.get(unit.root());
2224             let convert_root = convert_unit.get(convert_unit.root());
2225             assert_eq!(convert_root.tag(), root.tag());
2226             for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
2227                 assert_eq!(convert_attr, attr);
2228             }
2229         }
2230     }
2231 
2232     #[test]
test_attribute_value()2233     fn test_attribute_value() {
2234         // Create a string table and a string with a non-zero id/offset.
2235         let mut strings = StringTable::default();
2236         strings.add("string one");
2237         let string_id = strings.add("string two");
2238         let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
2239         let debug_str_offsets = strings.write(&mut debug_str).unwrap();
2240         let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian);
2241 
2242         let mut line_strings = LineStringTable::default();
2243         line_strings.add("line string one");
2244         let line_string_id = line_strings.add("line string two");
2245         let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian));
2246         let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap();
2247         let read_debug_line_str =
2248             read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian));
2249 
2250         let data = vec![1, 2, 3, 4];
2251         let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian);
2252 
2253         let mut expression = Expression::new();
2254         expression.op_constu(57);
2255         let read_expression = read::Expression(read::EndianSlice::new(
2256             &[constants::DW_OP_constu.0, 57],
2257             LittleEndian,
2258         ));
2259 
2260         let mut ranges = RangeListTable::default();
2261         let range_id = ranges.add(RangeList(vec![Range::StartEnd {
2262             begin: Address::Constant(0x1234),
2263             end: Address::Constant(0x2345),
2264         }]));
2265 
2266         let mut locations = LocationListTable::default();
2267         let loc_id = locations.add(LocationList(vec![Location::StartEnd {
2268             begin: Address::Constant(0x1234),
2269             end: Address::Constant(0x2345),
2270             data: expression.clone(),
2271         }]));
2272 
2273         for &version in &[2, 3, 4, 5] {
2274             for &address_size in &[4, 8] {
2275                 for &format in &[Format::Dwarf32, Format::Dwarf64] {
2276                     let encoding = Encoding {
2277                         format,
2278                         version,
2279                         address_size,
2280                     };
2281 
2282                     let mut sections = Sections::new(EndianVec::new(LittleEndian));
2283                     let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
2284                     let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap();
2285 
2286                     let read_debug_ranges =
2287                         read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian);
2288                     let read_debug_rnglists =
2289                         read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian);
2290 
2291                     let read_debug_loc =
2292                         read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
2293                     let read_debug_loclists =
2294                         read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
2295 
2296                     let mut units = UnitTable::default();
2297                     let unit = units.add(Unit::new(encoding, LineProgram::none()));
2298                     let unit = units.get(unit);
2299                     let encoding = Encoding {
2300                         format,
2301                         version,
2302                         address_size,
2303                     };
2304                     let from_unit = read::UnitHeader::new(
2305                         encoding,
2306                         0,
2307                         DebugAbbrevOffset(0),
2308                         read::EndianSlice::new(&[], LittleEndian),
2309                     );
2310 
2311                     for &(ref name, ref value, ref expect_value) in &[
2312                         (
2313                             constants::DW_AT_name,
2314                             AttributeValue::Address(Address::Constant(0x1234)),
2315                             read::AttributeValue::Addr(0x1234),
2316                         ),
2317                         (
2318                             constants::DW_AT_name,
2319                             AttributeValue::Block(data.clone()),
2320                             read::AttributeValue::Block(read_data),
2321                         ),
2322                         (
2323                             constants::DW_AT_name,
2324                             AttributeValue::Data1(0x12),
2325                             read::AttributeValue::Data1(0x12),
2326                         ),
2327                         (
2328                             constants::DW_AT_name,
2329                             AttributeValue::Data2(0x1234),
2330                             read::AttributeValue::Data2(0x1234),
2331                         ),
2332                         (
2333                             constants::DW_AT_name,
2334                             AttributeValue::Data4(0x1234),
2335                             read::AttributeValue::Data4(0x1234),
2336                         ),
2337                         (
2338                             constants::DW_AT_name,
2339                             AttributeValue::Data8(0x1234),
2340                             read::AttributeValue::Data8(0x1234),
2341                         ),
2342                         (
2343                             constants::DW_AT_name,
2344                             AttributeValue::Sdata(0x1234),
2345                             read::AttributeValue::Sdata(0x1234),
2346                         ),
2347                         (
2348                             constants::DW_AT_name,
2349                             AttributeValue::Udata(0x1234),
2350                             read::AttributeValue::Udata(0x1234),
2351                         ),
2352                         (
2353                             constants::DW_AT_name,
2354                             AttributeValue::Exprloc(expression.clone()),
2355                             read::AttributeValue::Exprloc(read_expression),
2356                         ),
2357                         (
2358                             constants::DW_AT_name,
2359                             AttributeValue::Flag(false),
2360                             read::AttributeValue::Flag(false),
2361                         ),
2362                         /*
2363                         (
2364                             constants::DW_AT_name,
2365                             AttributeValue::FlagPresent,
2366                             read::AttributeValue::Flag(true),
2367                         ),
2368                         */
2369                         (
2370                             constants::DW_AT_name,
2371                             AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
2372                             read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
2373                         ),
2374                         (
2375                             constants::DW_AT_location,
2376                             AttributeValue::LocationListRef(loc_id),
2377                             read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0),
2378                         ),
2379                         (
2380                             constants::DW_AT_macro_info,
2381                             AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)),
2382                             read::AttributeValue::SecOffset(0x1234),
2383                         ),
2384                         (
2385                             constants::DW_AT_macros,
2386                             AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)),
2387                             read::AttributeValue::SecOffset(0x1234),
2388                         ),
2389                         (
2390                             constants::DW_AT_ranges,
2391                             AttributeValue::RangeListRef(range_id),
2392                             read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0),
2393                         ),
2394                         (
2395                             constants::DW_AT_name,
2396                             AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
2397                             read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
2398                         ),
2399                         (
2400                             constants::DW_AT_name,
2401                             AttributeValue::StringRef(string_id),
2402                             read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)),
2403                         ),
2404                         (
2405                             constants::DW_AT_name,
2406                             AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
2407                             read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
2408                         ),
2409                         (
2410                             constants::DW_AT_name,
2411                             AttributeValue::LineStringRef(line_string_id),
2412                             read::AttributeValue::DebugLineStrRef(
2413                                 debug_line_str_offsets.get(line_string_id),
2414                             ),
2415                         ),
2416                         (
2417                             constants::DW_AT_name,
2418                             AttributeValue::String(data.clone()),
2419                             read::AttributeValue::String(read_data),
2420                         ),
2421                         (
2422                             constants::DW_AT_encoding,
2423                             AttributeValue::Encoding(constants::DwAte(0x12)),
2424                             read::AttributeValue::Udata(0x12),
2425                         ),
2426                         (
2427                             constants::DW_AT_decimal_sign,
2428                             AttributeValue::DecimalSign(constants::DwDs(0x12)),
2429                             read::AttributeValue::Udata(0x12),
2430                         ),
2431                         (
2432                             constants::DW_AT_endianity,
2433                             AttributeValue::Endianity(constants::DwEnd(0x12)),
2434                             read::AttributeValue::Udata(0x12),
2435                         ),
2436                         (
2437                             constants::DW_AT_accessibility,
2438                             AttributeValue::Accessibility(constants::DwAccess(0x12)),
2439                             read::AttributeValue::Udata(0x12),
2440                         ),
2441                         (
2442                             constants::DW_AT_visibility,
2443                             AttributeValue::Visibility(constants::DwVis(0x12)),
2444                             read::AttributeValue::Udata(0x12),
2445                         ),
2446                         (
2447                             constants::DW_AT_virtuality,
2448                             AttributeValue::Virtuality(constants::DwVirtuality(0x12)),
2449                             read::AttributeValue::Udata(0x12),
2450                         ),
2451                         (
2452                             constants::DW_AT_language,
2453                             AttributeValue::Language(constants::DwLang(0x12)),
2454                             read::AttributeValue::Udata(0x12),
2455                         ),
2456                         (
2457                             constants::DW_AT_address_class,
2458                             AttributeValue::AddressClass(constants::DwAddr(0x12)),
2459                             read::AttributeValue::Udata(0x12),
2460                         ),
2461                         (
2462                             constants::DW_AT_identifier_case,
2463                             AttributeValue::IdentifierCase(constants::DwId(0x12)),
2464                             read::AttributeValue::Udata(0x12),
2465                         ),
2466                         (
2467                             constants::DW_AT_calling_convention,
2468                             AttributeValue::CallingConvention(constants::DwCc(0x12)),
2469                             read::AttributeValue::Udata(0x12),
2470                         ),
2471                         (
2472                             constants::DW_AT_ordering,
2473                             AttributeValue::Ordering(constants::DwOrd(0x12)),
2474                             read::AttributeValue::Udata(0x12),
2475                         ),
2476                         (
2477                             constants::DW_AT_inline,
2478                             AttributeValue::Inline(constants::DwInl(0x12)),
2479                             read::AttributeValue::Udata(0x12),
2480                         ),
2481                     ][..]
2482                     {
2483                         let form = value.form(encoding).unwrap();
2484                         let attr = Attribute {
2485                             name: *name,
2486                             value: value.clone(),
2487                         };
2488 
2489                         let offsets = UnitOffsets::none();
2490                         let line_program_offset = None;
2491                         let mut debug_info_refs = Vec::new();
2492                         let mut unit_refs = Vec::new();
2493                         let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
2494                         attr.value
2495                             .write(
2496                                 &mut debug_info,
2497                                 &mut debug_info_refs,
2498                                 &mut unit_refs,
2499                                 &unit,
2500                                 &offsets,
2501                                 line_program_offset,
2502                                 &debug_line_str_offsets,
2503                                 &debug_str_offsets,
2504                                 &range_list_offsets,
2505                                 &loc_list_offsets,
2506                             )
2507                             .unwrap();
2508 
2509                         let spec = read::AttributeSpecification::new(*name, form, None);
2510                         let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
2511                         let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
2512                         let read_value = &read_attr.raw_value();
2513                         // read::AttributeValue is invariant in the lifetime of R.
2514                         // The lifetimes here are all okay, so transmute it.
2515                         let read_value = unsafe {
2516                             mem::transmute::<
2517                                 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2518                                 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2519                             >(read_value)
2520                         };
2521                         assert_eq!(read_value, expect_value);
2522 
2523                         let dwarf = read::Dwarf {
2524                             debug_str: read_debug_str.clone(),
2525                             debug_line_str: read_debug_line_str.clone(),
2526                             ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists),
2527                             locations: read::LocationLists::new(
2528                                 read_debug_loc,
2529                                 read_debug_loclists,
2530                             ),
2531                             ..Default::default()
2532                         };
2533 
2534                         let unit = read::Unit {
2535                             offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)),
2536                             header: from_unit,
2537                             abbreviations: read::Abbreviations::default(),
2538                             name: None,
2539                             comp_dir: None,
2540                             low_pc: 0,
2541                             str_offsets_base: DebugStrOffsetsBase(0),
2542                             addr_base: DebugAddrBase(0),
2543                             loclists_base: DebugLocListsBase(0),
2544                             rnglists_base: DebugRngListsBase(0),
2545                             line_program: None,
2546                         };
2547 
2548                         let mut context = convert::ConvertUnitContext {
2549                             dwarf: &dwarf,
2550                             unit: &unit,
2551                             line_strings: &mut line_strings,
2552                             strings: &mut strings,
2553                             ranges: &mut ranges,
2554                             locations: &mut locations,
2555                             convert_address: &|address| Some(Address::Constant(address)),
2556                             base_address: Address::Constant(0),
2557                             line_program_offset: None,
2558                             line_program_files: Vec::new(),
2559                             entry_ids: &HashMap::new(),
2560                         };
2561 
2562                         let convert_attr =
2563                             Attribute::from(&mut context, &read_attr).unwrap().unwrap();
2564                         assert_eq!(convert_attr, attr);
2565                     }
2566                 }
2567             }
2568         }
2569     }
2570 
2571     #[test]
2572     #[allow(clippy::cyclomatic_complexity)]
test_unit_ref()2573     fn test_unit_ref() {
2574         let mut units = UnitTable::default();
2575         let unit_id1 = units.add(Unit::new(
2576             Encoding {
2577                 version: 4,
2578                 address_size: 8,
2579                 format: Format::Dwarf32,
2580             },
2581             LineProgram::none(),
2582         ));
2583         assert_eq!(unit_id1, units.id(0));
2584         let unit_id2 = units.add(Unit::new(
2585             Encoding {
2586                 version: 2,
2587                 address_size: 4,
2588                 format: Format::Dwarf64,
2589             },
2590             LineProgram::none(),
2591         ));
2592         assert_eq!(unit_id2, units.id(1));
2593         let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1);
2594         let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2);
2595         let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1);
2596         let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2);
2597         {
2598             let unit1 = units.get_mut(unit_id1);
2599             let root = unit1.root();
2600             let child_id1 = unit1.add(root, constants::DW_TAG_subprogram);
2601             assert_eq!(child_id1, unit1_child1);
2602             let child_id2 = unit1.add(root, constants::DW_TAG_subprogram);
2603             assert_eq!(child_id2, unit1_child2);
2604             {
2605                 let child1 = unit1.get_mut(child_id1);
2606                 child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
2607             }
2608             {
2609                 let child2 = unit1.get_mut(child_id2);
2610                 child2.set(
2611                     constants::DW_AT_type,
2612                     AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)),
2613                 );
2614             }
2615         }
2616         {
2617             let unit2 = units.get_mut(unit_id2);
2618             let root = unit2.root();
2619             let child_id1 = unit2.add(root, constants::DW_TAG_subprogram);
2620             assert_eq!(child_id1, unit2_child1);
2621             let child_id2 = unit2.add(root, constants::DW_TAG_subprogram);
2622             assert_eq!(child_id2, unit2_child2);
2623             {
2624                 let child1 = unit2.get_mut(child_id1);
2625                 child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
2626             }
2627             {
2628                 let child2 = unit2.get_mut(child_id2);
2629                 child2.set(
2630                     constants::DW_AT_type,
2631                     AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)),
2632                 );
2633             }
2634         }
2635 
2636         let debug_line_str_offsets = DebugLineStrOffsets::none();
2637         let debug_str_offsets = DebugStrOffsets::none();
2638         let mut sections = Sections::new(EndianVec::new(LittleEndian));
2639         let debug_info_offsets = units
2640             .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2641             .unwrap();
2642 
2643         println!("{:?}", sections.debug_info);
2644         println!("{:?}", sections.debug_abbrev);
2645 
2646         let dwarf = read::Dwarf {
2647             debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
2648             debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
2649             ..Default::default()
2650         };
2651 
2652         let mut read_units = dwarf.units();
2653         {
2654             let read_unit1 = read_units.next().unwrap().unwrap();
2655             assert_eq!(read_unit1.offset(), debug_info_offsets.unit(unit_id1));
2656 
2657             let abbrevs = dwarf.abbreviations(&read_unit1).unwrap();
2658             let mut read_entries = read_unit1.entries(&abbrevs);
2659             {
2660                 let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
2661             }
2662             {
2663                 let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
2664                 let offset = debug_info_offsets
2665                     .entry(unit_id1, unit1_child2)
2666                     .to_unit_offset(&read_unit1)
2667                     .unwrap();
2668                 assert_eq!(
2669                     read_child1.attr_value(constants::DW_AT_type).unwrap(),
2670                     Some(read::AttributeValue::UnitRef(offset))
2671                 );
2672             }
2673             {
2674                 let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
2675                 let offset = debug_info_offsets.entry(unit_id2, unit2_child1);
2676                 assert_eq!(
2677                     read_child2.attr_value(constants::DW_AT_type).unwrap(),
2678                     Some(read::AttributeValue::DebugInfoRef(offset))
2679                 );
2680             }
2681         }
2682         {
2683             let read_unit2 = read_units.next().unwrap().unwrap();
2684             assert_eq!(read_unit2.offset(), debug_info_offsets.unit(unit_id2));
2685 
2686             let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
2687             let mut read_entries = read_unit2.entries(&abbrevs);
2688             {
2689                 let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
2690             }
2691             {
2692                 let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
2693                 let offset = debug_info_offsets
2694                     .entry(unit_id2, unit2_child2)
2695                     .to_unit_offset(&read_unit2)
2696                     .unwrap();
2697                 assert_eq!(
2698                     read_child1.attr_value(constants::DW_AT_type).unwrap(),
2699                     Some(read::AttributeValue::UnitRef(offset))
2700                 );
2701             }
2702             {
2703                 let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
2704                 let offset = debug_info_offsets.entry(unit_id1, unit1_child1);
2705                 assert_eq!(
2706                     read_child2.attr_value(constants::DW_AT_type).unwrap(),
2707                     Some(read::AttributeValue::DebugInfoRef(offset))
2708                 );
2709             }
2710         }
2711 
2712         let mut convert_line_strings = LineStringTable::default();
2713         let mut convert_strings = StringTable::default();
2714         let convert_units = UnitTable::from(
2715             &dwarf,
2716             &mut convert_line_strings,
2717             &mut convert_strings,
2718             &|address| Some(Address::Constant(address)),
2719         )
2720         .unwrap();
2721         assert_eq!(convert_units.count(), units.count());
2722 
2723         for i in 0..convert_units.count() {
2724             let unit = units.get(units.id(i));
2725             let convert_unit = convert_units.get(convert_units.id(i));
2726             assert_eq!(convert_unit.version(), unit.version());
2727             assert_eq!(convert_unit.address_size(), unit.address_size());
2728             assert_eq!(convert_unit.format(), unit.format());
2729             assert_eq!(convert_unit.count(), unit.count());
2730 
2731             let root = unit.get(unit.root());
2732             let convert_root = convert_unit.get(convert_unit.root());
2733             assert_eq!(convert_root.tag(), root.tag());
2734             for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
2735                 assert_eq!(convert_attr, attr);
2736             }
2737 
2738             let child1 = unit.get(UnitEntryId::new(unit.base_id, 1));
2739             let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1));
2740             assert_eq!(convert_child1.tag(), child1.tag());
2741             for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) {
2742                 assert_eq!(convert_attr.name, attr.name);
2743                 match (convert_attr.value.clone(), attr.value.clone()) {
2744                     (
2745                         AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
2746                         AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
2747                     ) => {
2748                         assert_eq!(convert_unit.index, unit.index);
2749                         assert_eq!(convert_entry.index, entry.index);
2750                     }
2751                     (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
2752                         assert_eq!(convert_id.index, id.index);
2753                     }
2754                     (convert_value, value) => assert_eq!(convert_value, value),
2755                 }
2756             }
2757 
2758             let child2 = unit.get(UnitEntryId::new(unit.base_id, 2));
2759             let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2));
2760             assert_eq!(convert_child2.tag(), child2.tag());
2761             for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) {
2762                 assert_eq!(convert_attr.name, attr.name);
2763                 match (convert_attr.value.clone(), attr.value.clone()) {
2764                     (
2765                         AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
2766                         AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
2767                     ) => {
2768                         assert_eq!(convert_unit.index, unit.index);
2769                         assert_eq!(convert_entry.index, entry.index);
2770                     }
2771                     (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
2772                         assert_eq!(convert_id.index, id.index);
2773                     }
2774                     (convert_value, value) => assert_eq!(convert_value, value),
2775                 }
2776             }
2777         }
2778     }
2779 
2780     #[test]
test_sibling()2781     fn test_sibling() {
2782         fn add_child(
2783             unit: &mut Unit,
2784             parent: UnitEntryId,
2785             tag: constants::DwTag,
2786             name: &str,
2787         ) -> UnitEntryId {
2788             let id = unit.add(parent, tag);
2789             let child = unit.get_mut(id);
2790             child.set(constants::DW_AT_name, AttributeValue::String(name.into()));
2791             child.set_sibling(true);
2792             id
2793         }
2794 
2795         fn add_children(units: &mut UnitTable, unit_id: UnitId) {
2796             let unit = units.get_mut(unit_id);
2797             let root = unit.root();
2798             let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1");
2799             add_child(unit, child1, constants::DW_TAG_variable, "grandchild1");
2800             add_child(unit, root, constants::DW_TAG_subprogram, "child2");
2801             add_child(unit, root, constants::DW_TAG_subprogram, "child3");
2802         }
2803 
2804         fn next_child<R: read::Reader<Offset = usize>>(
2805             entries: &mut read::EntriesCursor<R>,
2806         ) -> (read::UnitOffset, Option<read::UnitOffset>) {
2807             let (_, entry) = entries.next_dfs().unwrap().unwrap();
2808             let offset = entry.offset();
2809             let sibling =
2810                 entry
2811                     .attr_value(constants::DW_AT_sibling)
2812                     .unwrap()
2813                     .map(|attr| match attr {
2814                         read::AttributeValue::UnitRef(offset) => offset,
2815                         _ => panic!("bad sibling value"),
2816                     });
2817             (offset, sibling)
2818         }
2819 
2820         fn check_sibling<R: read::Reader<Offset = usize>>(
2821             unit: &read::CompilationUnitHeader<R>,
2822             debug_abbrev: &read::DebugAbbrev<R>,
2823         ) {
2824             let abbrevs = unit.abbreviations(debug_abbrev).unwrap();
2825             let mut entries = unit.entries(&abbrevs);
2826             // root
2827             entries.next_dfs().unwrap().unwrap();
2828             // child1
2829             let (_, sibling1) = next_child(&mut entries);
2830             // grandchild1
2831             entries.next_dfs().unwrap().unwrap();
2832             // child2
2833             let (offset2, sibling2) = next_child(&mut entries);
2834             // child3
2835             let (_, _) = next_child(&mut entries);
2836             assert_eq!(sibling1, Some(offset2));
2837             assert_eq!(sibling2, None);
2838         }
2839 
2840         let encoding = Encoding {
2841             format: Format::Dwarf32,
2842             version: 4,
2843             address_size: 8,
2844         };
2845         let mut units = UnitTable::default();
2846         let unit_id1 = units.add(Unit::new(encoding, LineProgram::none()));
2847         add_children(&mut units, unit_id1);
2848         let unit_id2 = units.add(Unit::new(encoding, LineProgram::none()));
2849         add_children(&mut units, unit_id2);
2850 
2851         let debug_line_str_offsets = DebugLineStrOffsets::none();
2852         let debug_str_offsets = DebugStrOffsets::none();
2853         let mut sections = Sections::new(EndianVec::new(LittleEndian));
2854         units
2855             .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2856             .unwrap();
2857 
2858         println!("{:?}", sections.debug_info);
2859         println!("{:?}", sections.debug_abbrev);
2860 
2861         let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian);
2862         let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian);
2863         let mut read_units = read_debug_info.units();
2864         check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
2865         check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
2866     }
2867 
2868     #[test]
test_line_ref()2869     fn test_line_ref() {
2870         for &version in &[2, 3, 4, 5] {
2871             for &address_size in &[4, 8] {
2872                 for &format in &[Format::Dwarf32, Format::Dwarf64] {
2873                     let encoding = Encoding {
2874                         format,
2875                         version,
2876                         address_size,
2877                     };
2878 
2879                     // The line program we'll be referencing.
2880                     let mut line_program = LineProgram::new(
2881                         encoding,
2882                         LineEncoding::default(),
2883                         LineString::String(b"comp_dir".to_vec()),
2884                         LineString::String(b"comp_name".to_vec()),
2885                         None,
2886                     );
2887                     let dir = line_program.default_directory();
2888                     let file1 =
2889                         line_program.add_file(LineString::String(b"file1".to_vec()), dir, None);
2890                     let file2 =
2891                         line_program.add_file(LineString::String(b"file2".to_vec()), dir, None);
2892 
2893                     // Write, read, and convert the line program, so that we have the info
2894                     // required to convert the attributes.
2895                     let line_strings = DebugLineStrOffsets::none();
2896                     let strings = DebugStrOffsets::none();
2897                     let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
2898                     let line_program_offset = line_program
2899                         .write(&mut debug_line, encoding, &line_strings, &strings)
2900                         .unwrap();
2901                     let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
2902                     let read_line_program = read_debug_line
2903                         .program(
2904                             line_program_offset,
2905                             address_size,
2906                             Some(read::EndianSlice::new(b"comp_dir", LittleEndian)),
2907                             Some(read::EndianSlice::new(b"comp_name", LittleEndian)),
2908                         )
2909                         .unwrap();
2910                     let dwarf = read::Dwarf::default();
2911                     let mut convert_line_strings = LineStringTable::default();
2912                     let mut convert_strings = StringTable::default();
2913                     let (_, line_program_files) = LineProgram::from(
2914                         read_line_program,
2915                         &dwarf,
2916                         &mut convert_line_strings,
2917                         &mut convert_strings,
2918                         &|address| Some(Address::Constant(address)),
2919                     )
2920                     .unwrap();
2921 
2922                     // Fake the unit.
2923                     let mut units = UnitTable::default();
2924                     let unit = units.add(Unit::new(encoding, LineProgram::none()));
2925                     let unit = units.get(unit);
2926                     let from_unit = read::UnitHeader::new(
2927                         encoding,
2928                         0,
2929                         DebugAbbrevOffset(0),
2930                         read::EndianSlice::new(&[], LittleEndian),
2931                     );
2932 
2933                     for &(ref name, ref value, ref expect_value) in &[
2934                         (
2935                             constants::DW_AT_stmt_list,
2936                             AttributeValue::LineProgramRef,
2937                             read::AttributeValue::SecOffset(line_program_offset.0),
2938                         ),
2939                         (
2940                             constants::DW_AT_decl_file,
2941                             AttributeValue::FileIndex(Some(file1)),
2942                             read::AttributeValue::Udata(file1.raw()),
2943                         ),
2944                         (
2945                             constants::DW_AT_decl_file,
2946                             AttributeValue::FileIndex(Some(file2)),
2947                             read::AttributeValue::Udata(file2.raw()),
2948                         ),
2949                     ][..]
2950                     {
2951                         let mut ranges = RangeListTable::default();
2952                         let mut locations = LocationListTable::default();
2953                         let mut strings = StringTable::default();
2954                         let mut line_strings = LineStringTable::default();
2955 
2956                         let form = value.form(encoding).unwrap();
2957                         let attr = Attribute {
2958                             name: *name,
2959                             value: value.clone(),
2960                         };
2961 
2962                         let mut debug_info_refs = Vec::new();
2963                         let mut unit_refs = Vec::new();
2964                         let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
2965                         let offsets = UnitOffsets::none();
2966                         let debug_line_str_offsets = DebugLineStrOffsets::none();
2967                         let debug_str_offsets = DebugStrOffsets::none();
2968                         let range_list_offsets = RangeListOffsets::none();
2969                         let loc_list_offsets = LocationListOffsets::none();
2970                         attr.value
2971                             .write(
2972                                 &mut debug_info,
2973                                 &mut debug_info_refs,
2974                                 &mut unit_refs,
2975                                 &unit,
2976                                 &offsets,
2977                                 Some(line_program_offset),
2978                                 &debug_line_str_offsets,
2979                                 &debug_str_offsets,
2980                                 &range_list_offsets,
2981                                 &loc_list_offsets,
2982                             )
2983                             .unwrap();
2984 
2985                         let spec = read::AttributeSpecification::new(*name, form, None);
2986                         let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
2987                         let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
2988                         let read_value = &read_attr.raw_value();
2989                         // read::AttributeValue is invariant in the lifetime of R.
2990                         // The lifetimes here are all okay, so transmute it.
2991                         let read_value = unsafe {
2992                             mem::transmute::<
2993                                 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2994                                 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2995                             >(read_value)
2996                         };
2997                         assert_eq!(read_value, expect_value);
2998 
2999                         let unit = read::Unit {
3000                             offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)),
3001                             header: from_unit,
3002                             abbreviations: read::Abbreviations::default(),
3003                             name: None,
3004                             comp_dir: None,
3005                             low_pc: 0,
3006                             str_offsets_base: DebugStrOffsetsBase(0),
3007                             addr_base: DebugAddrBase(0),
3008                             loclists_base: DebugLocListsBase(0),
3009                             rnglists_base: DebugRngListsBase(0),
3010                             line_program: None,
3011                         };
3012 
3013                         let mut context = convert::ConvertUnitContext {
3014                             dwarf: &dwarf,
3015                             unit: &unit,
3016                             line_strings: &mut line_strings,
3017                             strings: &mut strings,
3018                             ranges: &mut ranges,
3019                             locations: &mut locations,
3020                             convert_address: &|address| Some(Address::Constant(address)),
3021                             base_address: Address::Constant(0),
3022                             line_program_offset: Some(line_program_offset),
3023                             line_program_files: line_program_files.clone(),
3024                             entry_ids: &HashMap::new(),
3025                         };
3026 
3027                         let convert_attr =
3028                             Attribute::from(&mut context, &read_attr).unwrap().unwrap();
3029                         assert_eq!(convert_attr, attr);
3030                     }
3031                 }
3032             }
3033         }
3034     }
3035 
3036     #[test]
test_line_program_used()3037     fn test_line_program_used() {
3038         for used in vec![false, true] {
3039             let encoding = Encoding {
3040                 format: Format::Dwarf32,
3041                 version: 5,
3042                 address_size: 8,
3043             };
3044 
3045             let line_program = LineProgram::new(
3046                 encoding,
3047                 LineEncoding::default(),
3048                 LineString::String(b"comp_dir".to_vec()),
3049                 LineString::String(b"comp_name".to_vec()),
3050                 None,
3051             );
3052 
3053             let mut unit = Unit::new(encoding, line_program);
3054             let file_id = if used { Some(FileId::new(0)) } else { None };
3055             let root = unit.root();
3056             unit.get_mut(root).set(
3057                 constants::DW_AT_decl_file,
3058                 AttributeValue::FileIndex(file_id),
3059             );
3060 
3061             let mut units = UnitTable::default();
3062             units.add(unit);
3063 
3064             let debug_line_str_offsets = DebugLineStrOffsets::none();
3065             let debug_str_offsets = DebugStrOffsets::none();
3066             let mut sections = Sections::new(EndianVec::new(LittleEndian));
3067             units
3068                 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
3069                 .unwrap();
3070             assert_eq!(!used, sections.debug_line.slice().is_empty());
3071         }
3072     }
3073 }
3074