Skip to content

Commit 246fa9a

Browse files
peremyachArslan Khabutdinov
andauthored
Revert gsymutil changes due to concurrency problems (#142829)
We saw occasional segfaults while processing some binaries. The reason probably is that we may clear the DIE while we are reading it's data from another thread which happens due to cross-unit references. --------- Co-authored-by: Arslan Khabutdinov <akhabutdinov@fb.com>
1 parent ad6575f commit 246fa9a

File tree

5 files changed

+111
-148
lines changed

5 files changed

+111
-148
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ class DWARFContext : public DIContext {
102102
/// Parse a macro[.dwo] or macinfo[.dwo] section.
103103
std::unique_ptr<DWARFDebugMacro>
104104
parseMacroOrMacinfo(MacroSecType SectionType);
105-
106-
virtual Error doWorkThreadSafely(function_ref<Error()> Work) = 0;
107105
};
108106
friend class DWARFContextState;
109107

@@ -492,10 +490,6 @@ class DWARFContext : public DIContext {
492490
/// manually only for DWARF5.
493491
void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; }
494492

495-
Error doWorkThreadSafely(function_ref<Error()> Work) {
496-
return State->doWorkThreadSafely(Work);
497-
}
498-
499493
private:
500494
void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die,
501495
std::vector<DILocal> &Result);

llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,9 +566,6 @@ class DWARFUnit {
566566

567567
Error tryExtractDIEsIfNeeded(bool CUDieOnly);
568568

569-
/// clearDIEs - Clear parsed DIEs to keep memory usage low.
570-
void clearDIEs(bool KeepCUDie, bool KeepDWODies = false);
571-
572569
private:
573570
/// Size in bytes of the .debug_info data associated with this compile unit.
574571
size_t getDebugInfoSize() const {
@@ -584,6 +581,9 @@ class DWARFUnit {
584581
void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs,
585582
std::vector<DWARFDebugInfoEntry> &DIEs) const;
586583

584+
/// clearDIEs - Clear parsed DIEs to keep memory usage low.
585+
void clearDIEs(bool KeepCUDie);
586+
587587
/// parseDWO - Parses .dwo file for current compile unit. Returns true if
588588
/// it was actually constructed.
589589
/// The \p AlternativeLocation specifies an alternative location to get

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -621,10 +621,6 @@ class ThreadUnsafeDWARFContextState : public DWARFContext::DWARFContextState {
621621
else
622622
return getNormalTypeUnitMap();
623623
}
624-
625-
Error doWorkThreadSafely(function_ref<Error()> Work) override {
626-
return Work();
627-
}
628624
};
629625

630626
class ThreadSafeState : public ThreadUnsafeDWARFContextState {
@@ -740,11 +736,6 @@ class ThreadSafeState : public ThreadUnsafeDWARFContextState {
740736
std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
741737
return ThreadUnsafeDWARFContextState::getTypeUnitMap(IsDWO);
742738
}
743-
744-
Error doWorkThreadSafely(function_ref<Error()> Work) override {
745-
std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
746-
return ThreadUnsafeDWARFContextState::doWorkThreadSafely(Work);
747-
}
748739
};
749740
} // namespace
750741

llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp

Lines changed: 102 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -496,111 +496,107 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
496496
}
497497

498498
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
499-
return Context.doWorkThreadSafely([&]() -> Error {
500-
if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
501-
return Error::success(); // Already parsed.
502-
503-
bool HasCUDie = !DieArray.empty();
504-
extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
505-
506-
if (DieArray.empty())
507-
return Error::success();
508-
509-
// If CU DIE was just parsed, copy several attribute values from it.
510-
if (HasCUDie)
511-
return Error::success();
512-
513-
DWARFDie UnitDie(this, &DieArray[0]);
514-
if (std::optional<uint64_t> DWOId =
515-
toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
516-
Header.setDWOId(*DWOId);
517-
if (!IsDWO) {
518-
assert(AddrOffsetSectionBase == std::nullopt);
519-
assert(RangeSectionBase == 0);
520-
assert(LocSectionBase == 0);
521-
AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base));
522-
if (!AddrOffsetSectionBase)
523-
AddrOffsetSectionBase =
524-
toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base));
525-
RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
526-
LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
527-
}
499+
if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
500+
return Error::success(); // Already parsed.
528501

