[BOLT][DWARF] Write new .debug_abbrev sections

Summary:
Instead of patching the original .debug_abbrev section contents,
generate new section data based on parsed compilation unit
abbreviations.

This eliminates the dependency on the LLVM extension that records
abbreviation attribute offsets while parsing .debug_abbrev contents.

The output with this patch should stay the same (NFC).

(cherry picked from FBD31133611)
This commit is contained in:
Maksim Panchenko 2021-09-17 14:48:14 -07:00
parent e1da1539e3
commit 4d5cd1bf82
5 changed files with 319 additions and 241 deletions

View File

@ -163,17 +163,11 @@ static bool isHighPcFormEightBytes(dwarf::Form DwarfForm) {
}
void DWARFRewriter::updateDebugInfo() {
ErrorOr<BinarySection &> DebugAbbrev =
BC.getUniqueSectionByName(".debug_abbrev");
ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
if (!DebugAbbrev || !DebugInfo)
if (!DebugInfo)
return;
DebugAbbrev->registerPatcher(std::make_unique<DebugAbbrevPatcher>());
auto *AbbrevPatcher =
static_cast<DebugAbbrevPatcher *>(DebugAbbrev->getPatcher());
DebugInfo->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
auto *DebugInfoPatcher =
static_cast<SimpleBinaryPatcher *>(DebugInfo->getPatcher());
@ -181,6 +175,7 @@ void DWARFRewriter::updateDebugInfo() {
ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
RangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
StrWriter = std::make_unique<DebugStrWriter>(&BC);
AbbrevWriter = std::make_unique<DebugAbbrevWriter>();
AddrWriter = std::make_unique<DebugAddrWriter>(&BC);
DebugLoclistWriter::setAddressWriter(AddrWriter.get());
@ -223,7 +218,6 @@ void DWARFRewriter::updateDebugInfo() {
}
};
uint32_t AbbrevOffsetModifier = 0;
// Case 1) Range_base found: patch .debug_info
// Case 2) Range_base not found, but Ranges will be used: patch
// .debug_info/.debug_abbrev
@ -234,7 +228,6 @@ void DWARFRewriter::updateDebugInfo() {
findAttributeInfo(DIE, dwarf::DW_AT_GNU_ranges_base);
const bool NeedToPatch = AttrInfoVal.hasValue();
uint64_t AttrOffset = NeedToPatch ? AttrInfoVal->Offset : 0;
const uint32_t PrevAbbrevOffsetModifier = AbbrevOffsetModifier;
// Case where Skeleton CU doesn't have DW_AT_GNU_ranges_base
if (!NeedToPatch && WasRangeBaseUsed) {
const DWARFAbbreviationDeclaration *AbbreviationDecl =
@ -252,15 +245,15 @@ void DWARFRewriter::updateDebugInfo() {
Optional<DWARFFormValue> ValHighPC = DIE.find(dwarf::DW_AT_high_pc);
uint32_t NumBytesToFill = 7;
AbbrevPatcher->addAttributePatch(AbbreviationDecl, dwarf::DW_AT_low_pc,
dwarf::DW_AT_GNU_ranges_base,
dwarf::DW_FORM_indirect);
AbbrevWriter->addAttributePatch(
Unit, AbbreviationDecl, dwarf::DW_AT_low_pc,
dwarf::DW_AT_GNU_ranges_base, dwarf::DW_FORM_indirect);
// Bolt converts DW_AT_low_pc/DW_AT_high_pc to DW_AT_low_pc/DW_at_ranges
// DW_AT_high_pc can be 4 or 8 bytes. If it's 8 bytes need to use first
// 4 bytes.
if (ValHighPC && isHighPcFormEightBytes(ValHighPC->getForm()))
if (ValHighPC && isHighPcFormEightBytes(ValHighPC->getForm())) {
NumBytesToFill += 4;
}
LLVM_DEBUG(if (opts::DebugSkeletonCu) dbgs()
<< "AttrOffset: " << Twine::utohexstr(AttrOffset) << "\n"
<< "Die Offset: " << Twine::utohexstr(DIE.getOffset())
@ -272,56 +265,49 @@ void DWARFRewriter::updateDebugInfo() {
DebugInfoPatcher->addUDataPatch(AttrOffset, dwarf::DW_FORM_udata, 1);
DebugInfoPatcher->addUDataPatch(AttrOffset + 1, RangeBase,
NumBytesToFill);
// 1 Byte for DW_AT_GNU_ranges_base (since it's 2 bytes vs DW_AT_low_pc)
AbbrevOffsetModifier += 1;
}
if (NeedToPatch)
DebugInfoPatcher->addLE32Patch(AttrOffset,
static_cast<uint32_t>(RangeBase));
// DWARF4
// unit_length - 4 bytes
// version - 2 bytes
// So + 6 to patch debug_abbrev_offset
if (PrevAbbrevOffsetModifier)
DebugInfoPatcher->addLE32Patch(
Unit.getOffset() + 6, static_cast<uint32_t>(Unit.getAbbrOffset()) +
PrevAbbrevOffsetModifier);
};
auto processUnitDIE = [&](size_t CUIndex, DWARFUnit *Unit) {
uint64_t RangeBase = RangesSectionWriter->getSectionOffset();
updateUnitDebugInfo(CUIndex, *Unit, *DebugInfoPatcher, *AbbrevPatcher);
updateUnitDebugInfo(CUIndex, *Unit, *DebugInfoPatcher, *AbbrevWriter);
// Check if the unit is a skeleton and we need more updates for the CU and
// its matching split CU.
Optional<DWARFUnit *> SplitCU;
llvm::Optional<uint64_t> DWOId = Unit->getDWOId();
if (!DWOId)
return;
if (DWOId)
SplitCU = BC.getDWOCU(*DWOId);
// Skipping CUs that failed to load.
Optional<DWARFUnit *> SplitCU = BC.getDWOCU(*DWOId);
if (!SplitCU)
return;
if (SplitCU) {
updateDWONameCompDir(*Unit);
updateDWONameCompDir(*Unit);
// Assuming there is unique DWOID per binary. i.e. two or more CUs don't
// have same DWO ID.
assert(LocListWritersByCU.count(*DWOId) == 0 &&
"LocList writer for DWO unit already exists.");
LocListWritersByCU[*DWOId] =
std::make_unique<DebugLoclistWriter>(&BC, *DWOId);
SimpleBinaryPatcher *DwoDebugInfoPatcher =
getBinaryDWODebugInfoPatcher(*DWOId);
DwoDebugInfoPatcher->setRangeBase(RangeBase);
DebugAbbrevWriter *DWOAbbrevWriter = getBinaryDWOAbbrevWriter(*DWOId);
updateUnitDebugInfo(*DWOId, *(*SplitCU), *DwoDebugInfoPatcher,
*DWOAbbrevWriter);
DWOAbbrevWriter->addUnitAbbreviations(*(*SplitCU));
static_cast<DebugLoclistWriter *>(LocListWritersByCU[*DWOId].get())
->finalizePatches();
updateRangeBase(*Unit, RangeBase,
DwoDebugInfoPatcher->getWasRangBasedUsed());
}
// Assuming there is unique DWOID per binary. i.e. two or more CUs don't
// have same DWO ID.
assert(LocListWritersByCU.count(*DWOId) == 0 &&
"LocList writer for DWO unit already exists.");
LocListWritersByCU[*DWOId] =
std::make_unique<DebugLoclistWriter>(&BC, *DWOId);
SimpleBinaryPatcher *DwoDebugInfoPatcher =
getBinaryDWODebugInfoPatcher(*DWOId);
DwoDebugInfoPatcher->setRangeBase(RangeBase);
updateUnitDebugInfo(*DWOId, *(*SplitCU), *DwoDebugInfoPatcher,
*getBinaryDWOAbbrevPatcher(*DWOId));
static_cast<DebugLoclistWriter *>(LocListWritersByCU[*DWOId].get())
->finalizePatches();
updateRangeBase(*Unit, RangeBase,
DwoDebugInfoPatcher->getWasRangBasedUsed());
// Add abbreviations for the main unit. Note: the action is delayed until
// after updateRangeBase() call.
AbbrevWriter->addUnitAbbreviations(*Unit);
};
if (opts::NoThreads || opts::DeterministicDebugInfo) {
@ -354,7 +340,7 @@ void DWARFRewriter::updateDebugInfo() {
void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevPatcher &AbbrevPatcher) {
DebugAbbrevWriter &AbbrevWriter) {
// Cache debug ranges so that the offset for identical ranges could be reused.
std::map<DebugAddressRangesVector, uint64_t> CachedRanges;
@ -398,7 +384,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
ARangesSectionWriter->addCURanges(Unit.getOffset(),
std::move(OutputRanges));
updateDWARFObjectAddressRanges(DIE, RangesSectionOffset, DebugInfoPatcher,
AbbrevPatcher);
AbbrevWriter);
break;
}
case dwarf::DW_TAG_subprogram: {
@ -433,7 +419,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
if (UsesRanges) {
updateDWARFObjectAddressRanges(
DIE, RangesSectionWriter->addRanges(FunctionRanges),
DebugInfoPatcher, AbbrevPatcher);
DebugInfoPatcher, AbbrevWriter);
} else {
// Delay conversion of [LowPC, HighPC) into DW_AT_ranges if possible.
const DWARFAbbreviationDeclaration *Abbrev =
@ -445,7 +431,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
std::unique_lock<std::shared_timed_mutex> Lock(CriticalSectionMutex);
if (FunctionRanges.size() > 1) {
convertPending(Abbrev, DebugInfoPatcher, AbbrevPatcher);
convertPending(Unit, Abbrev, DebugInfoPatcher, AbbrevWriter);
// Exit critical section early.
Lock.unlock();
convertToRanges(DIE, FunctionRanges, DebugInfoPatcher);
@ -486,7 +472,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
consumeError(RangesOrError.takeError());
}
updateDWARFObjectAddressRanges(DIE, RangesSectionOffset, DebugInfoPatcher,
AbbrevPatcher);
AbbrevWriter);
break;
}
default: {
@ -662,7 +648,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
void DWARFRewriter::updateDWARFObjectAddressRanges(
const DWARFDie DIE, uint64_t DebugRangesOffset,
SimpleBinaryPatcher &DebugInfoPatcher, DebugAbbrevPatcher &AbbrevPatcher) {
SimpleBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter) {
// Some objects don't have an associated DIE and cannot be updated (such as
// compiler-generated functions).
@ -704,7 +690,7 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
// large size.
if (AbbreviationDecl->findAttributeIndex(dwarf::DW_AT_low_pc) &&
AbbreviationDecl->findAttributeIndex(dwarf::DW_AT_high_pc)) {
convertToRanges(AbbreviationDecl, AbbrevPatcher);
convertToRanges(*DIE.getDwarfUnit(), AbbreviationDecl, AbbrevWriter);
convertToRanges(DIE, DebugRangesOffset, DebugInfoPatcher);
} else {
if (opts::Verbosity >= 1) {
@ -862,17 +848,41 @@ void DWARFRewriter::finalizeDebugSections(
}
}
std::unique_ptr<RangesBufferVector> RangesSectionContents =
std::unique_ptr<DebugBufferVector> RangesSectionContents =
RangesSectionWriter->finalize();
BC.registerOrUpdateNoteSection(".debug_ranges",
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
std::unique_ptr<LocBufferVector> LocationListSectionContents =
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
makeFinalLocListsSection(DebugInfoPatcher);
BC.registerOrUpdateNoteSection(".debug_loc",
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
std::unique_ptr<DebugBufferVector> AbbrevSectionContents =
AbbrevWriter->finalize();
BC.registerOrUpdateNoteSection(".debug_abbrev",
copyByteArray(*AbbrevSectionContents),
AbbrevSectionContents->size());
// Update abbreviation offsets if they were changed.
for (auto &CU : BC.DwCtx->compile_units()) {
if (CU->isDWOUnit())
continue;
const uint64_t NewAbbrevOffset =
AbbrevWriter->getAbbreviationsOffsetForUnit(*CU);
if (CU->getAbbreviationsOffset() == NewAbbrevOffset)
continue;
// DWARFv4
// unit_length - 4 bytes
// version - 2 bytes
// So + 6 to patch debug_abbrev_offset
DebugInfoPatcher.addLE32Patch(CU->getOffset() + 6,
static_cast<uint32_t>(NewAbbrevOffset));
}
}
// Creates all the data structures necessary for creating MCStreamer.
@ -915,13 +925,13 @@ StringRef getSectionName(const SectionRef &Section) {
}
// Exctracts an appropriate slice if input is DWP.
// Applies patches to debug and its abbrev section.
// Applies patches or overwrites the section.
Optional<StringRef>
patchDebugData(std::string &Storage, const SectionRef &Section,
const StringMap<KnownSectionsEntry> &KnownSections,
MCStreamer &Streamer, DWARFRewriter &Writer,
const DWARFUnitIndex::Entry *DWOEntry, uint64_t DWOId,
std::unique_ptr<LocBufferVector> &LocVectorOut) {
updateDebugData(std::string &Storage, const SectionRef &Section,
const StringMap<KnownSectionsEntry> &KnownSections,
MCStreamer &Streamer, DWARFRewriter &Writer,
const DWARFUnitIndex::Entry *DWOEntry, uint64_t DWOId,
std::unique_ptr<DebugBufferVector> &OutputBuffer) {
auto applyPatch = [&](BinaryPatcher *Patcher, StringRef Data,
uint32_t Offset) -> StringRef {
Storage = Data.str();
@ -973,19 +983,22 @@ patchDebugData(std::string &Storage, const SectionRef &Section,
DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset);
}
case DWARFSectionKind::DW_SECT_ABBREV: {
OutData = getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_ABBREV,
DWPOffset);
DebugAbbrevPatcher *Patcher = Writer.getBinaryDWOAbbrevPatcher(DWOId);
return applyPatch(Patcher, OutData, DWPOffset);
}
case DWARFSectionKind::DW_SECT_EXT_LOC: {
DebugLocWriter *LocWriter = Writer.getDebugLocWriter(DWOId);
LocVectorOut = LocWriter->finalize();
DebugAbbrevWriter *AbbrevWriter = Writer.getBinaryDWOAbbrevWriter(DWOId);
OutputBuffer = AbbrevWriter->finalize();
// Creating explicit StringRef here, otherwise
// with impicit conversion it will take null byte as end of
// string.
return StringRef(reinterpret_cast<const char *>(LocVectorOut->data()),
LocVectorOut->size());
return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),
OutputBuffer->size());
}
case DWARFSectionKind::DW_SECT_EXT_LOC: {
DebugLocWriter *LocWriter = Writer.getDebugLocWriter(DWOId);
OutputBuffer = LocWriter->finalize();
// Creating explicit StringRef here, otherwise
// with impicit conversion it will take null byte as end of
// string.
return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),
OutputBuffer->size());
}
case DWARFSectionKind::DW_SECT_LINE: {
return getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_LINE,
@ -1080,10 +1093,10 @@ void DWARFRewriter::writeDWP(
(*DWOCU)->getContext().getDWARFObj().getFile();
for (const SectionRef &Section : DWOFile->sections()) {
std::string Storage = "";
std::unique_ptr<LocBufferVector> LocData;
std::unique_ptr<DebugBufferVector> OutputData;
Optional<StringRef> TOutData =
patchDebugData(Storage, Section, KnownSections, *Streamer, *this,
DWOEntry, *DWOId, LocData);
updateDebugData(Storage, Section, KnownSections, *Streamer, *this,
DWOEntry, *DWOId, OutputData);
if (!TOutData)
continue;
@ -1180,10 +1193,10 @@ void DWARFRewriter::writeDWOFiles(
for (const SectionRef &Section : File->sections()) {
std::string Storage = "";
std::unique_ptr<LocBufferVector> LocData;
std::unique_ptr<DebugBufferVector> OutputData;
if (Optional<StringRef> OutData =
patchDebugData(Storage, Section, KnownSections, *Streamer, *this,
DWOEntry, *DWOId, LocData))
updateDebugData(Storage, Section, KnownSections, *Streamer, *this,
DWOEntry, *DWOId, OutputData))
Streamer->emitBytes(*OutData);
}
Streamer->Finish();
@ -1299,25 +1312,25 @@ void DWARFRewriter::updateGdbIndexSection() {
NewGdbIndexSize);
}
void DWARFRewriter::convertToRanges(const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevPatcher &AbbrevPatcher) {
void DWARFRewriter::convertToRanges(const DWARFUnit &Unit,
const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevWriter &AbbrevWriter) {
dwarf::Form HighPCForm = Abbrev->findAttribute(dwarf::DW_AT_high_pc)->Form;
dwarf::Form LowPCForm = Abbrev->findAttribute(dwarf::DW_AT_low_pc)->Form;
std::lock_guard<std::mutex> Lock(AbbrevPatcherMutex);
// DW_FORM_GNU_addr_index is already variable encoding so nothing to do
// there. If HighForm is 8 bytes need to change low_pc to be variable
// encoding to consume extra bytes from high_pc, since DW_FORM_sec_offset is
// 4 bytes for DWARF32.
if (LowPCForm != dwarf::DW_FORM_GNU_addr_index &&
isHighPcFormEightBytes(HighPCForm))
AbbrevPatcher.addAttributePatch(Abbrev, dwarf::DW_AT_low_pc,
dwarf::DW_AT_low_pc,
dwarf::DW_FORM_indirect);
AbbrevWriter.addAttributePatch(Unit, Abbrev, dwarf::DW_AT_low_pc,
dwarf::DW_AT_low_pc,
dwarf::DW_FORM_indirect);
AbbrevPatcher.addAttributePatch(Abbrev, dwarf::DW_AT_high_pc,
dwarf::DW_AT_ranges,
dwarf::DW_FORM_sec_offset);
AbbrevWriter.addAttributePatch(Unit, Abbrev, dwarf::DW_AT_high_pc,
dwarf::DW_AT_ranges,
dwarf::DW_FORM_sec_offset);
}
void DWARFRewriter::convertToRanges(DWARFDie DIE,
@ -1333,13 +1346,14 @@ void DWARFRewriter::convertToRanges(DWARFDie DIE,
convertToRanges(DIE, RangesSectionOffset, DebugInfoPatcher);
}
void DWARFRewriter::convertPending(const DWARFAbbreviationDeclaration *Abbrev,
void DWARFRewriter::convertPending(const DWARFUnit &Unit,
const DWARFAbbreviationDeclaration *Abbrev,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevPatcher &AbbrevPatcher) {
DebugAbbrevWriter &AbbrevWriter) {
if (ConvertedRangesAbbrevs.count(Abbrev))
return;
convertToRanges(Abbrev, AbbrevPatcher);
convertToRanges(Unit, Abbrev, AbbrevWriter);
auto I = PendingRanges.find(Abbrev);
if (I != PendingRanges.end()) {
@ -1382,9 +1396,9 @@ void DWARFRewriter::addToPendingRanges(
std::make_pair(DWARFDieWrapper(DIE), FunctionRanges.front()));
}
std::unique_ptr<LocBufferVector>
std::unique_ptr<DebugBufferVector>
DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher) {
auto LocBuffer = std::make_unique<LocBufferVector>();
auto LocBuffer = std::make_unique<DebugBufferVector>();
auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
auto Writer =
std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));
@ -1406,7 +1420,7 @@ DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher) {
if (llvm::isa<DebugLoclistWriter>(*LocWriter))
continue;
SectionOffsetByCU[CUIndex] = SectionOffset;
std::unique_ptr<LocBufferVector> CurrCULocationLists =
std::unique_ptr<DebugBufferVector> CurrCULocationLists =
LocWriter->finalize();
*LocStream << *CurrCULocationLists;
SectionOffset += CurrCULocationLists->size();

View File

@ -33,8 +33,6 @@ class DWARFRewriter {
std::mutex DebugInfoPatcherMutex;
std::mutex AbbrevPatcherMutex;
/// Stores and serializes information that will be put into the
/// .debug_ranges DWARF section.
std::unique_ptr<DebugRangesSectionWriter> RangesSectionWriter;
@ -52,15 +50,18 @@ class DWARFRewriter {
/// Does not do de-duplication.
std::unique_ptr<DebugStrWriter> StrWriter;
/// .debug_abbrev section writer for the main binary.
std::unique_ptr<DebugAbbrevWriter> AbbrevWriter;
using LocWriters =
std::unordered_map<uint64_t, std::unique_ptr<DebugLocWriter>>;
/// Use a separate location list writer for each compilation unit
LocWriters LocListWritersByCU;
using DebugAbbrevDWOPatchers =
std::unordered_map<uint64_t, std::unique_ptr<DebugAbbrevPatcher>>;
/// Binary patchers for DWO Abbrev sections.
DebugAbbrevDWOPatchers BinaryDWOAbbrevPatchers;
using DebugAbbrevDWOWriters =
std::unordered_map<uint64_t, std::unique_ptr<DebugAbbrevWriter>>;
/// Abbrev section writers for DWOs.
DebugAbbrevDWOWriters BinaryDWOAbbrevWriters;
using DebugInfoDWOPatchers =
std::unordered_map<uint64_t, std::unique_ptr<SimpleBinaryPatcher>>;
@ -86,7 +87,7 @@ class DWARFRewriter {
/// Update debug info for all DIEs in \p Unit.
void updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevPatcher &AbbrevPatcher);
DebugAbbrevWriter &AbbrevWriter);
/// Patches the binary for an object's address ranges to be updated.
/// The object can be a anything that has associated address ranges via either
@ -98,12 +99,12 @@ class DWARFRewriter {
void updateDWARFObjectAddressRanges(const DWARFDie DIE,
uint64_t DebugRangesOffset,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevPatcher &AbbrevPatcher);
DebugAbbrevWriter &AbbrevWriter);
std::unique_ptr<LocBufferVector>
std::unique_ptr<DebugBufferVector>
makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher);
/// Generate new contents for .debug_ranges and .debug_aranges section.
/// Finalize debug sections in the main binary.
void finalizeDebugSections(SimpleBinaryPatcher &DebugInfoPatcher);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
@ -154,8 +155,9 @@ class DWARFRewriter {
/// Convert \p Abbrev from using a simple DW_AT_(low|high)_pc range to
/// DW_AT_ranges.
void convertToRanges(const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevPatcher &AbbrevPatcher);
void convertToRanges(const DWARFUnit &Unit,
const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevWriter &AbbrevWriter);
/// Update \p DIE that was using DW_AT_(low|high)_pc with DW_AT_ranges offset.
void convertToRanges(DWARFDie DIE, uint64_t RangesSectionOffset,
@ -170,9 +172,10 @@ class DWARFRewriter {
SimpleBinaryPatcher &DebugInfoPatcher);
/// Convert pending ranges associated with the given \p Abbrev.
void convertPending(const DWARFAbbreviationDeclaration *Abbrev,
void convertPending(const DWARFUnit &Unit,
const DWARFAbbreviationDeclaration *Abbrev,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevPatcher &AbbrevPatcher);
DebugAbbrevWriter &AbbrevWriter);
/// Adds to Pending Ranges.
/// For Debug Fission also adding to .debug_addr to take care of a case where
@ -185,8 +188,7 @@ class DWARFRewriter {
/// Once all DIEs were seen, update DW_AT_(low|high)_pc values.
void flushPendingRanges(SimpleBinaryPatcher &DebugInfoPatcher);
/// Helper function for creating and returnning DWO DebugInfo and Abbrev
/// patchers.
/// Helper function for creating and returning per-DWO patchers/writers.
template <class T, class Patcher>
Patcher *getBinaryDWOPatcherHelper(T &BinaryPatchers, uint64_t DwoId) {
auto Iter = BinaryPatchers.find(DwoId);
@ -218,12 +220,11 @@ public:
BinaryDWODebugInfoPatchers, DwoId);
}
/// Returns a DWO Abbrev Patcher for DWO ID.
/// Creates a new instance if it's not already exists.
DebugAbbrevPatcher *getBinaryDWOAbbrevPatcher(uint64_t DwoId) {
return getBinaryDWOPatcherHelper<DebugAbbrevDWOPatchers,
DebugAbbrevPatcher>(
BinaryDWOAbbrevPatchers, DwoId);
/// Returns a DWO abbrev writer for DWO ID.
/// Creates a new instance if it does not already exists.
DebugAbbrevWriter *getBinaryDWOAbbrevWriter(uint64_t DwoId) {
return getBinaryDWOPatcherHelper<DebugAbbrevDWOWriters, DebugAbbrevWriter>(
BinaryDWOAbbrevWriters, DwoId);
}
/// Given a DWO ID, return its DebugLocWriter if it exists.

View File

@ -59,7 +59,7 @@ uint64_t writeAddressRanges(
} // namespace
DebugRangesSectionWriter::DebugRangesSectionWriter() {
RangesBuffer = std::make_unique<RangesBufferVector>();
RangesBuffer = std::make_unique<DebugBufferVector>();
RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer);
// Add an empty range as the first entry;
@ -257,7 +257,7 @@ uint64_t DebugAddrWriter::getOffset(uint64_t DWOId) {
}
DebugLocWriter::DebugLocWriter(BinaryContext *BC) {
LocBuffer = std::make_unique<LocBufferVector>();
LocBuffer = std::make_unique<DebugBufferVector>();
LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
}
@ -385,71 +385,6 @@ void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents,
}
}
void DebugAbbrevPatcher::addAttributePatch(
const DWARFAbbreviationDeclaration *Abbrev, dwarf::Attribute AttrTag,
dwarf::Attribute NewAttrTag, uint8_t NewAttrForm) {
assert(Abbrev && "no abbreviation specified");
if (std::numeric_limits<uint8_t>::max() >= NewAttrTag)
AbbrevPatches.emplace(
AbbrevAttrPatch{Abbrev, AttrTag, NewAttrTag, NewAttrForm});
else
AbbrevNonStandardPatches.emplace_back(
AbbrevAttrPatch{Abbrev, AttrTag, NewAttrTag, NewAttrForm});
}
void DebugAbbrevPatcher::patchBinary(std::string &Contents,
uint32_t DWPOffset = 0) {
SimpleBinaryPatcher Patcher;
for (const AbbrevAttrPatch &Patch : AbbrevPatches) {
const DWARFAbbreviationDeclaration::AttributeSpec *const Attribute =
Patch.Abbrev->findAttribute(Patch.Attr);
assert(Attribute && "Specified attribute doesn't occur in abbreviation.");
Patcher.addBytePatch(Attribute->AttrOffset - DWPOffset,
static_cast<uint8_t>(Patch.NewAttr));
Patcher.addBytePatch(Attribute->FormOffset - DWPOffset, Patch.NewForm);
}
Patcher.patchBinary(Contents);
if (AbbrevNonStandardPatches.empty())
return;
std::string Section;
Section.reserve(Contents.size() + AbbrevNonStandardPatches.size() / 2);
const char *Ptr = Contents.c_str();
uint32_t Start = 0;
std::string Buff;
auto Encode = [&](uint16_t Value) -> std::string {
Buff.clear();
raw_string_ostream OS(Buff);
encodeULEB128(Value, OS, 2);
return Buff;
};
for (const AbbrevAttrPatch &Patch : AbbrevNonStandardPatches) {
const DWARFAbbreviationDeclaration::AttributeSpec *const Attribute =
Patch.Abbrev->findAttribute(Patch.Attr);
assert(Attribute && "Specified attribute doesn't occur in abbreviation.");
assert(Start <= Attribute->AttrOffset &&
"Offsets are not in sequential order.");
// Assuming old attribute is 1 byte. Otherwise will need to add logic to
// determine it's size at runtime.
assert(std::numeric_limits<uint8_t>::max() >= Patch.Attr &&
"Old attribute is greater then 1 byte.");
Section.append(Ptr + Start, Attribute->AttrOffset - Start);
Section.append(Encode(Patch.NewAttr));
Section.append(std::string(1, Patch.NewForm));
Start = Attribute->FormOffset + 1;
}
Section.append(Ptr + Start, Contents.size() - Start);
Contents = std::move(Section);
}
void DebugStrWriter::create() {
StrBuffer = std::make_unique<DebugStrBufferVector>();
StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer);
@ -469,5 +404,122 @@ uint32_t DebugStrWriter::addString(StringRef Str) {
return Offset;
}
void DebugAbbrevWriter::addUnitAbbreviations(DWARFUnit &Unit) {
const DWARFAbbreviationDeclarationSet *Abbrevs = Unit.getAbbreviations();
if (!Abbrevs)
return;
uint64_t CUIndex = Unit.getOffset();
if (CUAbbrevData.find(CUIndex) == CUAbbrevData.end()) {
std::lock_guard<std::mutex> Lock(WriterMutex);
AbbrevData &Data = CUAbbrevData[CUIndex];
Data.Buffer = std::make_unique<DebugBufferVector>();
Data.Stream = std::make_unique<raw_svector_ostream>(*Data.Buffer);
}
std::lock_guard<std::mutex> Lock(WriterMutex);
const auto &UnitPatches = Patches[&Unit];
raw_svector_ostream &OS = *CUAbbrevData[CUIndex].Stream.get();
// Take a fast path if there are no patches to apply. Simply copy the original
// contents.
if (UnitPatches.empty()) {
StringRef AbbrevSectionContents =
Unit.isDWOUnit() ? Unit.getContext().getDWARFObj().getAbbrevDWOSection()
: Unit.getContext().getDWARFObj().getAbbrevSection();
StringRef AbbrevContents;
const DWARFUnitIndex &CUIndex = Unit.getContext().getCUIndex();
if (!CUIndex.getRows().empty()) {
// Handle DWP section contribution.
const DWARFUnitIndex::Entry *DWOEntry =
CUIndex.getFromHash(*Unit.getDWOId());
if (!DWOEntry)
return;
const DWARFUnitIndex::Entry::SectionContribution *DWOContrubution =
DWOEntry->getContribution(DWARFSectionKind::DW_SECT_ABBREV);
AbbrevContents = AbbrevSectionContents.substr(DWOContrubution->Offset,
DWOContrubution->Length);
} else {
DWARFCompileUnit *NextUnit =
Unit.getContext().getCompileUnitForOffset(Unit.getNextUnitOffset());
const uint64_t StartOffset = Unit.getAbbreviationsOffset();
const uint64_t EndOffset = NextUnit ? NextUnit->getAbbreviationsOffset()
: AbbrevSectionContents.size();
AbbrevContents = AbbrevSectionContents.slice(StartOffset, EndOffset);
}
OS.reserveExtraSpace(AbbrevContents.size());
OS << AbbrevContents;
return;
}
for (auto I = Abbrevs->begin(), E = Abbrevs->end(); I != E; ++I) {
const DWARFAbbreviationDeclaration &Abbrev = *I;
auto Patch = UnitPatches.find(&Abbrev);
encodeULEB128(Abbrev.getCode(), OS);
encodeULEB128(Abbrev.getTag(), OS);
encodeULEB128(Abbrev.hasChildren(), OS);
for (const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec :
Abbrev.attributes()) {
if (Patch != UnitPatches.end()) {
bool Patched = false;
// Patches added later take a precedence over earlier ones.
for (auto I = Patch->second.rbegin(), E = Patch->second.rend(); I != E;
++I) {
if (I->OldAttr != AttrSpec.Attr)
continue;
encodeULEB128(I->NewAttr, OS);
encodeULEB128(I->NewAttrForm, OS);
Patched = true;
break;
}
if (Patched)
continue;
}
encodeULEB128(AttrSpec.Attr, OS);
encodeULEB128(AttrSpec.Form, OS);
if (AttrSpec.isImplicitConst())
encodeSLEB128(AttrSpec.getImplicitConstValue(), OS);
}
encodeULEB128(0, OS);
encodeULEB128(0, OS);
}
encodeULEB128(0, OS);
}
std::unique_ptr<DebugBufferVector> DebugAbbrevWriter::finalize() {
DebugBufferVector ReturnBuffer;
// Pre-calculate the total size of abbrev section.
uint64_t Size = 0;
for (const auto &KV : CUAbbrevData) {
const AbbrevData &Data = KV.second;
Size += Data.Buffer->size();
}
ReturnBuffer.reserve(Size);
uint64_t Pos = 0;
for (auto &KV : CUAbbrevData) {
AbbrevData &Data = KV.second;
ReturnBuffer.append(*Data.Buffer);
Data.Offset = Pos;
Pos += Data.Buffer->size();
Data.Buffer.reset();
Data.Stream.reset();
}
return std::make_unique<DebugBufferVector>(ReturnBuffer);
}
} // namespace bolt
} // namespace llvm

View File

@ -28,6 +28,8 @@
namespace llvm {
class DWARFAbbreviationDeclarationSet;
namespace bolt {
class BinaryContext;
@ -100,7 +102,8 @@ struct DebugLineTableRowRef {
}
};
using RangesBufferVector = SmallVector<char, 16>;
/// Common buffer vector used for debug info handling.
using DebugBufferVector = SmallVector<char, 16>;
/// Serializes the .debug_ranges DWARF section.
class DebugRangesSectionWriter {
@ -122,12 +125,12 @@ public:
/// Returns the SectionOffset.
uint64_t getSectionOffset();
std::unique_ptr<RangesBufferVector> finalize() {
std::unique_ptr<DebugBufferVector> finalize() {
return std::move(RangesBuffer);
}
private:
std::unique_ptr<RangesBufferVector> RangesBuffer;
std::unique_ptr<DebugBufferVector> RangesBuffer;
std::unique_ptr<raw_svector_ostream> RangesStream;
@ -277,8 +280,6 @@ private:
BinaryContext *BC;
};
using LocBufferVector = SmallVector<char, 16>;
enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter };
/// Serializes part of a .debug_loc DWARF section with LocationLists.
@ -290,7 +291,7 @@ public:
virtual uint64_t addList(const DebugLocationsVector &LocList);
virtual std::unique_ptr<LocBufferVector> finalize() {
virtual std::unique_ptr<DebugBufferVector> finalize() {
return std::move(LocBuffer);
}
@ -309,7 +310,7 @@ public:
}
protected:
std::unique_ptr<LocBufferVector> LocBuffer;
std::unique_ptr<DebugBufferVector> LocBuffer;
std::unique_ptr<raw_svector_ostream> LocStream;
/// Current offset in the section (updated as new entries are written).
@ -429,59 +430,69 @@ public:
uint32_t DWPOffset) override;
};
/// Apply small modifications to the .debug_abbrev DWARF section.
class DebugAbbrevPatcher : public BinaryPatcher {
public:
/// Patch of changing one attribute to another.
struct AbbrevAttrPatch {
const DWARFAbbreviationDeclaration *Abbrev;
dwarf::Attribute Attr; // ID of attribute to be replaced.
dwarf::Attribute NewAttr; // ID of the new attribute.
uint8_t NewForm; // Form of the new attribute.
/// Class to facilitate modifying and writing abbreviations for compilation
/// units. One class instance manages all abbreviation sections in a file
/// or in a section contribution for DWPs.
class DebugAbbrevWriter {
bool operator==(const AbbrevAttrPatch &RHS) const {
return Abbrev == RHS.Abbrev && Attr == RHS.Attr;
}
std::mutex WriterMutex;
struct AbbrevData {
/// Offset in the final section.
uint64_t Offset{0};
std::unique_ptr<DebugBufferVector> Buffer;
std::unique_ptr<raw_svector_ostream> Stream;
};
/// Map CU offset to abbreviations data.
std::map<uint64_t, AbbrevData> CUAbbrevData;
/// Attributes Substitution information.
struct PatchInfo {
dwarf::Attribute OldAttr;
dwarf::Attribute NewAttr;
uint8_t NewAttrForm;
};
struct AbbrevHash {
size_t operator()(const AbbrevAttrPatch &P) const {
return std::hash<uint64_t>()(((uint64_t)P.Abbrev << 16) + P.Attr);
}
};
private:
std::unordered_set<AbbrevAttrPatch, AbbrevHash> AbbrevPatches;
/// Using Vector because this is currently being used for specific purpose of
/// patching DW_AT_GNU_ranges_base. So don't need fast look up, but do need
/// them to be in order.
std::vector<AbbrevAttrPatch> AbbrevNonStandardPatches;
using PatchesTy = std::unordered_map<const DWARFAbbreviationDeclaration *,
SmallVector<PatchInfo, 2>>;
std::unordered_map<const DWARFUnit *, PatchesTy> Patches;
public:
virtual ~DebugAbbrevPatcher() {}
/// Adds a patch to change an attribute of the abbreviation
/// \p Abbrev the abbreviation to be modified.
/// \p AttrTag ID of the attribute to be replaced.
/// \p NewAttrTag ID of the new attribute.
/// \p NewAttrForm Form of the new attribute.
/// If None standard form is added through this API it will expand the section
/// to accomidate it.
void addAttributePatch(const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevWriter() = default;
DebugAbbrevWriter(const DebugAbbrevWriter &) = delete;
DebugAbbrevWriter &operator=(const DebugAbbrevWriter &) = delete;
DebugAbbrevWriter(DebugAbbrevWriter &&) = delete;
DebugAbbrevWriter &operator=(DebugAbbrevWriter &&) = delete;
virtual ~DebugAbbrevWriter() = default;
/// Substitute attribute \p AttrTag in abbreviation declaration \p Abbrev
/// belonging to CU \p Unit with new attribute \p NewAttrTag having
/// \p NewAttrForm form.
void addAttributePatch(const DWARFUnit &Unit,
const DWARFAbbreviationDeclaration *Abbrev,
dwarf::Attribute AttrTag, dwarf::Attribute NewAttrTag,
uint8_t NewAttrForm);
uint8_t NewAttrForm) {
std::lock_guard<std::mutex> Lock(WriterMutex);
Patches[&Unit][Abbrev].emplace_back(
PatchInfo{AttrTag, NewAttrTag, NewAttrForm});
}
virtual void patchBinary(std::string &Contents, uint32_t DWPOffset) override;
/// Add abbreviations from CU \p Unit to the writer.
void addUnitAbbreviations(DWARFUnit &Unit);
/// Finds an abbreviation patch.
/// \p AbbrevDecl the abbreviation declaration.
/// \p AttrTag Attribute to search for.
/// Returns nullptr if patch doesn't exist.
const AbbrevAttrPatch *find(const DWARFAbbreviationDeclaration *AbbrevDecl,
dwarf::Attribute AttrTag) {
auto Iter = AbbrevPatches.find({AbbrevDecl, AttrTag, AttrTag, 0});
if (Iter == AbbrevPatches.end())
return nullptr;
return &(*Iter);
/// Return a buffer with concatenated abbrev sections for all added CUs.
/// Section offsets for CUs could be queried using
/// getAbbreviationsOffsetForUnit() interface.
std::unique_ptr<DebugBufferVector> finalize();
/// Return an offset in the finalized section corresponding to CU \p Unit.
uint64_t getAbbreviationsOffsetForUnit(const DWARFUnit &Unit) {
assert(CUAbbrevData.find(Unit.getOffset()) != CUAbbrevData.end() &&
"no abbrev data found for unit");
return CUAbbrevData[Unit.getOffset()].Offset;
}
};

View File

@ -446,8 +446,8 @@ bool processAllFunctions() {
constexpr const char *RewriteInstance::SectionsToOverwrite[];
std::vector<std::string> RewriteInstance::DebugSectionsToOverwrite = {
".debug_aranges", ".debug_line", ".debug_loc",
".debug_ranges", ".gdb_index", ".debug_addr"};
".debug_abbrev", ".debug_aranges", ".debug_line", ".debug_loc",
".debug_ranges", ".gdb_index", ".debug_addr"};
const char RewriteInstance::TimerGroupName[] = "rewrite";
const char RewriteInstance::TimerGroupDesc[] = "Rewrite passes";