summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo')
-rw-r--r--llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp2
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp16
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp6
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp8
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFContext.cpp154
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp4
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp121
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp524
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp76
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp13
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDie.cpp96
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp2
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp7
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp19
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp163
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp80
-rw-r--r--llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp106
-rw-r--r--llvm/lib/DebugInfo/GSYM/GsymReader.cpp22
-rw-r--r--llvm/lib/DebugInfo/GSYM/InlineInfo.cpp110
-rw-r--r--llvm/lib/DebugInfo/GSYM/LineTable.cpp12
-rw-r--r--llvm/lib/DebugInfo/GSYM/LookupResult.cpp69
-rw-r--r--llvm/lib/DebugInfo/GSYM/Range.cpp12
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp7
-rw-r--r--llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp15
-rw-r--r--llvm/lib/DebugInfo/Symbolize/Symbolize.cpp94
25 files changed, 1204 insertions, 534 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp b/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
index 51a5a9e9243e..2562c633bb99 100644
--- a/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
@@ -14,7 +14,7 @@
using namespace llvm;
using namespace llvm::codeview;
-template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
+template <typename RecordT> static RecordT createRecord(const CVSymbol &sym) {
RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
return record;
diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
index aba0e96d606e..f9fca74a2199 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -15,6 +15,7 @@
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/Support/Error.h"
using namespace llvm;
@@ -202,21 +203,6 @@ private:
const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
-static bool isIdRecord(TypeLeafKind K) {
- switch (K) {
- case TypeLeafKind::LF_FUNC_ID:
- case TypeLeafKind::LF_MFUNC_ID:
- case TypeLeafKind::LF_STRING_ID:
- case TypeLeafKind::LF_SUBSTR_LIST:
- case TypeLeafKind::LF_BUILDINFO:
- case TypeLeafKind::LF_UDT_SRC_LINE:
- case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
- return true;
- default:
- return false;
- }
-}
-
void TypeStreamMerger::addMapping(TypeIndex Idx) {
if (!IsSecondPass) {
assert(IndexMap.size() == slotForIndex(CurIndex) &&
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 875f5e9989a0..575edba51ee8 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -277,7 +277,7 @@ Optional<DWARFFormValue>
AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
assert(HdrData && "Dereferencing end iterator?");
assert(HdrData->Atoms.size() == Values.size());
- for (const auto &Tuple : zip_first(HdrData->Atoms, Values)) {
+ for (auto Tuple : zip_first(HdrData->Atoms, Values)) {
if (std::get<0>(Tuple).first == Atom)
return std::get<1>(Tuple);
}
@@ -531,7 +531,7 @@ DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
Optional<DWARFFormValue>
DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
assert(Abbr->Attributes.size() == Values.size());
- for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+ for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
if (std::get<0>(Tuple).Index == Index)
return std::get<1>(Tuple);
}
@@ -565,7 +565,7 @@ void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
W.printHex("Abbrev", Abbr->Code);
W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
assert(Abbr->Attributes.size() == Values.size());
- for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+ for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index);
std::get<1>(Tuple).dump(W.getOStream());
W.getOStream() << '\n';
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
index ef6da08d34aa..ddf307de2221 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
@@ -7,19 +7,23 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
-
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize,
- DIDumpOptions DumpOpts) const {
+ DIDumpOptions DumpOpts,
+ const DWARFObject *Obj) const {
OS << (DumpOpts.DisplayRawContents ? " " : "[");
OS << format("0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC)
<< format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2, HighPC);
OS << (DumpOpts.DisplayRawContents ? "" : ")");
+
+ if (Obj)
+ DWARFFormValue::dumpAddressSection(*Obj, OS, DumpOpts, SectionIndex);
}
raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index c06d85d50609..aaa6d5250f23 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -288,6 +288,7 @@ static void dumpRnglistsSection(
static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
DWARFDataExtractor Data,
const MCRegisterInfo *MRI,
+ const DWARFObject &Obj,
Optional<uint64_t> DumpOffset) {
uint64_t Offset = 0;
@@ -299,13 +300,21 @@ static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
}
Header.dump(OS, DumpOpts);
- DataExtractor LocData(Data.getData(),
- Data.isLittleEndian(), Header.getAddrSize());
- DWARFDebugLoclists Loclists;
uint64_t EndOffset = Header.length() + Header.getHeaderOffset();
- Loclists.parse(LocData, Offset, EndOffset, Header.getVersion());
- Loclists.dump(OS, 0, MRI, DumpOpts, DumpOffset);
+ Data.setAddressSize(Header.getAddrSize());
+ DWARFDebugLoclists Loc(Data, Header.getVersion());
+ if (DumpOffset) {
+ if (DumpOffset >= Offset && DumpOffset < EndOffset) {
+ Offset = *DumpOffset;
+ Loc.dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, nullptr,
+ DumpOpts, /*Indent=*/0);
+ OS << "\n";
+ return;
+ }
+ } else {
+ Loc.dumpRange(Offset, EndOffset - Offset, OS, MRI, Obj, DumpOpts);
+ }
Offset = EndOffset;
}
}
@@ -380,21 +389,45 @@ void DWARFContext::dump(
dumpDebugType(".debug_types.dwo", dwo_types_section_units());
}
+ DIDumpOptions LLDumpOpts = DumpOpts;
+ if (LLDumpOpts.Verbose)
+ LLDumpOpts.DisplayRawContents = true;
+
if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
DObj->getLocSection().Data)) {
- getDebugLoc()->dump(OS, getRegisterInfo(), DumpOpts, *Off);
+ getDebugLoc()->dump(OS, getRegisterInfo(), *DObj, LLDumpOpts, *Off);
}
if (const auto *Off =
shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists,
DObj->getLoclistsSection().Data)) {
DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(),
0);
- dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), *Off);
+ dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off);
+ }
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_loclists.dwo", DIDT_ID_DebugLoclists,
+ DObj->getLoclistsDWOSection().Data)) {
+ DWARFDataExtractor Data(*DObj, DObj->getLoclistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off);
}
+
if (const auto *Off =
shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
DObj->getLocDWOSection().Data)) {
- getDebugLocDWO()->dump(OS, 0, getRegisterInfo(), DumpOpts, *Off);
+ DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(),
+ 4);
+ DWARFDebugLoclists Loc(Data, /*Version=*/4);
+ if (*Off) {
+ uint64_t Offset = **Off;
+ Loc.dumpLocationList(&Offset, OS,
+ /*BaseAddr=*/None, getRegisterInfo(), *DObj, nullptr,
+ LLDumpOpts, /*Indent=*/0);
+ OS << "\n";
+ } else {
+ Loc.dumpRange(0, Data.getData().size(), OS, getRegisterInfo(), *DObj,
+ LLDumpOpts);
+ }
}
if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
@@ -409,6 +442,9 @@ void DWARFContext::dump(
if (Explicit || !getDebugMacro()->empty()) {
OS << "\n.debug_macinfo contents:\n";
getDebugMacro()->dump(OS);
+ } else if (ExplicitDWO || !getDebugMacroDWO()->empty()) {
+ OS << "\n.debug_macinfo.dwo contents:\n";
+ getDebugMacroDWO()->dump(OS);
}
}
@@ -715,32 +751,16 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
if (Loc)
return Loc.get();
- Loc.reset(new DWARFDebugLoc);
// Assume all units have the same address byte size.
- if (getNumCompileUnits()) {
- DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
- getUnitAtIndex(0)->getAddressByteSize());
- Loc->parse(LocData);
- }
+ auto LocData =
+ getNumCompileUnits()
+ ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(),
+ getUnitAtIndex(0)->getAddressByteSize())
+ : DWARFDataExtractor("", isLittleEndian(), 0);
+ Loc.reset(new DWARFDebugLoc(std::move(LocData)));
return Loc.get();
}
-const DWARFDebugLoclists *DWARFContext::getDebugLocDWO() {
- if (LocDWO)
- return LocDWO.get();
-
- LocDWO.reset(new DWARFDebugLoclists());
- // Assume all compile units have the same address byte size.
- // FIXME: We don't need AddressSize for split DWARF since relocatable
- // addresses cannot appear there. At the moment DWARFExpression requires it.
- DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 4);
- // Use version 4. DWO does not support the DWARF v5 .debug_loclists yet and
- // that means we are parsing the new style .debug_loc (pre-standatized version
- // of the .debug_loclists).
- LocDWO->parse(LocData, 0, LocData.getData().size(), 4 /* Version */);
- return LocDWO.get();
-}
-
const DWARFDebugAranges *DWARFContext::getDebugAranges() {
if (Aranges)
return Aranges.get();
@@ -781,6 +801,17 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() {
return DebugFrame.get();
}
+const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() {
+ if (MacroDWO)
+ return MacroDWO.get();
+
+ DataExtractor MacinfoDWOData(DObj->getMacinfoDWOSection(), isLittleEndian(),
+ 0);
+ MacroDWO.reset(new DWARFDebugMacro());
+ MacroDWO->parse(MacinfoDWOData);
+ return MacroDWO.get();
+}
+
const DWARFDebugMacro *DWARFContext::getDebugMacro() {
if (Macro)
return Macro.get();
@@ -843,7 +874,7 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
}
Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
- DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+ DWARFUnit *U, function_ref<void(Error)> RecoverableErrorCallback) {
if (!Line)
Line.reset(new DWARFDebugLine);
@@ -1027,19 +1058,56 @@ static Optional<uint64_t> getTypeSize(DWARFDie Type, uint64_t PointerSize) {
return Optional<uint64_t>();
}
+static Optional<int64_t>
+getExpressionFrameOffset(ArrayRef<uint8_t> Expr,
+ Optional<unsigned> FrameBaseReg) {
+ if (!Expr.empty() &&
+ (Expr[0] == DW_OP_fbreg ||
+ (FrameBaseReg && Expr[0] == DW_OP_breg0 + *FrameBaseReg))) {
+ unsigned Count;
+ int64_t Offset = decodeSLEB128(Expr.data() + 1, &Count, Expr.end());
+ // A single DW_OP_fbreg or DW_OP_breg.
+ if (Expr.size() == Count + 1)
+ return Offset;
+ // Same + DW_OP_deref (Fortran arrays look like this).
+ if (Expr.size() == Count + 2 && Expr[Count + 1] == DW_OP_deref)
+ return Offset;
+ // Fallthrough. Do not accept ex. (DW_OP_breg W29, DW_OP_stack_value)
+ }
+ return None;
+}
+
void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram,
DWARFDie Die, std::vector<DILocal> &Result) {
if (Die.getTag() == DW_TAG_variable ||
Die.getTag() == DW_TAG_formal_parameter) {
DILocal Local;
- if (auto NameAttr = Subprogram.find(DW_AT_name))
- if (Optional<const char *> Name = NameAttr->getAsCString())
- Local.FunctionName = *Name;
- if (auto LocationAttr = Die.find(DW_AT_location))
- if (Optional<ArrayRef<uint8_t>> Location = LocationAttr->getAsBlock())
- if (!Location->empty() && (*Location)[0] == DW_OP_fbreg)
- Local.FrameOffset =
- decodeSLEB128(Location->data() + 1, nullptr, Location->end());
+ if (const char *Name = Subprogram.getSubroutineName(DINameKind::ShortName))
+ Local.FunctionName = Name;
+
+ Optional<unsigned> FrameBaseReg;
+ if (auto FrameBase = Subprogram.find(DW_AT_frame_base))
+ if (Optional<ArrayRef<uint8_t>> Expr = FrameBase->getAsBlock())
+ if (!Expr->empty() && (*Expr)[0] >= DW_OP_reg0 &&
+ (*Expr)[0] <= DW_OP_reg31) {
+ FrameBaseReg = (*Expr)[0] - DW_OP_reg0;
+ }
+
+ if (Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location)) {
+ for (const auto &Entry : *Loc) {
+ if (Optional<int64_t> FrameOffset =
+ getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) {
+ Local.FrameOffset = *FrameOffset;
+ break;
+ }
+ }
+ } else {
+ // FIXME: missing DW_AT_location is OK here, but other errors should be
+ // reported to the user.
+ consumeError(Loc.takeError());
+ }
+
if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset))
Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant();
@@ -1377,6 +1445,7 @@ class DWARFObjInMemory final : public DWARFObject {
DWARFSectionMap LocSection;
DWARFSectionMap LoclistsSection;
+ DWARFSectionMap LoclistsDWOSection;
DWARFSectionMap LineSection;
DWARFSectionMap RangesSection;
DWARFSectionMap RnglistsSection;
@@ -1403,6 +1472,7 @@ class DWARFObjInMemory final : public DWARFObject {
return StringSwitch<DWARFSectionMap *>(Name)
.Case("debug_loc", &LocSection)
.Case("debug_loclists", &LoclistsSection)
+ .Case("debug_loclists.dwo", &LoclistsDWOSection)
.Case("debug_line", &LineSection)
.Case("debug_frame", &FrameSection)
.Case("eh_frame", &EHFrameSection)
@@ -1431,6 +1501,7 @@ class DWARFObjInMemory final : public DWARFObject {
StringRef ArangesSection;
StringRef StrSection;
StringRef MacinfoSection;
+ StringRef MacinfoDWOSection;
StringRef AbbrevDWOSection;
StringRef StrDWOSection;
StringRef CUIndexSection;
@@ -1450,6 +1521,7 @@ class DWARFObjInMemory final : public DWARFObject {
.Case("debug_aranges", &ArangesSection)
.Case("debug_str", &StrSection)
.Case("debug_macinfo", &MacinfoSection)
+ .Case("debug_macinfo.dwo", &MacinfoDWOSection)
.Case("debug_abbrev.dwo", &AbbrevDWOSection)
.Case("debug_str.dwo", &StrDWOSection)
.Case("debug_cu_index", &CUIndexSection)
@@ -1733,6 +1805,9 @@ public:
const DWARFSection &getRnglistsDWOSection() const override {
return RnglistsDWOSection;
}
+ const DWARFSection &getLoclistsDWOSection() const override {
+ return LoclistsDWOSection;
+ }
const DWARFSection &getAddrSection() const override { return AddrSection; }
StringRef getCUIndexSection() const override { return CUIndexSection; }
StringRef getGdbIndexSection() const override { return GdbIndexSection; }
@@ -1773,6 +1848,7 @@ public:
return RnglistsSection;
}
StringRef getMacinfoSection() const override { return MacinfoSection; }
+ StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; }
const DWARFSection &getPubnamesSection() const override { return PubnamesSection; }
const DWARFSection &getPubtypesSection() const override { return PubtypesSection; }
const DWARFSection &getGnuPubnamesSection() const override {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
index ca6043109cdb..fa157e868851 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -113,10 +113,10 @@ void DWARFDebugAranges::construct() {
Endpoints.shrink_to_fit();
}
-uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const {
+uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const {
RangeCollIterator It =
partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; });
if (It != Aranges.end() && It->LowPC <= Address)
return It->CUOffset;
- return -1U;
+ return -1ULL;
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index dbee28ff5ab1..11adb1e47640 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -39,7 +39,7 @@ struct ContentDescriptor {
using ContentDescriptors = SmallVector<ContentDescriptor, 4>;
-} // end anonmyous namespace
+} // end anonymous namespace
void DWARFDebugLine::ContentTypeTracker::trackContentType(
dwarf::LineNumberEntryFormat ContentType) {
@@ -190,20 +190,11 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
// the end of the prologue.
static llvm::Expected<ContentDescriptors>
parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
- uint64_t EndPrologueOffset,
DWARFDebugLine::ContentTypeTracker *ContentTypes) {
ContentDescriptors Descriptors;
int FormatCount = DebugLineData.getU8(OffsetPtr);
bool HasPath = false;
for (int I = 0; I != FormatCount; ++I) {
- if (*OffsetPtr >= EndPrologueOffset)
- return createStringError(
- errc::invalid_argument,
- "failed to parse entry content descriptions at offset "
- "0x%8.8" PRIx64
- " because offset extends beyond the prologue end at offset "
- "0x%8.8" PRIx64,
- *OffsetPtr, EndPrologueOffset);
ContentDescriptor Descriptor;
Descriptor.Type =
dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
@@ -224,29 +215,20 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
static Error
parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
- uint64_t *OffsetPtr, uint64_t EndPrologueOffset,
- const dwarf::FormParams &FormParams,
+ uint64_t *OffsetPtr, const dwarf::FormParams &FormParams,
const DWARFContext &Ctx, const DWARFUnit *U,
DWARFDebugLine::ContentTypeTracker &ContentTypes,
std::vector<DWARFFormValue> &IncludeDirectories,
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
// Get the directory entry description.
llvm::Expected<ContentDescriptors> DirDescriptors =
- parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr);
+ parseV5EntryFormat(DebugLineData, OffsetPtr, nullptr);
if (!DirDescriptors)
return DirDescriptors.takeError();
// Get the directory entries, according to the format described above.
int DirEntryCount = DebugLineData.getU8(OffsetPtr);
for (int I = 0; I != DirEntryCount; ++I) {
- if (*OffsetPtr >= EndPrologueOffset)
- return createStringError(
- errc::invalid_argument,
- "failed to parse directory entry at offset "
- "0x%8.8" PRIx64
- " because offset extends beyond the prologue end at offset "
- "0x%8.8" PRIx64,
- *OffsetPtr, EndPrologueOffset);
for (auto Descriptor : *DirDescriptors) {
DWARFFormValue Value(Descriptor.Form);
switch (Descriptor.Type) {
@@ -267,22 +249,14 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
}
// Get the file entry description.
- llvm::Expected<ContentDescriptors> FileDescriptors = parseV5EntryFormat(
- DebugLineData, OffsetPtr, EndPrologueOffset, &ContentTypes);
+ llvm::Expected<ContentDescriptors> FileDescriptors =
+ parseV5EntryFormat(DebugLineData, OffsetPtr, &ContentTypes);
if (!FileDescriptors)
return FileDescriptors.takeError();
// Get the file entries, according to the format described above.
int FileEntryCount = DebugLineData.getU8(OffsetPtr);
for (int I = 0; I != FileEntryCount; ++I) {
- if (*OffsetPtr >= EndPrologueOffset)
- return createStringError(
- errc::invalid_argument,
- "failed to parse file entry at offset "
- "0x%8.8" PRIx64
- " because offset extends beyond the prologue end at offset "
- "0x%8.8" PRIx64,
- *OffsetPtr, EndPrologueOffset);
DWARFDebugLine::FileNameEntry FileEntry;
for (auto Descriptor : *FileDescriptors) {
DWARFFormValue Value(Descriptor.Form);
@@ -373,9 +347,9 @@ Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
}
if (getVersion() >= 5) {
- if (Error e = parseV5DirFileTables(
- DebugLineData, OffsetPtr, EndPrologueOffset, FormParams, Ctx, U,
- ContentTypes, IncludeDirectories, FileNames)) {
+ if (Error E =
+ parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U,
+ ContentTypes, IncludeDirectories, FileNames)) {
return joinErrors(
createStringError(
errc::invalid_argument,
@@ -383,7 +357,7 @@ Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
" found an invalid directory or file table description at"
" 0x%8.8" PRIx64,
PrologueOffset, *OffsetPtr),
- std::move(e));
+ std::move(E));
}
} else
parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
@@ -453,14 +427,18 @@ DWARFDebugLine::LineTable::LineTable() { clear(); }
void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
DIDumpOptions DumpOptions) const {
Prologue.dump(OS, DumpOptions);
- OS << '\n';
if (!Rows.empty()) {
+ OS << '\n';
Row::dumpTableHeader(OS);
for (const Row &R : Rows) {
R.dump(OS);
}
}
+
+ // Terminate the table with a final blank line to clearly delineate it from
+ // later dumps.
+ OS << '\n';
}
void DWARFDebugLine::LineTable::clear() {
@@ -510,7 +488,7 @@ DWARFDebugLine::getLineTable(uint64_t Offset) const {
Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx,
- const DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+ const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorCallback) {
if (!DebugLineData.isValidOffset(Offset))
return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64
" is not a valid debug line section offset",
@@ -531,7 +509,7 @@ Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
Error DWARFDebugLine::LineTable::parse(
DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
const DWARFContext &Ctx, const DWARFUnit *U,
- std::function<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
+ function_ref<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
const uint64_t DebugLineOffset = *OffsetPtr;
clear();
@@ -548,8 +526,23 @@ Error DWARFDebugLine::LineTable::parse(
if (PrologueErr)
return PrologueErr;
- const uint64_t EndOffset =
- DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength();
+ uint64_t ProgramLength = Prologue.TotalLength + Prologue.sizeofTotalLength();
+ if (!DebugLineData.isValidOffsetForDataOfSize(DebugLineOffset,
+ ProgramLength)) {
+ assert(DebugLineData.size() > DebugLineOffset &&
+ "prologue parsing should handle invalid offset");
+ uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset;
+ RecoverableErrorCallback(
+ createStringError(errc::invalid_argument,
+ "line table program with offset 0x%8.8" PRIx64
+ " has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64
+ " bytes are available",
+ DebugLineOffset, ProgramLength, BytesRemaining));
+ // Continue by capping the length at the number of remaining bytes.
+ ProgramLength = BytesRemaining;
+ }
+
+ const uint64_t EndOffset = DebugLineOffset + ProgramLength;
// See if we should tell the data extractor the address size.
if (DebugLineData.getAddressSize() == 0)
@@ -595,12 +588,12 @@ Error DWARFDebugLine::LineTable::parse(
// address is that of the byte after the last target machine instruction
// of the sequence.
State.Row.EndSequence = true;
- State.appendRowToMatrix();
if (OS) {
*OS << "\n";
OS->indent(12);
State.Row.dump(*OS);
}
+ State.appendRowToMatrix();
State.resetRowAndSequence();
break;
@@ -614,19 +607,28 @@ Error DWARFDebugLine::LineTable::parse(
//
// Make sure the extractor knows the address size. If not, infer it
// from the size of the operand.
- if (DebugLineData.getAddressSize() == 0)
+ {
+ uint8_t ExtractorAddressSize = DebugLineData.getAddressSize();
+ if (ExtractorAddressSize != Len - 1 && ExtractorAddressSize != 0)
+ RecoverableErrorCallback(createStringError(
+ errc::invalid_argument,
+ "mismatching address size at offset 0x%8.8" PRIx64
+ " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
+ ExtOffset, ExtractorAddressSize, Len - 1));
+
+ // Assume that the line table is correct and temporarily override the
+ // address size.
DebugLineData.setAddressSize(Len - 1);
- else if (DebugLineData.getAddressSize() != Len - 1) {
- return createStringError(errc::invalid_argument,
- "mismatching address size at offset 0x%8.8" PRIx64
- " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
- ExtOffset, DebugLineData.getAddressSize(),
- Len - 1);
+ State.Row.Address.Address = DebugLineData.getRelocatedAddress(
+ OffsetPtr, &State.Row.Address.SectionIndex);
+
+ // Restore the address size if the extractor already had it.
+ if (ExtractorAddressSize != 0)
+ DebugLineData.setAddressSize(ExtractorAddressSize);
+
+ if (OS)
+ *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address.Address);
}
- State.Row.Address.Address = DebugLineData.getRelocatedAddress(
- OffsetPtr, &State.Row.Address.SectionIndex);
- if (OS)
- *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address.Address);
break;
case DW_LNE_define_file:
@@ -813,7 +815,7 @@ Error DWARFDebugLine::LineTable::parse(
// column register of the state machine.
State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
if (OS)
- *OS << " (" << State.Row.Isa << ")";
+ *OS << " (" << (uint64_t)State.Row.Isa << ")";
break;
default:
@@ -888,9 +890,11 @@ Error DWARFDebugLine::LineTable::parse(
}
if (!State.Sequence.Empty)
- RecoverableErrorCallback(
- createStringError(errc::illegal_byte_sequence,
- "last sequence in debug line table is not terminated!"));
+ RecoverableErrorCallback(createStringError(
+ errc::illegal_byte_sequence,
+ "last sequence in debug line table at offset 0x%8.8" PRIx64
+ " is not terminated",
+ DebugLineOffset));
// Sort all sequences so that address lookup will work faster.
if (!Sequences.empty()) {
@@ -1046,7 +1050,10 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
return false;
const FileNameEntry &Entry = getFileNameEntry(FileIndex);
- StringRef FileName = Entry.Name.getAsCString().getValue();
+ Optional<const char *> Name = Entry.Name.getAsCString();
+ if (!Name)
+ return false;
+ StringRef FileName = *Name;
if (Kind != FileLineInfoKind::AbsoluteFilePath ||
isPathAbsoluteOnWindowsOrPosix(FileName)) {
Result = FileName;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index 4f7b01130a47..0c5f9a9c54ec 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -22,6 +22,89 @@
#include <cstdint>
using namespace llvm;
+using object::SectionedAddress;
+
+namespace {
+class DWARFLocationInterpreter {
+ Optional<object::SectionedAddress> Base;
+ std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr;
+
+public:
+ DWARFLocationInterpreter(
+ Optional<object::SectionedAddress> Base,
+ std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr)
+ : Base(Base), LookupAddr(std::move(LookupAddr)) {}
+
+ Expected<Optional<DWARFLocationExpression>>
+ Interpret(const DWARFLocationEntry &E);
+};
+} // namespace
+
+static Error createResolverError(uint32_t Index, unsigned Kind) {
+ return createStringError(errc::invalid_argument,
+ "Unable to resolve indirect address %u for: %s",
+ Index, dwarf::LocListEncodingString(Kind).data());
+}
+
+Expected<Optional<DWARFLocationExpression>>
+DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) {
+ switch (E.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ return None;
+ case dwarf::DW_LLE_base_addressx: {
+ Base = LookupAddr(E.Value0);
+ if (!Base)
+ return createResolverError(E.Value0, E.Kind);
+ return None;
+ }
+ case dwarf::DW_LLE_startx_endx: {
+ Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
+ if (!LowPC)
+ return createResolverError(E.Value0, E.Kind);
+ Optional<SectionedAddress> HighPC = LookupAddr(E.Value1);
+ if (!HighPC)
+ return createResolverError(E.Value1, E.Kind);
+ return DWARFLocationExpression{
+ DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex},
+ E.Loc};
+ }
+ case dwarf::DW_LLE_startx_length: {
+ Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
+ if (!LowPC)
+ return createResolverError(E.Value0, E.Kind);
+ return DWARFLocationExpression{DWARFAddressRange{LowPC->Address,
+ LowPC->Address + E.Value1,
+ LowPC->SectionIndex},
+ E.Loc};
+ }
+ case dwarf::DW_LLE_offset_pair: {
+ if (!Base) {
+ return createStringError(inconvertibleErrorCode(),
+ "Unable to resolve location list offset pair: "
+ "Base address not defined");
+ }
+ DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1,
+ Base->SectionIndex};
+ if (Range.SectionIndex == SectionedAddress::UndefSection)
+ Range.SectionIndex = E.SectionIndex;
+ return DWARFLocationExpression{Range, E.Loc};
+ }
+ case dwarf::DW_LLE_default_location:
+ return DWARFLocationExpression{None, E.Loc};
+ case dwarf::DW_LLE_base_address:
+ Base = SectionedAddress{E.Value0, E.SectionIndex};
+ return None;
+ case dwarf::DW_LLE_start_end:
+ return DWARFLocationExpression{
+ DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc};
+ case dwarf::DW_LLE_start_length:
+ return DWARFLocationExpression{
+ DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex},
+ E.Loc};
+ default:
+ llvm_unreachable("unreachable locations list kind");
+ }
+}
// When directly dumping the .debug_loc without a compile unit, we have to guess
// at the DWARF version. This only affects DW_OP_call_ref, which is a rare
@@ -35,126 +118,180 @@ static void dumpExpression(raw_ostream &OS, ArrayRef<uint8_t> Data,
DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U);
}
-void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, uint64_t BaseAddress,
- bool IsLittleEndian,
- unsigned AddressSize,
- const MCRegisterInfo *MRI, DWARFUnit *U,
- DIDumpOptions DumpOpts,
- unsigned Indent) const {
- for (const Entry &E : Entries) {
- OS << '\n';
+bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS,
+ Optional<SectionedAddress> BaseAddr,
+ const MCRegisterInfo *MRI,
+ const DWARFObject &Obj, DWARFUnit *U,
+ DIDumpOptions DumpOpts,
+ unsigned Indent) const {
+ DWARFLocationInterpreter Interp(
+ BaseAddr, [U](uint32_t Index) -> Optional<SectionedAddress> {
+ if (U)
+ return U->getAddrOffsetSectionItem(Index);
+ return None;
+ });
+ OS << format("0x%8.8" PRIx64 ": ", *Offset);
+ Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) {
+ Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
+ if (!Loc || DumpOpts.DisplayRawContents)
+ dumpRawEntry(E, OS, Indent, DumpOpts, Obj);
+ if (Loc && *Loc) {
+ OS << "\n";
+ OS.indent(Indent);
+ if (DumpOpts.DisplayRawContents)
+ OS << " => ";
+
+ DIDumpOptions RangeDumpOpts(DumpOpts);
+ RangeDumpOpts.DisplayRawContents = false;
+ if (Loc.get()->Range)
+ Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj);
+ else
+ OS << "<default>";
+ }
+ if (!Loc)
+ consumeError(Loc.takeError());
+
+ if (E.Kind != dwarf::DW_LLE_base_address &&
+ E.Kind != dwarf::DW_LLE_base_addressx &&
+ E.Kind != dwarf::DW_LLE_end_of_list) {
+ OS << ": ";
+ dumpExpression(OS, E.Loc, Data.isLittleEndian(), Data.getAddressSize(),
+ MRI, U);
+ }
+ return true;
+ });
+ if (E) {
+ OS << "\n";
OS.indent(Indent);
- OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2,
- BaseAddress + E.Begin);
- OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
- BaseAddress + E.End);
- OS << ": ";
-
- dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
+ OS << "error: " << toString(std::move(E));
+ return false;
}
+ return true;
}
-DWARFDebugLoc::LocationList const *
-DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
- auto It = partition_point(
- Locations, [=](const LocationList &L) { return L.Offset < Offset; });
- if (It != Locations.end() && It->Offset == Offset)
- return &(*It);
- return nullptr;
+Error DWARFLocationTable::visitAbsoluteLocationList(
+ uint64_t Offset, Optional<SectionedAddress> BaseAddr,
+ std::function<Optional<SectionedAddress>(uint32_t)> LookupAddr,
+ function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const {
+ DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr));
+ return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) {
+ Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
+ if (!Loc)
+ return Callback(Loc.takeError());
+ if (*Loc)
+ return Callback(**Loc);
+ return true;
+ });
}
-void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, DIDumpOptions DumpOpts,
- Optional<uint64_t> Offset) const {
- auto DumpLocationList = [&](const LocationList &L) {
- OS << format("0x%8.8" PRIx64 ": ", L.Offset);
- L.dump(OS, 0, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts, 12);
- OS << "\n";
- };
-
- if (Offset) {
- if (auto *L = getLocationListAtOffset(*Offset))
- DumpLocationList(*L);
- return;
- }
-
- for (const LocationList &L : Locations) {
- DumpLocationList(L);
- if (&L != &Locations.back())
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ const DWARFObject &Obj, DIDumpOptions DumpOpts,
+ Optional<uint64_t> DumpOffset) const {
+ auto BaseAddr = None;
+ unsigned Indent = 12;
+ if (DumpOffset) {
+ dumpLocationList(&*DumpOffset, OS, BaseAddr, MRI, Obj, nullptr, DumpOpts,
+ Indent);
+ } else {
+ uint64_t Offset = 0;
+ StringRef Separator;
+ bool CanContinue = true;
+ while (CanContinue && Data.isValidOffset(Offset)) {
+ OS << Separator;
+ Separator = "\n";
+
+ CanContinue = dumpLocationList(&Offset, OS, BaseAddr, MRI, Obj, nullptr,
+ DumpOpts, Indent);
OS << '\n';
+ }
}
}
-Expected<DWARFDebugLoc::LocationList>
-DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor &Data,
- uint64_t *Offset) {
- LocationList LL;
- LL.Offset = *Offset;
- AddressSize = Data.getAddressSize();
+Error DWARFDebugLoc::visitLocationList(
+ uint64_t *Offset,
+ function_ref<bool(const DWARFLocationEntry &)> Callback) const {
DataExtractor::Cursor C(*Offset);
-
- // 2.6.2 Location Lists
- // A location list entry consists of:
while (true) {
- Entry E;
-
- // 1. A beginning address offset. ...
- E.Begin = Data.getRelocatedAddress(C);
+ uint64_t SectionIndex;
+ uint64_t Value0 = Data.getRelocatedAddress(C);
+ uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex);
- // 2. An ending address offset. ...
- E.End = Data.getRelocatedAddress(C);
-
- if (Error Err = C.takeError())
- return std::move(Err);
+ DWARFLocationEntry E;
// The end of any given location list is marked by an end of list entry,
// which consists of a 0 for the beginning address offset and a 0 for the
- // ending address offset.
- if (E.Begin == 0 && E.End == 0) {
- *Offset = C.tell();
- return LL;
- }
-
- if (E.Begin != (AddressSize == 4 ? -1U : -1ULL)) {
+ // ending address offset. A beginning offset of 0xff...f marks the base
+ // address selection entry.
+ if (Value0 == 0 && Value1 == 0) {
+ E.Kind = dwarf::DW_LLE_end_of_list;
+ } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) {
+ E.Kind = dwarf::DW_LLE_base_address;
+ E.Value0 = Value1;
+ E.SectionIndex = SectionIndex;
+ } else {
+ E.Kind = dwarf::DW_LLE_offset_pair;
+ E.Value0 = Value0;
+ E.Value1 = Value1;
+ E.SectionIndex = SectionIndex;
unsigned Bytes = Data.getU16(C);
// A single location description describing the location of the object...
Data.getU8(C, E.Loc, Bytes);
}
- LL.Entries.push_back(std::move(E));
+ if (!C)
+ return C.takeError();
+ if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list)
+ break;
}
+ *Offset = C.tell();
+ return Error::success();
}
-void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
- IsLittleEndian = data.isLittleEndian();
- AddressSize = data.getAddressSize();
-
- uint64_t Offset = 0;
- while (Offset < data.getData().size()) {
- if (auto LL = parseOneLocationList(data, &Offset))
- Locations.push_back(std::move(*LL));
- else {
- logAllUnhandledErrors(LL.takeError(), WithColor::error());
- break;
- }
+void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry,
+ raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts,
+ const DWARFObject &Obj) const {
+ uint64_t Value0, Value1;
+ switch (Entry.Kind) {
+ case dwarf::DW_LLE_base_address:
+ Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL;
+ Value1 = Entry.Value0;
+ break;
+ case dwarf::DW_LLE_offset_pair:
+ Value0 = Entry.Value0;
+ Value1 = Entry.Value1;
+ break;
+ case dwarf::DW_LLE_end_of_list:
+ Value0 = Value1 = 0;
+ return;
+ default:
+ llvm_unreachable("Not possible in DWARF4!");
}
+ OS << '\n';
+ OS.indent(Indent);
+ OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", "
+ << format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')';
+ DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
}
-Expected<DWARFDebugLoclists::LocationList>
-DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data,
- uint64_t *Offset, unsigned Version) {
- LocationList LL;
- LL.Offset = *Offset;
- DataExtractor::Cursor C(*Offset);
+Error DWARFDebugLoclists::visitLocationList(
+ uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const {
- // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
- while (auto Kind = Data.getU8(C)) {
- Entry E;
- E.Kind = Kind;
- E.Offset = C.tell() - 1;
- switch (Kind) {
+ DataExtractor::Cursor C(*Offset);
+ bool Continue = true;
+ while (Continue) {
+ DWARFLocationEntry E;
+ E.Kind = Data.getU8(C);
+ switch (E.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ break;
case dwarf::DW_LLE_base_addressx:
E.Value0 = Data.getULEB128(C);
break;
+ case dwarf::DW_LLE_startx_endx:
+ E.Value0 = Data.getULEB128(C);
+ E.Value1 = Data.getULEB128(C);
+ break;
case dwarf::DW_LLE_startx_length:
E.Value0 = Data.getULEB128(C);
// Pre-DWARF 5 has different interpretation of the length field. We have
@@ -164,176 +301,109 @@ DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data,
else
E.Value1 = Data.getULEB128(C);
break;
- case dwarf::DW_LLE_start_length:
- E.Value0 = Data.getAddress(C);
- E.Value1 = Data.getULEB128(C);
- break;
case dwarf::DW_LLE_offset_pair:
E.Value0 = Data.getULEB128(C);
E.Value1 = Data.getULEB128(C);
+ E.SectionIndex = SectionedAddress::UndefSection;
+ break;
+ case dwarf::DW_LLE_default_location:
break;
case dwarf::DW_LLE_base_address:
- E.Value0 = Data.getAddress(C);
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ break;
+ case dwarf::DW_LLE_start_end:
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ E.Value1 = Data.getRelocatedAddress(C);
+ break;
+ case dwarf::DW_LLE_start_length:
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ E.Value1 = Data.getULEB128(C);
break;
default:
cantFail(C.takeError());
return createStringError(errc::illegal_byte_sequence,
- "LLE of kind %x not supported", (int)Kind);
+ "LLE of kind %x not supported", (int)E.Kind);
}
- if (Kind != dwarf::DW_LLE_base_address &&
- Kind != dwarf::DW_LLE_base_addressx) {
+ if (E.Kind != dwarf::DW_LLE_base_address &&
+ E.Kind != dwarf::DW_LLE_base_addressx &&
+ E.Kind != dwarf::DW_LLE_end_of_list) {
unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
// A single location description describing the location of the object...
Data.getU8(C, E.Loc, Bytes);
}
- LL.Entries.push_back(std::move(E));
+ if (!C)
+ return C.takeError();
+ Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;
}
- if (Error Err = C.takeError())
- return std::move(Err);
- Entry E;
- E.Kind = dwarf::DW_LLE_end_of_list;
- E.Offset = C.tell() - 1;
- LL.Entries.push_back(E);
*Offset = C.tell();
- return LL;
-}
-
-void DWARFDebugLoclists::parse(DataExtractor data, uint64_t Offset, uint64_t EndOffset, uint16_t Version) {
- IsLittleEndian = data.isLittleEndian();
- AddressSize = data.getAddressSize();
-
- while (Offset < EndOffset) {
- if (auto LL = parseOneLocationList(data, &Offset, Version))
- Locations.push_back(std::move(*LL));
- else {
- logAllUnhandledErrors(LL.takeError(), WithColor::error());
- return;
- }
- }
-}
-
-DWARFDebugLoclists::LocationList const *
-DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const {
- auto It = partition_point(
- Locations, [=](const LocationList &L) { return L.Offset < Offset; });
- if (It != Locations.end() && It->Offset == Offset)
- return &(*It);
- return nullptr;
+ return Error::success();
}
-void DWARFDebugLoclists::Entry::dump(raw_ostream &OS, uint64_t &BaseAddr,
- bool IsLittleEndian, unsigned AddressSize,
- const MCRegisterInfo *MRI, DWARFUnit *U,
- DIDumpOptions DumpOpts, unsigned Indent,
- size_t MaxEncodingStringLength) const {
- if (DumpOpts.Verbose) {
- OS << "\n";
- OS.indent(Indent);
- auto EncodingString = dwarf::LocListEncodingString(Kind);
- // Unsupported encodings should have been reported during parsing.
- assert(!EncodingString.empty() && "Unknown loclist entry encoding");
- OS << format("%s%*c", EncodingString.data(),
- MaxEncodingStringLength - EncodingString.size() + 1, '(');
- switch (Kind) {
- case dwarf::DW_LLE_startx_length:
- case dwarf::DW_LLE_start_length:
- case dwarf::DW_LLE_offset_pair:
- OS << format("0x%*.*" PRIx64 ", 0x%*.*" PRIx64, AddressSize * 2,
- AddressSize * 2, Value0, AddressSize * 2, AddressSize * 2,
- Value1);
- break;
- case dwarf::DW_LLE_base_addressx:
- case dwarf::DW_LLE_base_address:
- OS << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2,
- Value0);
- break;
- case dwarf::DW_LLE_end_of_list:
- break;
- }
- OS << ')';
- }
- auto PrintPrefix = [&] {
- OS << "\n";
- OS.indent(Indent);
- if (DumpOpts.Verbose)
- OS << format("%*s", MaxEncodingStringLength, (const char *)"=> ");
- };
- switch (Kind) {
- case dwarf::DW_LLE_startx_length:
- PrintPrefix();
- OS << "Addr idx " << Value0 << " (w/ length " << Value1 << "): ";
- break;
- case dwarf::DW_LLE_start_length:
- PrintPrefix();
- DWARFAddressRange(Value0, Value0 + Value1)
- .dump(OS, AddressSize, DumpOpts);
- OS << ": ";
+void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry,
+ raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts,
+ const DWARFObject &Obj) const {
+ size_t MaxEncodingStringLength = 0;
+#define HANDLE_DW_LLE(ID, NAME) \
+ MaxEncodingStringLength = std::max(MaxEncodingStringLength, \
+ dwarf::LocListEncodingString(ID).size());
+#include "llvm/BinaryFormat/Dwarf.def"
+
+ OS << "\n";
+ OS.indent(Indent);
+ StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind);
+ // Unsupported encodings should have been reported during parsing.
+ assert(!EncodingString.empty() && "Unknown loclist entry encoding");
+ OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data());
+ unsigned FieldSize = 2 + 2 * Data.getAddressSize();
+ switch (Entry.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ case dwarf::DW_LLE_default_location:
break;
+ case dwarf::DW_LLE_startx_endx:
+ case dwarf::DW_LLE_startx_length:
case dwarf::DW_LLE_offset_pair:
- PrintPrefix();
- DWARFAddressRange(BaseAddr + Value0, BaseAddr + Value1)
- .dump(OS, AddressSize, DumpOpts);
- OS << ": ";
+ case dwarf::DW_LLE_start_end:
+ case dwarf::DW_LLE_start_length:
+ OS << format_hex(Entry.Value0, FieldSize) << ", "
+ << format_hex(Entry.Value1, FieldSize);
break;
case dwarf::DW_LLE_base_addressx:
- if (!DumpOpts.Verbose)
- return;
- break;
- case dwarf::DW_LLE_end_of_list:
- if (!DumpOpts.Verbose)
- return;
+ case dwarf::DW_LLE_base_address:
+ OS << format_hex(Entry.Value0, FieldSize);
break;
+ }
+ OS << ')';
+ switch (Entry.Kind) {
case dwarf::DW_LLE_base_address:
- BaseAddr = Value0;
- if (!DumpOpts.Verbose)
- return;
+ case dwarf::DW_LLE_start_end:
+ case dwarf::DW_LLE_start_length:
+ DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
break;
default:
- llvm_unreachable("unreachable locations list kind");
+ break;
}
-
- dumpExpression(OS, Loc, IsLittleEndian, AddressSize, MRI, U);
-}
-void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr,
- bool IsLittleEndian,
- unsigned AddressSize,
- const MCRegisterInfo *MRI,
- DWARFUnit *U,
- DIDumpOptions DumpOpts,
- unsigned Indent) const {
- size_t MaxEncodingStringLength = 0;
- if (DumpOpts.Verbose)
- for (const auto &Entry : Entries)
- MaxEncodingStringLength =
- std::max(MaxEncodingStringLength,
- dwarf::LocListEncodingString(Entry.Kind).size());
-
- for (const Entry &E : Entries)
- E.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, U, DumpOpts, Indent,
- MaxEncodingStringLength);
}
-void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
- const MCRegisterInfo *MRI, DIDumpOptions DumpOpts,
- Optional<uint64_t> Offset) const {
- auto DumpLocationList = [&](const LocationList &L) {
- OS << format("0x%8.8" PRIx64 ": ", L.Offset);
- L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts,
- /*Indent=*/12);
- OS << "\n";
- };
-
- if (Offset) {
- if (auto *L = getLocationListAtOffset(*Offset))
- DumpLocationList(*L);
+void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size,
+ raw_ostream &OS, const MCRegisterInfo *MRI,
+ const DWARFObject &Obj,
+ DIDumpOptions DumpOpts) {
+ if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) {
+ OS << "Invalid dump range\n";
return;
}
-
- for (const LocationList &L : Locations) {
- DumpLocationList(L);
- if (&L != &Locations.back())
- OS << '\n';
+ uint64_t Offset = StartOffset;
+ StringRef Separator;
+ bool CanContinue = true;
+ while (CanContinue && Offset < StartOffset + Size) {
+ OS << Separator;
+ Separator = "\n";
+
+ CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj,
+ nullptr, DumpOpts, /*Indent=*/12);
+ OS << '\n';
}
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
index 9a0e770aed3d..8cb259ebc622 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
@@ -17,36 +17,39 @@ using namespace dwarf;
void DWARFDebugMacro::dump(raw_ostream &OS) const {
unsigned IndLevel = 0;
- for (const Entry &E : Macros) {
- // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
- // this check handles the case of corrupted ".debug_macinfo" section.
- if (IndLevel > 0)
- IndLevel -= (E.Type == DW_MACINFO_end_file);
- // Print indentation.
- for (unsigned I = 0; I < IndLevel; I++)
- OS << " ";
- IndLevel += (E.Type == DW_MACINFO_start_file);
+ for (const auto &Macros : MacroLists) {
+ for (const Entry &E : Macros) {
+ // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
+ // this check handles the case of corrupted ".debug_macinfo" section.
+ if (IndLevel > 0)
+ IndLevel -= (E.Type == DW_MACINFO_end_file);
+ // Print indentation.
+ for (unsigned I = 0; I < IndLevel; I++)
+ OS << " ";
+ IndLevel += (E.Type == DW_MACINFO_start_file);
- WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
- switch (E.Type) {
- default:
- // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
- break;
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- OS << " - lineno: " << E.Line;
- OS << " macro: " << E.MacroStr;
- break;
- case DW_MACINFO_start_file:
- OS << " - lineno: " << E.Line;
- OS << " filenum: " << E.File;
- break;
- case DW_MACINFO_end_file:
- break;
- case DW_MACINFO_vendor_ext:
- OS << " - constant: " << E.ExtConstant;
- OS << " string: " << E.ExtStr;
- break;
+ WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ OS << " - lineno: " << E.Line;
+ OS << " macro: " << E.MacroStr;
+ break;
+ case DW_MACINFO_start_file:
+ OS << " - lineno: " << E.Line;
+ OS << " filenum: " << E.File;
+ break;
+ case DW_MACINFO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ OS << " - constant: " << E.ExtConstant;
+ OS << " string: " << E.ExtStr;
+ break;
+ }
+ OS << "\n";
}
OS << "\n";
}
@@ -54,15 +57,21 @@ void DWARFDebugMacro::dump(raw_ostream &OS) const {
void DWARFDebugMacro::parse(DataExtractor data) {
uint64_t Offset = 0;
+ MacroList *M = nullptr;
while (data.isValidOffset(Offset)) {
+ if (!M) {
+ MacroLists.emplace_back();
+ M = &MacroLists.back();
+ }
// A macro list entry consists of:
- Entry E;
+ M->emplace_back();
+ Entry &E = M->back();
// 1. Macinfo type
E.Type = data.getULEB128(&Offset);
if (E.Type == 0) {
- // Reached end of ".debug_macinfo" section.
- return;
+ // Reached end of a ".debug_macinfo" section contribution.
+ continue;
}
switch (E.Type) {
@@ -70,7 +79,6 @@ void DWARFDebugMacro::parse(DataExtractor data) {
// Got a corrupted ".debug_macinfo" section (invalid macinfo type).
// Push the corrupted entry to the list and halt parsing.
E.Type = DW_MACINFO_invalid;
- Macros.push_back(E);
return;
case DW_MACINFO_define:
case DW_MACINFO_undef:
@@ -94,7 +102,5 @@ void DWARFDebugMacro::parse(DataExtractor data) {
E.ExtStr = data.getCStr(&Offset);
break;
}
-
- Macros.push_back(E);
}
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
index f6785b89e86d..9ae4c5b73ebe 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -114,12 +114,21 @@ Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t End,
DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
+ return getAbsoluteRanges(BaseAddr, [&](uint32_t Index) {
+ return U.getAddrOffsetSectionItem(Index);
+ });
+}
+
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+ Optional<object::SectionedAddress> BaseAddr,
+ function_ref<Optional<object::SectionedAddress>(uint32_t)>
+ LookupPooledAddress) const {
DWARFAddressRangesVector Res;
for (const RangeListEntry &RLE : Entries) {
if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
break;
if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
- BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
+ BaseAddr = LookupPooledAddress(RLE.Value0);
if (!BaseAddr)
BaseAddr = {RLE.Value0, -1ULL};
continue;
@@ -152,7 +161,7 @@ DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
E.HighPC = E.LowPC + RLE.Value1;
break;
case dwarf::DW_RLE_startx_length: {
- auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
+ auto Start = LookupPooledAddress(RLE.Value0);
if (!Start)
Start = {0, -1ULL};
E.SectionIndex = Start->SectionIndex;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index cec194e8b6b3..c1dc3b68c6ab 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -62,16 +62,10 @@ static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
if (!DumpOpts.ShowAddresses)
return;
- ArrayRef<SectionName> SectionNames;
- if (DumpOpts.Verbose)
- SectionNames = Obj.getSectionNames();
-
for (const DWARFAddressRange &R : Ranges) {
OS << '\n';
OS.indent(Indent);
- R.dump(OS, AddressSize);
-
- DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, R.SectionIndex);
+ R.dump(OS, AddressSize, DumpOpts, &Obj);
}
}
@@ -79,7 +73,6 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
DWARFUnit *U, unsigned Indent,
DIDumpOptions DumpOpts) {
DWARFContext &Ctx = U->getContext();
- const DWARFObject &Obj = Ctx.getDWARFObj();
const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) {
@@ -91,49 +84,24 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
return;
}
- FormValue.dump(OS, DumpOpts);
- const auto &DumpLL = [&](auto ExpectedLL) {
- if (ExpectedLL) {
- uint64_t BaseAddr = 0;
- if (Optional<object::SectionedAddress> BA = U->getBaseAddress())
- BaseAddr = BA->Address;
- auto LLDumpOpts = DumpOpts;
- LLDumpOpts.Verbose = false;
- ExpectedLL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(),
- MRI, U, LLDumpOpts, Indent);
- } else {
- OS << '\n';
- OS.indent(Indent);
- OS << formatv("error extracting location list: {0}",
- fmt_consume(ExpectedLL.takeError()));
- }
- };
if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
uint64_t Offset = *FormValue.getAsSectionOffset();
- if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) {
- DWARFDebugLoc DebugLoc;
- DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(),
- Obj.getAddressSize());
- DumpLL(DebugLoc.parseOneLocationList(Data, &Offset));
- return;
- }
- bool UseLocLists = !U->isDWOUnit();
- StringRef LoclistsSectionData =
- UseLocLists ? Obj.getLoclistsSection().Data : U->getLocSectionData();
+ if (FormValue.getForm() == DW_FORM_loclistx) {
+ FormValue.dump(OS, DumpOpts);
- if (!LoclistsSectionData.empty()) {
- DataExtractor Data(LoclistsSectionData, Ctx.isLittleEndian(),
- Obj.getAddressSize());
-
- // Old-style location list were used in DWARF v4 (.debug_loc.dwo section).
- // Modern locations list (.debug_loclists) are used starting from v5.
- // Ideally we should take the version from the .debug_loclists section
- // header, but using CU's version for simplicity.
- DumpLL(DWARFDebugLoclists::parseOneLocationList(
- Data, &Offset, UseLocLists ? U->getVersion() : 4));
+ if (auto LoclistOffset = U->getLoclistOffset(Offset))
+ Offset = *LoclistOffset;
+ else
+ return;
}
+ U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(),
+ MRI, Ctx.getDWARFObj(), U, DumpOpts,
+ Indent);
+ return;
}
+
+ FormValue.dump(OS, DumpOpts);
}
/// Dump the name encoded in the type tag.
@@ -311,7 +279,8 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
else
FormValue.dump(OS, DumpOpts);
}
- } else if (DWARFAttribute::mayHaveLocationDescription(Attr))
+ } else if (Form == dwarf::Form::DW_FORM_exprloc ||
+ DWARFAttribute::mayHaveLocationDescription(Attr))
dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
else
FormValue.dump(OS, DumpOpts);
@@ -441,6 +410,10 @@ Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
}
+Optional<uint64_t> DWARFDie::getLocBaseAttribute() const {
+ return toSectionOffset(find(DW_AT_loclists_base));
+}
+
Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
if (auto FormValue = find(DW_AT_high_pc)) {
if (auto Address = FormValue->getAsAddress()) {
@@ -516,6 +489,37 @@ bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
return false;
}
+Expected<DWARFLocationExpressionsVector>
+DWARFDie::getLocations(dwarf::Attribute Attr) const {
+ Optional<DWARFFormValue> Location = find(Attr);
+ if (!Location)
+ return createStringError(inconvertibleErrorCode(), "No %s",
+ dwarf::AttributeString(Attr).data());
+
+ if (Optional<uint64_t> Off = Location->getAsSectionOffset()) {
+ uint64_t Offset = *Off;
+
+ if (Location->getForm() == DW_FORM_loclistx) {
+ if (auto LoclistOffset = U->getLoclistOffset(Offset))
+ Offset = *LoclistOffset;
+ else
+ return createStringError(inconvertibleErrorCode(),
+ "Loclist table not found");
+ }
+ return U->findLoclistFromOffset(Offset);
+ }
+
+ if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
+ return DWARFLocationExpressionsVector{
+ DWARFLocationExpression{None, to_vector<4>(*Expr)}};
+ }
+
+ return createStringError(
+ inconvertibleErrorCode(), "Unsupported %s encoding: %s",
+ dwarf::AttributeString(Attr).data(),
+ dwarf::FormEncodingString(Location->getForm()).data());
+}
+
const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
if (!isSubroutineDIE())
return nullptr;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 5009b1b7b412..7d817d8a9925 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -93,6 +93,8 @@ static DescVector getDescriptions() {
Descriptions[DW_OP_implicit_value] =
Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_WASM_location] =
+ Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB);
Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 26090638b34c..e97ae81345b8 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -312,6 +312,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
case DW_FORM_udata:
case DW_FORM_ref_udata:
case DW_FORM_rnglistx:
+ case DW_FORM_loclistx:
Value.uval = Data.getULEB128(OffsetPtr);
break;
case DW_FORM_string:
@@ -411,7 +412,7 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
if (A)
dumpSectionedAddress(AddrOS, DumpOpts, *A);
else
- OS << "<no .debug_addr section>";
+ OS << "<unresolved>";
break;
}
case DW_FORM_flag_present:
@@ -551,6 +552,10 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
break;
+ case DW_FORM_loclistx:
+ OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue);
+ break;
+
// Should be formatted to 64-bit for DWARF64.
case DW_FORM_sec_offset:
AddrOS << format("0x%08x", (uint32_t)UValue);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp
new file mode 100644
index 000000000000..1cf73a666778
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp
@@ -0,0 +1,19 @@
+//===- DWARFLocationExpression.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+
+raw_ostream &llvm::operator<<(raw_ostream &OS,
+ const DWARFLocationExpression &Loc) {
+ return OS << Loc.Range << ": "
+ << formatv("{0}", make_range(Loc.Expr.begin(), Loc.Expr.end()));
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index a56402a707ad..7bb019466161 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -175,18 +175,37 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
const DWARFSection *AOS, const DWARFSection &LS, bool LE,
bool IsDWO, const DWARFUnitVector &UnitVector)
: Context(DC), InfoSection(Section), Header(Header), Abbrev(DA),
- RangeSection(RS), LocSection(LocSection), LineSection(LS),
- StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
- isLittleEndian(LE), IsDWO(IsDWO), UnitVector(UnitVector) {
+ RangeSection(RS), LineSection(LS), StringSection(SS),
+ StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE),
+ IsDWO(IsDWO), UnitVector(UnitVector) {
clear();
- // For split DWARF we only need to keep track of the location list section's
- // data (no relocations), and if we are reading a package file, we need to
- // adjust the location list data based on the index entries.
if (IsDWO) {
- LocSectionData = LocSection->Data;
+ // If we are reading a package file, we need to adjust the location list
+ // data based on the index entries.
+ StringRef Data = LocSection->Data;
if (auto *IndexEntry = Header.getIndexEntry())
if (const auto *C = IndexEntry->getOffset(DW_SECT_LOC))
- LocSectionData = LocSectionData.substr(C->Offset, C->Length);
+ Data = Data.substr(C->Offset, C->Length);
+
+ DWARFDataExtractor DWARFData =
+ Header.getVersion() >= 5
+ ? DWARFDataExtractor(Context.getDWARFObj(),
+ Context.getDWARFObj().getLoclistsDWOSection(),
+ isLittleEndian, getAddressByteSize())
+ : DWARFDataExtractor(Data, isLittleEndian, getAddressByteSize());
+ LocTable =
+ std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion());
+
+ } else if (Header.getVersion() >= 5) {
+ LocTable = std::make_unique<DWARFDebugLoclists>(
+ DWARFDataExtractor(Context.getDWARFObj(),
+ Context.getDWARFObj().getLoclistsSection(),
+ isLittleEndian, getAddressByteSize()),
+ Header.getVersion());
+ } else {
+ LocTable = std::make_unique<DWARFDebugLoc>(
+ DWARFDataExtractor(Context.getDWARFObj(), *LocSection, isLittleEndian,
+ getAddressByteSize()));
}
}
@@ -209,7 +228,9 @@ DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const {
if (I != R.end() && std::next(I) == R.end())
return (*I)->getAddrOffsetSectionItem(Index);
}
- uint64_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize();
+ if (!AddrOffsetSectionBase)
+ return None;
+ uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize();
if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
return None;
DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection,
@@ -238,23 +259,26 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
const DWARFUnitIndex *Index,
const DWARFUnitIndex::Entry *Entry) {
Offset = *offset_ptr;
+ Error Err = Error::success();
IndexEntry = Entry;
if (!IndexEntry && Index)
IndexEntry = Index->getFromOffset(*offset_ptr);
- Length = debug_info.getRelocatedValue(4, offset_ptr);
+ Length = debug_info.getRelocatedValue(4, offset_ptr, nullptr, &Err);
FormParams.Format = DWARF32;
if (Length == dwarf::DW_LENGTH_DWARF64) {
- Length = debug_info.getU64(offset_ptr);
+ Length = debug_info.getU64(offset_ptr, &Err);
FormParams.Format = DWARF64;
}
- FormParams.Version = debug_info.getU16(offset_ptr);
+ FormParams.Version = debug_info.getU16(offset_ptr, &Err);
if (FormParams.Version >= 5) {
- UnitType = debug_info.getU8(offset_ptr);
- FormParams.AddrSize = debug_info.getU8(offset_ptr);
- AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr);
+ UnitType = debug_info.getU8(offset_ptr, &Err);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
+ AbbrOffset = debug_info.getRelocatedValue(
+ FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
} else {
- AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr);
- FormParams.AddrSize = debug_info.getU8(offset_ptr);
+ AbbrOffset = debug_info.getRelocatedValue(
+ FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
// Fake a unit type based on the section type. This isn't perfect,
// but distinguishing compile and type units is generally enough.
if (SectionKind == DW_SECT_TYPES)
@@ -274,11 +298,14 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
AbbrOffset = AbbrEntry->Offset;
}
if (isTypeUnit()) {
- TypeHash = debug_info.getU64(offset_ptr);
- TypeOffset =
- debug_info.getUnsigned(offset_ptr, FormParams.getDwarfOffsetByteSize());
+ TypeHash = debug_info.getU64(offset_ptr, &Err);
+ TypeOffset = debug_info.getUnsigned(
+ offset_ptr, FormParams.getDwarfOffsetByteSize(), &Err);
} else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
- DWOId = debug_info.getU64(offset_ptr);
+ DWOId = debug_info.getU64(offset_ptr, &Err);
+
+ if (errorToBool(std::move(Err)))
+ return false;
// Header fields all parsed, capture the size of this unit header.
assert(*offset_ptr - Offset <= 255 && "unexpected header size");
@@ -305,8 +332,9 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
// Parse the rangelist table header, including the optional array of offsets
// following it (DWARF v5 and later).
-static Expected<DWARFDebugRnglistTable>
-parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset,
+template<typename ListTableType>
+static Expected<ListTableType>
+parseListTableHeader(DWARFDataExtractor &DA, uint64_t Offset,
DwarfFormat Format) {
// We are expected to be called with Offset 0 or pointing just past the table
// header. Correct Offset in the latter case so that it points to the start
@@ -314,12 +342,12 @@ parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset,
if (Offset > 0) {
uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format);
if (Offset < HeaderSize)
- return createStringError(errc::invalid_argument, "Did not detect a valid"
- " range list table with base = 0x%" PRIx64 "\n",
+ return createStringError(errc::invalid_argument, "did not detect a valid"
+ " list table with base = 0x%" PRIx64 "\n",
Offset);
Offset -= HeaderSize;
}
- llvm::DWARFDebugRnglistTable Table;
+ ListTableType Table;
if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
return std::move(E);
return Table;
@@ -339,7 +367,8 @@ void DWARFUnit::clear() {
Abbrevs = nullptr;
BaseAddr.reset();
RangeSectionBase = 0;
- AddrOffsetSectionBase = 0;
+ LocSectionBase = 0;
+ AddrOffsetSectionBase = None;
clearDIEs(false);
DWO.reset();
}
@@ -427,13 +456,15 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
Header.setDWOId(*DWOId);
if (!IsDWO) {
- assert(AddrOffsetSectionBase == 0);
+ assert(AddrOffsetSectionBase == None);
assert(RangeSectionBase == 0);
- AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0);
+ assert(LocSectionBase == 0);
+ AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base));
if (!AddrOffsetSectionBase)
AddrOffsetSectionBase =
- toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
+ toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base));
RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+ LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
}
// In general, in DWARF v5 and beyond we derive the start of the unit's
@@ -471,8 +502,8 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
// extracted lazily.
DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
isLittleEndian, 0);
- auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase,
- Header.getFormat());
+ auto TableOrError = parseListTableHeader<DWARFDebugRnglistTable>(
+ RangesDA, RangeSectionBase, Header.getFormat());
if (!TableOrError)
return createStringError(errc::invalid_argument,
"parsing a range list table: " +
@@ -485,6 +516,37 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
if (IsDWO && RngListTable)
RangeSectionBase = RngListTable->getHeaderSize();
}
+
+ // In a split dwarf unit, there is no DW_AT_loclists_base attribute.
+ // Setting LocSectionBase to point past the table header.
+ if (IsDWO)
+ setLocSection(&Context.getDWARFObj().getLoclistsDWOSection(),
+ DWARFListTableHeader::getHeaderSize(Header.getFormat()));
+ else
+ setLocSection(&Context.getDWARFObj().getLoclistsSection(),
+ toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0));
+
+ if (LocSection->Data.size()) {
+ if (IsDWO)
+ LoclistTableHeader.emplace(".debug_loclists.dwo", "locations");
+ else
+ LoclistTableHeader.emplace(".debug_loclists", "locations");
+
+ uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Header.getFormat());
+ uint64_t Offset = getLocSectionBase();
+ DWARFDataExtractor Data(Context.getDWARFObj(), *LocSection,
+ isLittleEndian, getAddressByteSize());
+ if (Offset < HeaderSize)
+ return createStringError(errc::invalid_argument,
+ "did not detect a valid"
+ " list table with base = 0x%" PRIx64 "\n",
+ Offset);
+ Offset -= HeaderSize;
+ if (Error E = LoclistTableHeader->extract(Data, &Offset))
+ return createStringError(errc::invalid_argument,
+ "parsing a loclist table: " +
+ toString(std::move(E)));
+ }
}
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
@@ -500,7 +562,9 @@ bool DWARFUnit::parseDWO() {
DWARFDie UnitDie = getUnitDIE();
if (!UnitDie)
return false;
- auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name));
+ auto DWOFileName = getVersion() >= 5
+ ? dwarf::toString(UnitDie.find(DW_AT_dwo_name))
+ : dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name));
if (!DWOFileName)
return false;
auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir));
@@ -522,13 +586,14 @@ bool DWARFUnit::parseDWO() {
return false;
DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
// Share .debug_addr and .debug_ranges section with compile unit in .dwo
- DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
+ if (AddrOffsetSectionBase)
+ DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase);
if (getVersion() >= 5) {
DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
isLittleEndian, 0);
- if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase,
- Header.getFormat()))
+ if (auto TableOrError = parseListTableHeader<DWARFDebugRnglistTable>(
+ RangesDA, RangeSectionBase, Header.getFormat()))
DWO->RngListTable = TableOrError.get();
else
WithColor::error() << "parsing a range list table: "
@@ -575,7 +640,7 @@ DWARFUnit::findRnglistFromOffset(uint64_t Offset) {
Expected<DWARFAddressRangesVector>
DWARFUnit::findRnglistFromIndex(uint32_t Index) {
if (auto Offset = getRnglistOffset(Index))
- return findRnglistFromOffset(*Offset + RangeSectionBase);
+ return findRnglistFromOffset(*Offset);
if (RngListTable)
return createStringError(errc::invalid_argument,
@@ -599,6 +664,30 @@ Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
return *CUDIERangesOrError;
}
+Expected<DWARFLocationExpressionsVector>
+DWARFUnit::findLoclistFromOffset(uint64_t Offset) {
+ DWARFLocationExpressionsVector Result;
+
+ Error InterpretationError = Error::success();
+
+ Error ParseError = getLocationTable().visitAbsoluteLocationList(
+ Offset, getBaseAddress(),
+ [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); },
+ [&](Expected<DWARFLocationExpression> L) {
+ if (L)
+ Result.push_back(std::move(*L));
+ else
+ InterpretationError =
+ joinErrors(L.takeError(), std::move(InterpretationError));
+ return !InterpretationError;
+ });
+
+ if (ParseError || InterpretationError)
+ return joinErrors(std::move(ParseError), std::move(InterpretationError));
+
+ return Result;
+}
+
void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
if (Die.isSubroutineDIE()) {
auto DIERangesOrError = Die.getAddressRanges();
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index bf499b6ee092..1fd6c1d7d282 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -196,6 +196,14 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) {
NumUnitErrors++;
}
+ // According to DWARF Debugging Information Format Version 5,
+ // 3.1.2 Skeleton Compilation Unit Entries:
+ // "A skeleton compilation unit has no children."
+ if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) {
+ error() << "Skeleton compilation unit has children.\n";
+ NumUnitErrors++;
+ }
+
DieRangeInfo RI;
NumUnitErrors += verifyDieRanges(Die, RI);
@@ -468,27 +476,21 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
ReportError("DIE has invalid DW_AT_stmt_list encoding:");
break;
case DW_AT_location: {
- auto VerifyLocationExpr = [&](ArrayRef<uint8_t> D) {
+ if (Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location)) {
DWARFUnit *U = Die.getDwarfUnit();
- DataExtractor Data(toStringRef(D), DCtx.isLittleEndian(), 0);
- DWARFExpression Expression(Data, U->getVersion(),
- U->getAddressByteSize());
- bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
- return Op.isError();
- });
- if (Error || !Expression.verify(U))
- ReportError("DIE contains invalid DWARF expression:");
- };
- if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) {
- // Verify inlined location.
- VerifyLocationExpr(*Expr);
- } else if (auto LocOffset = AttrValue.Value.getAsSectionOffset()) {
- // Verify location list.
- if (auto DebugLoc = DCtx.getDebugLoc())
- if (auto LocList = DebugLoc->getLocationListAtOffset(*LocOffset))
- for (const auto &Entry : LocList->Entries)
- VerifyLocationExpr(Entry.Loc);
- }
+ for (const auto &Entry : *Loc) {
+ DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0);
+ DWARFExpression Expression(Data, U->getVersion(),
+ U->getAddressByteSize());
+ bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) {
+ return Op.isError();
+ });
+ if (Error || !Expression.verify(U))
+ ReportError("DIE contains invalid DWARF expression:");
+ }
+ } else
+ ReportError(toString(Loc.takeError()));
break;
}
case DW_AT_specification:
@@ -640,7 +642,7 @@ unsigned DWARFVerifier::verifyDebugInfoReferences() {
// getting the DIE by offset and emitting an error
OS << "Verifying .debug_info references...\n";
unsigned NumErrors = 0;
- for (const std::pair<uint64_t, std::set<uint64_t>> &Pair :
+ for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair :
ReferenceToDIEOffsets) {
if (DCtx.getDIEForOffset(Pair.first))
continue;
@@ -968,7 +970,7 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
constexpr BucketInfo(uint32_t Bucket, uint32_t Index)
: Bucket(Bucket), Index(Index) {}
- bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; };
+ bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; }
};
uint32_t NumErrors = 0;
@@ -1278,36 +1280,24 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
}
static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
- Optional<DWARFFormValue> Location = Die.findRecursively(DW_AT_location);
- if (!Location)
+ Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location);
+ if (!Loc) {
+ consumeError(Loc.takeError());
return false;
-
- auto ContainsInterestingOperators = [&](ArrayRef<uint8_t> D) {
- DWARFUnit *U = Die.getDwarfUnit();
- DataExtractor Data(toStringRef(D), DCtx.isLittleEndian(), U->getAddressByteSize());
+ }
+ DWARFUnit *U = Die.getDwarfUnit();
+ for (const auto &Entry : *Loc) {
+ DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(),
+ U->getAddressByteSize());
DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
- return any_of(Expression, [](DWARFExpression::Operation &Op) {
+ bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) {
return !Op.isError() && (Op.getCode() == DW_OP_addr ||
Op.getCode() == DW_OP_form_tls_address ||
Op.getCode() == DW_OP_GNU_push_tls_address);
});
- };
-
- if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
- // Inlined location.
- if (ContainsInterestingOperators(*Expr))
+ if (IsInteresting)
return true;
- } else if (Optional<uint64_t> Offset = Location->getAsSectionOffset()) {
- // Location list.
- if (const DWARFDebugLoc *DebugLoc = DCtx.getDebugLoc()) {
- if (const DWARFDebugLoc::LocationList *LocList =
- DebugLoc->getLocationListAtOffset(*Offset)) {
- if (any_of(LocList->Entries, [&](const DWARFDebugLoc::Entry &E) {
- return ContainsInterestingOperators(E.Loc);
- }))
- return true;
- }
- }
}
return false;
}
diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
index ad022fec9e32..6731a8b27443 100644
--- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -8,6 +8,7 @@
#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
#include "llvm/DebugInfo/GSYM/LineTable.h"
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
#include "llvm/Support/DataExtractor.h"
@@ -114,7 +115,7 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const {
llvm::Error err = OptLineTable->encode(O, Range.Start);
if (err)
return std::move(err);
- const off_t Length = O.tell() - StartOffset;
+ const auto Length = O.tell() - StartOffset;
if (Length > UINT32_MAX)
return createStringError(std::errc::invalid_argument,
"LineTable length is greater than UINT32_MAX");
@@ -132,7 +133,7 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const {
llvm::Error err = Inline->encode(O, Range.Start);
if (err)
return std::move(err);
- const off_t Length = O.tell() - StartOffset;
+ const auto Length = O.tell() - StartOffset;
if (Length > UINT32_MAX)
return createStringError(std::errc::invalid_argument,
"InlineInfo length is greater than UINT32_MAX");
@@ -145,3 +146,104 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const {
O.writeU32(0);
return FuncInfoOffset;
}
+
+
+llvm::Expected<LookupResult> FunctionInfo::lookup(DataExtractor &Data,
+ const GsymReader &GR,
+ uint64_t FuncAddr,
+ uint64_t Addr) {
+ LookupResult LR;
+ LR.LookupAddr = Addr;
+ LR.FuncRange.Start = FuncAddr;
+ uint64_t Offset = 0;
+ LR.FuncRange.End = FuncAddr + Data.getU32(&Offset);
+ uint32_t NameOffset = Data.getU32(&Offset);
+ // The "lookup" functions doesn't report errors as accurately as the "decode"
+ // function as it is meant to be fast. For more accurage errors we could call
+ // "decode".
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ // This function will be called with the result of a binary search of the
+ // address table, we must still make sure the address does not fall into a
+ // gap between functions are after the last function.
+ if (Addr >= LR.FuncRange.End)
+ return createStringError(std::errc::io_error,
+ "address 0x%" PRIx64 " is not in GSYM", Addr);
+
+ if (NameOffset == 0)
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x00000000",
+ Offset - 4);
+ LR.FuncName = GR.getString(NameOffset);
+ bool Done = false;
+ Optional<LineEntry> LineEntry;
+ Optional<DataExtractor> InlineInfoData;
+ while (!Done) {
+ if (!Data.isValidOffsetForDataOfSize(Offset, 8))
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ const uint32_t IT = Data.getU32(&Offset);
+ const uint32_t InfoLength = Data.getU32(&Offset);
+ const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
+ if (InfoLength != InfoBytes.size())
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ DataExtractor InfoData(InfoBytes, Data.isLittleEndian(),
+ Data.getAddressSize());
+ switch (IT) {
+ case InfoType::EndOfList:
+ Done = true;
+ break;
+
+ case InfoType::LineTableInfo:
+ if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
+ LineEntry = ExpectedLE.get();
+ else
+ return ExpectedLE.takeError();
+ break;
+
+ case InfoType::InlineInfo:
+ // We will parse the inline info after our line table, but only if
+ // we have a line entry.
+ InlineInfoData = InfoData;
+ break;
+
+ default:
+ break;
+ }
+ Offset += InfoLength;
+ }
+
+ if (!LineEntry) {
+ // We don't have a valid line entry for our address, fill in our source
+ // location as best we can and return.
+ SourceLocation SrcLoc;
+ SrcLoc.Name = LR.FuncName;
+ LR.Locations.push_back(SrcLoc);
+ return LR;
+ }
+
+ Optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
+ if (!LineEntryFile)
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract file[%" PRIu32 "]",
+ LineEntry->File);
+
+ SourceLocation SrcLoc;
+ SrcLoc.Name = LR.FuncName;
+ SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
+ SrcLoc.Base = GR.getString(LineEntryFile->Base);
+ SrcLoc.Line = LineEntry->Line;
+ LR.Locations.push_back(SrcLoc);
+ // If we don't have inline information, we are done.
+ if (!InlineInfoData)
+ return LR;
+ // We have inline information. Try to augment the lookup result with this
+ // data.
+ llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
+ LR.Locations);
+ if (Err)
+ return std::move(Err);
+ return LR;
+}
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 1b448cf80b70..b4f3f2052ae7 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -1,9 +1,8 @@
//===- GsymReader.cpp -----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -263,3 +262,18 @@ llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
"failed to extract address[%" PRIu64 "]",
*AddressIndex);
}
+
+llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
+ Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
+ if (!AddressIndex)
+ return AddressIndex.takeError();
+ // Address info offsets size should have been checked in parse().
+ assert(*AddressIndex < AddrInfoOffsets.size());
+ auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
+ DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
+ if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex))
+ return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract address[%" PRIu64 "]",
+ *AddressIndex);
+}
diff --git a/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp b/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
index 32ed2c709575..1b8c974fdcd2 100644
--- a/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
@@ -1,14 +1,14 @@
//===- InlineInfo.cpp -------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/GSYM/FileEntry.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
#include "llvm/Support/DataExtractor.h"
#include <algorithm>
@@ -60,6 +60,108 @@ llvm::Optional<InlineInfo::InlineArray> InlineInfo::getInlineStack(uint64_t Addr
return llvm::None;
}
+/// Skip an InlineInfo object in the specified data at the specified offset.
+///
+/// Used during the InlineInfo::lookup() call to quickly skip child InlineInfo
+/// objects where the addres ranges isn't contained in the InlineInfo object
+/// or its children. This avoids allocations by not appending child InlineInfo
+/// objects to the InlineInfo::Children array.
+///
+/// \param Data The binary stream to read the data from.
+///
+/// \param Offset The byte offset within \a Data.
+///
+/// \param SkippedRanges If true, address ranges have already been skipped.
+
+static bool skip(DataExtractor &Data, uint64_t &Offset, bool SkippedRanges) {
+ if (!SkippedRanges) {
+ if (AddressRanges::skip(Data, Offset) == 0)
+ return false;
+ }
+ bool HasChildren = Data.getU8(&Offset) != 0;
+ Data.getU32(&Offset); // Skip Inline.Name.
+ Data.getULEB128(&Offset); // Skip Inline.CallFile.
+ Data.getULEB128(&Offset); // Skip Inline.CallLine.
+ if (HasChildren) {
+ while (skip(Data, Offset, false /* SkippedRanges */))
+ /* Do nothing */;
+ }
+ // We skipped a valid InlineInfo.
+ return true;
+}
+
+/// A Lookup helper functions.
+///
+/// Used during the InlineInfo::lookup() call to quickly only parse an
+/// InlineInfo object if the address falls within this object. This avoids
+/// allocations by not appending child InlineInfo objects to the
+/// InlineInfo::Children array and also skips any InlineInfo objects that do
+/// not contain the address we are looking up.
+///
+/// \param Data The binary stream to read the data from.
+///
+/// \param Offset The byte offset within \a Data.
+///
+/// \param BaseAddr The address that the relative address range offsets are
+/// relative to.
+
+static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset,
+ uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs,
+ llvm::Error &Err) {
+ InlineInfo Inline;
+ Inline.Ranges.decode(Data, BaseAddr, Offset);
+ if (Inline.Ranges.empty())
+ return true;
+ // Check if the address is contained within the inline information, and if
+ // not, quickly skip this InlineInfo object and all its children.
+ if (!Inline.Ranges.contains(Addr)) {
+ skip(Data, Offset, true /* SkippedRanges */);
+ return false;
+ }
+
+ // The address range is contained within this InlineInfo, add the source
+ // location for this InlineInfo and any children that contain the address.
+ bool HasChildren = Data.getU8(&Offset) != 0;
+ Inline.Name = Data.getU32(&Offset);
+ Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
+ Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
+ if (HasChildren) {
+ // Child address ranges are encoded relative to the first address in the
+ // parent InlineInfo object.
+ const auto ChildBaseAddr = Inline.Ranges[0].Start;
+ bool Done = false;
+ while (!Done)
+ Done = lookup(GR, Data, Offset, ChildBaseAddr, Addr, SrcLocs, Err);
+ }
+
+ Optional<FileEntry> CallFile = GR.getFile(Inline.CallFile);
+ if (!CallFile) {
+ Err = createStringError(std::errc::invalid_argument,
+ "failed to extract file[%" PRIu32 "]",
+ Inline.CallFile);
+ return false;
+ }
+
+ SourceLocation SrcLoc;
+ SrcLoc.Name = SrcLocs.back().Name;
+ SrcLoc.Dir = GR.getString(CallFile->Dir);
+ SrcLoc.Base = GR.getString(CallFile->Base);
+ SrcLoc.Line = Inline.CallLine;
+ SrcLocs.back().Name = GR.getString(Inline.Name);
+ SrcLocs.push_back(SrcLoc);
+ return true;
+}
+
+llvm::Error InlineInfo::lookup(const GsymReader &GR, DataExtractor &Data,
+ uint64_t BaseAddr, uint64_t Addr,
+ SourceLocations &SrcLocs) {
+ // Call our recursive helper function starting at offset zero.
+ uint64_t Offset = 0;
+ llvm::Error Err = Error::success();
+ ::lookup(GR, Data, Offset, BaseAddr, Addr, SrcLocs, Err);
+ return Err;
+}
+
/// Decode an InlineInfo in Data at the specified offset.
///
/// A local helper function to decode InlineInfo objects. This function is
diff --git a/llvm/lib/DebugInfo/GSYM/LineTable.cpp b/llvm/lib/DebugInfo/GSYM/LineTable.cpp
index 824c0041be9f..a49a3ba9bf2a 100644
--- a/llvm/lib/DebugInfo/GSYM/LineTable.cpp
+++ b/llvm/lib/DebugInfo/GSYM/LineTable.cpp
@@ -262,8 +262,8 @@ llvm::Expected<LineTable> LineTable::decode(DataExtractor &Data,
// Parse the line table on the fly and find the row we are looking for.
// We will need to determine if we need to cache the line table by calling
// LineTable::parseAllEntries(...) or just call this function each time.
-// There is a CPU vs memory tradeoff we will need to determine.
-LineEntry LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, uint64_t Addr) {
+// There is a CPU vs memory tradeoff we will need to determined.
+Expected<LineEntry> LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, uint64_t Addr) {
LineEntry Result;
llvm::Error Err = parse(Data, BaseAddr,
[Addr, &Result](const LineEntry &Row) -> bool {
@@ -277,7 +277,13 @@ LineEntry LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, uint64_t Add
}
return true; // Keep parsing till we find the right row.
});
- return Result;
+ if (Err)
+ return std::move(Err);
+ if (Result.isValid())
+ return Result;
+ return createStringError(std::errc::invalid_argument,
+ "address 0x%" PRIx64 " is not in the line table",
+ Addr);
}
raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const LineTable &LT) {
diff --git a/llvm/lib/DebugInfo/GSYM/LookupResult.cpp b/llvm/lib/DebugInfo/GSYM/LookupResult.cpp
new file mode 100644
index 000000000000..c54b166b2887
--- /dev/null
+++ b/llvm/lib/DebugInfo/GSYM/LookupResult.cpp
@@ -0,0 +1,69 @@
+//===- LookupResult.cpp -------------------------------------------------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/GSYM/LookupResult.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <ciso646>
+
+using namespace llvm;
+using namespace gsym;
+
+std::string LookupResult::getSourceFile(uint32_t Index) const {
+ std::string Fullpath;
+ if (Index < Locations.size()) {
+ if (!Locations[Index].Dir.empty()) {
+ if (Locations[Index].Base.empty()) {
+ Fullpath = Locations[Index].Dir;
+ } else {
+ llvm::SmallString<64> Storage;
+ llvm::sys::path::append(Storage, Locations[Index].Dir,
+ Locations[Index].Base);
+ Fullpath.assign(Storage.begin(), Storage.end());
+ }
+ } else if (!Locations[Index].Base.empty())
+ Fullpath = Locations[Index].Base;
+ }
+ return Fullpath;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const SourceLocation &SL) {
+ OS << SL.Name << " @ ";
+ if (!SL.Dir.empty()) {
+ OS << SL.Dir;
+ if (SL.Dir.contains('\\') and not SL.Dir.contains('/'))
+ OS << '\\';
+ else
+ OS << '/';
+ }
+ if (SL.Base.empty())
+ OS << "<invalid-file>";
+ else
+ OS << SL.Base;
+ OS << ':' << SL.Line;
+ return OS;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const LookupResult &LR) {
+ OS << HEX64(LR.LookupAddr) << ": ";
+ auto NumLocations = LR.Locations.size();
+ for (size_t I = 0; I < NumLocations; ++I) {
+ if (I > 0) {
+ OS << '\n';
+ OS.indent(20);
+ }
+ const bool IsInlined = I + 1 != NumLocations;
+ OS << LR.Locations[I];
+ if (IsInlined)
+ OS << " [inlined]";
+ }
+ OS << '\n';
+ return OS;
+}
diff --git a/llvm/lib/DebugInfo/GSYM/Range.cpp b/llvm/lib/DebugInfo/GSYM/Range.cpp
index 19ab700fdd57..f78101e49bf8 100644
--- a/llvm/lib/DebugInfo/GSYM/Range.cpp
+++ b/llvm/lib/DebugInfo/GSYM/Range.cpp
@@ -100,3 +100,15 @@ void AddressRanges::decode(DataExtractor &Data, uint64_t BaseAddr,
for (auto &Range : Ranges)
Range.decode(Data, BaseAddr, Offset);
}
+
+void AddressRange::skip(DataExtractor &Data, uint64_t &Offset) {
+ Data.getULEB128(&Offset);
+ Data.getULEB128(&Offset);
+}
+
+uint64_t AddressRanges::skip(DataExtractor &Data, uint64_t &Offset) {
+ uint64_t NumRanges = Data.getULEB128(&Offset);
+ for (uint64_t I=0; I<NumRanges; ++I)
+ AddressRange::skip(Data, Offset);
+ return NumRanges;
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
index 5095efcdee3c..9755f2ca3bdc 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
@@ -18,13 +18,6 @@ using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::support;
-DbiModuleDescriptor::DbiModuleDescriptor() = default;
-
-DbiModuleDescriptor::DbiModuleDescriptor(const DbiModuleDescriptor &Info) =
- default;
-
-DbiModuleDescriptor::~DbiModuleDescriptor() = default;
-
Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream,
DbiModuleDescriptor &Info) {
BinaryStreamReader Reader(Stream);
diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index b1a80cbc4580..2f3a2500c293 100644
--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -118,21 +118,32 @@ DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
}
DIPrinter &DIPrinter::operator<<(const DILocal &Local) {
- OS << Local.FunctionName << '\n';
- OS << Local.Name << '\n';
+ if (Local.FunctionName.empty())
+ OS << "??\n";
+ else
+ OS << Local.FunctionName << '\n';
+
+ if (Local.Name.empty())
+ OS << "??\n";
+ else
+ OS << Local.Name << '\n';
+
if (Local.DeclFile.empty())
OS << "??";
else
OS << Local.DeclFile;
OS << ':' << Local.DeclLine << '\n';
+
if (Local.FrameOffset)
OS << *Local.FrameOffset << ' ';
else
OS << "?? ";
+
if (Local.Size)
OS << *Local.Size << ' ';
else
OS << "?? ";
+
if (Local.TagOffset)
OS << *Local.TagOffset << '\n';
else
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index be79d9e637c1..35e3ead6317b 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -284,6 +284,79 @@ bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
}
+template <typename ELFT>
+Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> *Obj) {
+ if (!Obj)
+ return {};
+ auto PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ consumeError(PhdrsOrErr.takeError());
+ return {};
+ }
+ for (const auto &P : *PhdrsOrErr) {
+ if (P.p_type != ELF::PT_NOTE)
+ continue;
+ Error Err = Error::success();
+ for (auto N : Obj->notes(P, Err))
+ if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU)
+ return N.getDesc();
+ }
+ return {};
+}
+
+Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) {
+ Optional<ArrayRef<uint8_t>> BuildID;
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else
+ llvm_unreachable("unsupported file format");
+ return BuildID;
+}
+
+bool findDebugBinary(const std::vector<std::string> &DebugFileDirectory,
+ const ArrayRef<uint8_t> BuildID,
+ std::string &Result) {
+ auto getDebugPath = [&](StringRef Directory) {
+ SmallString<128> Path{Directory};
+ sys::path::append(Path, ".build-id",
+ llvm::toHex(BuildID[0], /*LowerCase=*/true),
+ llvm::toHex(BuildID.slice(1), /*LowerCase=*/true));
+ Path += ".debug";
+ return Path;
+ };
+ if (DebugFileDirectory.empty()) {
+ SmallString<128> Path = getDebugPath(
+#if defined(__NetBSD__)
+ // Try /usr/libdata/debug/.build-id/../...
+ "/usr/libdata/debug"
+#else
+ // Try /usr/lib/debug/.build-id/../...
+ "/usr/lib/debug"
+#endif
+ );
+ if (llvm::sys::fs::exists(Path)) {
+ Result = Path.str();
+ return true;
+ }
+ } else {
+ for (const auto &Directory : DebugFileDirectory) {
+ // Try <debug-file-directory>/.build-id/../...
+ SmallString<128> Path = getDebugPath(Directory);
+ if (llvm::sys::fs::exists(Path)) {
+ Result = Path.str();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
} // end anonymous namespace
ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
@@ -335,6 +408,25 @@ ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
return DbgObjOrErr.get();
}
+ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
+ const ELFObjectFileBase *Obj,
+ const std::string &ArchName) {
+ auto BuildID = getBuildID(Obj);
+ if (!BuildID)
+ return nullptr;
+ if (BuildID->size() < 2)
+ return nullptr;
+ std::string DebugBinaryPath;
+ if (!findDebugBinary(Opts.DebugFileDirectory, *BuildID, DebugBinaryPath))
+ return nullptr;
+ auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
+ if (!DbgObjOrErr) {
+ consumeError(DbgObjOrErr.takeError());
+ return nullptr;
+ }
+ return DbgObjOrErr.get();
+}
+
Expected<LLVMSymbolizer::ObjectPair>
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName) {
@@ -355,6 +447,8 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
+ else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
+ DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
if (!DbgObj)
DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
if (!DbgObj)