529-
// In general, in DWARF v5 and beyond we derive the start of the unit's
530-
// contribution to the string offsets table from the unit DIE's
531-
// DW_AT_str_offsets_base attribute. Split DWARF units do not use this
532-
// attribute, so we assume that there is a contribution to the string
533-
// offsets table starting at offset 0 of the debug_str_offsets.dwo section.
534-
// In both cases we need to determine the format of the contribution,
535-
// which may differ from the unit's format.
536-
DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
537-
IsLittleEndian, 0);
538-
if (IsDWO || getVersion() >= 5) {
539-
auto StringOffsetOrError =
540-
IsDWO ? determineStringOffsetsTableContributionDWO(DA)
541-
: determineStringOffsetsTableContribution(DA);
542-
if (!StringOffsetOrError) {
543-
return createStringError(errc::invalid_argument,
544-
"invalid reference to or invalid content in "
545-
".debug_str_offsets[.dwo]: " +
546-
toString(StringOffsetOrError.takeError()));
547-
}
502+
bool HasCUDie = !DieArray.empty();
503+
extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
548504

549-
StringOffsetsTableContribution = *StringOffsetOrError;
550-
}
505+
if (DieArray.empty())
506+
return Error::success();
551507

552-
// DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
553-
// describe address ranges.
554-
if (getVersion() >= 5) {
555-
// In case of DWP, the base offset from the index has to be added.
556-
if (IsDWO) {
557-
uint64_t ContributionBaseOffset = 0;
558-
if (auto *IndexEntry = Header.getIndexEntry())
559-
if (auto *Contrib = IndexEntry->getContribution(DW_SECT_RNGLISTS))
560-
ContributionBaseOffset = Contrib->getOffset();
561-
setRangesSection(
562-
&Context.getDWARFObj().getRnglistsDWOSection(),
563-
ContributionBaseOffset +
564-
DWARFListTableHeader::getHeaderSize(Header.getFormat()));
565-
} else
566-
setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
567-
toSectionOffset(UnitDie.find(DW_AT_rnglists_base),
568-
DWARFListTableHeader::getHeaderSize(
569-
Header.getFormat())));
570-
}
508+
// If CU DIE was just parsed, copy several attribute values from it.
509+
if (HasCUDie)
510+
return Error::success();
511+
512+
DWARFDie UnitDie(this, &DieArray[0]);
513+
if (std::optional<uint64_t> DWOId =
514+
toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
515+
Header.setDWOId(*DWOId);
516+
if (!IsDWO) {
517+
assert(AddrOffsetSectionBase == std::nullopt);
518+
assert(RangeSectionBase == 0);
519+
assert(LocSectionBase == 0);
520+
AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base));
521+
if (!AddrOffsetSectionBase)
522+
AddrOffsetSectionBase =
523+
toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base));
524+
RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
525+
LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
526+
}
527+
528+
// In general, in DWARF v5 and beyond we derive the start of the unit's
529+
// contribution to the string offsets table from the unit DIE's
530+
// DW_AT_str_offsets_base attribute. Split DWARF units do not use this
531+
// attribute, so we assume that there is a contribution to the string
532+
// offsets table starting at offset 0 of the debug_str_offsets.dwo section.
533+
// In both cases we need to determine the format of the contribution,
534+
// which may differ from the unit's format.
535+
DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
536+
IsLittleEndian, 0);
537+
if (IsDWO || getVersion() >= 5) {
538+
auto StringOffsetOrError =
539+
IsDWO ? determineStringOffsetsTableContributionDWO(DA)
540+
: determineStringOffsetsTableContribution(DA);
541+
if (!StringOffsetOrError)
542+
return createStringError(errc::invalid_argument,
543+
"invalid reference to or invalid content in "
544+
".debug_str_offsets[.dwo]: " +
545+
toString(StringOffsetOrError.takeError()));
546+
547+
StringOffsetsTableContribution = *StringOffsetOrError;
548+
}
571549

