aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp')
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp1256
1 files changed, 830 insertions, 426 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index dd3235244e24..eb23ca8229a3 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -31,6 +31,7 @@
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
@@ -40,12 +41,13 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>
-#include <tuple>
#include <utility>
#include <vector>
@@ -59,81 +61,128 @@ using DWARFLineTable = DWARFDebugLine::LineTable;
using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
-static void dumpAccelSection(raw_ostream &OS, StringRef Name,
- const DWARFSection& Section, StringRef StringSection,
- bool LittleEndian) {
- DWARFDataExtractor AccelSection(Section, LittleEndian, 0);
- DataExtractor StrData(StringSection, LittleEndian, 0);
- OS << "\n." << Name << " contents:\n";
- DWARFAcceleratorTable Accel(AccelSection, StrData);
- if (!Accel.extract())
+DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+ std::string DWPName)
+ : DIContext(CK_DWARF), DWPName(std::move(DWPName)), DObj(std::move(DObj)) {}
+
+DWARFContext::~DWARFContext() = default;
+
+/// Dump the UUID load command.
+static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
+ auto *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachO)
return;
- Accel.dump(OS);
+ for (auto LC : MachO->load_commands()) {
+ raw_ostream::uuid_t UUID;
+ if (LC.C.cmd == MachO::LC_UUID) {
+ if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) {
+ OS << "error: UUID load command is too short.\n";
+ return;
+ }
+ OS << "UUID: ";
+ memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
+ OS.write_uuid(UUID);
+ OS << ' ' << MachO->getFileFormatName();
+ OS << ' ' << MachO->getFileName() << '\n';
+ }
+ }
}
-static void
-dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
- const DWARFSection &StringOffsetsSection,
- StringRef StringSection, bool LittleEndian) {
- DWARFDataExtractor StrOffsetExt(StringOffsetsSection, LittleEndian, 0);
- uint32_t Offset = 0;
- uint64_t SectionSize = StringOffsetsSection.Data.size();
+using ContributionCollection =
+ std::vector<Optional<StrOffsetsContributionDescriptor>>;
+
+// Collect all the contributions to the string offsets table from all units,
+// sort them by their starting offsets and remove duplicates.
+static ContributionCollection
+collectContributionData(DWARFContext::cu_iterator_range CUs,
+ DWARFContext::tu_section_iterator_range TUSs) {
+ ContributionCollection Contributions;
+ for (const auto &CU : CUs)
+ Contributions.push_back(CU->getStringOffsetsTableContribution());
+ for (const auto &TUS : TUSs)
+ for (const auto &TU : TUS)
+ Contributions.push_back(TU->getStringOffsetsTableContribution());
+
+ // Sort the contributions so that any invalid ones are placed at
+ // the start of the contributions vector. This way they are reported
+ // first.
+ std::sort(Contributions.begin(), Contributions.end(),
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R) return L->Base < R->Base;
+ return R.hasValue();
+ });
+
+ // Uniquify contributions, as it is possible that units (specifically
+ // type units in dwo or dwp files) share contributions. We don't want
+ // to report them more than once.
+ Contributions.erase(
+ std::unique(Contributions.begin(), Contributions.end(),
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R)
+ return L->Base == R->Base && L->Size == R->Size;
+ return false;
+ }),
+ Contributions.end());
+ return Contributions;
+}
- while (Offset < SectionSize) {
- unsigned Version = 0;
- DwarfFormat Format = DWARF32;
- unsigned EntrySize = 4;
- // Perform validation and extract the segment size from the header.
- if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 4)) {
+static void dumpDWARFv5StringOffsetsSection(
+ raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
+ const DWARFSection &StringOffsetsSection, StringRef StringSection,
+ DWARFContext::cu_iterator_range CUs,
+ DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian) {
+ auto Contributions = collectContributionData(CUs, TUSs);
+ DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
+ DataExtractor StrData(StringSection, LittleEndian, 0);
+ uint64_t SectionSize = StringOffsetsSection.Data.size();
+ uint32_t Offset = 0;
+ for (auto &Contribution : Contributions) {
+ // Report an ill-formed contribution.
+ if (!Contribution) {
OS << "error: invalid contribution to string offsets table in section ."
<< SectionName << ".\n";
return;
}
- uint32_t ContributionStart = Offset;
- uint64_t ContributionSize = StrOffsetExt.getU32(&Offset);
- // A contribution size of 0xffffffff indicates DWARF64, with the actual size
- // in the following 8 bytes. Otherwise, the DWARF standard mandates that
- // the contribution size must be at most 0xfffffff0.
- if (ContributionSize == 0xffffffff) {
- if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 8)) {
- OS << "error: invalid contribution to string offsets table in section ."
- << SectionName << ".\n";
- return;
- }
- Format = DWARF64;
- EntrySize = 8;
- ContributionSize = StrOffsetExt.getU64(&Offset);
- } else if (ContributionSize > 0xfffffff0) {
- OS << "error: invalid contribution to string offsets table in section ."
+
+ dwarf::DwarfFormat Format = Contribution->getFormat();
+ uint16_t Version = Contribution->getVersion();
+ uint64_t ContributionHeader = Contribution->Base;
+ // In DWARF v5 there is a contribution header that immediately precedes
+ // the string offsets base (the location we have previously retrieved from
+ // the CU DIE's DW_AT_str_offsets attribute). The header is located either
+ // 8 or 16 bytes before the base, depending on the contribution's format.
+ if (Version >= 5)
+ ContributionHeader -= Format == DWARF32 ? 8 : 16;
+
+ // Detect overlapping contributions.
+ if (Offset > ContributionHeader) {
+ OS << "error: overlapping contributions to string offsets table in "
+ "section ."
<< SectionName << ".\n";
return;
}
-
- // We must ensure that we don't read a partial record at the end, so we
- // validate for a multiple of EntrySize. Also, we're expecting a version
- // number and padding, which adds an additional 4 bytes.
- uint64_t ValidationSize =
- 4 + ((ContributionSize + EntrySize - 1) & (-(uint64_t)EntrySize));
- if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, ValidationSize)) {
- OS << "error: contribution to string offsets table in section ."
- << SectionName << " has invalid length.\n";
- return;
+ // Report a gap in the table.
+ if (Offset < ContributionHeader) {
+ OS << format("0x%8.8x: Gap, length = ", Offset);
+ OS << (ContributionHeader - Offset) << "\n";
}
-
- Version = StrOffsetExt.getU16(&Offset);
- Offset += 2;
- OS << format("0x%8.8x: ", ContributionStart);
- OS << "Contribution size = " << ContributionSize
+ OS << format("0x%8.8x: ", (uint32_t)ContributionHeader);
+ OS << "Contribution size = " << Contribution->Size
+ << ", Format = " << (Format == DWARF32 ? "DWARF32" : "DWARF64")
<< ", Version = " << Version << "\n";
- uint32_t ContributionBase = Offset;
- DataExtractor StrData(StringSection, LittleEndian, 0);
- while (Offset - ContributionBase < ContributionSize) {
+ Offset = Contribution->Base;
+ unsigned EntrySize = Contribution->getDwarfOffsetByteSize();
+ while (Offset - Contribution->Base < Contribution->Size) {
OS << format("0x%8.8x: ", Offset);
- // FIXME: We can only extract strings in DWARF32 format at the moment.
+ // FIXME: We can only extract strings if the offset fits in 32 bits.
uint64_t StringOffset =
StrOffsetExt.getRelocatedValue(EntrySize, &Offset);
- if (Format == DWARF32) {
+ // Extract the string if we can and display it. Otherwise just report
+ // the offset.
+ if (StringOffset <= std::numeric_limits<uint32_t>::max()) {
uint32_t StringOffset32 = (uint32_t)StringOffset;
OS << format("%8.8x ", StringOffset32);
const char *S = StrData.getCStr(&StringOffset32);
@@ -144,6 +193,11 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
OS << "\n";
}
}
+ // Report a gap at the end of the table.
+ if (Offset < SectionSize) {
+ OS << format("0x%8.8x: Gap, length = ", Offset);
+ OS << (SectionSize - Offset) << "\n";
+ }
}
// Dump a DWARF string offsets section. This may be a DWARF v5 formatted
@@ -152,19 +206,18 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
// a header containing size and version number. Alternatively, it may be a
// monolithic series of string offsets, as generated by the pre-DWARF v5
// implementation of split DWARF.
-static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
- const DWARFSection &StringOffsetsSection,
- StringRef StringSection, bool LittleEndian,
- unsigned MaxVersion) {
- if (StringOffsetsSection.Data.empty())
- return;
- OS << "\n." << SectionName << " contents:\n";
+static void dumpStringOffsetsSection(
+ raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
+ const DWARFSection &StringOffsetsSection, StringRef StringSection,
+ DWARFContext::cu_iterator_range CUs,
+ DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian,
+ unsigned MaxVersion) {
// If we have at least one (compile or type) unit with DWARF v5 or greater,
// we assume that the section is formatted like a DWARF v5 string offsets
// section.
if (MaxVersion >= 5)
- dumpDWARFv5StringOffsetsSection(OS, SectionName, StringOffsetsSection,
- StringSection, LittleEndian);
+ dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection,
+ StringSection, CUs, TUSs, LittleEndian);
else {
DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0);
uint32_t offset = 0;
@@ -188,140 +241,217 @@ static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
}
}
-void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
- DIDumpType DumpType = DumpOpts.DumpType;
- bool DumpEH = DumpOpts.DumpEH;
- bool SummarizeTypes = DumpOpts.SummarizeTypes;
+// We want to supply the Unit associated with a .debug_line[.dwo] table when
+// we dump it, if possible, but still dump the table even if there isn't a Unit.
+// Therefore, collect up handles on all the Units that point into the
+// line-table section.
+typedef std::map<uint64_t, DWARFUnit *> LineToUnitMap;
+
+static LineToUnitMap
+buildLineToUnitMap(DWARFContext::cu_iterator_range CUs,
+ DWARFContext::tu_section_iterator_range TUSections) {
+ LineToUnitMap LineToUnit;
+ for (const auto &CU : CUs)
+ if (auto CUDIE = CU->getUnitDIE())
+ if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list)))
+ LineToUnit.insert(std::make_pair(*StmtOffset, &*CU));
+ for (const auto &TUS : TUSections)
+ for (const auto &TU : TUS)
+ if (auto TUDIE = TU->getUnitDIE())
+ if (auto StmtOffset = toSectionOffset(TUDIE.find(DW_AT_stmt_list)))
+ LineToUnit.insert(std::make_pair(*StmtOffset, &*TU));
+ return LineToUnit;
+}
- if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
- OS << ".debug_abbrev contents:\n";
+void DWARFContext::dump(
+ raw_ostream &OS, DIDumpOptions DumpOpts,
+ std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
+
+ Optional<uint64_t> DumpOffset;
+ uint64_t DumpType = DumpOpts.DumpType;
+
+ StringRef Extension = sys::path::extension(DObj->getFileName());
+ bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp");
+
+ // Print UUID header.
+ const auto *ObjFile = DObj->getFile();
+ if (DumpType & DIDT_UUID)
+ dumpUUID(OS, *ObjFile);
+
+ // Print a header for each explicitly-requested section.
+ // Otherwise just print one for non-empty sections.
+ // Only print empty .dwo section headers when dumping a .dwo file.
+ bool Explicit = DumpType != DIDT_All && !IsDWO;
+ bool ExplicitDWO = Explicit && IsDWO;
+ auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
+ StringRef Section) {
+ DumpOffset = DumpOffsets[ID];
+ unsigned Mask = 1U << ID;
+ bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
+ if (Should)
+ OS << "\n" << Name << " contents:\n";
+ return Should;
+ };
+
+ // Dump individual sections.
+ if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevSection()))
getDebugAbbrev()->dump(OS);
- }
-
- if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo)
- if (const DWARFDebugAbbrev *D = getDebugAbbrevDWO()) {
- OS << "\n.debug_abbrev.dwo contents:\n";
- D->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevDWOSection()))
+ getDebugAbbrevDWO()->dump(OS);
+
+ auto dumpDebugInfo = [&](bool IsExplicit, const char *Name,
+ DWARFSection Section, cu_iterator_range CUs) {
+ if (shouldDump(IsExplicit, Name, DIDT_ID_DebugInfo, Section.Data)) {
+ if (DumpOffset)
+ getDIEForOffset(DumpOffset.getValue())
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ for (const auto &CU : CUs)
+ CU->dump(OS, DumpOpts);
}
-
- if (DumpType == DIDT_All || DumpType == DIDT_Info) {
- OS << "\n.debug_info contents:\n";
- for (const auto &CU : compile_units())
- CU->dump(OS, DumpOpts);
- }
-
- if ((DumpType == DIDT_All || DumpType == DIDT_InfoDwo) &&
- getNumDWOCompileUnits()) {
- OS << "\n.debug_info.dwo contents:\n";
- for (const auto &DWOCU : dwo_compile_units())
- DWOCU->dump(OS, DumpOpts);
- }
-
- if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) {
- OS << "\n.debug_types contents:\n";
- for (const auto &TUS : type_unit_sections())
+ };
+ dumpDebugInfo(Explicit, ".debug_info", DObj->getInfoSection(),
+ compile_units());
+ dumpDebugInfo(ExplicitDWO, ".debug_info.dwo", DObj->getInfoDWOSection(),
+ dwo_compile_units());
+
+ auto dumpDebugType = [&](const char *Name,
+ tu_section_iterator_range TUSections) {
+ OS << '\n' << Name << " contents:\n";
+ DumpOffset = DumpOffsets[DIDT_ID_DebugTypes];
+ for (const auto &TUS : TUSections)
for (const auto &TU : TUS)
- TU->dump(OS, SummarizeTypes);
+ if (DumpOffset)
+ TU->getDIEForOffset(*DumpOffset)
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ TU->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugTypes)) {
+ if (Explicit || getNumTypeUnits())
+ dumpDebugType(".debug_types", type_unit_sections());
+ if (ExplicitDWO || getNumDWOTypeUnits())
+ dumpDebugType(".debug_types.dwo", dwo_type_unit_sections());
}
- if ((DumpType == DIDT_All || DumpType == DIDT_TypesDwo) &&
- getNumDWOTypeUnits()) {
- OS << "\n.debug_types.dwo contents:\n";
- for (const auto &DWOTUS : dwo_type_unit_sections())
- for (const auto &DWOTU : DWOTUS)
- DWOTU->dump(OS, SummarizeTypes);
+ if (shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
+ DObj->getLocSection().Data)) {
+ getDebugLoc()->dump(OS, getRegisterInfo(), DumpOffset);
}
-
- if (DumpType == DIDT_All || DumpType == DIDT_Loc) {
- OS << "\n.debug_loc contents:\n";
- getDebugLoc()->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
+ DObj->getLocDWOSection().Data)) {
+ getDebugLocDWO()->dump(OS, getRegisterInfo(), DumpOffset);
}
- if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) {
- OS << "\n.debug_loc.dwo contents:\n";
- getDebugLocDWO()->dump(OS);
- }
+ if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
+ DObj->getDebugFrameSection()))
+ getDebugFrame()->dump(OS, DumpOffset);
- if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
- OS << "\n.debug_frame contents:\n";
- getDebugFrame()->dump(OS);
- if (DumpEH) {
- OS << "\n.eh_frame contents:\n";
- getEHFrame()->dump(OS);
- }
- }
+ if (shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
+ DObj->getEHFrameSection()))
+ getEHFrame()->dump(OS, DumpOffset);
- if (DumpType == DIDT_All || DumpType == DIDT_Macro) {
- OS << "\n.debug_macinfo contents:\n";
- getDebugMacro()->dump(OS);
+ if (DumpType & DIDT_DebugMacro) {
+ if (Explicit || !getDebugMacro()->empty()) {
+ OS << "\n.debug_macinfo contents:\n";
+ getDebugMacro()->dump(OS);
+ }
}
- uint32_t offset = 0;
- if (DumpType == DIDT_All || DumpType == DIDT_Aranges) {
- OS << "\n.debug_aranges contents:\n";
- DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
+ if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
+ DObj->getARangeSection())) {
+ uint32_t offset = 0;
+ DataExtractor arangesData(DObj->getARangeSection(), isLittleEndian(), 0);
DWARFDebugArangeSet set;
while (set.extract(arangesData, &offset))
set.dump(OS);
}
- uint8_t savedAddressByteSize = 0;
- if (DumpType == DIDT_All || DumpType == DIDT_Line) {
- OS << "\n.debug_line contents:\n";
- for (const auto &CU : compile_units()) {
- savedAddressByteSize = CU->getAddressByteSize();
- auto CUDIE = CU->getUnitDIE();
- if (!CUDIE)
+ if (shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
+ DObj->getLineSection().Data)) {
+ LineToUnitMap LineToUnit =
+ buildLineToUnitMap(compile_units(), type_unit_sections());
+ unsigned Offset = 0;
+ DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(),
+ 0);
+ while (Offset < LineData.getData().size()) {
+ DWARFUnit *U = nullptr;
+ auto It = LineToUnit.find(Offset);
+ if (It != LineToUnit.end())
+ U = It->second;
+ LineData.setAddressSize(U ? U->getAddressByteSize() : 0);
+ DWARFDebugLine::LineTable LineTable;
+ if (DumpOffset && Offset != *DumpOffset) {
+ // Find the size of this part of the line table section and skip it.
+ unsigned OldOffset = Offset;
+ LineTable.Prologue.parse(LineData, &Offset, U);
+ Offset = OldOffset + LineTable.Prologue.TotalLength +
+ LineTable.Prologue.sizeofTotalLength();
continue;
- if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) {
- DWARFDataExtractor lineData(getLineSection(), isLittleEndian(),
- savedAddressByteSize);
- DWARFDebugLine::LineTable LineTable;
- uint32_t Offset = *StmtOffset;
- LineTable.parse(lineData, &Offset);
+ }
+ // Verbose dumping is done during parsing and not on the intermediate
+ // representation.
+ OS << "debug_line[" << format("0x%8.8x", Offset) << "]\n";
+ unsigned OldOffset = Offset;
+ if (DumpOpts.Verbose) {
+ LineTable.parse(LineData, &Offset, U, &OS);
+ } else {
+ LineTable.parse(LineData, &Offset, U);
LineTable.dump(OS);
}
+ // Check for unparseable prologue, to avoid infinite loops.
+ if (OldOffset == Offset)
+ break;
}
}
- if (DumpType == DIDT_All || DumpType == DIDT_CUIndex) {
- OS << "\n.debug_cu_index contents:\n";
- getCUIndex().dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
+ DObj->getLineDWOSection().Data)) {
+ LineToUnitMap LineToUnit =
+ buildLineToUnitMap(dwo_compile_units(), dwo_type_unit_sections());
+ unsigned Offset = 0;
+ DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(),
+ isLittleEndian(), 0);
+ while (Offset < LineData.getData().size()) {
+ DWARFUnit *U = nullptr;
+ auto It = LineToUnit.find(Offset);
+ if (It != LineToUnit.end())
+ U = It->second;
+ DWARFDebugLine::LineTable LineTable;
+ unsigned OldOffset = Offset;
+ if (!LineTable.Prologue.parse(LineData, &Offset, U))
+ break;
+ if (!DumpOffset || OldOffset == *DumpOffset)
+ LineTable.dump(OS);
+ }
}
- if (DumpType == DIDT_All || DumpType == DIDT_TUIndex) {
- OS << "\n.debug_tu_index contents:\n";
- getTUIndex().dump(OS);
+ if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
+ DObj->getCUIndexSection())) {
+ getCUIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) {
- OS << "\n.debug_line.dwo contents:\n";
- unsigned stmtOffset = 0;
- DWARFDataExtractor lineData(getLineDWOSection(), isLittleEndian(),
- savedAddressByteSize);
- DWARFDebugLine::LineTable LineTable;
- while (LineTable.Prologue.parse(lineData, &stmtOffset)) {
- LineTable.dump(OS);
- LineTable.clear();
- }
+ if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
+ DObj->getTUIndexSection())) {
+ getTUIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_Str) {
- OS << "\n.debug_str contents:\n";
- DataExtractor strData(getStringSection(), isLittleEndian(), 0);
- offset = 0;
+ if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
+ DObj->getStringSection())) {
+ DataExtractor strData(DObj->getStringSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
uint32_t strOffset = 0;
while (const char *s = strData.getCStr(&offset)) {
OS << format("0x%8.8x: \"%s\"\n", strOffset, s);
strOffset = offset;
}
}
-
- if ((DumpType == DIDT_All || DumpType == DIDT_StrDwo) &&
- !getStringDWOSection().empty()) {
- OS << "\n.debug_str.dwo contents:\n";
- DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0);
- offset = 0;
+ if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
+ DObj->getStringDWOSection())) {
+ DataExtractor strDWOData(DObj->getStringDWOSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
uint32_t strDWOOffset = 0;
while (const char *s = strDWOData.getCStr(&offset)) {
OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
@@ -329,75 +459,96 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
- if (DumpType == DIDT_All || DumpType == DIDT_Ranges) {
- OS << "\n.debug_ranges contents:\n";
+ if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+ DObj->getRangeSection().Data)) {
// In fact, different compile units may have different address byte
- // sizes, but for simplicity we just use the address byte size of the last
- // compile unit (there is no easy and fast way to associate address range
- // list and the compile unit it describes).
- DWARFDataExtractor rangesData(getRangeSection(), isLittleEndian(),
- savedAddressByteSize);
- offset = 0;
+ // sizes, but for simplicity we just use the address byte size of the
+ // last compile unit (there is no easy and fast way to associate address
+ // range list and the compile unit it describes).
+ // FIXME: savedAddressByteSize seems sketchy.
+ uint8_t savedAddressByteSize = 0;
+ for (const auto &CU : compile_units()) {
+ savedAddressByteSize = CU->getAddressByteSize();
+ break;
+ }
+ DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(),
+ isLittleEndian(), savedAddressByteSize);
+ uint32_t offset = 0;
DWARFDebugRangeList rangeList;
while (rangeList.extract(rangesData, &offset))
rangeList.dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_Pubnames)
- DWARFDebugPubTable(getPubNamesSection(), isLittleEndian(), false)
- .dump("debug_pubnames", OS);
+ if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
+ DObj->getPubNamesSection()))
+ DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false)
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes)
- DWARFDebugPubTable(getPubTypesSection(), isLittleEndian(), false)
- .dump("debug_pubtypes", OS);
+ if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
+ DObj->getPubTypesSection()))
+ DWARFDebugPubTable(DObj->getPubTypesSection(), isLittleEndian(), false)
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames)
- DWARFDebugPubTable(getGnuPubNamesSection(), isLittleEndian(),
+ if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
+ DObj->getGnuPubNamesSection()))
+ DWARFDebugPubTable(DObj->getGnuPubNamesSection(), isLittleEndian(),
true /* GnuStyle */)
- .dump("debug_gnu_pubnames", OS);
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes)
- DWARFDebugPubTable(getGnuPubTypesSection(), isLittleEndian(),
+ if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
+ DObj->getGnuPubTypesSection()))
+ DWARFDebugPubTable(DObj->getGnuPubTypesSection(), isLittleEndian(),
true /* GnuStyle */)
- .dump("debug_gnu_pubtypes", OS);
-
- if (DumpType == DIDT_All || DumpType == DIDT_StrOffsets)
- dumpStringOffsetsSection(OS, "debug_str_offsets", getStringOffsetSection(),
- getStringSection(), isLittleEndian(),
- getMaxVersion());
-
- if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) {
- dumpStringOffsetsSection(OS, "debug_str_offsets.dwo",
- getStringOffsetDWOSection(), getStringDWOSection(),
- isLittleEndian(), getMaxVersion());
- }
-
- if ((DumpType == DIDT_All || DumpType == DIDT_GdbIndex) &&
- !getGdbIndexSection().empty()) {
- OS << "\n.gnu_index contents:\n";
+ .dump(OS);
+
+ if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetSection().Data))
+ dumpStringOffsetsSection(
+ OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(),
+ DObj->getStringSection(), compile_units(), type_unit_sections(),
+ isLittleEndian(), getMaxVersion());
+ if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetDWOSection().Data))
+ dumpStringOffsetsSection(
+ OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(),
+ DObj->getStringDWOSection(), dwo_compile_units(),
+ dwo_type_unit_sections(), isLittleEndian(), getMaxVersion());
+
+ if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex,
+ DObj->getGdbIndexSection())) {
getGdbIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNames)
- dumpAccelSection(OS, "apple_names", getAppleNamesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
+ DObj->getAppleNamesSection().Data))
+ getAppleNames().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleTypes)
- dumpAccelSection(OS, "apple_types", getAppleTypesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
+ DObj->getAppleTypesSection().Data))
+ getAppleTypes().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNamespaces)
- dumpAccelSection(OS, "apple_namespaces", getAppleNamespacesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
+ DObj->getAppleNamespacesSection().Data))
+ getAppleNamespaces().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleObjC)
- dumpAccelSection(OS, "apple_objc", getAppleObjCSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
+ DObj->getAppleObjCSection().Data))
+ getAppleObjC().dump(OS);
}
DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
- // FIXME: Improve this for the case where this DWO file is really a DWP file
- // with an index - use the index for lookup instead of a linear search.
+ DWOCUs.parseDWO(*this, DObj->getInfoDWOSection(), true);
+
+ if (const auto &CUI = getCUIndex()) {
+ if (const auto *R = CUI.getFromHash(Hash))
+ return DWOCUs.getUnitForIndexEntry(*R);
+ return nullptr;
+ }
+
+ // If there's no index, just search through the CUs in the DWO - there's
+ // probably only one unless this is something like LTO - though an in-process
+ // built/cached lookup table could be used in that case to improve repeated
+ // lookups of different CUs in the DWO.
for (const auto &DWOCU : dwo_compile_units())
if (DWOCU->getDWOId() == Hash)
return DWOCU.get();
@@ -411,21 +562,16 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
return DWARFDie();
}
-bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
+bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
bool Success = true;
- DWARFVerifier verifier(OS, *this);
- if (DumpType == DIDT_All || DumpType == DIDT_Info) {
- if (!verifier.handleDebugInfo())
- Success = false;
- }
- if (DumpType == DIDT_All || DumpType == DIDT_Line) {
- if (!verifier.handleDebugLine())
- Success = false;
- }
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) {
- if (!verifier.handleAppleNames())
- Success = false;
- }
+ DWARFVerifier verifier(OS, *this, DumpOpts);
+
+ Success &= verifier.handleDebugAbbrev();
+ if (DumpOpts.DumpType & DIDT_DebugInfo)
+ Success &= verifier.handleDebugInfo();
+ if (DumpOpts.DumpType & DIDT_DebugLine)
+ Success &= verifier.handleDebugLine();
+ Success &= verifier.handleAccelTables();
return Success;
}
@@ -433,7 +579,7 @@ const DWARFUnitIndex &DWARFContext::getCUIndex() {
if (CUIndex)
return *CUIndex;
- DataExtractor CUIndexData(getCUIndexSection(), isLittleEndian(), 0);
+ DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
CUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
CUIndex->parse(CUIndexData);
@@ -444,7 +590,7 @@ const DWARFUnitIndex &DWARFContext::getTUIndex() {
if (TUIndex)
return *TUIndex;
- DataExtractor TUIndexData(getTUIndexSection(), isLittleEndian(), 0);
+ DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
TUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_TYPES);
TUIndex->parse(TUIndexData);
@@ -455,7 +601,7 @@ DWARFGdbIndex &DWARFContext::getGdbIndex() {
if (GdbIndex)
return *GdbIndex;
- DataExtractor GdbIndexData(getGdbIndexSection(), true /*LE*/, 0);
+ DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
GdbIndex = llvm::make_unique<DWARFGdbIndex>();
GdbIndex->parse(GdbIndexData);
return *GdbIndex;
@@ -465,7 +611,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
if (Abbrev)
return Abbrev.get();
- DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0);
+ DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
Abbrev.reset(new DWARFDebugAbbrev());
Abbrev->extract(abbrData);
@@ -476,7 +622,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
if (AbbrevDWO)
return AbbrevDWO.get();
- DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0);
+ DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
AbbrevDWO.reset(new DWARFDebugAbbrev());
AbbrevDWO->extract(abbrData);
return AbbrevDWO.get();
@@ -489,7 +635,7 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
Loc.reset(new DWARFDebugLoc);
// assume all compile units have the same address byte size
if (getNumCompileUnits()) {
- DWARFDataExtractor LocData(getLocSection(), isLittleEndian(),
+ DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
getCompileUnitAtIndex(0)->getAddressByteSize());
Loc->parse(LocData);
}
@@ -500,7 +646,7 @@ const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
if (LocDWO)
return LocDWO.get();
- DataExtractor LocData(getLocDWOSection().Data, isLittleEndian(), 0);
+ DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 0);
LocDWO.reset(new DWARFDebugLocDWO());
LocDWO->parse(LocData);
return LocDWO.get();
@@ -528,8 +674,8 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
// provides this information). This problem is fixed in DWARFv4
// See this dwarf-discuss discussion for more details:
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
- DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(),
- getAddressSize());
+ DataExtractor debugFrameData(DObj->getDebugFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -539,8 +685,8 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() {
if (EHFrame)
return EHFrame.get();
- DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(),
- getAddressSize());
+ DataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -550,12 +696,47 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() {
if (Macro)
return Macro.get();
- DataExtractor MacinfoData(getMacinfoSection(), isLittleEndian(), 0);
+ DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0);
Macro.reset(new DWARFDebugMacro());
Macro->parse(MacinfoData);
return Macro.get();
}
+static DWARFAcceleratorTable &
+getAccelTable(std::unique_ptr<DWARFAcceleratorTable> &Cache,
+ const DWARFObject &Obj, const DWARFSection &Section,
+ StringRef StringSection, bool IsLittleEndian) {
+ if (Cache)
+ return *Cache;
+ DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
+ DataExtractor StrData(StringSection, IsLittleEndian, 0);
+ Cache.reset(new DWARFAcceleratorTable(AccelSection, StrData));
+ if (Error E = Cache->extract())
+ llvm::consumeError(std::move(E));
+ return *Cache;
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleNames() {
+ return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleTypes() {
+ return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleNamespaces() {
+ return getAccelTable(AppleNamespaces, *DObj,
+ DObj->getAppleNamespacesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleObjC() {
+ return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
const DWARFLineTable *
DWARFContext::getLineTableForUnit(DWARFUnit *U) {
if (!Line)
@@ -576,35 +757,35 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
// Make sure the offset is good before we try to parse.
if (stmtOffset >= U->getLineSection().Data.size())
- return nullptr;
+ return nullptr;
// We have to parse it first.
- DWARFDataExtractor lineData(U->getLineSection(), isLittleEndian(),
+ DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
U->getAddressByteSize());
- return Line->getOrParseLineTable(lineData, stmtOffset);
+ return Line->getOrParseLineTable(lineData, stmtOffset, U);
}
void DWARFContext::parseCompileUnits() {
- CUs.parse(*this, getInfoSection());
+ CUs.parse(*this, DObj->getInfoSection());
}
void DWARFContext::parseTypeUnits() {
if (!TUs.empty())
return;
- forEachTypesSections([&](const DWARFSection &S) {
+ DObj->forEachTypesSections([&](const DWARFSection &S) {
TUs.emplace_back();
TUs.back().parse(*this, S);
});
}
void DWARFContext::parseDWOCompileUnits() {
- DWOCUs.parseDWO(*this, getInfoDWOSection());
+ DWOCUs.parseDWO(*this, DObj->getInfoDWOSection());
}
void DWARFContext::parseDWOTypeUnits() {
if (!DWOTUs.empty())
return;
- forEachTypesDWOSections([&](const DWARFSection &S) {
+ DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
DWOTUs.emplace_back();
DWOTUs.back().parseDWO(*this, S);
});
@@ -622,6 +803,35 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
return getCompileUnitForOffset(CUOffset);
}
+DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
+ DIEsForAddress Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+
+ Result.CompileUnit = CU;
+ Result.FunctionDIE = CU->getSubroutineForAddress(Address);
+
+ std::vector<DWARFDie> Worklist;
+ Worklist.push_back(Result.FunctionDIE);
+ while (!Worklist.empty()) {
+ DWARFDie DIE = Worklist.back();
+ Worklist.pop_back();
+
+ if (DIE.getTag() == DW_TAG_lexical_block &&
+ DIE.addressRangeContainsAddress(Address)) {
+ Result.BlockDIE = DIE;
+ break;
+ }
+
+ for (auto Child : DIE)
+ Worklist.push_back(Child);
+ }
+
+ return Result;
+}
+
static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
uint64_t Address,
FunctionNameKind Kind,
@@ -793,11 +1003,13 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) {
return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
}
- SmallString<128> DWPName;
Expected<OwningBinary<ObjectFile>> Obj = [&] {
if (!CheckedForDWP) {
- (getFileName() + ".dwp").toVector(DWPName);
- auto Obj = object::ObjectFile::createObjectFile(DWPName);
+ SmallString<128> DWPName;
+ auto Obj = object::ObjectFile::createObjectFile(
+ this->DWPName.empty()
+ ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
+ : StringRef(this->DWPName));
if (Obj) {
Entry = &DWP;
return Obj;
@@ -820,7 +1032,7 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) {
auto S = std::make_shared<DWOFile>();
S->File = std::move(Obj.get());
- S->Context = llvm::make_unique<DWARFContextInMemory>(*S->File.getBinary());
+ S->Context = DWARFContext::create(*S->File.getBinary());
*Entry = S;
auto *Ctxt = S->Context.get();
return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
@@ -906,208 +1118,400 @@ static bool isRelocScattered(const object::ObjectFile &Obj,
return MachObj->isRelocationScattered(RelocInfo);
}
-Error DWARFContextInMemory::maybeDecompress(const SectionRef &Sec,
- StringRef Name, StringRef &Data) {
- if (!Decompressor::isCompressed(Sec))
- return Error::success();
+ErrorPolicy DWARFContext::defaultErrorHandler(Error E) {
+ errs() << "error: " + toString(std::move(E)) << '\n';
+ return ErrorPolicy::Continue;
+}
- Expected<Decompressor> Decompressor =
- Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
- if (!Decompressor)
- return Decompressor.takeError();
+namespace {
+struct DWARFSectionMap final : public DWARFSection {
+ RelocAddrMap Relocs;
+};
- SmallString<32> Out;
- if (auto Err = Decompressor->resizeAndDecompress(Out))
- return Err;
+class DWARFObjInMemory final : public DWARFObject {
+ bool IsLittleEndian;
+ uint8_t AddressSize;
+ StringRef FileName;
+ const object::ObjectFile *Obj = nullptr;
+ std::vector<SectionName> SectionNames;
+
+ using TypeSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
+ std::map<object::SectionRef, unsigned>>;
+
+ TypeSectionMap TypesSections;
+ TypeSectionMap TypesDWOSections;
+
+ DWARFSectionMap InfoSection;
+ DWARFSectionMap LocSection;
+ DWARFSectionMap LineSection;
+ DWARFSectionMap RangeSection;
+ DWARFSectionMap StringOffsetSection;
+ DWARFSectionMap InfoDWOSection;
+ DWARFSectionMap LineDWOSection;
+ DWARFSectionMap LocDWOSection;
+ DWARFSectionMap StringOffsetDWOSection;
+ DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap AddrSection;
+ DWARFSectionMap AppleNamesSection;
+ DWARFSectionMap AppleTypesSection;
+ DWARFSectionMap AppleNamespacesSection;
+ DWARFSectionMap AppleObjCSection;
+
+ DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
+ return StringSwitch<DWARFSectionMap *>(Name)
+ .Case("debug_info", &InfoSection)
+ .Case("debug_loc", &LocSection)
+ .Case("debug_line", &LineSection)
+ .Case("debug_str_offsets", &StringOffsetSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_info.dwo", &InfoDWOSection)
+ .Case("debug_loc.dwo", &LocDWOSection)
+ .Case("debug_line.dwo", &LineDWOSection)
+ .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
+ .Case("debug_addr", &AddrSection)
+ .Case("apple_names", &AppleNamesSection)
+ .Case("apple_types", &AppleTypesSection)
+ .Case("apple_namespaces", &AppleNamespacesSection)
+ .Case("apple_namespac", &AppleNamespacesSection)
+ .Case("apple_objc", &AppleObjCSection)
+ .Default(nullptr);
+ }
- UncompressedSections.emplace_back(std::move(Out));
- Data = UncompressedSections.back();
+ StringRef AbbrevSection;
+ StringRef ARangeSection;
+ StringRef DebugFrameSection;
+ StringRef EHFrameSection;
+ StringRef StringSection;
+ StringRef MacinfoSection;
+ StringRef PubNamesSection;
+ StringRef PubTypesSection;
+ StringRef GnuPubNamesSection;
+ StringRef AbbrevDWOSection;
+ StringRef StringDWOSection;
+ StringRef GnuPubTypesSection;
+ StringRef CUIndexSection;
+ StringRef GdbIndexSection;
+ StringRef TUIndexSection;
+
+ SmallVector<SmallString<32>, 4> UncompressedSections;
+
+ StringRef *mapSectionToMember(StringRef Name) {
+ if (DWARFSection *Sec = mapNameToDWARFSection(Name))
+ return &Sec->Data;
+ return StringSwitch<StringRef *>(Name)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("eh_frame", &EHFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_macinfo", &MacinfoSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_pubtypes", &PubTypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_str.dwo", &StringDWOSection)
+ .Case("debug_cu_index", &CUIndexSection)
+ .Case("debug_tu_index", &TUIndexSection)
+ .Case("gdb_index", &GdbIndexSection)
+ // Any more debug info sections go here.
+ .Default(nullptr);
+ }
- return Error::success();
-}
+ /// If Sec is compressed section, decompresses and updates its contents
+ /// provided by Data. Otherwise leaves it unchanged.
+ Error maybeDecompress(const object::SectionRef &Sec, StringRef Name,
+ StringRef &Data) {
+ if (!Decompressor::isCompressed(Sec))
+ return Error::success();
-ErrorPolicy DWARFContextInMemory::defaultErrorHandler(Error E) {
- errs() << "error: " + toString(std::move(E)) << '\n';
- return ErrorPolicy::Continue;
-}
+ Expected<Decompressor> Decompressor =
+ Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
+ if (!Decompressor)
+ return Decompressor.takeError();
-DWARFContextInMemory::DWARFContextInMemory(
- const object::ObjectFile &Obj, const LoadedObjectInfo *L,
- function_ref<ErrorPolicy(Error)> HandleError)
- : FileName(Obj.getFileName()), IsLittleEndian(Obj.isLittleEndian()),
- AddressSize(Obj.getBytesInAddress()) {
- for (const SectionRef &Section : Obj.sections()) {
- StringRef Name;
- Section.getName(Name);
- // Skip BSS and Virtual sections, they aren't interesting.
- if (Section.isBSS() || Section.isVirtual())
- continue;
-
- StringRef Data;
- section_iterator RelocatedSection = Section.getRelocatedSection();
- // Try to obtain an already relocated version of this section.
- // Else use the unrelocated section from the object file. We'll have to
- // apply relocations ourselves later.
- if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data))
- Section.getContents(Data);
-
- if (auto Err = maybeDecompress(Section, Name, Data)) {
- ErrorPolicy EP = HandleError(
- createError("failed to decompress '" + Name + "', ", std::move(Err)));
- if (EP == ErrorPolicy::Halt)
- return;
- continue;
+ SmallString<32> Out;
+ if (auto Err = Decompressor->resizeAndDecompress(Out))
+ return Err;
+
+ UncompressedSections.emplace_back(std::move(Out));
+ Data = UncompressedSections.back();
+
+ return Error::success();
+ }
+
+public:
+ DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool IsLittleEndian)
+ : IsLittleEndian(IsLittleEndian) {
+ for (const auto &SecIt : Sections) {
+ if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
+ *SectionData = SecIt.second->getBuffer();
}
+ }
+ DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError)
+ : IsLittleEndian(Obj.isLittleEndian()),
+ AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()),
+ Obj(&Obj) {
+
+ StringMap<unsigned> SectionAmountMap;
+ for (const SectionRef &Section : Obj.sections()) {
+ StringRef Name;
+ Section.getName(Name);
+ ++SectionAmountMap[Name];
+ SectionNames.push_back({ Name, true });
+
+ // Skip BSS and Virtual sections, they aren't interesting.
+ if (Section.isBSS() || Section.isVirtual())
+ continue;
- // Compressed sections names in GNU style starts from ".z",
- // at this point section is decompressed and we drop compression prefix.
- Name = Name.substr(
- Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+ // Skip sections stripped by dsymutil.
+ if (Section.isStripped())
+ continue;
- // Map platform specific debug section names to DWARF standard section
- // names.
- Name = Obj.mapDebugSectionName(Name);
+ StringRef Data;
+ section_iterator RelocatedSection = Section.getRelocatedSection();
+ // Try to obtain an already relocated version of this section.
+ // Else use the unrelocated section from the object file. We'll have to
+ // apply relocations ourselves later.
+ if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data))
+ Section.getContents(Data);
+
+ if (auto Err = maybeDecompress(Section, Name, Data)) {
+ ErrorPolicy EP = HandleError(createError(
+ "failed to decompress '" + Name + "', ", std::move(Err)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
- if (StringRef *SectionData = mapSectionToMember(Name)) {
- *SectionData = Data;
- if (Name == "debug_ranges") {
- // FIXME: Use the other dwo range section when we emit it.
- RangeDWOSection.Data = Data;
+ // Compressed sections names in GNU style starts from ".z",
+ // at this point section is decompressed and we drop compression prefix.
+ Name = Name.substr(
+ Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+
+ // Map platform specific debug section names to DWARF standard section
+ // names.
+ Name = Obj.mapDebugSectionName(Name);
+
+ if (StringRef *SectionData = mapSectionToMember(Name)) {
+ *SectionData = Data;
+ if (Name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangeDWOSection.Data = Data;
+ }
+ } else if (Name == "debug_types") {
+ // Find debug_types data by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ TypesSections[Section].Data = Data;
+ } else if (Name == "debug_types.dwo") {
+ TypesDWOSections[Section].Data = Data;
}
- } else if (Name == "debug_types") {
- // Find debug_types data by section rather than name as there are
- // multiple, comdat grouped, debug_types sections.
- TypesSections[Section].Data = Data;
- } else if (Name == "debug_types.dwo") {
- TypesDWOSections[Section].Data = Data;
- }
- if (RelocatedSection == Obj.section_end())
- continue;
-
- StringRef RelSecName;
- StringRef RelSecData;
- RelocatedSection->getName(RelSecName);
-
- // If the section we're relocating was relocated already by the JIT,
- // then we used the relocated version above, so we do not need to process
- // relocations for it now.
- if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
- continue;
-
- // In Mach-o files, the relocations do not need to be applied if
- // there is no load offset to apply. The value read at the
- // relocation point already factors in the section address
- // (actually applying the relocations will produce wrong results
- // as the section address will be added twice).
- if (!L && isa<MachOObjectFile>(&Obj))
- continue;
-
- RelSecName = RelSecName.substr(
- RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
-
- // TODO: Add support for relocations in other sections as needed.
- // Record relocations for the debug_info and debug_line sections.
- DWARFSection *Sec = mapNameToDWARFSection(RelSecName);
- RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
- if (!Map) {
- // Find debug_types relocs by section rather than name as there are
- // multiple, comdat grouped, debug_types sections.
- if (RelSecName == "debug_types")
- Map = &TypesSections[*RelocatedSection].Relocs;
- else if (RelSecName == "debug_types.dwo")
- Map = &TypesDWOSections[*RelocatedSection].Relocs;
- else
+ if (RelocatedSection == Obj.section_end())
continue;
- }
- if (Section.relocation_begin() == Section.relocation_end())
- continue;
+ StringRef RelSecName;
+ StringRef RelSecData;
+ RelocatedSection->getName(RelSecName);
- // Symbol to [address, section index] cache mapping.
- std::map<SymbolRef, SymInfo> AddrCache;
- for (const RelocationRef &Reloc : Section.relocations()) {
- // FIXME: it's not clear how to correctly handle scattered
- // relocations.
- if (isRelocScattered(Obj, Reloc))
+ // If the section we're relocating was relocated already by the JIT,
+ // then we used the relocated version above, so we do not need to process
+ // relocations for it now.
+ if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
continue;
- Expected<SymInfo> SymInfoOrErr = getSymbolInfo(Obj, Reloc, L, AddrCache);
- if (!SymInfoOrErr) {
- if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
- return;
+ // In Mach-o files, the relocations do not need to be applied if
+ // there is no load offset to apply. The value read at the
+ // relocation point already factors in the section address
+ // (actually applying the relocations will produce wrong results
+ // as the section address will be added twice).
+ if (!L && isa<MachOObjectFile>(&Obj))
continue;
+
+ RelSecName = RelSecName.substr(
+ RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
+ RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
+ if (!Map) {
+ // Find debug_types relocs by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ if (RelSecName == "debug_types")
+ Map =
+ &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_types.dwo")
+ Map = &static_cast<DWARFSectionMap &>(
+ TypesDWOSections[*RelocatedSection])
+ .Relocs;
+ else
+ continue;
}
- object::RelocVisitor V(Obj);
- uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address);
- if (V.error()) {
- SmallString<32> Type;
- Reloc.getTypeName(Type);
- ErrorPolicy EP = HandleError(
- createError("failed to compute relocation: " + Type + ", ",
- errorCodeToError(object_error::parse_failed)));
- if (EP == ErrorPolicy::Halt)
- return;
+ if (Section.relocation_begin() == Section.relocation_end())
continue;
+
+ // Symbol to [address, section index] cache mapping.
+ std::map<SymbolRef, SymInfo> AddrCache;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ // FIXME: it's not clear how to correctly handle scattered
+ // relocations.
+ if (isRelocScattered(Obj, Reloc))
+ continue;
+
+ Expected<SymInfo> SymInfoOrErr =
+ getSymbolInfo(Obj, Reloc, L, AddrCache);
+ if (!SymInfoOrErr) {
+ if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+
+ object::RelocVisitor V(Obj);
+ uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address);
+ if (V.error()) {
+ SmallString<32> Type;
+ Reloc.getTypeName(Type);
+ ErrorPolicy EP = HandleError(
+ createError("failed to compute relocation: " + Type + ", ",
+ errorCodeToError(object_error::parse_failed)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+ RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val};
+ Map->insert({Reloc.getOffset(), Rel});
}
- RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val};
- Map->insert({Reloc.getOffset(), Rel});
}
+
+ for (SectionName &S : SectionNames)
+ if (SectionAmountMap[S.Name] > 1)
+ S.IsNameUnique = false;
}
-}
-DWARFContextInMemory::DWARFContextInMemory(
- const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, uint8_t AddrSize,
- bool isLittleEndian)
- : IsLittleEndian(isLittleEndian), AddressSize(AddrSize) {
- for (const auto &SecIt : Sections) {
- if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
- *SectionData = SecIt.second->getBuffer();
+ Optional<RelocAddrEntry> find(const DWARFSection &S,
+ uint64_t Pos) const override {
+ auto &Sec = static_cast<const DWARFSectionMap &>(S);
+ RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos);
+ if (AI == Sec.Relocs.end())
+ return None;
+ return AI->second;
}
-}
-DWARFSection *DWARFContextInMemory::mapNameToDWARFSection(StringRef Name) {
- return StringSwitch<DWARFSection *>(Name)
- .Case("debug_info", &InfoSection)
- .Case("debug_loc", &LocSection)
- .Case("debug_line", &LineSection)
- .Case("debug_str_offsets", &StringOffsetSection)
- .Case("debug_ranges", &RangeSection)
- .Case("debug_info.dwo", &InfoDWOSection)
- .Case("debug_loc.dwo", &LocDWOSection)
- .Case("debug_line.dwo", &LineDWOSection)
- .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
- .Case("debug_addr", &AddrSection)
- .Case("apple_names", &AppleNamesSection)
- .Case("apple_types", &AppleTypesSection)
- .Case("apple_namespaces", &AppleNamespacesSection)
- .Case("apple_namespac", &AppleNamespacesSection)
- .Case("apple_objc", &AppleObjCSection)
- .Default(nullptr);
+ const object::ObjectFile *getFile() const override { return Obj; }
+
+ ArrayRef<SectionName> getSectionNames() const override {
+ return SectionNames;
+ }
+
+ bool isLittleEndian() const override { return IsLittleEndian; }
+ StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; }
+ const DWARFSection &getLineDWOSection() const override {
+ return LineDWOSection;
+ }
+ const DWARFSection &getLocDWOSection() const override {
+ return LocDWOSection;
+ }
+ StringRef getStringDWOSection() const override { return StringDWOSection; }
+ const DWARFSection &getStringOffsetDWOSection() const override {
+ return StringOffsetDWOSection;
+ }
+ const DWARFSection &getRangeDWOSection() const override {
+ return RangeDWOSection;
+ }
+ const DWARFSection &getAddrSection() const override { return AddrSection; }
+ StringRef getCUIndexSection() const override { return CUIndexSection; }
+ StringRef getGdbIndexSection() const override { return GdbIndexSection; }
+ StringRef getTUIndexSection() const override { return TUIndexSection; }
+
+ // DWARF v5
+ const DWARFSection &getStringOffsetSection() const override {
+ return StringOffsetSection;
+ }
+
+ // Sections for DWARF5 split dwarf proposal.
+ const DWARFSection &getInfoDWOSection() const override {
+ return InfoDWOSection;
+ }
+ void forEachTypesDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesDWOSections)
+ F(P.second);
+ }
+
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ const DWARFSection &getLocSection() const override { return LocSection; }
+ StringRef getARangeSection() const override { return ARangeSection; }
+ StringRef getDebugFrameSection() const override { return DebugFrameSection; }
+ StringRef getEHFrameSection() const override { return EHFrameSection; }
+ const DWARFSection &getLineSection() const override { return LineSection; }
+ StringRef getStringSection() const override { return StringSection; }
+ const DWARFSection &getRangeSection() const override { return RangeSection; }
+ StringRef getMacinfoSection() const override { return MacinfoSection; }
+ StringRef getPubNamesSection() const override { return PubNamesSection; }
+ StringRef getPubTypesSection() const override { return PubTypesSection; }
+ StringRef getGnuPubNamesSection() const override {
+ return GnuPubNamesSection;
+ }
+ StringRef getGnuPubTypesSection() const override {
+ return GnuPubTypesSection;
+ }
+ const DWARFSection &getAppleNamesSection() const override {
+ return AppleNamesSection;
+ }
+ const DWARFSection &getAppleTypesSection() const override {
+ return AppleTypesSection;
+ }
+ const DWARFSection &getAppleNamespacesSection() const override {
+ return AppleNamespacesSection;
+ }
+ const DWARFSection &getAppleObjCSection() const override {
+ return AppleObjCSection;
+ }
+
+ StringRef getFileName() const override { return FileName; }
+ uint8_t getAddressSize() const override { return AddressSize; }
+ const DWARFSection &getInfoSection() const override { return InfoSection; }
+ void forEachTypesSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesSections)
+ F(P.second);
+ }
+};
+} // namespace
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError,
+ std::string DWPName) {
+ auto DObj = llvm::make_unique<DWARFObjInMemory>(Obj, L, HandleError);
+ return llvm::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName));
}
-StringRef *DWARFContextInMemory::mapSectionToMember(StringRef Name) {
- if (DWARFSection *Sec = mapNameToDWARFSection(Name))
- return &Sec->Data;
- return StringSwitch<StringRef *>(Name)
- .Case("debug_abbrev", &AbbrevSection)
- .Case("debug_aranges", &ARangeSection)
- .Case("debug_frame", &DebugFrameSection)
- .Case("eh_frame", &EHFrameSection)
- .Case("debug_str", &StringSection)
- .Case("debug_macinfo", &MacinfoSection)
- .Case("debug_pubnames", &PubNamesSection)
- .Case("debug_pubtypes", &PubTypesSection)
- .Case("debug_gnu_pubnames", &GnuPubNamesSection)
- .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
- .Case("debug_abbrev.dwo", &AbbrevDWOSection)
- .Case("debug_str.dwo", &StringDWOSection)
- .Case("debug_cu_index", &CUIndexSection)
- .Case("debug_tu_index", &TUIndexSection)
- .Case("gdb_index", &GdbIndexSection)
- // Any more debug info sections go here.
- .Default(nullptr);
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool isLittleEndian) {
+ auto DObj =
+ llvm::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
+ return llvm::make_unique<DWARFContext>(std::move(DObj), "");
}
-void DWARFContextInMemory::anchor() {}
+Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
+ // Detect the architecture from the object file. We usually don't need OS
+ // info to lookup a target and create register info.
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+ std::string TargetLookupError;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
+ if (!TargetLookupError.empty())
+ return make_error<StringError>(TargetLookupError, inconvertibleErrorCode());
+ RegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return Error::success();
+}