1use std::{collections::HashSet, fmt};
2
3use gimli::{Encoding, RunTimeEndian, UnitHeader, UnitIndex, UnitSectionOffset, UnitType};
4use object::{
5 write::{Object as WritableObject, SectionId},
6 BinaryFormat, Object, ObjectSection, SectionKind,
7};
8use tracing::debug;
9
10use crate::{
11 error::{Error, Result},
12 ext::{CompressedDataRangeExt, EndianityExt, IndexSectionExt, PackageFormatExt},
13 index::{write_index, Bucketable, Contribution, ContributionOffset, IndexEntry},
14 relocate::RelocationMap,
15 strings::PackageStringTable,
16 Session,
17};
18
19/// New-type'd index (constructed from `gimli::DwoId`) with a custom `Debug` implementation to
20/// print in hexadecimal.
21#[derive(Copy, Clone, Eq, Hash, PartialEq)]
22pub(crate) struct DwoId(pub(crate) u64);
23
24impl Bucketable for DwoId {
25 fn index(&self) -> u64 {
26 self.0
27 }
28}
29
30impl fmt::Debug for DwoId {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(f, "DwoId({:#x})", self.0)
33 }
34}
35
36impl From<gimli::DwoId> for DwoId {
37 fn from(dwo_id: gimli::DwoId) -> Self {
38 Self(dwo_id.0)
39 }
40}
41
42/// New-type'd index (constructed from `gimli::DebugTypeSignature`) with a custom `Debug`
43/// implementation to print in hexadecimal.
44#[derive(Copy, Clone, Eq, Hash, PartialEq)]
45pub(crate) struct DebugTypeSignature(pub(crate) u64);
46
47impl Bucketable for DebugTypeSignature {
48 fn index(&self) -> u64 {
49 self.0
50 }
51}
52
53impl fmt::Debug for DebugTypeSignature {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "DebugTypeSignature({:#x})", self.0)
56 }
57}
58
59impl From<gimli::DebugTypeSignature> for DebugTypeSignature {
60 fn from(signature: gimli::DebugTypeSignature) -> Self {
61 Self(signature.0)
62 }
63}
64
65/// Identifier for a DWARF object.
66#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
67pub(crate) enum DwarfObject {
68 /// `DwoId` identifying compilation units.
69 Compilation(DwoId),
70 /// `DebugTypeSignature` identifying type units.
71 Type(DebugTypeSignature),
72}
73
74impl Bucketable for DwarfObject {
75 fn index(&self) -> u64 {
76 match *self {
77 DwarfObject::Compilation(dwo_id: DwoId) => dwo_id.index(),
78 DwarfObject::Type(type_signature: DebugTypeSignature) => type_signature.index(),
79 }
80 }
81}
82
83/// Returns the `DwoId` or `DebugTypeSignature` of a unit.
84///
85/// **DWARF 5:**
86///
87/// - `DwoId` is in the unit header of a skeleton unit (identifying the split compilation unit
88/// that contains the debuginfo) or split compilation unit (identifying the skeleton unit that this
89/// debuginfo corresponds to).
90/// - `DebugTypeSignature` is in the unit header of a split type unit.
91///
92/// **Earlier DWARF versions with GNU extension:**
93///
94/// - `DW_AT_GNU_dwo_id` attribute of the DIE contains the `DwoId`.
95#[tracing::instrument(level = "trace", skip(debug_abbrev, header))]
96pub(crate) fn dwo_identifier_of_unit<R: gimli::Reader>(
97 debug_abbrev: &gimli::DebugAbbrev<R>,
98 header: &gimli::UnitHeader<R>,
99) -> Result<Option<DwarfObject>> {
100 match header.type_() {
101 // Compilation units with DWARF 5
102 UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => {
103 Ok(Some(DwarfObject::Compilation(dwo_id.into())))
104 }
105 // Compilation units with GNU Extension
106 UnitType::Compilation => {
107 let abbreviations =
108 header.abbreviations(&debug_abbrev).map_err(Error::ParseUnitAbbreviations)?;
109 let mut cursor = header.entries(&abbreviations);
110 cursor.next_dfs()?;
111 let root = cursor.current().ok_or(Error::NoDie)?;
112 match root.tag() {
113 gimli::DW_TAG_compile_unit | gimli::DW_TAG_type_unit => (),
114 _ => return Err(Error::TopLevelDieNotUnit),
115 }
116 let mut attrs = root.attrs();
117 while let Some(attr) = attrs.next().map_err(Error::ParseUnitAttribute)? {
118 match (attr.name(), attr.value()) {
119 (gimli::constants::DW_AT_GNU_dwo_id, gimli::AttributeValue::DwoId(dwo_id)) => {
120 return Ok(Some(DwarfObject::Compilation(dwo_id.into())))
121 }
122 _ => (),
123 }
124 }
125
126 Ok(None)
127 }
128 // Type units with DWARF 5
129 UnitType::SplitType { type_signature, .. } => {
130 Ok(Some(DwarfObject::Type(type_signature.into())))
131 }
132 // Type units with GNU extension
133 UnitType::Type { type_signature, .. } => Ok(Some(DwarfObject::Type(type_signature.into()))),
134 // Wrong compilation unit type.
135 _ => Ok(None),
136 }
137}
138
139/// Wrapper around `.debug_info.dwo` and `debug_types.dwo` unit iterators for uniform handling.
140enum UnitHeaderIterator<R: gimli::Reader> {
141 DebugInfo(gimli::read::DebugInfoUnitHeadersIter<R>),
142 DebugTypes(gimli::read::DebugTypesUnitHeadersIter<R>),
143}
144
145impl<R: gimli::Reader> UnitHeaderIterator<R> {
146 fn next(&mut self) -> gimli::read::Result<Option<UnitHeader<R>>> {
147 match self {
148 UnitHeaderIterator::DebugInfo(iter: &mut DebugInfoUnitHeadersIter<…>) => iter.next(),
149 UnitHeaderIterator::DebugTypes(iter: &mut DebugTypesUnitHeadersIter<…>) => iter.next(),
150 }
151 }
152}
153
154/// Returns the parsed unit index from a `.debug_{cu,tu}_index` section.
155pub(crate) fn maybe_load_index_section<'input, 'session: 'input, Endian, Index, R, Sess>(
156 sess: &'session Sess,
157 encoding: Encoding,
158 endian: Endian,
159 input: &object::File<'input>,
160) -> Result<Option<UnitIndex<R>>>
161where
162 Endian: gimli::Endianity,
163 Index: IndexSectionExt<'input, Endian, R>,
164 R: gimli::Reader,
165 Sess: Session<RelocationMap>,
166{
167 let index_name = Index::id().dwo_name().expect("index id w/out known value");
168 if let Some(index_section) = input.section_by_name(index_name) {
169 let index_data = index_section
170 .compressed_data()
171 .and_then(|d| d.decompress())
172 .map_err(Error::DecompressData)?;
173 let index_data_ref = sess.alloc_owned_cow(index_data);
174 let unit_index = Index::new(index_data_ref, endian)
175 .index()
176 .map_err(|e| Error::ParseIndex(e, index_name.to_string()))?;
177
178 if !encoding.is_compatible_dwarf_package_index_version(unit_index.version()) {
179 return Err(Error::IncompatibleIndexVersion(
180 index_name.to_string(),
181 encoding.dwarf_package_index_version(),
182 unit_index.version(),
183 ));
184 }
185
186 Ok(Some(unit_index))
187 } else {
188 Ok(None)
189 }
190}
191
192/// Returns a closure which takes an identifier and a `Option<Contribution>`, and returns an
193/// adjusted contribution if the input file is a DWARF package (and the contribution was
194/// present).
195///
196/// For example, consider the `.debug_str_offsets` section: DWARF packages have a single
197/// `.debug_str_offsets` section which contains the string offsets of all of its compilation/type
198/// units, the contributions of each unit into that section are tracked in its
199/// `.debug_{cu,tu}_index` section.
200///
201/// When a DWARF package is the input, the contributions of the units which constituted that
202/// package should not be lost when its `.debug_str_offsets` section is merged with the new
203/// DWARF package currently being created.
204///
205/// Given a parsed index section, use the size of its contribution to `.debug_str_offsets` as the
206/// size of its contribution in the new unit (without this, it would be the size of the entire
207/// `.debug_str_offsets` section from the input, rather than the part that the compilation unit
208/// originally contributed to that). For subsequent units from the input, the offset in the
209/// contribution will need to be adjusted to based on the size of the previous units.
210///
211/// This function returns a "contribution adjustor" closure, which adjusts the contribution's
212/// offset and size according to its contribution in the input's index and with an offset
213/// accumulated over all calls to the closure.
214pub(crate) fn create_contribution_adjustor<'input, R: 'input>(
215 cu_index: Option<&'input UnitIndex<R>>,
216 tu_index: Option<&'input UnitIndex<R>>,
217 target_section_id: gimli::SectionId,
218) -> impl FnMut(DwarfObject, Option<Contribution>) -> Result<Option<Contribution>> + 'input
219where
220 R: gimli::Reader,
221{
222 let mut cu_adjustment = 0;
223 let mut tu_adjustment = 0;
224
225 move |identifier: DwarfObject,
226 contribution: Option<Contribution>|
227 -> Result<Option<Contribution>> {
228 let (adjustment, index) = match identifier {
229 DwarfObject::Compilation(_) => (&mut cu_adjustment, &cu_index),
230 DwarfObject::Type(_) => (&mut tu_adjustment, &tu_index),
231 };
232 match (index, contribution) {
233 // dwp input with section
234 (Some(index), Some(contribution)) => {
235 let idx = identifier.index();
236 let row_id = index.find(idx).ok_or(Error::UnitNotInIndex(idx))?;
237 let section = index
238 .sections(row_id)
239 .map_err(|e| Error::RowNotInIndex(e, row_id))?
240 .find(|index_section| index_section.section == target_section_id)
241 .ok_or(Error::SectionNotInRow)?;
242 let adjusted_offset: u64 = contribution.offset.0 + *adjustment;
243 *adjustment += section.size as u64;
244
245 Ok(Some(Contribution {
246 offset: ContributionOffset(adjusted_offset),
247 size: section.size as u64,
248 }))
249 }
250 // dwp input without section
251 (Some(_) | None, None) => Ok(contribution),
252 // dwo input with section, but we aren't adjusting this particular index
253 (None, Some(_)) => Ok(contribution),
254 }
255 }
256}
257
258/// Wrapper around `object::write::Object` that keeps track of the section indexes relevant to
259/// DWARF packaging.
260struct DwarfPackageObject<'file> {
261 /// Object file being created.
262 obj: WritableObject<'file>,
263
264 /// Identifier for output `.debug_cu_index.dwo` section.
265 debug_cu_index: Option<SectionId>,
266 /// `.debug_tu_index.dwo`
267 debug_tu_index: Option<SectionId>,
268 /// `.debug_info.dwo`
269 debug_info: Option<SectionId>,
270 /// `.debug_abbrev.dwo`
271 debug_abbrev: Option<SectionId>,
272 /// `.debug_str.dwo`
273 debug_str: Option<SectionId>,
274 /// `.debug_types.dwo`
275 debug_types: Option<SectionId>,
276 /// `.debug_line.dwo`
277 debug_line: Option<SectionId>,
278 /// `.debug_loc.dwo`
279 debug_loc: Option<SectionId>,
280 /// `.debug_loclists.dwo`
281 debug_loclists: Option<SectionId>,
282 /// `.debug_rnglists.dwo`
283 debug_rnglists: Option<SectionId>,
284 /// `.debug_str_offsets.dwo`
285 debug_str_offsets: Option<SectionId>,
286 /// `.debug_macinfo.dwo`
287 debug_macinfo: Option<SectionId>,
288 /// `.debug_macro.dwo`
289 debug_macro: Option<SectionId>,
290}
291
292/// Macro for generating helper functions which appending non-empty data to specific sections.
293macro_rules! generate_append_for {
294 ( $( $fn_name:ident => ($name:ident, $section_name:expr) ),+ ) => {
295 $(
296 fn $fn_name(&mut self, data: &[u8]) -> Option<Contribution> {
297 if data.is_empty() {
298 return None;
299 }
300
301 let id = *self.$name.get_or_insert_with(|| self.obj.add_section(
302 Vec::new(),
303 Vec::from($section_name),
304 SectionKind::Debug,
305 ));
306
307 // FIXME: correct alignment
308 let offset = self.obj.append_section_data(id, data, 1);
309 debug!(?offset, ?data);
310 Some(Contribution {
311 offset: ContributionOffset(offset),
312 size: data.len().try_into().expect("data size larger than u64"),
313 })
314 }
315 )+
316 };
317}
318
319impl<'file> DwarfPackageObject<'file> {
320 /// Create a new `DwarfPackageObject` from an architecture and endianness.
321 #[tracing::instrument(level = "trace")]
322 pub(crate) fn new(
323 architecture: object::Architecture,
324 endianness: object::Endianness,
325 ) -> DwarfPackageObject<'file> {
326 let obj = WritableObject::new(BinaryFormat::Elf, architecture, endianness);
327 Self {
328 obj,
329 debug_cu_index: Default::default(),
330 debug_tu_index: Default::default(),
331 debug_info: Default::default(),
332 debug_abbrev: Default::default(),
333 debug_str: Default::default(),
334 debug_types: Default::default(),
335 debug_line: Default::default(),
336 debug_loc: Default::default(),
337 debug_loclists: Default::default(),
338 debug_rnglists: Default::default(),
339 debug_str_offsets: Default::default(),
340 debug_macinfo: Default::default(),
341 debug_macro: Default::default(),
342 }
343 }
344
345 generate_append_for! {
346 append_to_debug_abbrev => (debug_abbrev, ".debug_abbrev.dwo"),
347 append_to_debug_cu_index => (debug_cu_index, ".debug_cu_index"),
348 append_to_debug_info => (debug_info, ".debug_info.dwo"),
349 append_to_debug_line => (debug_line, ".debug_line.dwo"),
350 append_to_debug_loc => (debug_loc, ".debug_loc.dwo"),
351 append_to_debug_loclists => (debug_loclists, ".debug_loclists.dwo"),
352 append_to_debug_macinfo => (debug_macinfo, ".debug_macinfo.dwo"),
353 append_to_debug_macro => (debug_macro, ".debug_macro.dwo"),
354 append_to_debug_rnglists => (debug_rnglists, ".debug_rnglists.dwo"),
355 append_to_debug_str => (debug_str, ".debug_str.dwo"),
356 append_to_debug_str_offsets => (debug_str_offsets, ".debug_str_offsets.dwo"),
357 append_to_debug_tu_index => (debug_tu_index, ".debug_tu_index"),
358 append_to_debug_types => (debug_types, ".debug_types.dwo")
359 }
360
361 /// Return the DWARF package object file.
362 pub(crate) fn finish(self) -> WritableObject<'file> {
363 self.obj
364 }
365}
366
367/// In-progress DWARF package being produced.
368pub(crate) struct InProgressDwarfPackage<'file> {
369 /// Endianness of the DWARF package being created.
370 endian: RunTimeEndian,
371
372 /// Object file being created.
373 obj: DwarfPackageObject<'file>,
374 /// In-progress string table being accumulated.
375 ///
376 /// Used to write final `.debug_str.dwo` and `.debug_str_offsets.dwo`.
377 string_table: PackageStringTable,
378
379 /// Compilation unit index entries (offsets + sizes) being accumulated.
380 cu_index_entries: Vec<IndexEntry>,
381 /// Type unit index entries (offsets + sizes) being accumulated.
382 tu_index_entries: Vec<IndexEntry>,
383
384 /// `DebugTypeSignature`s of type units and `DwoId`s of compilation units that have already
385 /// been added to the output package.
386 ///
387 /// Used when adding new TU index entries to de-duplicate type units (as required by the
388 /// specification). Also used to check that all dwarf objects referenced by executables
389 /// have been found.
390 contained_units: HashSet<DwarfObject>,
391}
392
393impl<'file> InProgressDwarfPackage<'file> {
394 /// Create an object file with empty sections that will be later populated from DWARF object
395 /// files.
396 #[tracing::instrument(level = "trace")]
397 pub(crate) fn new(
398 architecture: object::Architecture,
399 endianness: object::Endianness,
400 ) -> InProgressDwarfPackage<'file> {
401 let endian = endianness.as_runtime_endian();
402 Self {
403 endian,
404 obj: DwarfPackageObject::new(architecture, endianness),
405 string_table: PackageStringTable::new(),
406 cu_index_entries: Default::default(),
407 tu_index_entries: Default::default(),
408 contained_units: Default::default(),
409 }
410 }
411
412 /// Returns the units contained within the DWARF package.
413 pub(crate) fn contained_units(&self) -> &HashSet<DwarfObject> {
414 &self.contained_units
415 }
416
417 /// Process an input DWARF object.
418 ///
419 /// Copies relevant debug sections, compilation/type units and strings from the `input` DWARF
420 /// object into this DWARF package.
421 #[tracing::instrument(level = "trace", skip(sess, input,))]
422 pub(crate) fn add_input_object<'input, 'session: 'input>(
423 &mut self,
424 sess: &'session impl Session<RelocationMap>,
425 input: &object::File<'input>,
426 encoding: Encoding,
427 ) -> Result<()> {
428 // Load index sections (if they exist).
429 let cu_index = maybe_load_index_section::<_, gimli::DebugCuIndex<_>, _, _>(
430 sess,
431 encoding,
432 self.endian,
433 input,
434 )?;
435 let tu_index = maybe_load_index_section::<_, gimli::DebugTuIndex<_>, _, _>(
436 sess,
437 encoding,
438 self.endian,
439 input,
440 )?;
441
442 let mut debug_abbrev = None;
443 let mut debug_line = None;
444 let mut debug_loc = None;
445 let mut debug_loclists = None;
446 let mut debug_macinfo = None;
447 let mut debug_macro = None;
448 let mut debug_rnglists = None;
449 let mut debug_str_offsets = None;
450
451 macro_rules! update {
452 ($target:ident += $source:expr) => {
453 if let Some(other) = $source {
454 let contribution = $target.get_or_insert(Contribution { size: 0, ..other });
455 contribution.size += other.size;
456 }
457 debug!(?$target);
458 };
459 }
460
461 // Iterate over sections rather than using `section_by_name` because sections can be
462 // repeated.
463 for section in input.sections() {
464 match section.name() {
465 Ok(".debug_abbrev.dwo" | ".zdebug_abbrev.dwo") => {
466 let data = section.compressed_data()?.decompress()?;
467 update!(debug_abbrev += self.obj.append_to_debug_abbrev(&data));
468 }
469 Ok(".debug_line.dwo" | ".zdebug_line.dwo") => {
470 let data = section.compressed_data()?.decompress()?;
471 update!(debug_line += self.obj.append_to_debug_line(&data));
472 }
473 Ok(".debug_loc.dwo" | ".zdebug_loc.dwo") => {
474 let data = section.compressed_data()?.decompress()?;
475 update!(debug_loc += self.obj.append_to_debug_loc(&data));
476 }
477 Ok(".debug_loclists.dwo" | ".zdebug_loclists.dwo") => {
478 let data = section.compressed_data()?.decompress()?;
479 update!(debug_loclists += self.obj.append_to_debug_loclists(&data));
480 }
481 Ok(".debug_macinfo.dwo" | ".zdebug_macinfo.dwo") => {
482 let data = section.compressed_data()?.decompress()?;
483 update!(debug_macinfo += self.obj.append_to_debug_macinfo(&data));
484 }
485 Ok(".debug_macro.dwo" | ".zdebug_macro.dwo") => {
486 let data = section.compressed_data()?.decompress()?;
487 update!(debug_macro += self.obj.append_to_debug_macro(&data));
488 }
489 Ok(".debug_rnglists.dwo" | ".zdebug_rnglists.dwo") => {
490 let data = section.compressed_data()?.decompress()?;
491 update!(debug_rnglists += self.obj.append_to_debug_rnglists(&data));
492 }
493 Ok(".debug_str_offsets.dwo" | ".zdebug_str_offsets.dwo") => {
494 let (debug_str_offsets_section, debug_str_offsets_section_len) = {
495 let data = section.compressed_data()?.decompress()?;
496 let len = data.len() as u64;
497 let data_ref = sess.alloc_owned_cow(data);
498 (
499 gimli::DebugStrOffsets::from(gimli::EndianSlice::new(
500 data_ref,
501 self.endian,
502 )),
503 len,
504 )
505 };
506
507 let debug_str_section =
508 if let Some(section) = input.section_by_name(".debug_str.dwo") {
509 let data = section.compressed_data()?.decompress()?;
510 let data_ref = sess.alloc_owned_cow(data);
511 gimli::DebugStr::new(data_ref, self.endian)
512 } else {
513 return Err(Error::MissingRequiredSection(".debug_str.dwo"));
514 };
515
516 let data = self.string_table.remap_str_offsets_section(
517 debug_str_section,
518 debug_str_offsets_section,
519 debug_str_offsets_section_len,
520 self.endian,
521 encoding,
522 )?;
523 update!(
524 debug_str_offsets += self.obj.append_to_debug_str_offsets(data.slice())
525 );
526 }
527 _ => (),
528 }
529 }
530
531 // `.debug_abbrev.dwo`'s contribution will already have been processed, but getting the
532 // `DwoId` of a GNU Extension compilation unit requires access to it.
533 let debug_abbrev_section = if let Some(section) = input.section_by_name(".debug_abbrev.dwo")
534 {
535 let data = section.compressed_data()?.decompress()?;
536 let data_ref = sess.alloc_owned_cow(data);
537 gimli::DebugAbbrev::new(data_ref, self.endian)
538 } else {
539 return Err(Error::MissingRequiredSection(".debug_abbrev.dwo"));
540 };
541
542 // Create offset adjustor functions, see comment on `create_contribution_adjustor` for
543 // explanation.
544 let mut abbrev_adjustor = create_contribution_adjustor(
545 cu_index.as_ref(),
546 tu_index.as_ref(),
547 gimli::SectionId::DebugAbbrev,
548 );
549 let mut line_adjustor = create_contribution_adjustor(
550 cu_index.as_ref(),
551 tu_index.as_ref(),
552 gimli::SectionId::DebugLine,
553 );
554 let mut loc_adjustor = create_contribution_adjustor(
555 cu_index.as_ref(),
556 tu_index.as_ref(),
557 gimli::SectionId::DebugLoc,
558 );
559 let mut loclists_adjustor = create_contribution_adjustor(
560 cu_index.as_ref(),
561 tu_index.as_ref(),
562 gimli::SectionId::DebugLocLists,
563 );
564 let mut rnglists_adjustor = create_contribution_adjustor(
565 cu_index.as_ref(),
566 tu_index.as_ref(),
567 gimli::SectionId::DebugRngLists,
568 );
569 let mut str_offsets_adjustor = create_contribution_adjustor(
570 cu_index.as_ref(),
571 tu_index.as_ref(),
572 gimli::SectionId::DebugStrOffsets,
573 );
574 let mut macinfo_adjustor = create_contribution_adjustor(
575 cu_index.as_ref(),
576 tu_index.as_ref(),
577 gimli::SectionId::DebugMacinfo,
578 );
579 let mut macro_adjustor = create_contribution_adjustor(
580 cu_index.as_ref(),
581 tu_index.as_ref(),
582 gimli::SectionId::DebugMacro,
583 );
584
585 let mut seen_debug_info = false;
586 let mut seen_debug_types = false;
587
588 for section in input.sections() {
589 let data;
590 let mut iter = match section.name() {
591 Ok(".debug_info.dwo" | ".zdebug_info.dwo")
592 // Report an error if a input DWARF package has multiple `.debug_info`
593 // sections.
594 if seen_debug_info && cu_index.is_some() =>
595 {
596 return Err(Error::MultipleDebugInfoSection);
597 }
598 Ok(".debug_info.dwo" | ".zdebug_info.dwo") => {
599 data = section.compressed_data()?.decompress()?;
600 seen_debug_info = true;
601 UnitHeaderIterator::DebugInfo(
602 gimli::DebugInfo::new(&data, self.endian).units(),
603 )
604 }
605 Ok(".debug_types.dwo" | ".zdebug_types.dwo")
606 // Report an error if a input DWARF package has multiple `.debug_types`
607 // sections.
608 if seen_debug_types && tu_index.is_some() =>
609 {
610 return Err(Error::MultipleDebugTypesSection);
611 }
612 Ok(".debug_types.dwo" | ".zdebug_types.dwo") => {
613 data = section.compressed_data()?.decompress()?;
614 seen_debug_types = true;
615 UnitHeaderIterator::DebugTypes(
616 gimli::DebugTypes::new(&data, self.endian).units(),
617 )
618 }
619 _ => continue,
620 };
621
622 while let Some(header) = iter.next().map_err(Error::ParseUnitHeader)? {
623 let id = match dwo_identifier_of_unit(&debug_abbrev_section, &header)? {
624 // Report an error if the unit doesn't have a `DwoId` or `DebugTypeSignature`.
625 None => {
626 return Err(Error::NotSplitUnit);
627 }
628 // Report an error when a duplicate compilation unit is found.
629 Some(id @ DwarfObject::Compilation(dwo_id))
630 if self.contained_units.contains(&id) =>
631 {
632 return Err(Error::DuplicateUnit(dwo_id.0));
633 }
634 // Skip duplicate type units, these happen during proper operation of `thorin`.
635 Some(id @ DwarfObject::Type(type_sig))
636 if self.contained_units.contains(&id) =>
637 {
638 debug!(?type_sig, "skipping duplicate type unit, already seen");
639 continue;
640 }
641 Some(id) => id,
642 };
643
644 let size: u64 = header
645 .length_including_self()
646 .try_into()
647 .expect("unit header length larger than u64");
648 let offset = match header.offset() {
649 UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
650 UnitSectionOffset::DebugTypesOffset(offset) => offset.0,
651 };
652
653 let data = section
654 .compressed_data_range(
655 sess,
656 offset.try_into().expect("offset larger than u64"),
657 size,
658 )
659 .map_err(Error::DecompressData)?
660 .ok_or(Error::EmptyUnit(id.index()))?;
661
662 let (debug_info, debug_types) = match (&iter, id) {
663 (UnitHeaderIterator::DebugTypes(_), DwarfObject::Type(_)) => {
664 (None, self.obj.append_to_debug_types(data))
665 }
666 (_, DwarfObject::Compilation(_) | DwarfObject::Type(_)) => {
667 (self.obj.append_to_debug_info(data), None)
668 }
669 };
670
671 let debug_abbrev = abbrev_adjustor(id, debug_abbrev)?;
672 let debug_line = line_adjustor(id, debug_line)?;
673 let debug_loc = loc_adjustor(id, debug_loc)?;
674 let debug_loclists = loclists_adjustor(id, debug_loclists)?;
675 let debug_rnglists = rnglists_adjustor(id, debug_rnglists)?;
676 let debug_str_offsets = str_offsets_adjustor(id, debug_str_offsets)?;
677 let debug_macinfo = macinfo_adjustor(id, debug_macinfo)?;
678 let debug_macro = macro_adjustor(id, debug_macro)?;
679
680 let entry = IndexEntry {
681 encoding,
682 id,
683 debug_info,
684 debug_types,
685 debug_abbrev,
686 debug_line,
687 debug_loc,
688 debug_loclists,
689 debug_rnglists,
690 debug_str_offsets,
691 debug_macinfo,
692 debug_macro,
693 };
694 debug!(?entry);
695
696 match id {
697 DwarfObject::Compilation(_) => self.cu_index_entries.push(entry),
698 DwarfObject::Type(_) => self.tu_index_entries.push(entry),
699 }
700 self.contained_units.insert(id);
701 }
702 }
703
704 if !seen_debug_info {
705 // Report an error if no `.debug_info` section was found.
706 return Err(Error::MissingRequiredSection(".debug_info.dwo"));
707 }
708
709 Ok(())
710 }
711
712 /// Return the DWARF package object being created, writing any final sections.
713 pub(crate) fn finish(self) -> Result<WritableObject<'file>> {
714 let Self { mut obj, string_table, cu_index_entries, tu_index_entries, .. } = self;
715
716 // Write `.debug_str` to the object.
717 let _ = obj.append_to_debug_str(&string_table.finish());
718
719 // Write `.debug_{cu,tu}_index` sections to the object.
720 debug!("writing cu index");
721 let cu_index_data = write_index(self.endian, &cu_index_entries)?;
722 let _ = obj.append_to_debug_cu_index(cu_index_data.slice());
723 debug!("writing tu index");
724 let tu_index_data = write_index(self.endian, &tu_index_entries)?;
725 let _ = obj.append_to_debug_tu_index(tu_index_data.slice());
726
727 Ok(obj.finish())
728 }
729}
730
731impl<'file> fmt::Debug for InProgressDwarfPackage<'file> {
732 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
733 write!(f, "InProgressDwarfPackage")
734 }
735}
736