550+
// DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
551+
// describe address ranges.
552+
if (getVersion() >= 5) {
553+
// In case of DWP, the base offset from the index has to be added.
572554
if (IsDWO) {
573-
// If we are reading a package file, we need to adjust the location list
574-
// data based on the index entries.
575-
StringRef Data = Header.getVersion() >= 5
576-
? Context.getDWARFObj().getLoclistsDWOSection().Data
577-
: Context.getDWARFObj().getLocDWOSection().Data;
555+
uint64_t ContributionBaseOffset = 0;
578556
if (auto *IndexEntry = Header.getIndexEntry())
579-
if (const auto *C = IndexEntry->getContribution(
580-
Header.getVersion() >= 5 ? DW_SECT_LOCLISTS : DW_SECT_EXT_LOC))
581-
Data = Data.substr(C->getOffset(), C->getLength());
582-
583-
DWARFDataExtractor DWARFData(Data, IsLittleEndian, getAddressByteSize());
584-
LocTable =
585-
std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion());
586-
LocSectionBase = DWARFListTableHeader::getHeaderSize(Header.getFormat());
587-
} else if (getVersion() >= 5) {
588-
LocTable = std::make_unique<DWARFDebugLoclists>(
589-
DWARFDataExtractor(Context.getDWARFObj(),
590-
Context.getDWARFObj().getLoclistsSection(),
591-
IsLittleEndian, getAddressByteSize()),
592-
getVersion());
593-
} else {
594-
LocTable = std::make_unique<DWARFDebugLoc>(DWARFDataExtractor(
595-
Context.getDWARFObj(), Context.getDWARFObj().getLocSection(),
596-
IsLittleEndian, getAddressByteSize()));
597-
}
557+
if (auto *Contrib = IndexEntry->getContribution(DW_SECT_RNGLISTS))
558+
ContributionBaseOffset = Contrib->getOffset();
559+
setRangesSection(
560+
&Context.getDWARFObj().getRnglistsDWOSection(),
561+
ContributionBaseOffset +
562+
DWARFListTableHeader::getHeaderSize(Header.getFormat()));
563+
} else
564+
setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
565+
toSectionOffset(UnitDie.find(DW_AT_rnglists_base),
566+
DWARFListTableHeader::getHeaderSize(
567+
Header.getFormat())));
568+
}
598569

599-
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
600-
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
570+
if (IsDWO) {
571+
// If we are reading a package file, we need to adjust the location list
572+
// data based on the index entries.
573+
StringRef Data = Header.getVersion() >= 5
574+
? Context.getDWARFObj().getLoclistsDWOSection().Data
575+
: Context.getDWARFObj().getLocDWOSection().Data;
576+
if (auto *IndexEntry = Header.getIndexEntry())
577+
if (const auto *C = IndexEntry->getContribution(
578+
Header.getVersion() >= 5 ? DW_SECT_LOCLISTS : DW_SECT_EXT_LOC))
579+
Data = Data.substr(C->getOffset(), C->getLength());
580+
581+
DWARFDataExtractor DWARFData(Data, IsLittleEndian, getAddressByteSize());
582+
LocTable =
583+
std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion());
584+
LocSectionBase = DWARFListTableHeader::getHeaderSize(Header.getFormat());
585+
} else if (getVersion() >= 5) {
586+
LocTable = std::make_unique<DWARFDebugLoclists>(
587+
DWARFDataExtractor(Context.getDWARFObj(),
588+
Context.getDWARFObj().getLoclistsSection(),
589+
IsLittleEndian, getAddressByteSize()),
590+
getVersion());
591+
} else {
592+
LocTable = std::make_unique<DWARFDebugLoc>(DWARFDataExtractor(
593+
Context.getDWARFObj(), Context.getDWARFObj().getLocSection(),
594+
IsLittleEndian, getAddressByteSize()));
595+
}
601596

602-
return Error::success();
603-
});
597+
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
598+
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
599+
return Error::success();
604600
}
605601

