mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-24 20:44:09 +00:00
Rebase: [BOLT] DWP output support
Summary: Added support for writing out DWP file. Works with regular dwo as input or DWP as input. (cherry picked from FBD31361619)
This commit is contained in:
parent
900914d3c6
commit
d217e2f338
@ -53,6 +53,7 @@ set(LLVM_LINK_COMPONENTS
|
|||||||
CodeGen
|
CodeGen
|
||||||
Core
|
Core
|
||||||
DebugInfoDWARF
|
DebugInfoDWARF
|
||||||
|
DWP
|
||||||
MC
|
MC
|
||||||
MCDisassembler
|
MCDisassembler
|
||||||
MCParser
|
MCParser
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
#include "llvm/BinaryFormat/Dwarf.h"
|
||||||
|
#include "llvm/DWP/DWP.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||||
#include "llvm/MC/MCAsmBackend.h"
|
#include "llvm/MC/MCAsmBackend.h"
|
||||||
@ -60,6 +61,7 @@ namespace opts {
|
|||||||
|
|
||||||
extern cl::OptionCategory BoltCategory;
|
extern cl::OptionCategory BoltCategory;
|
||||||
extern cl::opt<unsigned> Verbosity;
|
extern cl::opt<unsigned> Verbosity;
|
||||||
|
extern cl::opt<std::string> OutputFilename;
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
KeepARanges("keep-aranges",
|
KeepARanges("keep-aranges",
|
||||||
@ -75,14 +77,20 @@ DeterministicDebugInfo("deterministic-debuginfo",
|
|||||||
cl::init(true),
|
cl::init(true),
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string> DwarfOutputPath(
|
||||||
DwoOutputPath("dwo-output-path",
|
"dwarf-output-path",
|
||||||
cl::desc("Path to where .dwo files will be written out to."),
|
cl::desc("Path to where .dwo files or dwp file will be written out to."),
|
||||||
cl::init(""), cl::cat(BoltCategory));
|
cl::init(""), cl::cat(BoltCategory));
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
WriteDWP("write-out-dwp",
|
||||||
|
cl::desc("output a single dwarf package file (dwp) instead of "
|
||||||
|
"multiple non-relocatable dwarf object files (dwo)."),
|
||||||
|
cl::init(false), cl::cat(BoltCategory));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
DebugSkeletonCu("debug-skeleton-cu",
|
DebugSkeletonCu("debug-skeleton-cu",
|
||||||
cl::desc("Prints out offsetrs for abbrev and debu_info of "
|
cl::desc("prints out offsetrs for abbrev and debu_info of "
|
||||||
"Skeleton CUs that get patched."),
|
"Skeleton CUs that get patched."),
|
||||||
cl::ZeroOrMore, cl::Hidden, cl::init(false),
|
cl::ZeroOrMore, cl::Hidden, cl::init(false),
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
@ -106,7 +114,7 @@ getDWOName(llvm::DWARFUnit &CU,
|
|||||||
"");
|
"");
|
||||||
assert(!DWOName.empty() &&
|
assert(!DWOName.empty() &&
|
||||||
"DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exists.");
|
"DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exists.");
|
||||||
if (NameToIndexMap && !opts::DwoOutputPath.empty()) {
|
if (NameToIndexMap && !opts::DwarfOutputPath.empty()) {
|
||||||
auto Iter = NameToIndexMap->find(DWOName);
|
auto Iter = NameToIndexMap->find(DWOName);
|
||||||
if (Iter == NameToIndexMap->end()) {
|
if (Iter == NameToIndexMap->end()) {
|
||||||
Iter = NameToIndexMap->insert({DWOName, 0}).first;
|
Iter = NameToIndexMap->insert({DWOName, 0}).first;
|
||||||
@ -179,8 +187,8 @@ void DWARFRewriter::updateDebugInfo() {
|
|||||||
DIE.find(dwarf::DW_AT_comp_dir, &AttrOffset);
|
DIE.find(dwarf::DW_AT_comp_dir, &AttrOffset);
|
||||||
(void)ValCompDir;
|
(void)ValCompDir;
|
||||||
assert(ValCompDir && "DW_AT_comp_dir is not in Skeleton CU.");
|
assert(ValCompDir && "DW_AT_comp_dir is not in Skeleton CU.");
|
||||||
if (!opts::DwoOutputPath.empty()) {
|
if (!opts::DwarfOutputPath.empty()) {
|
||||||
uint32_t NewOffset = StrWriter->addString(opts::DwoOutputPath.c_str());
|
uint32_t NewOffset = StrWriter->addString(opts::DwarfOutputPath.c_str());
|
||||||
DebugInfoPatcher->addLE32Patch(AttrOffset, NewOffset);
|
DebugInfoPatcher->addLE32Patch(AttrOffset, NewOffset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -298,7 +306,10 @@ void DWARFRewriter::updateDebugInfo() {
|
|||||||
|
|
||||||
finalizeDebugSections(*DebugInfoPatcher);
|
finalizeDebugSections(*DebugInfoPatcher);
|
||||||
|
|
||||||
writeOutDWOFiles(DWOIdToName);
|
if (opts::WriteDWP)
|
||||||
|
writeDWP(DWOIdToName);
|
||||||
|
else
|
||||||
|
writeDWOFiles(DWOIdToName);
|
||||||
|
|
||||||
updateGdbIndexSection();
|
updateGdbIndexSection();
|
||||||
}
|
}
|
||||||
@ -823,14 +834,58 @@ void DWARFRewriter::finalizeDebugSections(
|
|||||||
LocationListSectionContents->size());
|
LocationListSectionContents->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DWARFRewriter::writeOutDWOFiles(
|
// Creates all the data structures necessary for creating MCStreamer.
|
||||||
std::unordered_map<uint64_t, std::string> &DWOIdToName) {
|
// They are passed by reference because they need to be kept around.
|
||||||
std::string DebugData = "";
|
// Also creates known debug sections. These are sections handled by
|
||||||
|
// handleDebugDataPatching.
|
||||||
|
using KnownSectionsEntry = std::pair<MCSection *, DWARFSectionKind>;
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::unique_ptr<BinaryContext>
|
||||||
|
createDwarfOnlyBC(const object::ObjectFile &File) {
|
||||||
|
return BinaryContext::createBinaryContext(
|
||||||
|
&File, false,
|
||||||
|
DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Process,
|
||||||
|
nullptr, "", WithColor::defaultErrorHandler,
|
||||||
|
WithColor::defaultWarningHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
StringMap<KnownSectionsEntry>
|
||||||
|
createKnownSectionsMap(const MCObjectFileInfo &MCOFI) {
|
||||||
|
StringMap<KnownSectionsEntry> KnownSectionsTemp = {
|
||||||
|
{"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}},
|
||||||
|
{"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}},
|
||||||
|
{"debug_str_offsets.dwo",
|
||||||
|
{MCOFI.getDwarfStrOffDWOSection(), DW_SECT_STR_OFFSETS}},
|
||||||
|
{"debug_str.dwo", {MCOFI.getDwarfStrDWOSection(), DW_SECT_EXT_unknown}},
|
||||||
|
{"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
|
||||||
|
{"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
|
||||||
|
{"debug_line.dwo",
|
||||||
|
{MCOFI.getDwarfLineDWOSection(), DW_SECT_EXT_unknown}}};
|
||||||
|
return KnownSectionsTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef getSectionName(const SectionRef &Section) {
|
||||||
|
Expected<StringRef> SectionName = Section.getName();
|
||||||
|
assert(SectionName && "Invalid section name.");
|
||||||
|
StringRef Name = *SectionName;
|
||||||
|
Name = Name.substr(Name.find_first_not_of("._"));
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exctracts an appropriate slice if input is DWP.
|
||||||
|
// Applies patches to debug and its abbrev 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) {
|
||||||
auto applyPatch = [&](BinaryPatcher *Patcher, StringRef Data,
|
auto applyPatch = [&](BinaryPatcher *Patcher, StringRef Data,
|
||||||
uint32_t Offset) -> StringRef {
|
uint32_t Offset) -> StringRef {
|
||||||
DebugData = Data.str();
|
Storage = Data.str();
|
||||||
Patcher->patchBinary(DebugData, Offset);
|
Patcher->patchBinary(Storage, Offset);
|
||||||
return StringRef(DebugData.c_str(), DebugData.size());
|
return StringRef(Storage.c_str(), Storage.size());
|
||||||
};
|
};
|
||||||
|
|
||||||
using DWOSectionContribution =
|
using DWOSectionContribution =
|
||||||
@ -846,6 +901,87 @@ void DWARFRewriter::writeOutDWOFiles(
|
|||||||
return OutData;
|
return OutData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StringRef Name = getSectionName(Section);
|
||||||
|
auto SectionIter = KnownSections.find(Name);
|
||||||
|
if (SectionIter == KnownSections.end())
|
||||||
|
return None;
|
||||||
|
Streamer.SwitchSection(SectionIter->second.first);
|
||||||
|
Expected<StringRef> Contents = Section.getContents();
|
||||||
|
assert(Contents && "Invalid contents.");
|
||||||
|
StringRef OutData = *Contents;
|
||||||
|
uint32_t DWPOffset = 0;
|
||||||
|
|
||||||
|
switch (SectionIter->second.second) {
|
||||||
|
default: {
|
||||||
|
if (!Name.equals("debug_str.dwo"))
|
||||||
|
errs() << "BOLT-WARNING: Unsupported Debug section: " << Name << "\n";
|
||||||
|
return OutData;
|
||||||
|
}
|
||||||
|
case DWARFSectionKind::DW_SECT_INFO: {
|
||||||
|
OutData = getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_INFO,
|
||||||
|
DWPOffset);
|
||||||
|
SimpleBinaryPatcher *Patcher = Writer.getBinaryDWODebugInfoPatcher(DWOId);
|
||||||
|
return applyPatch(Patcher, OutData, DWPOffset);
|
||||||
|
}
|
||||||
|
case DWARFSectionKind::DW_SECT_EXT_TYPES: {
|
||||||
|
return getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_EXT_TYPES,
|
||||||
|
DWPOffset);
|
||||||
|
}
|
||||||
|
case DWARFSectionKind::DW_SECT_STR_OFFSETS: {
|
||||||
|
return getSliceData(DWOEntry, OutData,
|
||||||
|
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();
|
||||||
|
// 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());
|
||||||
|
}
|
||||||
|
case DWARFSectionKind::DW_SECT_LINE: {
|
||||||
|
return getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_LINE,
|
||||||
|
DWPOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void DWARFRewriter::writeDWP(
|
||||||
|
std::unordered_map<uint64_t, std::string> &DWOIdToName) {
|
||||||
|
std::string CompDir =
|
||||||
|
opts::DwarfOutputPath.empty() ? "." : opts::DwarfOutputPath.c_str();
|
||||||
|
auto FullPath = CompDir.append("/").append(opts::OutputFilename);
|
||||||
|
FullPath.append(".dwp");
|
||||||
|
std::error_code EC;
|
||||||
|
std::unique_ptr<ToolOutputFile> Out =
|
||||||
|
std::make_unique<ToolOutputFile>(FullPath, EC, sys::fs::OF_None);
|
||||||
|
|
||||||
|
const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile();
|
||||||
|
std::unique_ptr<BinaryContext> TmpBC = createDwarfOnlyBC(*File);
|
||||||
|
std::unique_ptr<MCStreamer> Streamer = TmpBC->createStreamer(Out->os());
|
||||||
|
const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo();
|
||||||
|
StringMap<KnownSectionsEntry> KnownSections = createKnownSectionsMap(MCOFI);
|
||||||
|
MCSection *const StrSection = MCOFI.getDwarfStrDWOSection();
|
||||||
|
MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection();
|
||||||
|
|
||||||
|
// Data Structures for DWP book keeping
|
||||||
|
// Size of array corresponds to the number of sections supported by DWO format
|
||||||
|
// in DWARF4/5.
|
||||||
|
uint32_t ContributionOffsets[8] = {};
|
||||||
|
std::deque<SmallString<32>> UncompressedSections;
|
||||||
|
DWPStringPool Strings(*Streamer, StrSection);
|
||||||
|
MapVector<uint64_t, UnitIndexEntry> IndexEntries;
|
||||||
|
constexpr uint32_t IndexVersion = 2;
|
||||||
|
|
||||||
// Setup DWP code once.
|
// Setup DWP code once.
|
||||||
DWARFContext *DWOCtx = BC.getDWOContext();
|
DWARFContext *DWOCtx = BC.getDWOContext();
|
||||||
const DWARFUnitIndex *CUIndex = nullptr;
|
const DWARFUnitIndex *CUIndex = nullptr;
|
||||||
@ -860,15 +996,117 @@ void DWARFRewriter::writeOutDWOFiles(
|
|||||||
if (!DWOId)
|
if (!DWOId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Skipping CUs that we failed to load.
|
||||||
Optional<DWARFUnit *> DWOCU = BC.getDWOCU(*DWOId);
|
Optional<DWARFUnit *> DWOCU = BC.getDWOCU(*DWOId);
|
||||||
if (!DWOCU)
|
if (!DWOCU)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const object::ObjectFile *File =
|
assert(CU->getVersion() == 4 && "For DWP output only DWARF4 is supported");
|
||||||
|
UnitIndexEntry CurEntry = {};
|
||||||
|
CurEntry.DWOName =
|
||||||
|
dwarf::toString(CU->getUnitDIE().find(
|
||||||
|
{dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
|
||||||
|
"");
|
||||||
|
const char *Name = CU->getUnitDIE().getShortName();
|
||||||
|
if (Name)
|
||||||
|
CurEntry.Name = Name;
|
||||||
|
StringRef CurStrSection;
|
||||||
|
StringRef CurStrOffsetSection;
|
||||||
|
|
||||||
|
// This maps each section contained in this file to its length.
|
||||||
|
// This information is later on used to calculate the contributions,
|
||||||
|
// i.e. offset and length, of each compile/type unit to a section.
|
||||||
|
std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLength;
|
||||||
|
|
||||||
|
const DWARFUnitIndex::Entry *DWOEntry = nullptr;
|
||||||
|
if (IsDWP)
|
||||||
|
DWOEntry = CUIndex->getFromHash(*DWOId);
|
||||||
|
|
||||||
|
bool StrSectionWrittenOut = false;
|
||||||
|
const object::ObjectFile *DWOFile =
|
||||||
(*DWOCU)->getContext().getDWARFObj().getFile();
|
(*DWOCU)->getContext().getDWARFObj().getFile();
|
||||||
std::string CompDir = opts::DwoOutputPath.empty()
|
for (const SectionRef &Section : DWOFile->sections()) {
|
||||||
|
std::string Storage = "";
|
||||||
|
std::unique_ptr<LocBufferVector> LocData;
|
||||||
|
Optional<StringRef> TOutData =
|
||||||
|
patchDebugData(Storage, Section, KnownSections, *Streamer, *this,
|
||||||
|
DWOEntry, *DWOId, LocData);
|
||||||
|
if (!TOutData)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StringRef OutData = *TOutData;
|
||||||
|
StringRef Name = getSectionName(Section);
|
||||||
|
if (Name.equals("debug_str.dwo"))
|
||||||
|
CurStrSection = OutData;
|
||||||
|
else {
|
||||||
|
// Since handleDebugDataPatching returned true, we already know this is
|
||||||
|
// a known section.
|
||||||
|
auto SectionIter = KnownSections.find(Name);
|
||||||
|
if (SectionIter->second.second == DWARFSectionKind::DW_SECT_STR_OFFSETS)
|
||||||
|
CurStrOffsetSection = OutData;
|
||||||
|
else
|
||||||
|
Streamer->emitBytes(OutData);
|
||||||
|
auto Index =
|
||||||
|
getContributionIndex(SectionIter->second.second, IndexVersion);
|
||||||
|
CurEntry.Contributions[Index].Offset = ContributionOffsets[Index];
|
||||||
|
CurEntry.Contributions[Index].Length = OutData.size();
|
||||||
|
ContributionOffsets[Index] += CurEntry.Contributions[Index].Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings are combined in to a new string section, and de-duplicated
|
||||||
|
// based on hash.
|
||||||
|
if (!StrSectionWrittenOut && !CurStrOffsetSection.empty() &&
|
||||||
|
!CurStrSection.empty()) {
|
||||||
|
writeStringsAndOffsets(*Streamer.get(), Strings, StrOffsetSection,
|
||||||
|
CurStrSection, CurStrOffsetSection,
|
||||||
|
CU->getVersion());
|
||||||
|
StrSectionWrittenOut = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompileUnitIdentifiers CUI{*DWOId, CurEntry.Name.c_str(),
|
||||||
|
CurEntry.DWOName.c_str()};
|
||||||
|
auto P = IndexEntries.insert(std::make_pair(CUI.Signature, CurEntry));
|
||||||
|
if (!P.second) {
|
||||||
|
Error Err = buildDuplicateError(*P.first, CUI, "");
|
||||||
|
errs() << "BOLT-ERROR: " << toString(std::move(Err)) << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lie about the type contribution for DWARF < 5. In DWARFv5 the type
|
||||||
|
// section does not exist, so no need to do anything about this.
|
||||||
|
ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0;
|
||||||
|
writeIndex(*Streamer.get(), MCOFI.getDwarfCUIndexSection(),
|
||||||
|
ContributionOffsets, IndexEntries, IndexVersion);
|
||||||
|
|
||||||
|
Streamer->Finish();
|
||||||
|
Out->keep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DWARFRewriter::writeDWOFiles(
|
||||||
|
std::unordered_map<uint64_t, std::string> &DWOIdToName) {
|
||||||
|
// 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)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skipping CUs that we failed to load.
|
||||||
|
Optional<DWARFUnit *> DWOCU = BC.getDWOCU(*DWOId);
|
||||||
|
if (!DWOCU)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string CompDir = opts::DwarfOutputPath.empty()
|
||||||
? CU->getCompilationDir()
|
? CU->getCompilationDir()
|
||||||
: opts::DwoOutputPath.c_str();
|
: opts::DwarfOutputPath.c_str();
|
||||||
std::string ObjectName = getDWOName(*CU.get(), nullptr, DWOIdToName);
|
std::string ObjectName = getDWOName(*CU.get(), nullptr, DWOIdToName);
|
||||||
auto FullPath = CompDir.append("/").append(ObjectName);
|
auto FullPath = CompDir.append("/").append(ObjectName);
|
||||||
|
|
||||||
@ -876,76 +1114,24 @@ void DWARFRewriter::writeOutDWOFiles(
|
|||||||
std::unique_ptr<ToolOutputFile> TempOut =
|
std::unique_ptr<ToolOutputFile> TempOut =
|
||||||
std::make_unique<ToolOutputFile>(FullPath, EC, sys::fs::OF_None);
|
std::make_unique<ToolOutputFile>(FullPath, EC, sys::fs::OF_None);
|
||||||
|
|
||||||
std::unique_ptr<BinaryContext> TmpBC = BinaryContext::createBinaryContext(
|
|
||||||
File, false,
|
|
||||||
DWARFContext::create(*File, nullptr, "", WithColor::defaultErrorHandler,
|
|
||||||
WithColor::defaultWarningHandler,
|
|
||||||
/*UsesRelocs=*/false));
|
|
||||||
std::unique_ptr<MCStreamer> Streamer = TmpBC->createStreamer(TempOut->os());
|
|
||||||
const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo();
|
|
||||||
|
|
||||||
const DWARFUnitIndex::Entry *DWOEntry = nullptr;
|
const DWARFUnitIndex::Entry *DWOEntry = nullptr;
|
||||||
if (IsDWP)
|
if (IsDWP)
|
||||||
DWOEntry = CUIndex->getFromHash(*DWOId);
|
DWOEntry = CUIndex->getFromHash(*DWOId);
|
||||||
|
|
||||||
const StringMap<MCSection *> KnownSections = {
|
const object::ObjectFile *File =
|
||||||
{".debug_info.dwo", MCOFI.getDwarfInfoDWOSection()},
|
(*DWOCU)->getContext().getDWARFObj().getFile();
|
||||||
{".debug_types.dwo", MCOFI.getDwarfTypesDWOSection()},
|
std::unique_ptr<BinaryContext> TmpBC = createDwarfOnlyBC(*File);
|
||||||
{".debug_str.dwo", MCOFI.getDwarfStrDWOSection()},
|
std::unique_ptr<MCStreamer> Streamer = TmpBC->createStreamer(TempOut->os());
|
||||||
{".debug_str_offsets.dwo", MCOFI.getDwarfStrOffDWOSection()},
|
StringMap<KnownSectionsEntry> KnownSections =
|
||||||
{".debug_abbrev.dwo", MCOFI.getDwarfAbbrevDWOSection()},
|
createKnownSectionsMap(*Streamer->getContext().getObjectFileInfo());
|
||||||
{".debug_loc.dwo", MCOFI.getDwarfLocDWOSection()},
|
|
||||||
{".debug_line.dwo", MCOFI.getDwarfLineDWOSection()}};
|
|
||||||
|
|
||||||
for (const SectionRef &Section : File->sections()) {
|
for (const SectionRef &Section : File->sections()) {
|
||||||
Expected<StringRef> SectionName = Section.getName();
|
std::string Storage = "";
|
||||||
assert(SectionName && "Invalid section name.");
|
std::unique_ptr<LocBufferVector> LocData;
|
||||||
auto SectionIter = KnownSections.find(*SectionName);
|
if (Optional<StringRef> OutData =
|
||||||
if (SectionIter == KnownSections.end())
|
patchDebugData(Storage, Section, KnownSections, *Streamer, *this,
|
||||||
continue;
|
DWOEntry, *DWOId, LocData))
|
||||||
Streamer->SwitchSection(SectionIter->second);
|
Streamer->emitBytes(*OutData);
|
||||||
Expected<StringRef> Contents = Section.getContents();
|
|
||||||
assert(Contents && "Invalid contents.");
|
|
||||||
StringRef OutData(*Contents);
|
|
||||||
std::unique_ptr<LocBufferVector> Data;
|
|
||||||
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
|
|
||||||
// with impicit conversion it will take null byte as end of
|
|
||||||
// string.
|
|
||||||
OutData = StringRef(reinterpret_cast<const char *>(Data->data()),
|
|
||||||
Data->size());
|
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
Streamer->Finish();
|
Streamer->Finish();
|
||||||
TempOut->keep();
|
TempOut->keep();
|
||||||
@ -956,8 +1142,8 @@ void DWARFRewriter::updateGdbIndexSection() {
|
|||||||
if (!BC.getGdbIndexSection())
|
if (!BC.getGdbIndexSection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html for
|
// See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
|
||||||
// .gdb_index section format.
|
// for .gdb_index section format.
|
||||||
|
|
||||||
StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents();
|
StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents();
|
||||||
|
|
||||||
@ -1056,9 +1242,8 @@ void DWARFRewriter::updateGdbIndexSection() {
|
|||||||
memcpy(Buffer, Data, TrailingSize);
|
memcpy(Buffer, Data, TrailingSize);
|
||||||
|
|
||||||
// Register the new section.
|
// Register the new section.
|
||||||
BC.registerOrUpdateNoteSection(".gdb_index",
|
BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents,
|
||||||
NewGdbIndexContents,
|
NewGdbIndexSize);
|
||||||
NewGdbIndexSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DWARFRewriter::convertToRanges(const DWARFAbbreviationDeclaration *Abbrev,
|
void DWARFRewriter::convertToRanges(const DWARFAbbreviationDeclaration *Abbrev,
|
||||||
@ -1067,10 +1252,10 @@ void DWARFRewriter::convertToRanges(const DWARFAbbreviationDeclaration *Abbrev,
|
|||||||
dwarf::Form LowPCForm = Abbrev->findAttribute(dwarf::DW_AT_low_pc)->Form;
|
dwarf::Form LowPCForm = Abbrev->findAttribute(dwarf::DW_AT_low_pc)->Form;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> Lock(AbbrevPatcherMutex);
|
std::lock_guard<std::mutex> Lock(AbbrevPatcherMutex);
|
||||||
// DW_FORM_GNU_addr_index is already variable encoding so nothing to do there.
|
// DW_FORM_GNU_addr_index is already variable encoding so nothing to do
|
||||||
// If HighForm is 8 bytes need to change low_pc to be variable encoding to
|
// there. If HighForm is 8 bytes need to change low_pc to be variable
|
||||||
// consume extra bytes from high_pc, since DW_FORM_sec_offset is 4 bytes for
|
// encoding to consume extra bytes from high_pc, since DW_FORM_sec_offset is
|
||||||
// DWARF32.
|
// 4 bytes for DWARF32.
|
||||||
if (LowPCForm != dwarf::DW_FORM_GNU_addr_index &&
|
if (LowPCForm != dwarf::DW_FORM_GNU_addr_index &&
|
||||||
isHighPcFormEightBytes(HighPCForm))
|
isHighPcFormEightBytes(HighPCForm))
|
||||||
AbbrevPatcher.addAttributePatch(Abbrev, dwarf::DW_AT_low_pc,
|
AbbrevPatcher.addAttributePatch(Abbrev, dwarf::DW_AT_low_pc,
|
||||||
@ -1149,7 +1334,7 @@ DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher) {
|
|||||||
auto LocBuffer = std::make_unique<LocBufferVector>();
|
auto LocBuffer = std::make_unique<LocBufferVector>();
|
||||||
auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
|
auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
|
||||||
auto Writer =
|
auto Writer =
|
||||||
std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));
|
std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));
|
||||||
|
|
||||||
uint64_t SectionOffset = 0;
|
uint64_t SectionOffset = 0;
|
||||||
|
|
||||||
@ -1207,10 +1392,9 @@ void DWARFRewriter::flushPendingRanges(SimpleBinaryPatcher &DebugInfoPatcher) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void getRangeAttrData(
|
void getRangeAttrData(DWARFDie DIE, uint64_t &LowPCOffset,
|
||||||
DWARFDie DIE,
|
uint64_t &HighPCOffset, DWARFFormValue &LowPCFormValue,
|
||||||
uint64_t &LowPCOffset, uint64_t &HighPCOffset,
|
DWARFFormValue &HighPCFormValue) {
|
||||||
DWARFFormValue &LowPCFormValue, DWARFFormValue &HighPCFormValue) {
|
|
||||||
LowPCOffset = -1U;
|
LowPCOffset = -1U;
|
||||||
HighPCOffset = -1U;
|
HighPCOffset = -1U;
|
||||||
LowPCFormValue = *DIE.find(dwarf::DW_AT_low_pc, &LowPCOffset);
|
LowPCFormValue = *DIE.find(dwarf::DW_AT_low_pc, &LowPCOffset);
|
||||||
@ -1234,14 +1418,14 @@ void getRangeAttrData(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
void DWARFRewriter::patchLowHigh(DWARFDie DIE, DebugAddressRange Range,
|
void DWARFRewriter::patchLowHigh(DWARFDie DIE, DebugAddressRange Range,
|
||||||
SimpleBinaryPatcher &DebugInfoPatcher) {
|
SimpleBinaryPatcher &DebugInfoPatcher) {
|
||||||
uint64_t LowPCOffset, HighPCOffset;
|
uint64_t LowPCOffset, HighPCOffset;
|
||||||
DWARFFormValue LowPCFormValue, HighPCFormValue;
|
DWARFFormValue LowPCFormValue, HighPCFormValue;
|
||||||
getRangeAttrData(
|
getRangeAttrData(DIE, LowPCOffset, HighPCOffset, LowPCFormValue,
|
||||||
DIE, LowPCOffset, HighPCOffset, LowPCFormValue, HighPCFormValue);
|
HighPCFormValue);
|
||||||
auto *TempDebugPatcher = &DebugInfoPatcher;
|
auto *TempDebugPatcher = &DebugInfoPatcher;
|
||||||
if (LowPCFormValue.getForm() == dwarf::DW_FORM_GNU_addr_index) {
|
if (LowPCFormValue.getForm() == dwarf::DW_FORM_GNU_addr_index) {
|
||||||
DWARFUnit *Unit = DIE.getDwarfUnit();
|
DWARFUnit *Unit = DIE.getDwarfUnit();
|
||||||
|
@ -114,7 +114,11 @@ class DWARFRewriter {
|
|||||||
void updateGdbIndexSection();
|
void updateGdbIndexSection();
|
||||||
|
|
||||||
/// Output .dwo files.
|
/// Output .dwo files.
|
||||||
void writeOutDWOFiles(std::unordered_map<uint64_t, std::string> &DWOIdToName);
|
void writeDWOFiles(std::unordered_map<uint64_t, std::string> &DWOIdToName);
|
||||||
|
|
||||||
|
/// Output .dwp files.
|
||||||
|
void writeDWP(std::unordered_map<uint64_t, std::string> &DWOIdToName);
|
||||||
|
|
||||||
/// Abbreviations that were converted to use DW_AT_ranges.
|
/// Abbreviations that were converted to use DW_AT_ranges.
|
||||||
std::set<const DWARFAbbreviationDeclaration *> ConvertedRangesAbbrevs;
|
std::set<const DWARFAbbreviationDeclaration *> ConvertedRangesAbbrevs;
|
||||||
|
|
||||||
@ -221,6 +225,13 @@ public:
|
|||||||
DebugAbbrevPatcher>(
|
DebugAbbrevPatcher>(
|
||||||
BinaryDWOAbbrevPatchers, DwoId);
|
BinaryDWOAbbrevPatchers, DwoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a DWO ID, return its DebugLocWriter if it exists.
|
||||||
|
DebugLocWriter *getDebugLocWriter(uint64_t DWOId) {
|
||||||
|
auto Iter = LocListWritersByCU.find(DWOId);
|
||||||
|
return Iter == LocListWritersByCU.end() ? nullptr
|
||||||
|
: LocListWritersByCU[DWOId].get();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace bolt
|
} // namespace bolt
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
# RUN: llvm-mc -g -filetype=obj -triple x86_64-unknown-unknown --split-dwarf-file=debug-fission-simple.dwo \
|
# RUN: llvm-mc -g -filetype=obj -triple x86_64-unknown-unknown --split-dwarf-file=debug-fission-simple.dwo \
|
||||||
# RUN: ./debug-fission-simple.s -o ./debug-fission-simple.o
|
# RUN: ./debug-fission-simple.s -o ./debug-fission-simple.o
|
||||||
# RUN: %host_cxx %cxxflags -g -Wl,--gc-sections,-q,-nostdlib -Wl,--undefined=_Z6_startv -nostartfiles -Wl,--script=debug-fission-script.txt ./debug-fission-simple.o -o out.exe
|
# RUN: %host_cxx %cxxflags -g -Wl,--gc-sections,-q,-nostdlib -Wl,--undefined=_Z6_startv -nostartfiles -Wl,--script=debug-fission-script.txt ./debug-fission-simple.o -o out.exe
|
||||||
# RUN: llvm-bolt out.exe --reorder-blocks=reverse -update-debug-sections -dwo-output-path=%t.dir -o out.bolt
|
# RUN: llvm-bolt out.exe --reorder-blocks=reverse -update-debug-sections -dwarf-output-path=%t.dir -o out.bolt
|
||||||
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.dir/debug-fission-simple.dwo0.dwo | grep DW_FORM_GNU_addr_index | FileCheck %s --check-prefix=CHECK-ADDR-INDEX
|
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.dir/debug-fission-simple.dwo0.dwo | grep DW_FORM_GNU_addr_index | FileCheck %s --check-prefix=CHECK-ADDR-INDEX
|
||||||
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr out.bolt | FileCheck %s --check-prefix=CHECK-ADDR-SEC
|
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr out.bolt | FileCheck %s --check-prefix=CHECK-ADDR-SEC
|
||||||
|
# RUN: llvm-bolt out.exe --reorder-blocks=reverse -update-debug-sections -dwarf-output-path=%t.dir -o out.bolt -write-out-dwp=true
|
||||||
|
# RUN: llvm-dwarfdump --show-form --verbose --debug-info out.bolt.dwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG
|
||||||
|
|
||||||
# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000001)
|
# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000001)
|
||||||
# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000002)
|
# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000002)
|
||||||
@ -21,6 +23,15 @@
|
|||||||
# CHECK-ADDR-SEC: 0x0000000000000000
|
# CHECK-ADDR-SEC: 0x0000000000000000
|
||||||
# CHECK-ADDR-SEC: 0x0000000000a00040
|
# CHECK-ADDR-SEC: 0x0000000000a00040
|
||||||
|
|
||||||
|
|
||||||
|
# CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] *
|
||||||
|
# CHECK-DWP-DEBUG: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (0000000a) string = "clang version 13.0.0")
|
||||||
|
# CHECK-DWP-DEBUG: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
|
||||||
|
# CHECK-DWP-DEBUG: DW_AT_name [DW_FORM_GNU_str_index] (indexed (0000000b) string = "foo")
|
||||||
|
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (0000000c) string = "foo")
|
||||||
|
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x06105e732fad3796)
|
||||||
|
|
||||||
|
|
||||||
//clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s
|
//clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s
|
||||||
static int foo = 2;
|
static int foo = 2;
|
||||||
int doStuff(int val) {
|
int doStuff(int val) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user