]> git.proxmox.com Git - rustc.git/blob - vendor/gimli-0.23.0/src/write/unit.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / gimli-0.23.0 / src / write / unit.rs
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, DwoId, 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]
36 pub fn add(&mut self, unit: Unit) -> UnitId {
37 let id = UnitId::new(self.base_id, self.units.len());
38 self.units.push(unit);
39 id
40 }
41
42 /// Return the number of units.
43 #[inline]
44 pub fn count(&self) -> usize {
45 self.units.len()
46 }
47
48 /// Return the id of a unit.
49 ///
50 /// # Panics
51 ///
52 /// Panics if `index >= self.count()`.
53 #[inline]
54 pub fn id(&self, index: usize) -> UnitId {
55 assert!(index < self.count());
56 UnitId::new(self.base_id, index)
57 }
58
59 /// Get a reference to a unit.
60 ///
61 /// # Panics
62 ///
63 /// Panics if `id` is invalid.
64 #[inline]
65 pub fn get(&self, id: UnitId) -> &Unit {
66 debug_assert_eq!(self.base_id, id.base_id);
67 &self.units[id.index]
68 }
69
70 /// Get a mutable reference to a unit.
71 ///
72 /// # Panics
73 ///
74 /// Panics if `id` is invalid.
75 #[inline]
76 pub fn get_mut(&mut self, id: UnitId) -> &mut Unit {
77 debug_assert_eq!(self.base_id, id.base_id);
78 &mut self.units[id.index]
79 }
80
81 /// Write the units to the given sections.
82 ///
83 /// `strings` must contain the `.debug_str` offsets of the corresponding
84 /// `StringTable`.
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
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`.
171 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]
195 pub fn encoding(&self) -> Encoding {
196 self.encoding
197 }
198
199 /// Return the DWARF version for this unit.
200 #[inline]
201 pub fn version(&self) -> u16 {
202 self.encoding.version
203 }
204
205 /// Return the address size in bytes for this unit.
206 #[inline]
207 pub fn address_size(&self) -> u8 {
208 self.encoding.address_size
209 }
210
211 /// Return the DWARF format for this unit.
212 #[inline]
213 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]
221 pub fn count(&self) -> usize {
222 self.entries.len()
223 }
224
225 /// Return the id of the root entry.
226 #[inline]
227 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]
239 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]
250 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]
261 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.
267 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.
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.
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)]
434 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]
459 pub fn id(&self) -> UnitEntryId {
460 self.id
461 }
462
463 /// Return the parent of this entry.
464 #[inline]
465 pub fn parent(&self) -> Option<UnitEntryId> {
466 self.parent
467 }
468
469 /// Return the tag of this entry.
470 #[inline]
471 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]
477 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]
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]
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]
497 pub fn attrs_mut(&mut self) -> slice::IterMut<Attribute> {
498 self.attrs.iter_mut()
499 }
500
501 /// Get an attribute.
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.
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.
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.
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]
544 pub fn children(&self) -> slice::Iter<UnitEntryId> {
545 self.children.iter()
546 }
547
548 /// Return the type abbreviation for this DIE.
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
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
591 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)]
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]
684 pub fn name(&self) -> constants::DwAt {
685 self.name
686 }
687
688 /// Get the value of this attribute.
689 #[inline]
690 pub fn get(&self) -> &AttributeValue {
691 &self.value
692 }
693
694 /// Set the value of this attribute.
695 #[inline]
696 pub fn set(&mut self, value: AttributeValue) {
697 self.value = value;
698 }
699
700 /// Return the type specification for this attribute.
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.
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
946 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)]
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)]
1381 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]
1388 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]
1395 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)]
1411 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]
1421 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]
1430 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]
1437 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 {
1450 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 }`.
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)]
1557 pub(crate) fn convert_entries<R: Reader<Offset = usize>>(
1558 from_header: read::UnitHeader<R>,
1559 unit_id: UnitId,
1560 entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1561 dwarf: &read::Dwarf<R>,
1562 ) -> ConvertResult<ConvertUnit<R>> {
1563 match from_header.type_() {
1564 read::UnitType::Compilation => (),
1565 _ => return Err(ConvertError::UnsupportedUnitType),
1566 }
1567 let base_id = BaseId::default();
1568
1569 let from_unit = dwarf.unit(from_header)?;
1570 let encoding = from_unit.encoding();
1571
1572 let mut entries = Vec::new();
1573 let mut entry_offsets = Vec::new();
1574
1575 let mut from_tree = from_unit.entries_tree(None)?;
1576 let from_root = from_tree.root()?;
1577 let root = DebuggingInformationEntry::convert_entry(
1578 from_root,
1579 &from_unit,
1580 base_id,
1581 &mut entries,
1582 &mut entry_offsets,
1583 entry_ids,
1584 None,
1585 unit_id,
1586 )?;
1587
1588 Ok(ConvertUnit {
1589 from_unit,
1590 base_id,
1591 encoding,
1592 entries,
1593 entry_offsets,
1594 root,
1595 })
1596 }
1597
1598 /// Create entry attributes by reading the data in the input sections.
1599 fn convert_attributes<R: Reader<Offset = usize>>(
1600 unit: ConvertUnit<R>,
1601 entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1602 dwarf: &read::Dwarf<R>,
1603 line_strings: &mut write::LineStringTable,
1604 strings: &mut write::StringTable,
1605 convert_address: &dyn Fn(u64) -> Option<Address>,
1606 ) -> ConvertResult<Unit> {
1607 let from_unit = unit.from_unit;
1608 let base_address =
1609 convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?;
1610
1611 let (line_program_offset, line_program, line_program_files) =
1612 match from_unit.line_program {
1613 Some(ref from_program) => {
1614 let from_program = from_program.clone();
1615 let line_program_offset = from_program.header().offset();
1616 let (line_program, line_program_files) = LineProgram::from(
1617 from_program,
1618 dwarf,
1619 line_strings,
1620 strings,
1621 convert_address,
1622 )?;
1623 (Some(line_program_offset), line_program, line_program_files)
1624 }
1625 None => (None, LineProgram::none(), Vec::new()),
1626 };
1627
1628 let mut ranges = RangeListTable::default();
1629 let mut locations = LocationListTable::default();
1630
1631 let mut context = ConvertUnitContext {
1632 entry_ids,
1633 dwarf,
1634 unit: &from_unit,
1635 line_strings,
1636 strings,
1637 ranges: &mut ranges,
1638 locations: &mut locations,
1639 convert_address,
1640 base_address,
1641 line_program_offset,
1642 line_program_files,
1643 };
1644
1645 let mut entries = unit.entries;
1646 for entry in &mut entries {
1647 entry.convert_attributes(&mut context, &unit.entry_offsets)?;
1648 }
1649
1650 Ok(Unit {
1651 base_id: unit.base_id,
1652 encoding: unit.encoding,
1653 line_program,
1654 ranges,
1655 locations,
1656 entries,
1657 root: unit.root,
1658 })
1659 }
1660 }
1661
1662 impl DebuggingInformationEntry {
1663 /// Create an entry by reading the data in the input sections.
1664 ///
1665 /// Does not add the entry attributes.
1666 fn convert_entry<R: Reader<Offset = usize>>(
1667 from: read::EntriesTreeNode<R>,
1668 from_unit: &read::Unit<R>,
1669 base_id: BaseId,
1670 entries: &mut Vec<DebuggingInformationEntry>,
1671 entry_offsets: &mut Vec<read::UnitOffset>,
1672 entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
1673 parent: Option<UnitEntryId>,
1674 unit_id: UnitId,
1675 ) -> ConvertResult<UnitEntryId> {
1676 let from_entry = from.entry();
1677 let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag());
1678 let offset = from_entry.offset();
1679 entry_offsets.push(offset);
1680 entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id));
1681
1682 let mut from_children = from.children();
1683 while let Some(from_child) = from_children.next()? {
1684 DebuggingInformationEntry::convert_entry(
1685 from_child,
1686 from_unit,
1687 base_id,
1688 entries,
1689 entry_offsets,
1690 entry_ids,
1691 Some(id),
1692 unit_id,
1693 )?;
1694 }
1695 Ok(id)
1696 }
1697
1698 /// Create an entry's attributes by reading the data in the input sections.
1699 fn convert_attributes<R: Reader<Offset = usize>>(
1700 &mut self,
1701 context: &mut ConvertUnitContext<R>,
1702 entry_offsets: &[read::UnitOffset],
1703 ) -> ConvertResult<()> {
1704 let offset = entry_offsets[self.id.index];
1705 let from = context.unit.entry(offset)?;
1706 let mut from_attrs = from.attrs();
1707 while let Some(from_attr) = from_attrs.next()? {
1708 if from_attr.name() == constants::DW_AT_sibling {
1709 // This may point to a null entry, so we have to treat it differently.
1710 self.set_sibling(true);
1711 } else if let Some(attr) = Attribute::from(context, &from_attr)? {
1712 self.set(attr.name, attr.value);
1713 }
1714 }
1715 Ok(())
1716 }
1717 }
1718
1719 impl Attribute {
1720 /// Create an attribute by reading the data in the given sections.
1721 pub(crate) fn from<R: Reader<Offset = usize>>(
1722 context: &mut ConvertUnitContext<R>,
1723 from: &read::Attribute<R>,
1724 ) -> ConvertResult<Option<Attribute>> {
1725 let value = AttributeValue::from(context, from.value())?;
1726 Ok(value.map(|value| Attribute {
1727 name: from.name(),
1728 value,
1729 }))
1730 }
1731 }
1732
1733 impl AttributeValue {
1734 /// Create an attribute value by reading the data in the given sections.
1735 pub(crate) fn from<R: Reader<Offset = usize>>(
1736 context: &mut ConvertUnitContext<R>,
1737 from: read::AttributeValue<R>,
1738 ) -> ConvertResult<Option<AttributeValue>> {
1739 let to = match from {
1740 read::AttributeValue::Addr(val) => match (context.convert_address)(val) {
1741 Some(val) => AttributeValue::Address(val),
1742 None => return Err(ConvertError::InvalidAddress),
1743 },
1744 read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()),
1745 read::AttributeValue::Data1(val) => AttributeValue::Data1(val),
1746 read::AttributeValue::Data2(val) => AttributeValue::Data2(val),
1747 read::AttributeValue::Data4(val) => AttributeValue::Data4(val),
1748 read::AttributeValue::Data8(val) => AttributeValue::Data8(val),
1749 read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val),
1750 read::AttributeValue::Udata(val) => AttributeValue::Udata(val),
1751 read::AttributeValue::Exprloc(expression) => {
1752 let expression = Expression::from(
1753 expression,
1754 context.unit.encoding(),
1755 Some(context.dwarf),
1756 Some(context.unit),
1757 Some(context.entry_ids),
1758 context.convert_address,
1759 )?;
1760 AttributeValue::Exprloc(expression)
1761 }
1762 // TODO: it would be nice to preserve the flag form.
1763 read::AttributeValue::Flag(val) => AttributeValue::Flag(val),
1764 read::AttributeValue::DebugAddrBase(_base) => {
1765 // We convert all address indices to addresses,
1766 // so this is unneeded.
1767 return Ok(None);
1768 }
1769 read::AttributeValue::DebugAddrIndex(index) => {
1770 let val = context.dwarf.address(context.unit, index)?;
1771 match (context.convert_address)(val) {
1772 Some(val) => AttributeValue::Address(val),
1773 None => return Err(ConvertError::InvalidAddress),
1774 }
1775 }
1776 read::AttributeValue::UnitRef(val) => {
1777 if !context.unit.header.is_valid_offset(val) {
1778 return Err(ConvertError::InvalidUnitRef);
1779 }
1780 let id = context
1781 .entry_ids
1782 .get(&val.to_unit_section_offset(context.unit))
1783 .ok_or(ConvertError::InvalidUnitRef)?;
1784 AttributeValue::UnitRef(id.1)
1785 }
1786 read::AttributeValue::DebugInfoRef(val) => {
1787 // TODO: support relocation of this value
1788 let id = context
1789 .entry_ids
1790 .get(&UnitSectionOffset::DebugInfoOffset(val))
1791 .ok_or(ConvertError::InvalidDebugInfoRef)?;
1792 AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1))
1793 }
1794 read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val),
1795 read::AttributeValue::DebugLineRef(val) => {
1796 // There should only be the line program in the CU DIE which we've already
1797 // converted, so check if it matches that.
1798 if Some(val) == context.line_program_offset {
1799 AttributeValue::LineProgramRef
1800 } else {
1801 return Err(ConvertError::InvalidLineRef);
1802 }
1803 }
1804 read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val),
1805 read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val),
1806 read::AttributeValue::LocationListsRef(val) => {
1807 let iter = context
1808 .dwarf
1809 .locations
1810 .raw_locations(val, context.unit.encoding())?;
1811 let loc_list = LocationList::from(iter, context)?;
1812 let loc_id = context.locations.add(loc_list);
1813 AttributeValue::LocationListRef(loc_id)
1814 }
1815 read::AttributeValue::DebugLocListsBase(_base) => {
1816 // We convert all location list indices to offsets,
1817 // so this is unneeded.
1818 return Ok(None);
1819 }
1820 read::AttributeValue::DebugLocListsIndex(index) => {
1821 let offset = context.dwarf.locations_offset(context.unit, index)?;
1822 let iter = context
1823 .dwarf
1824 .locations
1825 .raw_locations(offset, context.unit.encoding())?;
1826 let loc_list = LocationList::from(iter, context)?;
1827 let loc_id = context.locations.add(loc_list);
1828 AttributeValue::LocationListRef(loc_id)
1829 }
1830 read::AttributeValue::RangeListsRef(val) => {
1831 let iter = context
1832 .dwarf
1833 .ranges
1834 .raw_ranges(val, context.unit.encoding())?;
1835 let range_list = RangeList::from(iter, context)?;
1836 let range_id = context.ranges.add(range_list);
1837 AttributeValue::RangeListRef(range_id)
1838 }
1839 read::AttributeValue::DebugRngListsBase(_base) => {
1840 // We convert all range list indices to offsets,
1841 // so this is unneeded.
1842 return Ok(None);
1843 }
1844 read::AttributeValue::DebugRngListsIndex(index) => {
1845 let offset = context.dwarf.ranges_offset(context.unit, index)?;
1846 let iter = context
1847 .dwarf
1848 .ranges
1849 .raw_ranges(offset, context.unit.encoding())?;
1850 let range_list = RangeList::from(iter, context)?;
1851 let range_id = context.ranges.add(range_list);
1852 AttributeValue::RangeListRef(range_id)
1853 }
1854 read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val),
1855 read::AttributeValue::DebugStrRef(offset) => {
1856 let r = context.dwarf.string(offset)?;
1857 let id = context.strings.add(r.to_slice()?);
1858 AttributeValue::StringRef(id)
1859 }
1860 read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val),
1861 read::AttributeValue::DebugStrOffsetsBase(_base) => {
1862 // We convert all string offsets to `.debug_str` references,
1863 // so this is unneeded.
1864 return Ok(None);
1865 }
1866 read::AttributeValue::DebugStrOffsetsIndex(index) => {
1867 let offset = context.dwarf.string_offset(context.unit, index)?;
1868 let r = context.dwarf.string(offset)?;
1869 let id = context.strings.add(r.to_slice()?);
1870 AttributeValue::StringRef(id)
1871 }
1872 read::AttributeValue::DebugLineStrRef(offset) => {
1873 let r = context.dwarf.line_string(offset)?;
1874 let id = context.line_strings.add(r.to_slice()?);
1875 AttributeValue::LineStringRef(id)
1876 }
1877 read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()),
1878 read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val),
1879 read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val),
1880 read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val),
1881 read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val),
1882 read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val),
1883 read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val),
1884 read::AttributeValue::Language(val) => AttributeValue::Language(val),
1885 read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val),
1886 read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val),
1887 read::AttributeValue::CallingConvention(val) => {
1888 AttributeValue::CallingConvention(val)
1889 }
1890 read::AttributeValue::Inline(val) => AttributeValue::Inline(val),
1891 read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val),
1892 read::AttributeValue::FileIndex(val) => {
1893 if val == 0 {
1894 // 0 means not specified, even for version 5.
1895 AttributeValue::FileIndex(None)
1896 } else {
1897 match context.line_program_files.get(val as usize) {
1898 Some(id) => AttributeValue::FileIndex(Some(*id)),
1899 None => return Err(ConvertError::InvalidFileIndex),
1900 }
1901 }
1902 }
1903 // Should always be a more specific section reference.
1904 read::AttributeValue::SecOffset(_) => {
1905 return Err(ConvertError::InvalidAttributeValue);
1906 }
1907 read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val),
1908 };
1909 Ok(Some(to))
1910 }
1911 }
1912 }
1913
1914 #[cfg(test)]
1915 #[cfg(feature = "read")]
1916 mod tests {
1917 use super::*;
1918 use crate::common::{
1919 DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding,
1920 };
1921 use crate::constants;
1922 use crate::read;
1923 use crate::write::{
1924 DebugLine, DebugLineStr, DebugStr, EndianVec, LineString, LineStringTable, Location,
1925 LocationList, LocationListTable, Range, RangeList, RangeListOffsets, RangeListTable,
1926 StringTable,
1927 };
1928 use crate::LittleEndian;
1929 use std::collections::HashMap;
1930 use std::mem;
1931
1932 #[test]
1933 #[allow(clippy::cyclomatic_complexity)]
1934 fn test_unit_table() {
1935 let mut strings = StringTable::default();
1936
1937 let mut units = UnitTable::default();
1938 let unit_id1 = units.add(Unit::new(
1939 Encoding {
1940 version: 4,
1941 address_size: 8,
1942 format: Format::Dwarf32,
1943 },
1944 LineProgram::none(),
1945 ));
1946 let unit2 = units.add(Unit::new(
1947 Encoding {
1948 version: 2,
1949 address_size: 4,
1950 format: Format::Dwarf64,
1951 },
1952 LineProgram::none(),
1953 ));
1954 let unit3 = units.add(Unit::new(
1955 Encoding {
1956 version: 5,
1957 address_size: 4,
1958 format: Format::Dwarf32,
1959 },
1960 LineProgram::none(),
1961 ));
1962 assert_eq!(units.count(), 3);
1963 {
1964 let unit1 = units.get_mut(unit_id1);
1965 assert_eq!(unit1.version(), 4);
1966 assert_eq!(unit1.address_size(), 8);
1967 assert_eq!(unit1.format(), Format::Dwarf32);
1968 assert_eq!(unit1.count(), 1);
1969
1970 let root_id = unit1.root();
1971 assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0));
1972 {
1973 let root = unit1.get_mut(root_id);
1974 assert_eq!(root.id(), root_id);
1975 assert!(root.parent().is_none());
1976 assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
1977
1978 // Test get/get_mut
1979 assert!(root.get(constants::DW_AT_producer).is_none());
1980 assert!(root.get_mut(constants::DW_AT_producer).is_none());
1981 let mut producer = AttributeValue::String(b"root"[..].into());
1982 root.set(constants::DW_AT_producer, producer.clone());
1983 assert_eq!(root.get(constants::DW_AT_producer), Some(&producer));
1984 assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer));
1985
1986 // Test attrs
1987 let mut attrs = root.attrs();
1988 let attr = attrs.next().unwrap();
1989 assert_eq!(attr.name(), constants::DW_AT_producer);
1990 assert_eq!(attr.get(), &producer);
1991 assert!(attrs.next().is_none());
1992 }
1993
1994 let child1 = unit1.add(root_id, constants::DW_TAG_subprogram);
1995 assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1));
1996 {
1997 let child1 = unit1.get_mut(child1);
1998 assert_eq!(child1.parent(), Some(root_id));
1999
2000 let tmp = AttributeValue::String(b"tmp"[..].into());
2001 child1.set(constants::DW_AT_name, tmp.clone());
2002 assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp));
2003
2004 // Test attrs_mut
2005 let name = AttributeValue::StringRef(strings.add(&b"child1"[..]));
2006 {
2007 let attr = child1.attrs_mut().next().unwrap();
2008 assert_eq!(attr.name(), constants::DW_AT_name);
2009 attr.set(name.clone());
2010 }
2011 assert_eq!(child1.get(constants::DW_AT_name), Some(&name));
2012 }
2013
2014 let child2 = unit1.add(root_id, constants::DW_TAG_subprogram);
2015 assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2));
2016 {
2017 let child2 = unit1.get_mut(child2);
2018 assert_eq!(child2.parent(), Some(root_id));
2019
2020 let tmp = AttributeValue::String(b"tmp"[..].into());
2021 child2.set(constants::DW_AT_name, tmp.clone());
2022 assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp));
2023
2024 // Test replace
2025 let name = AttributeValue::StringRef(strings.add(&b"child2"[..]));
2026 child2.set(constants::DW_AT_name, name.clone());
2027 assert_eq!(child2.get(constants::DW_AT_name), Some(&name));
2028 }
2029
2030 {
2031 let root = unit1.get(root_id);
2032 assert_eq!(
2033 root.children().cloned().collect::<Vec<_>>(),
2034 vec![child1, child2]
2035 );
2036 }
2037 }
2038 {
2039 let unit2 = units.get(unit2);
2040 assert_eq!(unit2.version(), 2);
2041 assert_eq!(unit2.address_size(), 4);
2042 assert_eq!(unit2.format(), Format::Dwarf64);
2043 assert_eq!(unit2.count(), 1);
2044
2045 let root = unit2.root();
2046 assert_eq!(root, UnitEntryId::new(unit2.base_id, 0));
2047 let root = unit2.get(root);
2048 assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0));
2049 assert!(root.parent().is_none());
2050 assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
2051 }
2052
2053 let mut sections = Sections::new(EndianVec::new(LittleEndian));
2054 let debug_line_str_offsets = DebugLineStrOffsets::none();
2055 let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap();
2056 units
2057 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2058 .unwrap();
2059
2060 println!("{:?}", sections.debug_str);
2061 println!("{:?}", sections.debug_info);
2062 println!("{:?}", sections.debug_abbrev);
2063
2064 let dwarf = read::Dwarf {
2065 debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
2066 debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
2067 debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian),
2068 ..Default::default()
2069 };
2070 let mut read_units = dwarf.units();
2071
2072 {
2073 let read_unit1 = read_units.next().unwrap().unwrap();
2074 let unit1 = units.get(unit_id1);
2075 assert_eq!(unit1.version(), read_unit1.version());
2076 assert_eq!(unit1.address_size(), read_unit1.address_size());
2077 assert_eq!(unit1.format(), read_unit1.format());
2078
2079 let read_unit1 = dwarf.unit(read_unit1).unwrap();
2080 let mut read_entries = read_unit1.entries();
2081
2082 let root = unit1.get(unit1.root());
2083 {
2084 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2085 assert_eq!(depth, 0);
2086 assert_eq!(root.tag(), read_root.tag());
2087 assert!(read_root.has_children());
2088
2089 let producer = match root.get(constants::DW_AT_producer).unwrap() {
2090 AttributeValue::String(ref producer) => &**producer,
2091 otherwise => panic!("unexpected {:?}", otherwise),
2092 };
2093 assert_eq!(producer, b"root");
2094 let read_producer = read_root
2095 .attr_value(constants::DW_AT_producer)
2096 .unwrap()
2097 .unwrap();
2098 assert_eq!(
2099 dwarf
2100 .attr_string(&read_unit1, read_producer)
2101 .unwrap()
2102 .slice(),
2103 producer
2104 );
2105 }
2106
2107 let mut children = root.children().cloned();
2108
2109 {
2110 let child = children.next().unwrap();
2111 assert_eq!(child, UnitEntryId::new(unit1.base_id, 1));
2112 let child = unit1.get(child);
2113 let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
2114 assert_eq!(depth, 1);
2115 assert_eq!(child.tag(), read_child.tag());
2116 assert!(!read_child.has_children());
2117
2118 let name = match child.get(constants::DW_AT_name).unwrap() {
2119 AttributeValue::StringRef(name) => *name,
2120 otherwise => panic!("unexpected {:?}", otherwise),
2121 };
2122 let name = strings.get(name);
2123 assert_eq!(name, b"child1");
2124 let read_name = read_child
2125 .attr_value(constants::DW_AT_name)
2126 .unwrap()
2127 .unwrap();
2128 assert_eq!(
2129 dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
2130 name
2131 );
2132 }
2133
2134 {
2135 let child = children.next().unwrap();
2136 assert_eq!(child, UnitEntryId::new(unit1.base_id, 2));
2137 let child = unit1.get(child);
2138 let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
2139 assert_eq!(depth, 0);
2140 assert_eq!(child.tag(), read_child.tag());
2141 assert!(!read_child.has_children());
2142
2143 let name = match child.get(constants::DW_AT_name).unwrap() {
2144 AttributeValue::StringRef(name) => *name,
2145 otherwise => panic!("unexpected {:?}", otherwise),
2146 };
2147 let name = strings.get(name);
2148 assert_eq!(name, b"child2");
2149 let read_name = read_child
2150 .attr_value(constants::DW_AT_name)
2151 .unwrap()
2152 .unwrap();
2153 assert_eq!(
2154 dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
2155 name
2156 );
2157 }
2158
2159 assert!(read_entries.next_dfs().unwrap().is_none());
2160 }
2161
2162 {
2163 let read_unit2 = read_units.next().unwrap().unwrap();
2164 let unit2 = units.get(unit2);
2165 assert_eq!(unit2.version(), read_unit2.version());
2166 assert_eq!(unit2.address_size(), read_unit2.address_size());
2167 assert_eq!(unit2.format(), read_unit2.format());
2168
2169 let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
2170 let mut read_entries = read_unit2.entries(&abbrevs);
2171
2172 {
2173 let root = unit2.get(unit2.root());
2174 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2175 assert_eq!(depth, 0);
2176 assert_eq!(root.tag(), read_root.tag());
2177 assert!(!read_root.has_children());
2178 }
2179
2180 assert!(read_entries.next_dfs().unwrap().is_none());
2181 }
2182
2183 {
2184 let read_unit3 = read_units.next().unwrap().unwrap();
2185 let unit3 = units.get(unit3);
2186 assert_eq!(unit3.version(), read_unit3.version());
2187 assert_eq!(unit3.address_size(), read_unit3.address_size());
2188 assert_eq!(unit3.format(), read_unit3.format());
2189
2190 let abbrevs = dwarf.abbreviations(&read_unit3).unwrap();
2191 let mut read_entries = read_unit3.entries(&abbrevs);
2192
2193 {
2194 let root = unit3.get(unit3.root());
2195 let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
2196 assert_eq!(depth, 0);
2197 assert_eq!(root.tag(), read_root.tag());
2198 assert!(!read_root.has_children());
2199 }
2200
2201 assert!(read_entries.next_dfs().unwrap().is_none());
2202 }
2203
2204 assert!(read_units.next().unwrap().is_none());
2205
2206 let mut convert_line_strings = LineStringTable::default();
2207 let mut convert_strings = StringTable::default();
2208 let convert_units = UnitTable::from(
2209 &dwarf,
2210 &mut convert_line_strings,
2211 &mut convert_strings,
2212 &|address| Some(Address::Constant(address)),
2213 )
2214 .unwrap();
2215 assert_eq!(convert_units.count(), units.count());
2216
2217 for i in 0..convert_units.count() {
2218 let unit_id = units.id(i);
2219 let unit = units.get(unit_id);
2220 let convert_unit_id = convert_units.id(i);
2221 let convert_unit = convert_units.get(convert_unit_id);
2222 assert_eq!(convert_unit.version(), unit.version());
2223 assert_eq!(convert_unit.address_size(), unit.address_size());
2224 assert_eq!(convert_unit.format(), unit.format());
2225 assert_eq!(convert_unit.count(), unit.count());
2226
2227 let root = unit.get(unit.root());
2228 let convert_root = convert_unit.get(convert_unit.root());
2229 assert_eq!(convert_root.tag(), root.tag());
2230 for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
2231 assert_eq!(convert_attr, attr);
2232 }
2233 }
2234 }
2235
2236 #[test]
2237 fn test_attribute_value() {
2238 // Create a string table and a string with a non-zero id/offset.
2239 let mut strings = StringTable::default();
2240 strings.add("string one");
2241 let string_id = strings.add("string two");
2242 let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
2243 let debug_str_offsets = strings.write(&mut debug_str).unwrap();
2244 let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian);
2245
2246 let mut line_strings = LineStringTable::default();
2247 line_strings.add("line string one");
2248 let line_string_id = line_strings.add("line string two");
2249 let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian));
2250 let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap();
2251 let read_debug_line_str =
2252 read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian));
2253
2254 let data = vec![1, 2, 3, 4];
2255 let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian);
2256
2257 let mut expression = Expression::new();
2258 expression.op_constu(57);
2259 let read_expression = read::Expression(read::EndianSlice::new(
2260 &[constants::DW_OP_constu.0, 57],
2261 LittleEndian,
2262 ));
2263
2264 let mut ranges = RangeListTable::default();
2265 let range_id = ranges.add(RangeList(vec![Range::StartEnd {
2266 begin: Address::Constant(0x1234),
2267 end: Address::Constant(0x2345),
2268 }]));
2269
2270 let mut locations = LocationListTable::default();
2271 let loc_id = locations.add(LocationList(vec![Location::StartEnd {
2272 begin: Address::Constant(0x1234),
2273 end: Address::Constant(0x2345),
2274 data: expression.clone(),
2275 }]));
2276
2277 for &version in &[2, 3, 4, 5] {
2278 for &address_size in &[4, 8] {
2279 for &format in &[Format::Dwarf32, Format::Dwarf64] {
2280 let encoding = Encoding {
2281 format,
2282 version,
2283 address_size,
2284 };
2285
2286 let mut sections = Sections::new(EndianVec::new(LittleEndian));
2287 let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
2288 let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap();
2289
2290 let read_debug_ranges =
2291 read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian);
2292 let read_debug_rnglists =
2293 read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian);
2294
2295 let read_debug_loc =
2296 read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
2297 let read_debug_loclists =
2298 read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
2299
2300 let mut units = UnitTable::default();
2301 let unit = units.add(Unit::new(encoding, LineProgram::none()));
2302 let unit = units.get(unit);
2303 let encoding = Encoding {
2304 format,
2305 version,
2306 address_size,
2307 };
2308 let from_unit = read::UnitHeader::new(
2309 encoding,
2310 0,
2311 read::UnitType::Compilation,
2312 DebugAbbrevOffset(0),
2313 DebugInfoOffset(0).into(),
2314 read::EndianSlice::new(&[], LittleEndian),
2315 );
2316
2317 for &(ref name, ref value, ref expect_value) in &[
2318 (
2319 constants::DW_AT_name,
2320 AttributeValue::Address(Address::Constant(0x1234)),
2321 read::AttributeValue::Addr(0x1234),
2322 ),
2323 (
2324 constants::DW_AT_name,
2325 AttributeValue::Block(data.clone()),
2326 read::AttributeValue::Block(read_data),
2327 ),
2328 (
2329 constants::DW_AT_name,
2330 AttributeValue::Data1(0x12),
2331 read::AttributeValue::Data1(0x12),
2332 ),
2333 (
2334 constants::DW_AT_name,
2335 AttributeValue::Data2(0x1234),
2336 read::AttributeValue::Data2(0x1234),
2337 ),
2338 (
2339 constants::DW_AT_name,
2340 AttributeValue::Data4(0x1234),
2341 read::AttributeValue::Data4(0x1234),
2342 ),
2343 (
2344 constants::DW_AT_name,
2345 AttributeValue::Data8(0x1234),
2346 read::AttributeValue::Data8(0x1234),
2347 ),
2348 (
2349 constants::DW_AT_name,
2350 AttributeValue::Sdata(0x1234),
2351 read::AttributeValue::Sdata(0x1234),
2352 ),
2353 (
2354 constants::DW_AT_name,
2355 AttributeValue::Udata(0x1234),
2356 read::AttributeValue::Udata(0x1234),
2357 ),
2358 (
2359 constants::DW_AT_name,
2360 AttributeValue::Exprloc(expression.clone()),
2361 read::AttributeValue::Exprloc(read_expression),
2362 ),
2363 (
2364 constants::DW_AT_name,
2365 AttributeValue::Flag(false),
2366 read::AttributeValue::Flag(false),
2367 ),
2368 /*
2369 (
2370 constants::DW_AT_name,
2371 AttributeValue::FlagPresent,
2372 read::AttributeValue::Flag(true),
2373 ),
2374 */
2375 (
2376 constants::DW_AT_name,
2377 AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
2378 read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
2379 ),
2380 (
2381 constants::DW_AT_location,
2382 AttributeValue::LocationListRef(loc_id),
2383 read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0),
2384 ),
2385 (
2386 constants::DW_AT_macro_info,
2387 AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)),
2388 read::AttributeValue::SecOffset(0x1234),
2389 ),
2390 (
2391 constants::DW_AT_macros,
2392 AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)),
2393 read::AttributeValue::SecOffset(0x1234),
2394 ),
2395 (
2396 constants::DW_AT_ranges,
2397 AttributeValue::RangeListRef(range_id),
2398 read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0),
2399 ),
2400 (
2401 constants::DW_AT_name,
2402 AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
2403 read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
2404 ),
2405 (
2406 constants::DW_AT_name,
2407 AttributeValue::StringRef(string_id),
2408 read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)),
2409 ),
2410 (
2411 constants::DW_AT_name,
2412 AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
2413 read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
2414 ),
2415 (
2416 constants::DW_AT_name,
2417 AttributeValue::LineStringRef(line_string_id),
2418 read::AttributeValue::DebugLineStrRef(
2419 debug_line_str_offsets.get(line_string_id),
2420 ),
2421 ),
2422 (
2423 constants::DW_AT_name,
2424 AttributeValue::String(data.clone()),
2425 read::AttributeValue::String(read_data),
2426 ),
2427 (
2428 constants::DW_AT_encoding,
2429 AttributeValue::Encoding(constants::DwAte(0x12)),
2430 read::AttributeValue::Udata(0x12),
2431 ),
2432 (
2433 constants::DW_AT_decimal_sign,
2434 AttributeValue::DecimalSign(constants::DwDs(0x12)),
2435 read::AttributeValue::Udata(0x12),
2436 ),
2437 (
2438 constants::DW_AT_endianity,
2439 AttributeValue::Endianity(constants::DwEnd(0x12)),
2440 read::AttributeValue::Udata(0x12),
2441 ),
2442 (
2443 constants::DW_AT_accessibility,
2444 AttributeValue::Accessibility(constants::DwAccess(0x12)),
2445 read::AttributeValue::Udata(0x12),
2446 ),
2447 (
2448 constants::DW_AT_visibility,
2449 AttributeValue::Visibility(constants::DwVis(0x12)),
2450 read::AttributeValue::Udata(0x12),
2451 ),
2452 (
2453 constants::DW_AT_virtuality,
2454 AttributeValue::Virtuality(constants::DwVirtuality(0x12)),
2455 read::AttributeValue::Udata(0x12),
2456 ),
2457 (
2458 constants::DW_AT_language,
2459 AttributeValue::Language(constants::DwLang(0x12)),
2460 read::AttributeValue::Udata(0x12),
2461 ),
2462 (
2463 constants::DW_AT_address_class,
2464 AttributeValue::AddressClass(constants::DwAddr(0x12)),
2465 read::AttributeValue::Udata(0x12),
2466 ),
2467 (
2468 constants::DW_AT_identifier_case,
2469 AttributeValue::IdentifierCase(constants::DwId(0x12)),
2470 read::AttributeValue::Udata(0x12),
2471 ),
2472 (
2473 constants::DW_AT_calling_convention,
2474 AttributeValue::CallingConvention(constants::DwCc(0x12)),
2475 read::AttributeValue::Udata(0x12),
2476 ),
2477 (
2478 constants::DW_AT_ordering,
2479 AttributeValue::Ordering(constants::DwOrd(0x12)),
2480 read::AttributeValue::Udata(0x12),
2481 ),
2482 (
2483 constants::DW_AT_inline,
2484 AttributeValue::Inline(constants::DwInl(0x12)),
2485 read::AttributeValue::Udata(0x12),
2486 ),
2487 ][..]
2488 {
2489 let form = value.form(encoding).unwrap();
2490 let attr = Attribute {
2491 name: *name,
2492 value: value.clone(),
2493 };
2494
2495 let offsets = UnitOffsets::none();
2496 let line_program_offset = None;
2497 let mut debug_info_refs = Vec::new();
2498 let mut unit_refs = Vec::new();
2499 let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
2500 attr.value
2501 .write(
2502 &mut debug_info,
2503 &mut debug_info_refs,
2504 &mut unit_refs,
2505 &unit,
2506 &offsets,
2507 line_program_offset,
2508 &debug_line_str_offsets,
2509 &debug_str_offsets,
2510 &range_list_offsets,
2511 &loc_list_offsets,
2512 )
2513 .unwrap();
2514
2515 let spec = read::AttributeSpecification::new(*name, form, None);
2516 let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
2517 let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
2518 let read_value = &read_attr.raw_value();
2519 // read::AttributeValue is invariant in the lifetime of R.
2520 // The lifetimes here are all okay, so transmute it.
2521 let read_value = unsafe {
2522 mem::transmute::<
2523 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2524 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
2525 >(read_value)
2526 };
2527 assert_eq!(read_value, expect_value);
2528
2529 let dwarf = read::Dwarf {
2530 debug_str: read_debug_str.clone(),
2531 debug_line_str: read_debug_line_str.clone(),
2532 ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists),
2533 locations: read::LocationLists::new(
2534 read_debug_loc,
2535 read_debug_loclists,
2536 ),
2537 ..Default::default()
2538 };
2539
2540 let unit = read::Unit {
2541 header: from_unit,
2542 abbreviations: read::Abbreviations::default(),
2543 name: None,
2544 comp_dir: None,
2545 low_pc: 0,
2546 str_offsets_base: DebugStrOffsetsBase(0),
2547 addr_base: DebugAddrBase(0),
2548 loclists_base: DebugLocListsBase(0),
2549 rnglists_base: DebugRngListsBase(0),
2550 line_program: None,
2551 };
2552
2553 let mut context = convert::ConvertUnitContext {
2554 dwarf: &dwarf,
2555 unit: &unit,
2556 line_strings: &mut line_strings,
2557 strings: &mut strings,
2558 ranges: &mut ranges,
2559 locations: &mut locations,
2560 convert_address: &|address| Some(Address::Constant(address)),
2561 base_address: Address::Constant(0),
2562 line_program_offset: None,
2563 line_program_files: Vec::new(),
2564 entry_ids: &HashMap::new(),
2565 };
2566
2567 let convert_attr =
2568 Attribute::from(&mut context, &read_attr).unwrap().unwrap();
2569 assert_eq!(convert_attr, attr);
2570 }
2571 }
2572 }
2573 }
2574 }
2575
2576 #[test]
2577 #[allow(clippy::cyclomatic_complexity)]
2578 fn test_unit_ref() {
2579 let mut units = UnitTable::default();
2580 let unit_id1 = units.add(Unit::new(
2581 Encoding {
2582 version: 4,
2583 address_size: 8,
2584 format: Format::Dwarf32,
2585 },
2586 LineProgram::none(),
2587 ));
2588 assert_eq!(unit_id1, units.id(0));
2589 let unit_id2 = units.add(Unit::new(
2590 Encoding {
2591 version: 2,
2592 address_size: 4,
2593 format: Format::Dwarf64,
2594 },
2595 LineProgram::none(),
2596 ));
2597 assert_eq!(unit_id2, units.id(1));
2598 let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1);
2599 let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2);
2600 let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1);
2601 let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2);
2602 {
2603 let unit1 = units.get_mut(unit_id1);
2604 let root = unit1.root();
2605 let child_id1 = unit1.add(root, constants::DW_TAG_subprogram);
2606 assert_eq!(child_id1, unit1_child1);
2607 let child_id2 = unit1.add(root, constants::DW_TAG_subprogram);
2608 assert_eq!(child_id2, unit1_child2);
2609 {
2610 let child1 = unit1.get_mut(child_id1);
2611 child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
2612 }
2613 {
2614 let child2 = unit1.get_mut(child_id2);
2615 child2.set(
2616 constants::DW_AT_type,
2617 AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)),
2618 );
2619 }
2620 }
2621 {
2622 let unit2 = units.get_mut(unit_id2);
2623 let root = unit2.root();
2624 let child_id1 = unit2.add(root, constants::DW_TAG_subprogram);
2625 assert_eq!(child_id1, unit2_child1);
2626 let child_id2 = unit2.add(root, constants::DW_TAG_subprogram);
2627 assert_eq!(child_id2, unit2_child2);
2628 {
2629 let child1 = unit2.get_mut(child_id1);
2630 child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
2631 }
2632 {
2633 let child2 = unit2.get_mut(child_id2);
2634 child2.set(
2635 constants::DW_AT_type,
2636 AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)),
2637 );
2638 }
2639 }
2640
2641 let debug_line_str_offsets = DebugLineStrOffsets::none();
2642 let debug_str_offsets = DebugStrOffsets::none();
2643 let mut sections = Sections::new(EndianVec::new(LittleEndian));
2644 let debug_info_offsets = units
2645 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2646 .unwrap();
2647
2648 println!("{:?}", sections.debug_info);
2649 println!("{:?}", sections.debug_abbrev);
2650
2651 let dwarf = read::Dwarf {
2652 debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
2653 debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
2654 ..Default::default()
2655 };
2656
2657 let mut read_units = dwarf.units();
2658 {
2659 let read_unit1 = read_units.next().unwrap().unwrap();
2660 assert_eq!(
2661 read_unit1.offset(),
2662 debug_info_offsets.unit(unit_id1).into()
2663 );
2664
2665 let abbrevs = dwarf.abbreviations(&read_unit1).unwrap();
2666 let mut read_entries = read_unit1.entries(&abbrevs);
2667 {
2668 let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
2669 }
2670 {
2671 let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
2672 let offset = debug_info_offsets
2673 .entry(unit_id1, unit1_child2)
2674 .to_unit_offset(&read_unit1)
2675 .unwrap();
2676 assert_eq!(
2677 read_child1.attr_value(constants::DW_AT_type).unwrap(),
2678 Some(read::AttributeValue::UnitRef(offset))
2679 );
2680 }
2681 {
2682 let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
2683 let offset = debug_info_offsets.entry(unit_id2, unit2_child1);
2684 assert_eq!(
2685 read_child2.attr_value(constants::DW_AT_type).unwrap(),
2686 Some(read::AttributeValue::DebugInfoRef(offset))
2687 );
2688 }
2689 }
2690 {
2691 let read_unit2 = read_units.next().unwrap().unwrap();
2692 assert_eq!(
2693 read_unit2.offset(),
2694 debug_info_offsets.unit(unit_id2).into()
2695 );
2696
2697 let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
2698 let mut read_entries = read_unit2.entries(&abbrevs);
2699 {
2700 let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
2701 }
2702 {
2703 let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
2704 let offset = debug_info_offsets
2705 .entry(unit_id2, unit2_child2)
2706 .to_unit_offset(&read_unit2)
2707 .unwrap();
2708 assert_eq!(
2709 read_child1.attr_value(constants::DW_AT_type).unwrap(),
2710 Some(read::AttributeValue::UnitRef(offset))
2711 );
2712 }
2713 {
2714 let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
2715 let offset = debug_info_offsets.entry(unit_id1, unit1_child1);
2716 assert_eq!(
2717 read_child2.attr_value(constants::DW_AT_type).unwrap(),
2718 Some(read::AttributeValue::DebugInfoRef(offset))
2719 );
2720 }
2721 }
2722
2723 let mut convert_line_strings = LineStringTable::default();
2724 let mut convert_strings = StringTable::default();
2725 let convert_units = UnitTable::from(
2726 &dwarf,
2727 &mut convert_line_strings,
2728 &mut convert_strings,
2729 &|address| Some(Address::Constant(address)),
2730 )
2731 .unwrap();
2732 assert_eq!(convert_units.count(), units.count());
2733
2734 for i in 0..convert_units.count() {
2735 let unit = units.get(units.id(i));
2736 let convert_unit = convert_units.get(convert_units.id(i));
2737 assert_eq!(convert_unit.version(), unit.version());
2738 assert_eq!(convert_unit.address_size(), unit.address_size());
2739 assert_eq!(convert_unit.format(), unit.format());
2740 assert_eq!(convert_unit.count(), unit.count());
2741
2742 let root = unit.get(unit.root());
2743 let convert_root = convert_unit.get(convert_unit.root());
2744 assert_eq!(convert_root.tag(), root.tag());
2745 for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
2746 assert_eq!(convert_attr, attr);
2747 }
2748
2749 let child1 = unit.get(UnitEntryId::new(unit.base_id, 1));
2750 let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1));
2751 assert_eq!(convert_child1.tag(), child1.tag());
2752 for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) {
2753 assert_eq!(convert_attr.name, attr.name);
2754 match (convert_attr.value.clone(), attr.value.clone()) {
2755 (
2756 AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
2757 AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
2758 ) => {
2759 assert_eq!(convert_unit.index, unit.index);
2760 assert_eq!(convert_entry.index, entry.index);
2761 }
2762 (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
2763 assert_eq!(convert_id.index, id.index);
2764 }
2765 (convert_value, value) => assert_eq!(convert_value, value),
2766 }
2767 }
2768
2769 let child2 = unit.get(UnitEntryId::new(unit.base_id, 2));
2770 let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2));
2771 assert_eq!(convert_child2.tag(), child2.tag());
2772 for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) {
2773 assert_eq!(convert_attr.name, attr.name);
2774 match (convert_attr.value.clone(), attr.value.clone()) {
2775 (
2776 AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
2777 AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
2778 ) => {
2779 assert_eq!(convert_unit.index, unit.index);
2780 assert_eq!(convert_entry.index, entry.index);
2781 }
2782 (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
2783 assert_eq!(convert_id.index, id.index);
2784 }
2785 (convert_value, value) => assert_eq!(convert_value, value),
2786 }
2787 }
2788 }
2789 }
2790
2791 #[test]
2792 fn test_sibling() {
2793 fn add_child(
2794 unit: &mut Unit,
2795 parent: UnitEntryId,
2796 tag: constants::DwTag,
2797 name: &str,
2798 ) -> UnitEntryId {
2799 let id = unit.add(parent, tag);
2800 let child = unit.get_mut(id);
2801 child.set(constants::DW_AT_name, AttributeValue::String(name.into()));
2802 child.set_sibling(true);
2803 id
2804 }
2805
2806 fn add_children(units: &mut UnitTable, unit_id: UnitId) {
2807 let unit = units.get_mut(unit_id);
2808 let root = unit.root();
2809 let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1");
2810 add_child(unit, child1, constants::DW_TAG_variable, "grandchild1");
2811 add_child(unit, root, constants::DW_TAG_subprogram, "child2");
2812 add_child(unit, root, constants::DW_TAG_subprogram, "child3");
2813 }
2814
2815 fn next_child<R: read::Reader<Offset = usize>>(
2816 entries: &mut read::EntriesCursor<R>,
2817 ) -> (read::UnitOffset, Option<read::UnitOffset>) {
2818 let (_, entry) = entries.next_dfs().unwrap().unwrap();
2819 let offset = entry.offset();
2820 let sibling =
2821 entry
2822 .attr_value(constants::DW_AT_sibling)
2823 .unwrap()
2824 .map(|attr| match attr {
2825 read::AttributeValue::UnitRef(offset) => offset,
2826 _ => panic!("bad sibling value"),
2827 });
2828 (offset, sibling)
2829 }
2830
2831 fn check_sibling<R: read::Reader<Offset = usize>>(
2832 unit: &read::UnitHeader<R>,
2833 debug_abbrev: &read::DebugAbbrev<R>,
2834 ) {
2835 let abbrevs = unit.abbreviations(debug_abbrev).unwrap();
2836 let mut entries = unit.entries(&abbrevs);
2837 // root
2838 entries.next_dfs().unwrap().unwrap();
2839 // child1
2840 let (_, sibling1) = next_child(&mut entries);
2841 // grandchild1
2842 entries.next_dfs().unwrap().unwrap();
2843 // child2
2844 let (offset2, sibling2) = next_child(&mut entries);
2845 // child3
2846 let (_, _) = next_child(&mut entries);
2847 assert_eq!(sibling1, Some(offset2));
2848 assert_eq!(sibling2, None);
2849 }
2850
2851 let encoding = Encoding {
2852 format: Format::Dwarf32,
2853 version: 4,
2854 address_size: 8,
2855 };
2856 let mut units = UnitTable::default();
2857 let unit_id1 = units.add(Unit::new(encoding, LineProgram::none()));
2858 add_children(&mut units, unit_id1);
2859 let unit_id2 = units.add(Unit::new(encoding, LineProgram::none()));
2860 add_children(&mut units, unit_id2);
2861
2862 let debug_line_str_offsets = DebugLineStrOffsets::none();
2863 let debug_str_offsets = DebugStrOffsets::none();
2864 let mut sections = Sections::new(EndianVec::new(LittleEndian));
2865 units
2866 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
2867 .unwrap();
2868
2869 println!("{:?}", sections.debug_info);
2870 println!("{:?}", sections.debug_abbrev);
2871
2872 let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian);
2873 let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian);
2874 let mut read_units = read_debug_info.units();
2875 check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
2876 check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
2877 }
2878
2879 #[test]
2880 fn test_line_ref() {
2881 for &version in &[2, 3, 4, 5] {
2882 for &address_size in &[4, 8] {
2883 for &format in &[Format::Dwarf32, Format::Dwarf64] {
2884 let encoding = Encoding {
2885 format,
2886 version,
2887 address_size,
2888 };
2889
2890 // The line program we'll be referencing.
2891 let mut line_program = LineProgram::new(
2892 encoding,
2893 LineEncoding::default(),
2894 LineString::String(b"comp_dir".to_vec()),
2895 LineString::String(b"comp_name".to_vec()),
2896 None,
2897 );
2898 let dir = line_program.default_directory();
2899 let file1 =
2900 line_program.add_file(LineString::String(b"file1".to_vec()), dir, None);
2901 let file2 =
2902 line_program.add_file(LineString::String(b"file2".to_vec()), dir, None);
2903
2904 // Write, read, and convert the line program, so that we have the info
2905 // required to convert the attributes.
2906 let line_strings = DebugLineStrOffsets::none();
2907 let strings = DebugStrOffsets::none();
2908 let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
2909 let line_program_offset = line_program
2910 .write(&mut debug_line, encoding, &line_strings, &strings)
2911 .unwrap();
2912 let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
2913 let read_line_program = read_debug_line
2914 .program(
2915 line_program_offset,
2916 address_size,
2917 Some(read::EndianSlice::new(b"comp_dir", LittleEndian)),
2918 Some(read::EndianSlice::new(b"comp_name", LittleEndian)),
2919 )
2920 .unwrap();
2921 let dwarf = read::Dwarf::default();
2922 let mut convert_line_strings = LineStringTable::default();
2923 let mut convert_strings = StringTable::default();
2924 let (_, line_program_files) = LineProgram::from(
2925 read_line_program,
2926 &dwarf,
2927 &mut convert_line_strings,
2928 &mut convert_strings,
2929 &|address| Some(Address::Constant(address)),
2930 )
2931 .unwrap();
2932
2933 // Fake the unit.
2934 let mut units = UnitTable::default();
2935 let unit = units.add(Unit::new(encoding, LineProgram::none()));
2936 let unit = units.get(unit);
2937 let from_unit = read::UnitHeader::new(
2938 encoding,
2939 0,
2940 read::UnitType::Compilation,
2941 DebugAbbrevOffset(0),
2942 DebugInfoOffset(0).into(),
2943 read::EndianSlice::new(&[], LittleEndian),
2944 );
2945
2946 for &(ref name, ref value, ref expect_value) in &[
2947 (
2948 constants::DW_AT_stmt_list,
2949 AttributeValue::LineProgramRef,
2950 read::AttributeValue::SecOffset(line_program_offset.0),
2951 ),
2952 (
2953 constants::DW_AT_decl_file,
2954 AttributeValue::FileIndex(Some(file1)),
2955 read::AttributeValue::Udata(file1.raw()),
2956 ),
2957 (
2958 constants::DW_AT_decl_file,
2959 AttributeValue::FileIndex(Some(file2)),
2960 read::AttributeValue::Udata(file2.raw()),
2961 ),
2962 ][..]
2963 {
2964 let mut ranges = RangeListTable::default();
2965 let mut locations = LocationListTable::default();
2966 let mut strings = StringTable::default();
2967 let mut line_strings = LineStringTable::default();
2968
2969 let form = value.form(encoding).unwrap();
2970 let attr = Attribute {
2971 name: *name,
2972 value: value.clone(),
2973 };
2974
2975 let mut debug_info_refs = Vec::new();
2976 let mut unit_refs = Vec::new();
2977 let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
2978 let offsets = UnitOffsets::none();
2979 let debug_line_str_offsets = DebugLineStrOffsets::none();
2980 let debug_str_offsets = DebugStrOffsets::none();
2981 let range_list_offsets = RangeListOffsets::none();
2982 let loc_list_offsets = LocationListOffsets::none();
2983 attr.value
2984 .write(
2985 &mut debug_info,
2986 &mut debug_info_refs,
2987 &mut unit_refs,
2988 &unit,
2989 &offsets,
2990 Some(line_program_offset),
2991 &debug_line_str_offsets,
2992 &debug_str_offsets,
2993 &range_list_offsets,
2994 &loc_list_offsets,
2995 )
2996 .unwrap();
2997
2998 let spec = read::AttributeSpecification::new(*name, form, None);
2999 let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
3000 let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
3001 let read_value = &read_attr.raw_value();
3002 // read::AttributeValue is invariant in the lifetime of R.
3003 // The lifetimes here are all okay, so transmute it.
3004 let read_value = unsafe {
3005 mem::transmute::<
3006 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
3007 &read::AttributeValue<read::EndianSlice<LittleEndian>>,
3008 >(read_value)
3009 };
3010 assert_eq!(read_value, expect_value);
3011
3012 let unit = read::Unit {
3013 header: from_unit,
3014 abbreviations: read::Abbreviations::default(),
3015 name: None,
3016 comp_dir: None,
3017 low_pc: 0,
3018 str_offsets_base: DebugStrOffsetsBase(0),
3019 addr_base: DebugAddrBase(0),
3020 loclists_base: DebugLocListsBase(0),
3021 rnglists_base: DebugRngListsBase(0),
3022 line_program: None,
3023 };
3024
3025 let mut context = convert::ConvertUnitContext {
3026 dwarf: &dwarf,
3027 unit: &unit,
3028 line_strings: &mut line_strings,
3029 strings: &mut strings,
3030 ranges: &mut ranges,
3031 locations: &mut locations,
3032 convert_address: &|address| Some(Address::Constant(address)),
3033 base_address: Address::Constant(0),
3034 line_program_offset: Some(line_program_offset),
3035 line_program_files: line_program_files.clone(),
3036 entry_ids: &HashMap::new(),
3037 };
3038
3039 let convert_attr =
3040 Attribute::from(&mut context, &read_attr).unwrap().unwrap();
3041 assert_eq!(convert_attr, attr);
3042 }
3043 }
3044 }
3045 }
3046 }
3047
3048 #[test]
3049 fn test_line_program_used() {
3050 for used in vec![false, true] {
3051 let encoding = Encoding {
3052 format: Format::Dwarf32,
3053 version: 5,
3054 address_size: 8,
3055 };
3056
3057 let line_program = LineProgram::new(
3058 encoding,
3059 LineEncoding::default(),
3060 LineString::String(b"comp_dir".to_vec()),
3061 LineString::String(b"comp_name".to_vec()),
3062 None,
3063 );
3064
3065 let mut unit = Unit::new(encoding, line_program);
3066 let file_id = if used { Some(FileId::new(0)) } else { None };
3067 let root = unit.root();
3068 unit.get_mut(root).set(
3069 constants::DW_AT_decl_file,
3070 AttributeValue::FileIndex(file_id),
3071 );
3072
3073 let mut units = UnitTable::default();
3074 units.add(unit);
3075
3076 let debug_line_str_offsets = DebugLineStrOffsets::none();
3077 let debug_str_offsets = DebugStrOffsets::none();
3078 let mut sections = Sections::new(EndianVec::new(LittleEndian));
3079 units
3080 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
3081 .unwrap();
3082 assert_eq!(!used, sections.debug_line.slice().is_empty());
3083 }
3084 }
3085 }