606602
bool DWARFUnit::parseDWO(StringRef DWOAlternativeLocation) {
@@ -655,26 +651,15 @@ bool DWARFUnit::parseDWO(StringRef DWOAlternativeLocation) {
655651
return true;
656652
}
657653

658-
void DWARFUnit::clearDIEs(bool KeepCUDie, bool KeepDWODies) {
659-
cantFail(Context.doWorkThreadSafely([&] {
660-
if (!KeepDWODies && DWO) {
661-
DWO->clearDIEs(KeepCUDie, KeepDWODies);
662-
}
663-
if (!IsDWO) {
664-
RangeSectionBase = 0;
665-
LocSectionBase = 0;
666-
AddrOffsetSectionBase = std::nullopt;
667-
}
668-
// Do not use resize() + shrink_to_fit() to free memory occupied by dies.
669-
// shrink_to_fit() is a *non-binding* request to reduce capacity() to
670-
// size(). It depends on the implementation whether the request is
671-
// fulfilled. Create a new vector with a small capacity and assign it to the
672-
// DieArray to have previous contents freed.
673-
DieArray = (KeepCUDie && !DieArray.empty())
674-
? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
675-
: std::vector<DWARFDebugInfoEntry>();
676-
return Error::success();
677-
}));
654+
void DWARFUnit::clearDIEs(bool KeepCUDie) {
655+
// Do not use resize() + shrink_to_fit() to free memory occupied by dies.
656+
// shrink_to_fit() is a *non-binding* request to reduce capacity() to size().
657+
// It depends on the implementation whether the request is fulfilled.
658+
// Create a new vector with a small capacity and assign it to the DieArray to
659+
// have previous contents freed.
660+
DieArray = (KeepCUDie && !DieArray.empty())
661+
? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
662+
: std::vector<DWARFDebugInfoEntry>();
678663
}
679664

680665
Expected<DWARFAddressRangesVector>

llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -656,11 +656,6 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
656656
DWARFDie Die = getDie(*CU);
657657
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
658658
handleDie(Out, CUI, Die);
659-
// Release the line table, once we're done.
660-
DICtx.clearLineTableForUnit(CU.get());
661-
// Free any DIEs that were allocated by the DWARF parser.
662-
// If/when they're needed by other CU's, they'll be recreated.
663-
CU->clearDIEs(/*KeepCUDie=*/false, /*KeepDWODIEs=*/false);
664659
}
665660
} else {
666661
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
@@ -673,23 +668,24 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
673668
for (const auto &CU : DICtx.compile_units())
674669
CU->getAbbreviations();
675670

671+
// Now parse all DIEs in case we have cross compile unit references in a
672+
// thread pool.
676673
DefaultThreadPool pool(hardware_concurrency(NumThreads));
674+
for (const auto &CU : DICtx.compile_units())
675+
pool.async([&CU]() { CU->getUnitDIE(false /*CUDieOnly*/); });
676+
pool.wait();
677677

678678
// Now convert all DWARF to GSYM in a thread pool.
679679
std::mutex LogMutex;
680680
for (const auto &CU : DICtx.compile_units()) {
681681
DWARFDie Die = getDie(*CU);
682682
if (Die) {
683683
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
684-
pool.async([this, CUI, &CU, &LogMutex, &Out, Die]() mutable {
684+
pool.async([this, CUI, &LogMutex, &Out, Die]() mutable {
685685
std::string storage;
686686
raw_string_ostream StrStream(storage);
687687
OutputAggregator ThreadOut(Out.GetOS() ? &StrStream : nullptr);
688688
handleDie(ThreadOut, CUI, Die);
689-
DICtx.clearLineTableForUnit(CU.get());
690-
// Free any DIEs that were allocated by the DWARF parser.
691-
// If/when they're needed by other CU's, they'll be recreated.
692-
CU->clearDIEs(/*KeepCUDie=*/false, /*KeepDWODIEs=*/false);
693689
// Print ThreadLogStorage lines into an actual stream under a lock
694690
std::lock_guard<std::mutex> guard(LogMutex);
695691
if (Out.GetOS()) {
@@ -701,9 +697,6 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
701697
}
702698
pool.wait();
703699
}
704-
// Now get rid of all the DIEs that may have been recreated
705-
for (const auto &CU : DICtx.compile_units())
706-
CU->clearDIEs(/*KeepCUDie=*/false, /*KeepDWODIEs=*/false);
707700
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
708701
Out << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
709702
return Error::success();

0 commit comments

Comments
 (0)