[BOLT][DWARF] Fix writing out dwo with DWP as input

Summary:
The code for writing out dwo files wasn't handling case where DWP is an input.
Because all the sections are part of the same binary.

One note with current implementation. .debug-str.dwo will have strings for all the dwo objects.
This is because llvm-dwp de-duplicates strings and combines them in to one section. It then re-writes .debug-str-offsets.dwo to point to new .debug-str.dwo section.

(cherry picked from FBD29244835)
This commit is contained in:
Alexander Yermolovich 2021-06-18 15:57:34 -07:00 committed by Maksim Panchenko
parent 3e5ce1f282
commit f7499c6711
6 changed files with 80 additions and 19 deletions

View File

@ -1460,6 +1460,12 @@ Optional<DWARFUnit *> BinaryContext::getDWOCU(uint64_t DWOId) {
return Iter->second;
}
DWARFContext *BinaryContext::getDWOContext() {
if (DWOCUs.empty())
return nullptr;
return &DWOCUs.begin()->second->getContext();
}
/// Handles DWO sections that can either be in .o, .dwo or .dwp files.
void BinaryContext::preprocessDWODebugInfo() {
for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {

View File

@ -212,9 +212,12 @@ public:
createBinaryContext(const ObjectFile *File, bool IsPIC,
std::unique_ptr<DWARFContext> DwCtx);
/// Given DWOId returns CU if it existss in DWOCUs.
/// Given DWOId returns CU if it exists in DWOCUs.
Optional<DWARFUnit *> getDWOCU(uint64_t DWOId);
/// Returns DWOContext if it exists.
DWARFContext *getDWOContext();
/// Get Number of DWOCUs in a map.
uint32_t getNumDWOCUs() { return DWOCUs.size(); }

View File

@ -824,12 +824,35 @@ void DWARFRewriter::finalizeDebugSections(
void DWARFRewriter::writeOutDWOFiles(
std::unordered_map<uint64_t, std::string> &DWOIdToName) {
std::string DebugData = "";
auto ApplyPatch = [&](BinaryPatcher *Patcher, StringRef Data) -> StringRef {
auto applyPatch = [&](BinaryPatcher *Patcher, StringRef Data,
uint32_t Offset) -> StringRef {
DebugData = Data.str();
Patcher->patchBinary(DebugData);
Patcher->patchBinary(DebugData, Offset);
return StringRef(DebugData.c_str(), DebugData.size());
};
using DWOSectionContribution =
const DWARFUnitIndex::Entry::SectionContribution;
auto getSliceData = [&](const DWARFUnitIndex::Entry *DWOEntry,
StringRef OutData, DWARFSectionKind Sec,
uint32_t &DWPOffset) -> StringRef {
if (DWOEntry) {
DWOSectionContribution *DWOContrubution = DWOEntry->getContribution(Sec);
DWPOffset = DWOContrubution->Offset;
OutData = OutData.substr(DWPOffset, DWOContrubution->Length);
}
return OutData;
};
// Setup DWP code once.
DWARFContext *DWOCtx = BC.getDWOContext();
const DWARFUnitIndex *CUIndex = nullptr;
bool IsDWP = false;
if (DWOCtx) {
CUIndex = &DWOCtx->getCUIndex();
IsDWP = !CUIndex->getRows().empty();
}
for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
Optional<uint64_t> DWOId = CU->getDWOId();
if (!DWOId)
@ -859,6 +882,10 @@ void DWARFRewriter::writeOutDWOFiles(
std::unique_ptr<MCStreamer> Streamer = TmpBC->createStreamer(TempOut->os());
const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo();
const DWARFUnitIndex::Entry *DWOEntry = nullptr;
if (IsDWP)
DWOEntry = CUIndex->getFromHash(*DWOId);
const StringMap<MCSection *> KnownSections = {
{".debug_info.dwo", MCOFI.getDwarfInfoDWOSection()},
{".debug_types.dwo", MCOFI.getDwarfTypesDWOSection()},
@ -879,7 +906,28 @@ void DWARFRewriter::writeOutDWOFiles(
assert(Contents && "Invalid contents.");
StringRef OutData(*Contents);
std::unique_ptr<LocBufferVector> Data;
if (SectionName->equals(".debug_loc.dwo")) {
uint32_t DWPOffset = 0;
if (SectionName->equals(".debug_info.dwo")) {
OutData = getSliceData(DWOEntry, OutData,
DWARFSectionKind::DW_SECT_INFO, DWPOffset);
SimpleBinaryPatcher *Patcher = getBinaryDWODebugInfoPatcher(*DWOId);
OutData = applyPatch(Patcher, OutData, DWPOffset);
} else if (SectionName->equals(".debug_types.dwo")) {
OutData = getSliceData(DWOEntry, OutData,
DWARFSectionKind::DW_SECT_EXT_TYPES, DWPOffset);
} else if (SectionName->equals(".debug_str.dwo")) {
OutData = (*DWOCU)->getStringSection();
} else if (SectionName->equals(".debug_str_offsets.dwo")) {
OutData =
getSliceData(DWOEntry, OutData,
DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset);
} else if (SectionName->equals(".debug_abbrev.dwo")) {
OutData = getSliceData(DWOEntry, OutData,
DWARFSectionKind::DW_SECT_ABBREV, DWPOffset);
DebugAbbrevPatcher *Patcher = getBinaryDWOAbbrevPatcher(*DWOId);
OutData = applyPatch(Patcher, OutData, DWPOffset);
} else if (SectionName->equals(".debug_loc.dwo")) {
DebugLocWriter *LocWriter = LocListWritersByCU[*DWOId].get();
Data = LocWriter->finalize();
// Creating explicit with creating of StringRef here, otherwise
@ -887,12 +935,12 @@ void DWARFRewriter::writeOutDWOFiles(
// string.
OutData = StringRef(reinterpret_cast<const char *>(Data->data()),
Data->size());
} else if (SectionName->equals(".debug_info.dwo")) {
SimpleBinaryPatcher *Patcher = getBinaryDWODebugInfoPatcher(*DWOId);
OutData = ApplyPatch(Patcher, OutData);
} else if (SectionName->equals(".debug_abbrev.dwo")) {
DebugAbbrevPatcher *Patcher = getBinaryDWOAbbrevPatcher(*DWOId);
OutData = ApplyPatch(Patcher, OutData);
} else if (SectionName->equals(".debug_line.dwo")) {
OutData = getSliceData(DWOEntry, OutData,
DWARFSectionKind::DW_SECT_LINE, DWPOffset);
} else {
errs() << "BOLT-WARNING: Unsupported Debug section: " << *SectionName
<< "\n";
}
Streamer->emitBytes(OutData);

View File

@ -371,9 +371,10 @@ void SimpleBinaryPatcher::addLE32Patch(uint32_t Offset, uint32_t NewValue) {
addLEPatch(Offset, NewValue, 4);
}
void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents) {
void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents,
uint32_t DWPOffset = 0) {
for (const auto &Patch : Patches) {
uint32_t Offset = Patch.first;
uint32_t Offset = Patch.first - DWPOffset;
const std::string &ByteSequence = Patch.second;
assert(Offset + ByteSequence.size() <= BinaryContents.size() &&
"Applied patch runs over binary size.");
@ -396,7 +397,8 @@ void DebugAbbrevPatcher::addAttributePatch(
AbbrevAttrPatch{Abbrev, AttrTag, NewAttrTag, NewAttrForm});
}
void DebugAbbrevPatcher::patchBinary(std::string &Contents) {
void DebugAbbrevPatcher::patchBinary(std::string &Contents,
uint32_t DWPOffset = 0) {
SimpleBinaryPatcher Patcher;
for (const AbbrevAttrPatch &Patch : AbbrevPatches) {
@ -404,9 +406,9 @@ void DebugAbbrevPatcher::patchBinary(std::string &Contents) {
Patch.Abbrev->findAttribute(Patch.Attr);
assert(Attribute && "Specified attribute doesn't occur in abbreviation.");
Patcher.addBytePatch(Attribute->AttrOffset,
Patcher.addBytePatch(Attribute->AttrOffset - DWPOffset,
static_cast<uint8_t>(Patch.NewAttr));
Patcher.addBytePatch(Attribute->FormOffset, Patch.NewForm);
Patcher.addBytePatch(Attribute->FormOffset - DWPOffset, Patch.NewForm);
}
Patcher.patchBinary(Contents);

View File

@ -364,7 +364,8 @@ class BinaryPatcher {
public:
virtual ~BinaryPatcher() {}
/// Applies in-place modifications to the binary string \p BinaryContents .
virtual void patchBinary(std::string &BinaryContents) = 0;
/// \p DWPOffset used to correctly patch sections that come from DWP file.
virtual void patchBinary(std::string &BinaryContents, uint32_t DWPOffset) = 0;
};
/// Applies simple modifications to a binary string, such as directly replacing
@ -424,7 +425,8 @@ public:
/// Proxy for if we broke up low_pc/high_pc to ranges.
bool getWasRangBasedUsed() const { return WasRangeBaseUsed; }
virtual void patchBinary(std::string &BinaryContents) override;
virtual void patchBinary(std::string &BinaryContents,
uint32_t DWPOffset) override;
};
/// Apply small modifications to the .debug_abbrev DWARF section.
@ -468,7 +470,7 @@ public:
dwarf::Attribute AttrTag, dwarf::Attribute NewAttrTag,
uint8_t NewAttrForm);
virtual void patchBinary(std::string &Contents) override;
virtual void patchBinary(std::string &Contents, uint32_t DWPOffset) override;
/// Finds an abbreviation patch.
/// \p AbbrevDecl the abbreviation declaration.

View File

@ -3843,7 +3843,7 @@ void RewriteInstance::rewriteNoteSections() {
std::string Data =
std::string(InputFile->getData().substr(Section.sh_offset, Size));
if (BSec && BSec->getPatcher())
BSec->getPatcher()->patchBinary(Data);
BSec->getPatcher()->patchBinary(Data, 0);
// Section was expanded, so need to treat it as overwrite.
if (Size != Data.size()) {