@@ -1725,6 +1725,65 @@ StringRef getSectionName(const SectionRef &Section) {
17251725 return Name;
17261726}
17271727
1728+ // Exctracts some appropriate slices of .debug_str.dwo from DWP.
1729+ // Updates the .debug_str_offets.dwo for CUs.
1730+ void UpdateStrAndStrOffsets (StringRef StrDWOContent,
1731+ StringRef StrOffsetsContent,
1732+ SmallVectorImpl<StringRef> &StrDWOOutData,
1733+ std::string &StrOffsetsOutData,
1734+ unsigned DwarfVersion, bool IsLittleEndian) {
1735+ const llvm::endianness Endian =
1736+ IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;
1737+ // ignore DWARF64
1738+ const uint64_t HeaderOffset = (DwarfVersion >= 5 ) ? 8 : 0 ;
1739+ const uint64_t NumOffsets = (StrOffsetsContent.size () - HeaderOffset) / 4 ;
1740+
1741+ DataExtractor Extractor (StrOffsetsContent, IsLittleEndian, 0 );
1742+ uint64_t ExtractionOffset = HeaderOffset;
1743+
1744+ using StringFragment = DWARFUnitIndex::Entry::SectionContribution;
1745+ auto getStringLength = [](StringRef Content, uint64_t Offset) -> uint64_t {
1746+ size_t NullPos = Content.find (' \0 ' , Offset);
1747+ return (NullPos != StringRef::npos) ? (NullPos - Offset + 1 ) : 0 ;
1748+ };
1749+ auto isContiguous = [](const StringFragment &Fragment,
1750+ uint64_t NextOffset) -> bool {
1751+ return NextOffset == Fragment.getOffset () + Fragment.getLength ();
1752+ };
1753+ std::optional<StringFragment> CurrentFragment;
1754+ uint64_t AccumulatedStrLen = 0 ;
1755+ for (uint64_t I = 0 ; I < NumOffsets; ++I) {
1756+ const uint64_t StrOffset = Extractor.getU32 (&ExtractionOffset);
1757+ const uint64_t StringLength = getStringLength (StrDWOContent, StrOffset);
1758+ if (!CurrentFragment) {
1759+ // first init
1760+ CurrentFragment = StringFragment (StrOffset, StringLength);
1761+ } else {
1762+ if (isContiguous (*CurrentFragment, StrOffset)) {
1763+ // expand the current fragment
1764+ CurrentFragment->setLength (CurrentFragment->getLength () + StringLength);
1765+ } else {
1766+ // save the current fragment and start a new one
1767+ StrDWOOutData.push_back (StrDWOContent.substr (
1768+ CurrentFragment->getOffset (), CurrentFragment->getLength ()));
1769+ CurrentFragment = StringFragment (StrOffset, StringLength);
1770+ }
1771+ }
1772+ if (AccumulatedStrLen != StrOffset) {
1773+ // update str offsets
1774+ if (StrOffsetsOutData.empty ())
1775+ StrOffsetsOutData = StrOffsetsContent.str ();
1776+ llvm::support::endian::write32 (&StrOffsetsOutData[HeaderOffset + I * 4 ],
1777+ static_cast <uint32_t >(AccumulatedStrLen),
1778+ Endian);
1779+ }
1780+ AccumulatedStrLen += StringLength;
1781+ }
1782+ if (CurrentFragment)
1783+ StrDWOOutData.push_back (StrDWOContent.substr (CurrentFragment->getOffset (),
1784+ CurrentFragment->getLength ()));
1785+ }
1786+
17281787// Exctracts an appropriate slice if input is DWP.
17291788// Applies patches or overwrites the section.
17301789std::optional<StringRef> updateDebugData (
@@ -1890,18 +1949,58 @@ void DWARFRewriter::writeDWOFiles(
18901949 }
18911950 }
18921951
1952+ StringRef StrDWOContent;
1953+ StringRef StrOffsetsContent;
1954+ llvm::SmallVector<StringRef, 3 > StrDWOOutData;
1955+ std::string StrOffsetsOutData;
18931956 for (const SectionRef &Section : File->sections ()) {
18941957 std::unique_ptr<DebugBufferVector> OutputData;
18951958 StringRef SectionName = getSectionName (Section);
18961959 if (SectionName == " debug_rnglists.dwo" )
18971960 continue ;
18981961 Expected<StringRef> ContentsExp = Section.getContents ();
18991962 assert (ContentsExp && " Invalid contents." );
1963+ if (IsDWP && SectionName == " debug_str.dwo" ) {
1964+ StrDWOContent = *ContentsExp;
1965+ continue ;
1966+ }
19001967 if (std::optional<StringRef> OutData = updateDebugData (
19011968 (*DWOCU)->getContext (), SectionName, *ContentsExp, KnownSections,
19021969 *Streamer, *this , CUDWOEntry, DWOId, OutputData, RangeListssWriter,
1903- LocWriter, StrOffstsWriter, StrWriter, OverridenSections))
1970+ LocWriter, StrOffstsWriter, StrWriter, OverridenSections)) {
1971+ if (IsDWP && SectionName == " debug_str_offsets.dwo" ) {
1972+ StrOffsetsContent = *OutData;
1973+ continue ;
1974+ }
19041975 Streamer->emitBytes (*OutData);
1976+ }
1977+ }
1978+
1979+ if (IsDWP) {
1980+ // Handling both .debug_str.dwo and .debug_str_offsets.dwo concurrently. In
1981+ // the original DWP, .debug_str is a deduplicated global table, and the
1982+ // .debug_str.dwo slice for a single CU needs to be extracted according to
1983+ // .debug_str_offsets.dwo.
1984+ UpdateStrAndStrOffsets (StrDWOContent, StrOffsetsContent, StrDWOOutData,
1985+ StrOffsetsOutData, CU.getVersion (),
1986+ (*DWOCU)->getContext ().isLittleEndian ());
1987+ auto SectionIter = KnownSections.find (" debug_str.dwo" );
1988+ if (SectionIter != KnownSections.end ()) {
1989+ Streamer->switchSection (SectionIter->second .first );
1990+ for (size_t i = 0 ; i < StrDWOOutData.size (); ++i) {
1991+ StringRef OutData = StrDWOOutData[i];
1992+ if (!OutData.empty ())
1993+ Streamer->emitBytes (OutData);
1994+ }
1995+ }
1996+ SectionIter = KnownSections.find (" debug_str_offsets.dwo" );
1997+ if (SectionIter != KnownSections.end ()) {
1998+ Streamer->switchSection (SectionIter->second .first );
1999+ if (!StrOffsetsOutData.empty ())
2000+ Streamer->emitBytes (StrOffsetsOutData);
2001+ else
2002+ Streamer->emitBytes (StrOffsetsContent);
2003+ }
19052004 }
19062005 Streamer->finish ();
19072006 TempOut->keep ();
0 commit comments