@@ -413,33 +413,52 @@ Expected<InfoSectionUnitHeader> parseInfoSectionUnitHeader(StringRef Info) {
413413}
414414
415415static void writeNewOffsetsTo (MCStreamer &Out, DataExtractor &Data,
416- DenseMap<uint64_t , uint32_t > &OffsetRemapping,
417- uint64_t &Offset, uint64_t &Size) {
418-
416+ DenseMap<uint64_t , uint64_t > &OffsetRemapping,
417+ uint64_t &Offset, const uint64_t Size,
418+ uint32_t OldOffsetSize, uint32_t NewOffsetSize) {
419+ // Create a mask so we don't trigger a emitIntValue() assert below if the
420+ // NewOffset is over 4GB.
421+ const uint64_t NewOffsetMask = NewOffsetSize == 8 ? UINT64_MAX : UINT32_MAX;
419422 while (Offset < Size) {
420- auto OldOffset = Data.getU32 (&Offset);
421- auto NewOffset = OffsetRemapping[OldOffset];
422- Out.emitIntValue (NewOffset, 4 );
423+ const uint64_t OldOffset = Data.getUnsigned (&Offset, OldOffsetSize);
424+ const uint64_t NewOffset = OffsetRemapping[OldOffset];
425+ // Truncate the string offset like the old llvm-dwp would have if we aren't
426+ // promoting the .debug_str_offsets to DWARF64.
427+ Out.emitIntValue (NewOffset & NewOffsetMask, NewOffsetSize);
423428 }
424429}
425430
426- void writeStringsAndOffsets (MCStreamer &Out, DWPStringPool &Strings,
427- MCSection *StrOffsetSection,
428- StringRef CurStrSection,
429- StringRef CurStrOffsetSection, uint16_t Version) {
431+ void writeStringsAndOffsets (
432+ MCStreamer &Out, DWPStringPool &Strings, MCSection *StrOffsetSection,
433+ StringRef CurStrSection, StringRef CurStrOffsetSection, uint16_t Version,
434+ SectionLengths &SectionLength,
435+ const Dwarf64StrOffsetsPromotion StrOffsetsOptValue) {
430436 // Could possibly produce an error or warning if one of these was non-null but
431437 // the other was null.
432438 if (CurStrSection.empty () || CurStrOffsetSection.empty ())
433439 return ;
434440
435- DenseMap<uint64_t , uint32_t > OffsetRemapping;
441+ DenseMap<uint64_t , uint64_t > OffsetRemapping;
436442
437443 DataExtractor Data (CurStrSection, true , 0 );
438444 uint64_t LocalOffset = 0 ;
439445 uint64_t PrevOffset = 0 ;
446+
447+ // Keep track if any new string offsets exceed UINT32_MAX. If any do, we can
448+ // emit a DWARF64 .debug_str_offsets table for this compile unit. If the
449+ // \a StrOffsetsOptValue argument is Dwarf64StrOffsetsPromotion::Always, then
450+ // force the emission of DWARF64 .debug_str_offsets for testing.
451+ uint32_t OldOffsetSize = 4 ;
452+ uint32_t NewOffsetSize =
453+ StrOffsetsOptValue == Dwarf64StrOffsetsPromotion::Always ? 8 : 4 ;
440454 while (const char *S = Data.getCStr (&LocalOffset)) {
441- OffsetRemapping[PrevOffset] =
442- Strings.getOffset (S, LocalOffset - PrevOffset);
455+ uint64_t NewOffset = Strings.getOffset (S, LocalOffset - PrevOffset);
456+ OffsetRemapping[PrevOffset] = NewOffset;
457+ // Only promote the .debug_str_offsets to DWARF64 if our setting allows it.
458+ if (StrOffsetsOptValue != Dwarf64StrOffsetsPromotion::Disabled &&
459+ NewOffset > UINT32_MAX) {
460+ NewOffsetSize = 8 ;
461+ }
443462 PrevOffset = LocalOffset;
444463 }
445464
@@ -451,7 +470,7 @@ void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
451470 uint64_t Size = CurStrOffsetSection.size ();
452471 if (Version > 4 ) {
453472 while (Offset < Size) {
454- uint64_t HeaderSize = debugStrOffsetsHeaderSize (Data, Version);
473+ const uint64_t HeaderSize = debugStrOffsetsHeaderSize (Data, Version);
455474 assert (HeaderSize <= Size - Offset &&
456475 " StrOffsetSection size is less than its header" );
457476
@@ -461,16 +480,52 @@ void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
461480 if (HeaderSize == 8 ) {
462481 ContributionSize = Data.getU32 (&HeaderLengthOffset);
463482 } else if (HeaderSize == 16 ) {
483+ OldOffsetSize = 8 ;
464484 HeaderLengthOffset += 4 ; // skip the dwarf64 marker
465485 ContributionSize = Data.getU64 (&HeaderLengthOffset);
466486 }
467487 ContributionEnd = ContributionSize + HeaderLengthOffset;
468- Out.emitBytes (Data.getBytes (&Offset, HeaderSize));
469- writeNewOffsetsTo (Out, Data, OffsetRemapping, Offset, ContributionEnd);
488+
489+ StringRef HeaderBytes = Data.getBytes (&Offset, HeaderSize);
490+ if (OldOffsetSize == 4 && NewOffsetSize == 8 ) {
491+ // We had a DWARF32 .debug_str_offsets header, but we need to emit
492+ // some string offsets that require 64 bit offsets on the .debug_str
493+ // section. Emit the .debug_str_offsets header in DWARF64 format so we
494+ // can emit string offsets that exceed UINT32_MAX without truncating
495+ // the string offset.
496+
497+ // 2 bytes for DWARF version, 2 bytes pad.
498+ const uint64_t VersionPadSize = 4 ;
499+ const uint64_t NewLength =
500+ (ContributionSize - VersionPadSize) * 2 + VersionPadSize;
501+ // Emit the DWARF64 length that starts with a 4 byte DW_LENGTH_DWARF64
502+ // value followed by the 8 byte updated length.
503+ Out.emitIntValue (llvm::dwarf::DW_LENGTH_DWARF64, 4 );
504+ Out.emitIntValue (NewLength, 8 );
505+ // Emit DWARF version as a 2 byte integer.
506+ Out.emitIntValue (Version, 2 );
507+ // Emit 2 bytes of padding.
508+ Out.emitIntValue (0 , 2 );
509+ // Update the .debug_str_offsets section length contribution for the
510+ // this .dwo file.
511+ for (auto &Pair : SectionLength) {
512+ if (Pair.first == DW_SECT_STR_OFFSETS) {
513+ Pair.second = NewLength + 12 ;
514+ break ;
515+ }
516+ }
517+ } else {
518+ // Just emit the same .debug_str_offsets header.
519+ Out.emitBytes (HeaderBytes);
520+ }
521+ writeNewOffsetsTo (Out, Data, OffsetRemapping, Offset, ContributionEnd,
522+ OldOffsetSize, NewOffsetSize);
470523 }
471524
472525 } else {
473- writeNewOffsetsTo (Out, Data, OffsetRemapping, Offset, Size);
526+ assert (OldOffsetSize == NewOffsetSize);
527+ writeNewOffsetsTo (Out, Data, OffsetRemapping, Offset, Size, OldOffsetSize,
528+ NewOffsetSize);
474529 }
475530}
476531
@@ -562,7 +617,7 @@ Error handleSection(
562617 std::vector<StringRef> &CurTypesSection,
563618 std::vector<StringRef> &CurInfoSection, StringRef &AbbrevSection,
564619 StringRef &CurCUIndexSection, StringRef &CurTUIndexSection,
565- std::vector<std::pair<DWARFSectionKind, uint32_t>> &SectionLength) {
620+ SectionLengths &SectionLength) {
566621 if (Section.isBSS ())
567622 return Error::success ();
568623
@@ -620,7 +675,8 @@ Error handleSection(
620675}
621676
622677Error write (MCStreamer &Out, ArrayRef<std::string> Inputs,
623- OnCuIndexOverflow OverflowOptValue) {
678+ OnCuIndexOverflow OverflowOptValue,
679+ Dwarf64StrOffsetsPromotion StrOffsetsOptValue) {
624680 const auto &MCOFI = *Out.getContext ().getObjectFileInfo ();
625681 MCSection *const StrSection = MCOFI.getDwarfStrDWOSection ();
626682 MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection ();
@@ -684,7 +740,7 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
684740 // This maps each section contained in this file to its length.
685741 // This information is later on used to calculate the contributions,
686742 // i.e. offset and length, of each compile/type unit to a section.
687- std::vector<std::pair<DWARFSectionKind, uint32_t >> SectionLength;
743+ SectionLengths SectionLength;
688744
689745 for (const auto &Section : Obj.sections ())
690746 if (auto Err = handleSection (
@@ -713,7 +769,8 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
713769 }
714770
715771 writeStringsAndOffsets (Out, Strings, StrOffsetSection, CurStrSection,
716- CurStrOffsetSection, Header.Version );
772+ CurStrOffsetSection, Header.Version , SectionLength,
773+ StrOffsetsOptValue);
717774
718775 for (auto Pair : SectionLength) {
719776 auto Index = getContributionIndex (Pair.first , IndexVersion);
0 commit comments