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