aboutsummaryrefslogtreecommitdiff
path: root/lib/DebugInfo/DWARF
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/DWARF')
-rw-r--r--lib/DebugInfo/DWARF/CMakeLists.txt22
-rw-r--r--lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp97
-rw-r--r--lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp132
-rw-r--r--lib/DebugInfo/DWARF/DWARFCompileUnit.cpp33
-rw-r--r--lib/DebugInfo/DWARF/DWARFContext.cpp737
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp115
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp104
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugAranges.cpp129
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugFrame.cpp521
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp460
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLine.cpp698
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLoc.cpp127
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp69
-rw-r--r--lib/DebugInfo/DWARF/DWARFFormValue.cpp589
-rw-r--r--lib/DebugInfo/DWARF/DWARFTypeUnit.cpp40
-rw-r--r--lib/DebugInfo/DWARF/DWARFUnit.cpp377
-rw-r--r--lib/DebugInfo/DWARF/LLVMBuild.txt22
-rw-r--r--lib/DebugInfo/DWARF/Makefile14
-rw-r--r--lib/DebugInfo/DWARF/SyntaxHighlighting.cpp37
-rw-r--r--lib/DebugInfo/DWARF/SyntaxHighlighting.h39
-rw-r--r--lib/DebugInfo/DWARF/module.modulemap1
21 files changed, 4363 insertions, 0 deletions
diff --git a/lib/DebugInfo/DWARF/CMakeLists.txt b/lib/DebugInfo/DWARF/CMakeLists.txt
new file mode 100644
index 000000000000..d5f8a6f24eec
--- /dev/null
+++ b/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -0,0 +1,22 @@
+add_llvm_library(LLVMDebugInfoDWARF
+ DWARFAbbreviationDeclaration.cpp
+ DWARFAcceleratorTable.cpp
+ DWARFCompileUnit.cpp
+ DWARFContext.cpp
+ DWARFDebugAbbrev.cpp
+ DWARFDebugArangeSet.cpp
+ DWARFDebugAranges.cpp
+ DWARFDebugFrame.cpp
+ DWARFDebugInfoEntry.cpp
+ DWARFDebugLine.cpp
+ DWARFDebugLoc.cpp
+ DWARFDebugRangeList.cpp
+ DWARFFormValue.cpp
+ DWARFTypeUnit.cpp
+ DWARFUnit.cpp
+ SyntaxHighlighting.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/DWARF
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo
+ )
diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 000000000000..9314c9eabc48
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,97 @@
+//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFAbbreviationDeclaration::clear() {
+ Code = 0;
+ Tag = 0;
+ HasChildren = false;
+ AttributeSpecs.clear();
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
+ clear();
+}
+
+bool
+DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint32_t* OffsetPtr) {
+ clear();
+ Code = Data.getULEB128(OffsetPtr);
+ if (Code == 0) {
+ return false;
+ }
+ Tag = Data.getULEB128(OffsetPtr);
+ uint8_t ChildrenByte = Data.getU8(OffsetPtr);
+ HasChildren = (ChildrenByte == DW_CHILDREN_yes);
+
+ while (true) {
+ uint32_t CurOffset = *OffsetPtr;
+ uint16_t Attr = Data.getULEB128(OffsetPtr);
+ if (CurOffset == *OffsetPtr) {
+ clear();
+ return false;
+ }
+ CurOffset = *OffsetPtr;
+ uint16_t Form = Data.getULEB128(OffsetPtr);
+ if (CurOffset == *OffsetPtr) {
+ clear();
+ return false;
+ }
+ if (Attr == 0 && Form == 0)
+ break;
+ AttributeSpecs.push_back(AttributeSpec(Attr, Form));
+ }
+
+ if (Tag == 0) {
+ clear();
+ return false;
+ }
+ return true;
+}
+
+void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
+ const char *tagString = TagString(getTag());
+ OS << '[' << getCode() << "] ";
+ if (tagString)
+ OS << tagString;
+ else
+ OS << format("DW_TAG_Unknown_%x", getTag());
+ OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
+ for (const AttributeSpec &Spec : AttributeSpecs) {
+ OS << '\t';
+ const char *attrString = AttributeString(Spec.Attr);
+ if (attrString)
+ OS << attrString;
+ else
+ OS << format("DW_AT_Unknown_%x", Spec.Attr);
+ OS << '\t';
+ const char *formString = FormEncodingString(Spec.Form);
+ if (formString)
+ OS << formString;
+ else
+ OS << format("DW_FORM_Unknown_%x", Spec.Form);
+ OS << '\n';
+ }
+ OS << '\n';
+}
+
+uint32_t
+DWARFAbbreviationDeclaration::findAttributeIndex(uint16_t attr) const {
+ for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
+ if (AttributeSpecs[i].Attr == attr)
+ return i;
+ }
+ return -1U;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
new file mode 100644
index 000000000000..8ae05432869a
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -0,0 +1,132 @@
+//===--- DWARFAcceleratorTable.cpp ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+bool DWARFAcceleratorTable::extract() {
+ uint32_t Offset = 0;
+
+ // Check that we can at least read the header.
+ if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
+ return false;
+
+ Hdr.Magic = AccelSection.getU32(&Offset);
+ Hdr.Version = AccelSection.getU16(&Offset);
+ Hdr.HashFunction = AccelSection.getU16(&Offset);
+ Hdr.NumBuckets = AccelSection.getU32(&Offset);
+ Hdr.NumHashes = AccelSection.getU32(&Offset);
+ Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
+
+ // Check that we can read all the hashes and offsets from the
+ // section (see SourceLevelDebugging.rst for the structure of the index).
+ if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
+ Hdr.NumBuckets*4 + Hdr.NumHashes*8))
+ return false;
+
+ HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
+ uint32_t NumAtoms = AccelSection.getU32(&Offset);
+
+ for (unsigned i = 0; i < NumAtoms; ++i) {
+ uint16_t AtomType = AccelSection.getU16(&Offset);
+ uint16_t AtomForm = AccelSection.getU16(&Offset);
+ HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
+ }
+
+ return true;
+}
+
+void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
+ // Dump the header.
+ OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
+ << "Version = " << format("0x%04x", Hdr.Version) << '\n'
+ << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
+ << "Bucket count = " << Hdr.NumBuckets << '\n'
+ << "Hashes count = " << Hdr.NumHashes << '\n'
+ << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
+ << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
+ << "Number of atoms = " << HdrData.Atoms.size() << '\n';
+
+ unsigned i = 0;
+ SmallVector<DWARFFormValue, 3> AtomForms;
+ for (const auto &Atom: HdrData.Atoms) {
+ OS << format("Atom[%d] Type: ", i++);
+ if (const char *TypeString = dwarf::AtomTypeString(Atom.first))
+ OS << TypeString;
+ else
+ OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
+ OS << " Form: ";
+ if (const char *FormString = dwarf::FormEncodingString(Atom.second))
+ OS << FormString;
+ else
+ OS << format("DW_FORM_Unknown_0x%x", Atom.second);
+ OS << '\n';
+ AtomForms.push_back(DWARFFormValue(Atom.second));
+ }
+
+ // Now go through the actual tables and dump them.
+ uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
+ unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
+ unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
+
+ for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
+ unsigned Index = AccelSection.getU32(&Offset);
+
+ OS << format("Bucket[%d]\n", Bucket);
+ if (Index == UINT32_MAX) {
+ OS << " EMPTY\n";
+ continue;
+ }
+
+ for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
+ unsigned HashOffset = HashesBase + HashIdx*4;
+ unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.NumBuckets != Bucket)
+ break;
+
+ unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
+ OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
+ if (!AccelSection.isValidOffset(DataOffset)) {
+ OS << " Invalid section offset\n";
+ continue;
+ }
+ while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
+ unsigned StringOffset = AccelSection.getU32(&DataOffset);
+ RelocAddrMap::const_iterator Reloc = Relocs.find(DataOffset-4);
+ if (Reloc != Relocs.end())
+ StringOffset += Reloc->second.second;
+ if (!StringOffset)
+ break;
+ OS << format(" Name: %08x \"%s\"\n", StringOffset,
+ StringSection.getCStr(&StringOffset));
+ unsigned NumData = AccelSection.getU32(&DataOffset);
+ for (unsigned Data = 0; Data < NumData; ++Data) {
+ OS << format(" Data[%d] => ", Data);
+ unsigned i = 0;
+ for (auto &Atom : AtomForms) {
+ OS << format("{Atom[%d]: ", i++);
+ if (Atom.extractValue(AccelSection, &DataOffset, nullptr))
+ Atom.dump(OS, nullptr);
+ else
+ OS << "Error extracting the value";
+ OS << "} ";
+ }
+ OS << '\n';
+ }
+ }
+ }
+ }
+}
+}
diff --git a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 000000000000..39a7c772dc76
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,33 @@
+//===-- DWARFCompileUnit.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFCompileUnit::dump(raw_ostream &OS) {
+ OS << format("0x%08x", getOffset()) << ": Compile Unit:"
+ << " length = " << format("0x%08x", getLength())
+ << " version = " << format("0x%04x", getVersion())
+ << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
+ << " addr_size = " << format("0x%02x", getAddressByteSize())
+ << " (next unit at " << format("0x%08x", getNextUnitOffset())
+ << ")\n";
+
+ if (const DWARFDebugInfoEntryMinimal *CU = getUnitDIE(false))
+ CU->dump(OS, this, -1U);
+ else
+ OS << "<compile unit can't be parsed!>\n\n";
+}
+
+// VTable anchor.
+DWARFCompileUnit::~DWARFCompileUnit() {
+}
diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp
new file mode 100644
index 000000000000..cc2fbbdc8ca7
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -0,0 +1,737 @@
+//===-- DWARFContext.cpp --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+#define DEBUG_TYPE "dwarf"
+
+typedef DWARFDebugLine::LineTable DWARFLineTable;
+typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
+typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind;
+
+static void dumpPubSection(raw_ostream &OS, StringRef Name, StringRef Data,
+ bool LittleEndian, bool GnuStyle) {
+ OS << "\n." << Name << " contents:\n";
+ DataExtractor pubNames(Data, LittleEndian, 0);
+ uint32_t offset = 0;
+ while (pubNames.isValidOffset(offset)) {
+ OS << "length = " << format("0x%08x", pubNames.getU32(&offset));
+ OS << " version = " << format("0x%04x", pubNames.getU16(&offset));
+ OS << " unit_offset = " << format("0x%08x", pubNames.getU32(&offset));
+ OS << " unit_size = " << format("0x%08x", pubNames.getU32(&offset)) << '\n';
+ if (GnuStyle)
+ OS << "Offset Linkage Kind Name\n";
+ else
+ OS << "Offset Name\n";
+
+ while (offset < Data.size()) {
+ uint32_t dieRef = pubNames.getU32(&offset);
+ if (dieRef == 0)
+ break;
+ OS << format("0x%8.8x ", dieRef);
+ if (GnuStyle) {
+ PubIndexEntryDescriptor desc(pubNames.getU8(&offset));
+ OS << format("%-8s", dwarf::GDBIndexEntryLinkageString(desc.Linkage))
+ << ' ' << format("%-8s", dwarf::GDBIndexEntryKindString(desc.Kind))
+ << ' ';
+ }
+ OS << '\"' << pubNames.getCStr(&offset) << "\"\n";
+ }
+ }
+}
+
+static void dumpAccelSection(raw_ostream &OS, StringRef Name,
+ const DWARFSection& Section, StringRef StringSection,
+ bool LittleEndian) {
+ DataExtractor AccelSection(Section.Data, LittleEndian, 0);
+ DataExtractor StrData(StringSection, LittleEndian, 0);
+ OS << "\n." << Name << " contents:\n";
+ DWARFAcceleratorTable Accel(AccelSection, StrData, Section.Relocs);
+ if (!Accel.extract())
+ return;
+ Accel.dump(OS);
+}
+
+void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
+ if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
+ OS << ".debug_abbrev contents:\n";
+ 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 (DumpType == DIDT_All || DumpType == DIDT_Info) {
+ OS << "\n.debug_info contents:\n";
+ for (const auto &CU : compile_units())
+ CU->dump(OS);
+ }
+
+ 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);
+ }
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) {
+ OS << "\n.debug_types contents:\n";
+ for (const auto &TUS : type_unit_sections())
+ for (const auto &TU : TUS)
+ TU->dump(OS);
+ }
+
+ 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);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Loc) {
+ OS << "\n.debug_loc contents:\n";
+ getDebugLoc()->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) {
+ OS << "\n.debug_loc.dwo contents:\n";
+ getDebugLocDWO()->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
+ OS << "\n.debug_frame contents:\n";
+ getDebugFrame()->dump(OS);
+ }
+
+ uint32_t offset = 0;
+ if (DumpType == DIDT_All || DumpType == DIDT_Aranges) {
+ OS << "\n.debug_aranges contents:\n";
+ DataExtractor arangesData(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();
+ const auto *CUDIE = CU->getUnitDIE();
+ if (CUDIE == nullptr)
+ continue;
+ unsigned stmtOffset = CUDIE->getAttributeValueAsSectionOffset(
+ CU.get(), DW_AT_stmt_list, -1U);
+ if (stmtOffset != -1U) {
+ DataExtractor lineData(getLineSection().Data, isLittleEndian(),
+ savedAddressByteSize);
+ DWARFDebugLine::LineTable LineTable;
+ LineTable.parse(lineData, &getLineSection().Relocs, &stmtOffset);
+ LineTable.dump(OS);
+ }
+ }
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) {
+ OS << "\n.debug_line.dwo contents:\n";
+ unsigned stmtOffset = 0;
+ DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(),
+ savedAddressByteSize);
+ DWARFDebugLine::LineTable LineTable;
+ while (LineTable.Prologue.parse(lineData, &stmtOffset)) {
+ LineTable.dump(OS);
+ LineTable.clear();
+ }
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Str) {
+ OS << "\n.debug_str contents:\n";
+ DataExtractor strData(getStringSection(), isLittleEndian(), 0);
+ 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;
+ uint32_t strDWOOffset = 0;
+ while (const char *s = strDWOData.getCStr(&offset)) {
+ OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
+ strDWOOffset = offset;
+ }
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Ranges) {
+ OS << "\n.debug_ranges contents:\n";
+ // 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).
+ DataExtractor rangesData(getRangeSection(), isLittleEndian(),
+ savedAddressByteSize);
+ offset = 0;
+ DWARFDebugRangeList rangeList;
+ while (rangeList.extract(rangesData, &offset))
+ rangeList.dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Pubnames)
+ dumpPubSection(OS, "debug_pubnames", getPubNamesSection(),
+ isLittleEndian(), false);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes)
+ dumpPubSection(OS, "debug_pubtypes", getPubTypesSection(),
+ isLittleEndian(), false);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames)
+ dumpPubSection(OS, "debug_gnu_pubnames", getGnuPubNamesSection(),
+ isLittleEndian(), true /* GnuStyle */);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes)
+ dumpPubSection(OS, "debug_gnu_pubtypes", getGnuPubTypesSection(),
+ isLittleEndian(), true /* GnuStyle */);
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) &&
+ !getStringOffsetDWOSection().empty()) {
+ OS << "\n.debug_str_offsets.dwo contents:\n";
+ DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(),
+ 0);
+ offset = 0;
+ uint64_t size = getStringOffsetDWOSection().size();
+ while (offset < size) {
+ OS << format("0x%8.8x: ", offset);
+ OS << format("%8.8x\n", strOffsetExt.getU32(&offset));
+ }
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_AppleNames)
+ dumpAccelSection(OS, "apple_names", getAppleNamesSection(),
+ getStringSection(), isLittleEndian());
+
+ if (DumpType == DIDT_All || DumpType == DIDT_AppleTypes)
+ dumpAccelSection(OS, "apple_types", getAppleTypesSection(),
+ getStringSection(), isLittleEndian());
+
+ if (DumpType == DIDT_All || DumpType == DIDT_AppleNamespaces)
+ dumpAccelSection(OS, "apple_namespaces", getAppleNamespacesSection(),
+ getStringSection(), isLittleEndian());
+
+ if (DumpType == DIDT_All || DumpType == DIDT_AppleObjC)
+ dumpAccelSection(OS, "apple_objc", getAppleObjCSection(),
+ getStringSection(), isLittleEndian());
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
+ if (Abbrev)
+ return Abbrev.get();
+
+ DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0);
+
+ Abbrev.reset(new DWARFDebugAbbrev());
+ Abbrev->extract(abbrData);
+ return Abbrev.get();
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
+ if (AbbrevDWO)
+ return AbbrevDWO.get();
+
+ DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0);
+ AbbrevDWO.reset(new DWARFDebugAbbrev());
+ AbbrevDWO->extract(abbrData);
+ return AbbrevDWO.get();
+}
+
+const DWARFDebugLoc *DWARFContext::getDebugLoc() {
+ if (Loc)
+ return Loc.get();
+
+ DataExtractor LocData(getLocSection().Data, isLittleEndian(), 0);
+ Loc.reset(new DWARFDebugLoc(getLocSection().Relocs));
+ // assume all compile units have the same address byte size
+ if (getNumCompileUnits())
+ Loc->parse(LocData, getCompileUnitAtIndex(0)->getAddressByteSize());
+ return Loc.get();
+}
+
+const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
+ if (LocDWO)
+ return LocDWO.get();
+
+ DataExtractor LocData(getLocDWOSection().Data, isLittleEndian(), 0);
+ LocDWO.reset(new DWARFDebugLocDWO());
+ LocDWO->parse(LocData);
+ return LocDWO.get();
+}
+
+const DWARFDebugAranges *DWARFContext::getDebugAranges() {
+ if (Aranges)
+ return Aranges.get();
+
+ Aranges.reset(new DWARFDebugAranges());
+ Aranges->generate(this);
+ return Aranges.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getDebugFrame() {
+ if (DebugFrame)
+ return DebugFrame.get();
+
+ // There's a "bug" in the DWARFv3 standard with respect to the target address
+ // size within debug frame sections. While DWARF is supposed to be independent
+ // of its container, FDEs have fields with size being "target address size",
+ // which isn't specified in DWARF in general. It's only specified for CUs, but
+ // .eh_frame can appear without a .debug_info section. Follow the example of
+ // other tools (libdwarf) and extract this from the container (ObjectFile
+ // 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());
+ DebugFrame.reset(new DWARFDebugFrame());
+ DebugFrame->parse(debugFrameData);
+ return DebugFrame.get();
+}
+
+const DWARFLineTable *
+DWARFContext::getLineTableForUnit(DWARFUnit *U) {
+ if (!Line)
+ Line.reset(new DWARFDebugLine(&getLineSection().Relocs));
+ const auto *UnitDIE = U->getUnitDIE();
+ if (UnitDIE == nullptr)
+ return nullptr;
+ unsigned stmtOffset =
+ UnitDIE->getAttributeValueAsSectionOffset(U, DW_AT_stmt_list, -1U);
+ if (stmtOffset == -1U)
+ return nullptr; // No line table for this compile unit.
+
+ // See if the line table is cached.
+ if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
+ return lt;
+
+ // We have to parse it first.
+ DataExtractor lineData(getLineSection().Data, isLittleEndian(),
+ U->getAddressByteSize());
+ return Line->getOrParseLineTable(lineData, stmtOffset);
+}
+
+void DWARFContext::parseCompileUnits() {
+ CUs.parse(*this, getInfoSection());
+}
+
+void DWARFContext::parseTypeUnits() {
+ if (!TUs.empty())
+ return;
+ for (const auto &I : getTypesSections()) {
+ TUs.push_back(DWARFUnitSection<DWARFTypeUnit>());
+ TUs.back().parse(*this, I.second);
+ }
+}
+
+void DWARFContext::parseDWOCompileUnits() {
+ DWOCUs.parseDWO(*this, getInfoDWOSection());
+}
+
+void DWARFContext::parseDWOTypeUnits() {
+ if (!DWOTUs.empty())
+ return;
+ for (const auto &I : getTypesDWOSections()) {
+ DWOTUs.push_back(DWARFUnitSection<DWARFTypeUnit>());
+ DWOTUs.back().parseDWO(*this, I.second);
+ }
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t Offset) {
+ parseCompileUnits();
+ return CUs.getUnitForOffset(Offset);
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
+ // First, get the offset of the compile unit.
+ uint32_t CUOffset = getDebugAranges()->findAddress(Address);
+ // Retrieve the compile unit.
+ return getCompileUnitForOffset(CUOffset);
+}
+
+static bool getFunctionNameForAddress(DWARFCompileUnit *CU, uint64_t Address,
+ FunctionNameKind Kind,
+ std::string &FunctionName) {
+ if (Kind == FunctionNameKind::None)
+ return false;
+ // The address may correspond to instruction in some inlined function,
+ // so we have to build the chain of inlined functions and take the
+ // name of the topmost function in it.
+ const DWARFDebugInfoEntryInlinedChain &InlinedChain =
+ CU->getInlinedChainForAddress(Address);
+ if (InlinedChain.DIEs.size() == 0)
+ return false;
+ const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0];
+ if (const char *Name =
+ TopFunctionDIE.getSubroutineName(InlinedChain.U, Kind)) {
+ FunctionName = Name;
+ return true;
+ }
+ return false;
+}
+
+DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
+ DILineInfoSpecifier Spec) {
+ DILineInfo Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+ getFunctionNameForAddress(CU, Address, Spec.FNKind, Result.FunctionName);
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (const DWARFLineTable *LineTable = getLineTableForUnit(CU))
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Result);
+ }
+ return Result;
+}
+
+DILineInfoTable
+DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size,
+ DILineInfoSpecifier Spec) {
+ DILineInfoTable Lines;
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Lines;
+
+ std::string FunctionName = "<invalid>";
+ getFunctionNameForAddress(CU, Address, Spec.FNKind, FunctionName);
+
+ // If the Specifier says we don't need FileLineInfo, just
+ // return the top-most function at the starting address.
+ if (Spec.FLIKind == FileLineInfoKind::None) {
+ DILineInfo Result;
+ Result.FunctionName = FunctionName;
+ Lines.push_back(std::make_pair(Address, Result));
+ return Lines;
+ }
+
+ const DWARFLineTable *LineTable = getLineTableForUnit(CU);
+
+ // Get the index of row we're looking for in the line table.
+ std::vector<uint32_t> RowVector;
+ if (!LineTable->lookupAddressRange(Address, Size, RowVector))
+ return Lines;
+
+ for (uint32_t RowIndex : RowVector) {
+ // Take file number and line/column from the row.
+ const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
+ DILineInfo Result;
+ LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(),
+ Spec.FLIKind, Result.FileName);
+ Result.FunctionName = FunctionName;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ Lines.push_back(std::make_pair(Row.Address, Result));
+ }
+
+ return Lines;
+}
+
+DIInliningInfo
+DWARFContext::getInliningInfoForAddress(uint64_t Address,
+ DILineInfoSpecifier Spec) {
+ DIInliningInfo InliningInfo;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return InliningInfo;
+
+ const DWARFLineTable *LineTable = nullptr;
+ const DWARFDebugInfoEntryInlinedChain &InlinedChain =
+ CU->getInlinedChainForAddress(Address);
+ if (InlinedChain.DIEs.size() == 0) {
+ // If there is no DIE for address (e.g. it is in unavailable .dwo file),
+ // try to at least get file/line info from symbol table.
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ DILineInfo Frame;
+ LineTable = getLineTableForUnit(CU);
+ if (LineTable &&
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Frame))
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+ }
+
+ uint32_t CallFile = 0, CallLine = 0, CallColumn = 0;
+ for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) {
+ const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i];
+ DILineInfo Frame;
+ // Get function name if necessary.
+ if (const char *Name =
+ FunctionDIE.getSubroutineName(InlinedChain.U, Spec.FNKind))
+ Frame.FunctionName = Name;
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (i == 0) {
+ // For the topmost frame, initialize the line table of this
+ // compile unit and fetch file/line info from it.
+ LineTable = getLineTableForUnit(CU);
+ // For the topmost routine, get file/line info from line table.
+ if (LineTable)
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Frame);
+ } else {
+ // Otherwise, use call file, call line and call column from
+ // previous DIE in inlined chain.
+ if (LineTable)
+ LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(),
+ Spec.FLIKind, Frame.FileName);
+ Frame.Line = CallLine;
+ Frame.Column = CallColumn;
+ }
+ // Get call file/line/column of a current DIE.
+ if (i + 1 < n) {
+ FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine,
+ CallColumn);
+ }
+ }
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+}
+
+static bool consumeCompressedDebugSectionHeader(StringRef &data,
+ uint64_t &OriginalSize) {
+ // Consume "ZLIB" prefix.
+ if (!data.startswith("ZLIB"))
+ return false;
+ data = data.substr(4);
+ // Consume uncompressed section size (big-endian 8 bytes).
+ DataExtractor extractor(data, false, 8);
+ uint32_t Offset = 0;
+ OriginalSize = extractor.getU64(&Offset);
+ if (Offset == 0)
+ return false;
+ data = data.substr(Offset);
+ return true;
+}
+
+DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
+ const LoadedObjectInfo *L)
+ : 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.
+ bool IsBSS = Section.isBSS();
+ if (IsBSS)
+ continue;
+ bool IsVirtual = Section.isVirtual();
+ if (IsVirtual)
+ continue;
+ StringRef data;
+
+ // 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(name,data))
+ Section.getContents(data);
+
+ name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
+
+ // Check if debug info section is compressed with zlib.
+ if (name.startswith("zdebug_")) {
+ uint64_t OriginalSize;
+ if (!zlib::isAvailable() ||
+ !consumeCompressedDebugSectionHeader(data, OriginalSize))
+ continue;
+ UncompressedSections.resize(UncompressedSections.size() + 1);
+ if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) !=
+ zlib::StatusOK) {
+ UncompressedSections.pop_back();
+ continue;
+ }
+ // Make data point to uncompressed section contents and save its contents.
+ name = name.substr(1);
+ data = UncompressedSections.back();
+ }
+
+ StringRef *SectionData =
+ StringSwitch<StringRef *>(name)
+ .Case("debug_info", &InfoSection.Data)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_loc", &LocSection.Data)
+ .Case("debug_line", &LineSection.Data)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_pubtypes", &PubTypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case("debug_info.dwo", &InfoDWOSection.Data)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_loc.dwo", &LocDWOSection.Data)
+ .Case("debug_line.dwo", &LineDWOSection.Data)
+ .Case("debug_str.dwo", &StringDWOSection)
+ .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
+ .Case("debug_addr", &AddrSection)
+ .Case("apple_names", &AppleNamesSection.Data)
+ .Case("apple_types", &AppleTypesSection.Data)
+ .Case("apple_namespaces", &AppleNamespacesSection.Data)
+ .Case("apple_namespac", &AppleNamespacesSection.Data)
+ .Case("apple_objc", &AppleObjCSection.Data)
+ // Any more debug info sections go here.
+ .Default(nullptr);
+ if (SectionData) {
+ *SectionData = data;
+ if (name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangeDWOSection = 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;
+ }
+
+ section_iterator RelocatedSection = Section.getRelocatedSection();
+ 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(RelSecName,RelSecData))
+ continue;
+
+ RelSecName = RelSecName.substr(
+ RelSecName.find_first_not_of("._")); // Skip . and _ prefixes.
+
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName)
+ .Case("debug_info", &InfoSection.Relocs)
+ .Case("debug_loc", &LocSection.Relocs)
+ .Case("debug_info.dwo", &InfoDWOSection.Relocs)
+ .Case("debug_line", &LineSection.Relocs)
+ .Case("apple_names", &AppleNamesSection.Relocs)
+ .Case("apple_types", &AppleTypesSection.Relocs)
+ .Case("apple_namespaces", &AppleNamespacesSection.Relocs)
+ .Case("apple_namespac", &AppleNamespacesSection.Relocs)
+ .Case("apple_objc", &AppleObjCSection.Relocs)
+ .Default(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
+ continue;
+ }
+
+ if (Section.relocation_begin() != Section.relocation_end()) {
+ uint64_t SectionSize = RelocatedSection->getSize();
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ uint64_t Address;
+ Reloc.getOffset(Address);
+ uint64_t Type;
+ Reloc.getType(Type);
+ uint64_t SymAddr = 0;
+ uint64_t SectionLoadAddress = 0;
+ object::symbol_iterator Sym = Reloc.getSymbol();
+ object::section_iterator RSec = Reloc.getSection();
+
+ // First calculate the address of the symbol or section as it appears
+ // in the objct file
+ if (Sym != Obj.symbol_end()) {
+ Sym->getAddress(SymAddr);
+ // Also remember what section this symbol is in for later
+ Sym->getSection(RSec);
+ } else if (RSec != Obj.section_end())
+ SymAddr = RSec->getAddress();
+
+ // If we are given load addresses for the sections, we need to adjust:
+ // SymAddr = (Address of Symbol Or Section in File) -
+ // (Address of Section in File) +
+ // (Load Address of Section)
+ if (L != nullptr && RSec != Obj.section_end()) {
+ // RSec is now either the section being targetted or the section
+ // containing the symbol being targetted. In either case,
+ // we need to perform the same computation.
+ StringRef SecName;
+ RSec->getName(SecName);
+ SectionLoadAddress = L->getSectionLoadAddress(SecName);
+ if (SectionLoadAddress != 0)
+ SymAddr += SectionLoadAddress - RSec->getAddress();
+ }
+
+ object::RelocVisitor V(Obj);
+ object::RelocToApply R(V.visit(Type, Reloc, SymAddr));
+ if (V.error()) {
+ SmallString<32> Name;
+ std::error_code ec(Reloc.getTypeName(Name));
+ if (ec) {
+ errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n";
+ }
+ errs() << "error: failed to compute relocation: "
+ << Name << "\n";
+ continue;
+ }
+
+ if (Address + R.Width > SectionSize) {
+ errs() << "error: " << R.Width << "-byte relocation starting "
+ << Address << " bytes into section " << name << " which is "
+ << SectionSize << " bytes long.\n";
+ continue;
+ }
+ if (R.Width > 8) {
+ errs() << "error: can't handle a relocation of more than 8 bytes at "
+ "a time.\n";
+ continue;
+ }
+ DEBUG(dbgs() << "Writing " << format("%p", R.Value)
+ << " at " << format("%p", Address)
+ << " with width " << format("%d", R.Width)
+ << "\n");
+ Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value)));
+ }
+ }
+ }
+}
+
+void DWARFContextInMemory::anchor() { }
diff --git a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 000000000000..e63e28997ed0
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,115 @@
+//===-- DWARFDebugAbbrev.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {
+ clear();
+}
+
+void DWARFAbbreviationDeclarationSet::clear() {
+ Offset = 0;
+ FirstAbbrCode = 0;
+ Decls.clear();
+}
+
+bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data,
+ uint32_t *OffsetPtr) {
+ clear();
+ const uint32_t BeginOffset = *OffsetPtr;
+ Offset = BeginOffset;
+ DWARFAbbreviationDeclaration AbbrDecl;
+ uint32_t PrevAbbrCode = 0;
+ while (AbbrDecl.extract(Data, OffsetPtr)) {
+ if (FirstAbbrCode == 0) {
+ FirstAbbrCode = AbbrDecl.getCode();
+ } else {
+ if (PrevAbbrCode + 1 != AbbrDecl.getCode()) {
+ // Codes are not consecutive, can't do O(1) lookups.
+ FirstAbbrCode = UINT32_MAX;
+ }
+ }
+ PrevAbbrCode = AbbrDecl.getCode();
+ Decls.push_back(std::move(AbbrDecl));
+ }
+ return BeginOffset != *OffsetPtr;
+}
+
+void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {
+ for (const auto &Decl : Decls)
+ Decl.dump(OS);
+}
+
+const DWARFAbbreviationDeclaration *
+DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
+ uint32_t AbbrCode) const {
+ if (FirstAbbrCode == UINT32_MAX) {
+ for (const auto &Decl : Decls) {
+ if (Decl.getCode() == AbbrCode)
+ return &Decl;
+ }
+ return nullptr;
+ }
+ if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size())
+ return nullptr;
+ return &Decls[AbbrCode - FirstAbbrCode];
+}
+
+DWARFDebugAbbrev::DWARFDebugAbbrev() {
+ clear();
+}
+
+void DWARFDebugAbbrev::clear() {
+ AbbrDeclSets.clear();
+ PrevAbbrOffsetPos = AbbrDeclSets.end();
+}
+
+void DWARFDebugAbbrev::extract(DataExtractor Data) {
+ clear();
+
+ uint32_t Offset = 0;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ while (Data.isValidOffset(Offset)) {
+ uint32_t CUAbbrOffset = Offset;
+ if (!AbbrDecls.extract(Data, &Offset))
+ break;
+ AbbrDeclSets[CUAbbrOffset] = std::move(AbbrDecls);
+ }
+}
+
+void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
+ if (AbbrDeclSets.empty()) {
+ OS << "< EMPTY >\n";
+ return;
+ }
+
+ for (const auto &I : AbbrDeclSets) {
+ OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first);
+ I.second.dump(OS);
+ }
+}
+
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
+ const auto End = AbbrDeclSets.end();
+ if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) {
+ return &(PrevAbbrOffsetPos->second);
+ }
+
+ const auto Pos = AbbrDeclSets.find(CUAbbrOffset);
+ if (Pos != End) {
+ PrevAbbrOffsetPos = Pos;
+ return &(Pos->second);
+ }
+
+ return nullptr;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 000000000000..67589cd01e55
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,104 @@
+//===-- DWARFDebugArangeSet.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+using namespace llvm;
+
+void DWARFDebugArangeSet::clear() {
+ Offset = -1U;
+ std::memset(&HeaderData, 0, sizeof(Header));
+ ArangeDescriptors.clear();
+}
+
+bool
+DWARFDebugArangeSet::extract(DataExtractor data, uint32_t *offset_ptr) {
+ if (data.isValidOffset(*offset_ptr)) {
+ ArangeDescriptors.clear();
+ Offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header consisting of: a
+ // 4-byte length containing the length of the set of entries for this
+ // compilation unit, not including the length field itself; a 2-byte
+ // version identifier containing the value 2 for DWARF Version 2; a
+ // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+ // containing the size in bytes of an address (or the offset portion of
+ // an address for segmented addressing) on the target system; and a
+ // 1-byte unsigned integer containing the size in bytes of a segment
+ // descriptor on the target system. This header is followed by a series
+ // of tuples. Each tuple consists of an address and a length, each in
+ // the size appropriate for an address on the target architecture.
+ HeaderData.Length = data.getU32(offset_ptr);
+ HeaderData.Version = data.getU16(offset_ptr);
+ HeaderData.CuOffset = data.getU32(offset_ptr);
+ HeaderData.AddrSize = data.getU8(offset_ptr);
+ HeaderData.SegSize = data.getU8(offset_ptr);
+
+ // Perform basic validation of the header fields.
+ if (!data.isValidOffsetForDataOfSize(Offset, HeaderData.Length) ||
+ (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)) {
+ clear();
+ return false;
+ }
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - Offset;
+ const uint32_t tuple_size = HeaderData.AddrSize * 2;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = Offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ static_assert(sizeof(arangeDescriptor.Address) ==
+ sizeof(arangeDescriptor.Length),
+ "Different datatypes for addresses and sizes!");
+ assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
+
+ while (data.isValidOffset(*offset_ptr)) {
+ arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+ arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.Address || arangeDescriptor.Length)
+ ArangeDescriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+
+ return !ArangeDescriptors.empty();
+ }
+ return false;
+}
+
+void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
+ OS << format("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, ",
+ HeaderData.Length, HeaderData.Version)
+ << format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+ HeaderData.CuOffset, HeaderData.AddrSize, HeaderData.SegSize);
+
+ const uint32_t hex_width = HeaderData.AddrSize * 2;
+ for (const auto &Desc : ArangeDescriptors) {
+ OS << format("[0x%*.*" PRIx64 " -", hex_width, hex_width, Desc.Address)
+ << format(" 0x%*.*" PRIx64 ")\n",
+ hex_width, hex_width, Desc.getEndAddress());
+ }
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 000000000000..27a02c4c50d0
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,129 @@
+//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <set>
+using namespace llvm;
+
+void DWARFDebugAranges::extract(DataExtractor DebugArangesData) {
+ if (!DebugArangesData.isValidOffset(0))
+ return;
+ uint32_t Offset = 0;
+ DWARFDebugArangeSet Set;
+
+ while (Set.extract(DebugArangesData, &Offset)) {
+ uint32_t CUOffset = Set.getCompileUnitDIEOffset();
+ for (const auto &Desc : Set.descriptors()) {
+ uint64_t LowPC = Desc.Address;
+ uint64_t HighPC = Desc.getEndAddress();
+ appendRange(CUOffset, LowPC, HighPC);
+ }
+ ParsedCUOffsets.insert(CUOffset);
+ }
+}
+
+void DWARFDebugAranges::generate(DWARFContext *CTX) {
+ clear();
+ if (!CTX)
+ return;
+
+ // Extract aranges from .debug_aranges section.
+ DataExtractor ArangesData(CTX->getARangeSection(), CTX->isLittleEndian(), 0);
+ extract(ArangesData);
+
+ // Generate aranges from DIEs: even if .debug_aranges section is present,
+ // it may describe only a small subset of compilation units, so we need to
+ // manually build aranges for the rest of them.
+ for (const auto &CU : CTX->compile_units()) {
+ uint32_t CUOffset = CU->getOffset();
+ if (ParsedCUOffsets.insert(CUOffset).second) {
+ DWARFAddressRangesVector CURanges;
+ CU->collectAddressRanges(CURanges);
+ for (const auto &R : CURanges) {
+ appendRange(CUOffset, R.first, R.second);
+ }
+ }
+ }
+
+ construct();
+}
+
+void DWARFDebugAranges::clear() {
+ Endpoints.clear();
+ Aranges.clear();
+ ParsedCUOffsets.clear();
+}
+
+void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC,
+ uint64_t HighPC) {
+ if (LowPC >= HighPC)
+ return;
+ Endpoints.emplace_back(LowPC, CUOffset, true);
+ Endpoints.emplace_back(HighPC, CUOffset, false);
+}
+
+void DWARFDebugAranges::construct() {
+ std::multiset<uint32_t> ValidCUs; // Maintain the set of CUs describing
+ // a current address range.
+ std::sort(Endpoints.begin(), Endpoints.end());
+ uint64_t PrevAddress = -1ULL;
+ for (const auto &E : Endpoints) {
+ if (PrevAddress < E.Address && ValidCUs.size() > 0) {
+ // If the address range between two endpoints is described by some
+ // CU, first try to extend the last range in Aranges. If we can't
+ // do it, start a new range.
+ if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
+ ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
+ Aranges.back().setHighPC(E.Address);
+ } else {
+ Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
+ }
+ }
+ // Update the set of valid CUs.
+ if (E.IsRangeStart) {
+ ValidCUs.insert(E.CUOffset);
+ } else {
+ auto CUPos = ValidCUs.find(E.CUOffset);
+ assert(CUPos != ValidCUs.end());
+ ValidCUs.erase(CUPos);
+ }
+ PrevAddress = E.Address;
+ }
+ assert(ValidCUs.empty());
+
+ // Endpoints are not needed now.
+ std::vector<RangeEndpoint> EmptyEndpoints;
+ EmptyEndpoints.swap(Endpoints);
+}
+
+uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const {
+ if (!Aranges.empty()) {
+ Range range(Address);
+ RangeCollIterator begin = Aranges.begin();
+ RangeCollIterator end = Aranges.end();
+ RangeCollIterator pos =
+ std::lower_bound(begin, end, range);
+
+ if (pos != end && pos->containsAddress(Address)) {
+ return pos->CUOffset;
+ } else if (pos != begin) {
+ --pos;
+ if (pos->containsAddress(Address))
+ return pos->CUOffset;
+ }
+ }
+ return -1U;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
new file mode 100644
index 000000000000..1aa31be71fee
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -0,0 +1,521 @@
+//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+
+/// \brief Abstract frame entry defining the common interface concrete
+/// entries implement.
+class llvm::FrameEntry {
+public:
+ enum FrameKind {FK_CIE, FK_FDE};
+ FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length)
+ : Kind(K), Offset(Offset), Length(Length) {}
+
+ virtual ~FrameEntry() {
+ }
+
+ FrameKind getKind() const { return Kind; }
+ virtual uint64_t getOffset() const { return Offset; }
+
+ /// \brief Parse and store a sequence of CFI instructions from Data,
+ /// starting at *Offset and ending at EndOffset. If everything
+ /// goes well, *Offset should be equal to EndOffset when this method
+ /// returns. Otherwise, an error occurred.
+ virtual void parseInstructions(DataExtractor Data, uint32_t *Offset,
+ uint32_t EndOffset);
+
+ /// \brief Dump the entry header to the given output stream.
+ virtual void dumpHeader(raw_ostream &OS) const = 0;
+
+ /// \brief Dump the entry's instructions to the given output stream.
+ virtual void dumpInstructions(raw_ostream &OS) const;
+
+protected:
+ const FrameKind Kind;
+
+ /// \brief Offset of this entry in the section.
+ uint64_t Offset;
+
+ /// \brief Entry length as specified in DWARF.
+ uint64_t Length;
+
+ /// An entry may contain CFI instructions. An instruction consists of an
+ /// opcode and an optional sequence of operands.
+ typedef std::vector<uint64_t> Operands;
+ struct Instruction {
+ Instruction(uint8_t Opcode)
+ : Opcode(Opcode)
+ {}
+
+ uint8_t Opcode;
+ Operands Ops;
+ };
+
+ std::vector<Instruction> Instructions;
+
+ /// Convenience methods to add a new instruction with the given opcode and
+ /// operands to the Instructions vector.
+ void addInstruction(uint8_t Opcode) {
+ Instructions.push_back(Instruction(Opcode));
+ }
+
+ void addInstruction(uint8_t Opcode, uint64_t Operand1) {
+ Instructions.push_back(Instruction(Opcode));
+ Instructions.back().Ops.push_back(Operand1);
+ }
+
+ void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
+ Instructions.push_back(Instruction(Opcode));
+ Instructions.back().Ops.push_back(Operand1);
+ Instructions.back().Ops.push_back(Operand2);
+ }
+};
+
+
+// See DWARF standard v3, section 7.23
+const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
+const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
+
+void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
+ uint32_t EndOffset) {
+ while (*Offset < EndOffset) {
+ uint8_t Opcode = Data.getU8(Offset);
+ // Some instructions have a primary opcode encoded in the top bits.
+ uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
+
+ if (Primary) {
+ // If it's a primary opcode, the first operand is encoded in the bottom
+ // bits of the opcode itself.
+ uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
+ switch (Primary) {
+ default: llvm_unreachable("Impossible primary CFI opcode");
+ case DW_CFA_advance_loc:
+ case DW_CFA_restore:
+ addInstruction(Primary, Op1);
+ break;
+ case DW_CFA_offset:
+ addInstruction(Primary, Op1, Data.getULEB128(Offset));
+ break;
+ }
+ } else {
+ // Extended opcode - its value is Opcode itself.
+ switch (Opcode) {
+ default: llvm_unreachable("Invalid extended CFI opcode");
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ // No operands
+ addInstruction(Opcode);
+ break;
+ case DW_CFA_set_loc:
+ // Operands: Address
+ addInstruction(Opcode, Data.getAddress(Offset));
+ break;
+ case DW_CFA_advance_loc1:
+ // Operands: 1-byte delta
+ addInstruction(Opcode, Data.getU8(Offset));
+ break;
+ case DW_CFA_advance_loc2:
+ // Operands: 2-byte delta
+ addInstruction(Opcode, Data.getU16(Offset));
+ break;
+ case DW_CFA_advance_loc4:
+ // Operands: 4-byte delta
+ addInstruction(Opcode, Data.getU32(Offset));
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ // Operands: ULEB128
+ addInstruction(Opcode, Data.getULEB128(Offset));
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ // Operands: SLEB128
+ addInstruction(Opcode, Data.getSLEB128(Offset));
+ break;
+ case DW_CFA_offset_extended:
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ case DW_CFA_val_offset:
+ // Operands: ULEB128, ULEB128
+ addInstruction(Opcode, Data.getULEB128(Offset),
+ Data.getULEB128(Offset));
+ break;
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_val_offset_sf:
+ // Operands: ULEB128, SLEB128
+ addInstruction(Opcode, Data.getULEB128(Offset),
+ Data.getSLEB128(Offset));
+ break;
+ case DW_CFA_def_cfa_expression:
+ case DW_CFA_expression:
+ case DW_CFA_val_expression:
+ // TODO: implement this
+ report_fatal_error("Values with expressions not implemented yet!");
+ }
+ }
+ }
+}
+
+namespace {
+/// \brief DWARF Common Information Entry (CIE)
+class CIE : public FrameEntry {
+public:
+ // CIEs (and FDEs) are simply container classes, so the only sensible way to
+ // create them is by providing the full parsed contents in the constructor.
+ CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
+ SmallString<8> Augmentation, uint8_t AddressSize,
+ uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
+ int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
+ : FrameEntry(FK_CIE, Offset, Length), Version(Version),
+ Augmentation(std::move(Augmentation)),
+ AddressSize(AddressSize),
+ SegmentDescriptorSize(SegmentDescriptorSize),
+ CodeAlignmentFactor(CodeAlignmentFactor),
+ DataAlignmentFactor(DataAlignmentFactor),
+ ReturnAddressRegister(ReturnAddressRegister) {}
+
+ ~CIE() override {}
+
+ uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
+ int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
+
+ void dumpHeader(raw_ostream &OS) const override {
+ OS << format("%08x %08x %08x CIE",
+ (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID)
+ << "\n";
+ OS << format(" Version: %d\n", Version);
+ OS << " Augmentation: \"" << Augmentation << "\"\n";
+ if (Version >= 4) {
+ OS << format(" Address size: %u\n",
+ (uint32_t)AddressSize);
+ OS << format(" Segment desc size: %u\n",
+ (uint32_t)SegmentDescriptorSize);
+ }
+ OS << format(" Code alignment factor: %u\n",
+ (uint32_t)CodeAlignmentFactor);
+ OS << format(" Data alignment factor: %d\n",
+ (int32_t)DataAlignmentFactor);
+ OS << format(" Return address column: %d\n",
+ (int32_t)ReturnAddressRegister);
+ OS << "\n";
+ }
+
+ static bool classof(const FrameEntry *FE) {
+ return FE->getKind() == FK_CIE;
+ }
+
+private:
+ /// The following fields are defined in section 6.4.1 of the DWARF standard v4
+ uint8_t Version;
+ SmallString<8> Augmentation;
+ uint8_t AddressSize;
+ uint8_t SegmentDescriptorSize;
+ uint64_t CodeAlignmentFactor;
+ int64_t DataAlignmentFactor;
+ uint64_t ReturnAddressRegister;
+};
+
+
+/// \brief DWARF Frame Description Entry (FDE)
+class FDE : public FrameEntry {
+public:
+ // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
+ // an offset to the CIE (provided by parsing the FDE header). The CIE itself
+ // is obtained lazily once it's actually required.
+ FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
+ uint64_t InitialLocation, uint64_t AddressRange,
+ CIE *Cie)
+ : FrameEntry(FK_FDE, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
+ InitialLocation(InitialLocation), AddressRange(AddressRange),
+ LinkedCIE(Cie) {}
+
+ ~FDE() override {}
+
+ CIE *getLinkedCIE() const { return LinkedCIE; }
+
+ void dumpHeader(raw_ostream &OS) const override {
+ OS << format("%08x %08x %08x FDE ",
+ (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset);
+ OS << format("cie=%08x pc=%08x...%08x\n",
+ (int32_t)LinkedCIEOffset,
+ (uint32_t)InitialLocation,
+ (uint32_t)InitialLocation + (uint32_t)AddressRange);
+ }
+
+ static bool classof(const FrameEntry *FE) {
+ return FE->getKind() == FK_FDE;
+ }
+
+private:
+ /// The following fields are defined in section 6.4.1 of the DWARF standard v3
+ uint64_t LinkedCIEOffset;
+ uint64_t InitialLocation;
+ uint64_t AddressRange;
+ CIE *LinkedCIE;
+};
+
+/// \brief Types of operands to CF instructions.
+enum OperandType {
+ OT_Unset,
+ OT_None,
+ OT_Address,
+ OT_Offset,
+ OT_FactoredCodeOffset,
+ OT_SignedFactDataOffset,
+ OT_UnsignedFactDataOffset,
+ OT_Register,
+ OT_Expression
+};
+
+} // end anonymous namespace
+
+/// \brief Initialize the array describing the types of operands.
+static ArrayRef<OperandType[2]> getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore+1][2];
+
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
+ do { \
+ OpTypes[OP][0] = OPTYPE0; \
+ OpTypes[OP][1] = OPTYPE1; \
+ } while (0)
+#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
+#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
+
+ DECLARE_OP1(DW_CFA_set_loc, OT_Address);
+ DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
+ DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
+ DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+ DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
+ DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
+ DECLARE_OP1(DW_CFA_undefined, OT_Register);
+ DECLARE_OP1(DW_CFA_same_value, OT_Register);
+ DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
+ DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
+ DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
+ DECLARE_OP1(DW_CFA_restore, OT_Register);
+ DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
+ DECLARE_OP0(DW_CFA_remember_state);
+ DECLARE_OP0(DW_CFA_restore_state);
+ DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
+ DECLARE_OP0(DW_CFA_nop);
+
+#undef DECLARE_OP0
+#undef DECLARE_OP1
+#undef DECLARE_OP2
+ return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+}
+
+static ArrayRef<OperandType[2]> OpTypes = getOperandTypes();
+
+/// \brief Print \p Opcode's operand number \p OperandIdx which has
+/// value \p Operand.
+static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx,
+ uint64_t Operand, uint64_t CodeAlignmentFactor,
+ int64_t DataAlignmentFactor) {
+ assert(OperandIdx < 2);
+ OperandType Type = OpTypes[Opcode][OperandIdx];
+
+ switch (Type) {
+ case OT_Unset:
+ OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
+ if (const char *OpcodeName = CallFrameString(Opcode))
+ OS << " " << OpcodeName;
+ else
+ OS << format(" Opcode %x", Opcode);
+ break;
+ case OT_None:
+ break;
+ case OT_Address:
+ OS << format(" %" PRIx64, Operand);
+ break;
+ case OT_Offset:
+ // The offsets are all encoded in a unsigned form, but in practice
+ // consumers use them signed. It's most certainly legacy due to
+ // the lack of signed variants in the first Dwarf standards.
+ OS << format(" %+" PRId64, int64_t(Operand));
+ break;
+ case OT_FactoredCodeOffset: // Always Unsigned
+ if (CodeAlignmentFactor)
+ OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
+ break;
+ case OT_SignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
+ break;
+ case OT_UnsignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, Operand * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
+ break;
+ case OT_Register:
+ OS << format(" reg%" PRId64, Operand);
+ break;
+ case OT_Expression:
+ OS << " expression";
+ break;
+ }
+}
+
+void FrameEntry::dumpInstructions(raw_ostream &OS) const {
+ uint64_t CodeAlignmentFactor = 0;
+ int64_t DataAlignmentFactor = 0;
+ const CIE *Cie = dyn_cast<CIE>(this);
+
+ if (!Cie)
+ Cie = cast<FDE>(this)->getLinkedCIE();
+ if (Cie) {
+ CodeAlignmentFactor = Cie->getCodeAlignmentFactor();
+ DataAlignmentFactor = Cie->getDataAlignmentFactor();
+ }
+
+ for (const auto &Instr : Instructions) {
+ uint8_t Opcode = Instr.Opcode;
+ if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
+ Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
+ OS << " " << CallFrameString(Opcode) << ":";
+ for (unsigned i = 0; i < Instr.Ops.size(); ++i)
+ printOperand(OS, Opcode, i, Instr.Ops[i], CodeAlignmentFactor,
+ DataAlignmentFactor);
+ OS << '\n';
+ }
+}
+
+DWARFDebugFrame::DWARFDebugFrame() {
+}
+
+DWARFDebugFrame::~DWARFDebugFrame() {
+}
+
+static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
+ uint32_t Offset, int Length) {
+ errs() << "DUMP: ";
+ for (int i = 0; i < Length; ++i) {
+ uint8_t c = Data.getU8(&Offset);
+ errs().write_hex(c); errs() << " ";
+ }
+ errs() << "\n";
+}
+
+
+void DWARFDebugFrame::parse(DataExtractor Data) {
+ uint32_t Offset = 0;
+ DenseMap<uint32_t, CIE *> CIEs;
+
+ while (Data.isValidOffset(Offset)) {
+ uint32_t StartOffset = Offset;
+
+ bool IsDWARF64 = false;
+ uint64_t Length = Data.getU32(&Offset);
+ uint64_t Id;
+
+ if (Length == UINT32_MAX) {
+ // DWARF-64 is distinguished by the first 32 bits of the initial length
+ // field being 0xffffffff. Then, the next 64 bits are the actual entry
+ // length.
+ IsDWARF64 = true;
+ Length = Data.getU64(&Offset);
+ }
+
+ // At this point, Offset points to the next field after Length.
+ // Length is the structure size excluding itself. Compute an offset one
+ // past the end of the structure (needed to know how many instructions to
+ // read).
+ // TODO: For honest DWARF64 support, DataExtractor will have to treat
+ // offset_ptr as uint64_t*
+ uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
+
+ // The Id field's size depends on the DWARF format
+ Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
+ bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);
+
+ if (IsCIE) {
+ uint8_t Version = Data.getU8(&Offset);
+ const char *Augmentation = Data.getCStr(&Offset);
+ uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset);
+ Data.setAddressSize(AddressSize);
+ uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
+ uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
+ int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
+ uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
+
+ auto Cie = make_unique<CIE>(StartOffset, Length, Version,
+ StringRef(Augmentation), AddressSize,
+ SegmentDescriptorSize, CodeAlignmentFactor,
+ DataAlignmentFactor, ReturnAddressRegister);
+ CIEs[StartOffset] = Cie.get();
+ Entries.emplace_back(std::move(Cie));
+ } else {
+ // FDE
+ uint64_t CIEPointer = Id;
+ uint64_t InitialLocation = Data.getAddress(&Offset);
+ uint64_t AddressRange = Data.getAddress(&Offset);
+
+ Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
+ InitialLocation, AddressRange,
+ CIEs[CIEPointer]));
+ }
+
+ Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
+
+ if (Offset != EndStructureOffset) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << format("Parsing entry instructions at %lx failed", StartOffset);
+ report_fatal_error(Str);
+ }
+ }
+}
+
+
+void DWARFDebugFrame::dump(raw_ostream &OS) const {
+ OS << "\n";
+ for (const auto &Entry : Entries) {
+ Entry->dumpHeader(OS);
+ Entry->dumpInstructions(OS);
+ OS << "\n";
+ }
+}
+
diff --git a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 000000000000..5abbde4ac0fe
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,460 @@
+//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntaxHighlighting.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+using namespace dwarf;
+using namespace syntax;
+
+// Small helper to extract a DIE pointed by a reference
+// attribute. It looks up the Unit containing the DIE and calls
+// DIE.extractFast with the right unit. Returns new unit on success,
+// nullptr otherwise.
+static const DWARFUnit *findUnitAndExtractFast(DWARFDebugInfoEntryMinimal &DIE,
+ const DWARFUnit *Unit,
+ uint32_t *Offset) {
+ Unit = Unit->getUnitSection().getUnitForOffset(*Offset);
+ return (Unit && DIE.extractFast(Unit, Offset)) ? Unit : nullptr;
+}
+
+void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, DWARFUnit *u,
+ unsigned recurseDepth,
+ unsigned indent) const {
+ DataExtractor debug_info_data = u->getDebugInfoExtractor();
+ uint32_t offset = Offset;
+
+ if (debug_info_data.isValidOffset(offset)) {
+ uint32_t abbrCode = debug_info_data.getULEB128(&offset);
+ WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset);
+
+ if (abbrCode) {
+ if (AbbrevDecl) {
+ const char *tagString = TagString(getTag());
+ if (tagString)
+ WithColor(OS, syntax::Tag).get().indent(indent) << tagString;
+ else
+ WithColor(OS, syntax::Tag).get().indent(indent) <<
+ format("DW_TAG_Unknown_%x", getTag());
+
+ OS << format(" [%u] %c\n", abbrCode,
+ AbbrevDecl->hasChildren() ? '*' : ' ');
+
+ // Dump all data in the DIE for the attributes.
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ dumpAttribute(OS, u, &offset, AttrSpec.Attr, AttrSpec.Form, indent);
+ }
+
+ const DWARFDebugInfoEntryMinimal *child = getFirstChild();
+ if (recurseDepth > 0 && child) {
+ while (child) {
+ child->dump(OS, u, recurseDepth-1, indent+2);
+ child = child->getSibling();
+ }
+ }
+ } else {
+ OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
+ << abbrCode << '\n';
+ }
+ } else {
+ OS.indent(indent) << "NULL\n";
+ }
+ }
+}
+
+static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
+ OS << " (";
+ do {
+ uint64_t Shift = countTrailingZeros(Val);
+ assert(Shift < 64 && "undefined behavior");
+ uint64_t Bit = 1ULL << Shift;
+ if (const char *PropName = ApplePropertyString(Bit))
+ OS << PropName;
+ else
+ OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit);
+ if (!(Val ^= Bit))
+ break;
+ OS << ", ";
+ } while (true);
+ OS << ")";
+}
+
+static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges,
+ unsigned AddressSize, unsigned Indent) {
+ if (Ranges.empty())
+ return;
+
+ for (const auto &Range: Ranges) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")",
+ AddressSize*2, Range.first,
+ AddressSize*2, Range.second);
+ }
+}
+
+void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS,
+ DWARFUnit *u,
+ uint32_t *offset_ptr,
+ uint16_t attr, uint16_t form,
+ unsigned indent) const {
+ const char BaseIndent[] = " ";
+ OS << BaseIndent;
+ OS.indent(indent+2);
+ const char *attrString = AttributeString(attr);
+ if (attrString)
+ WithColor(OS, syntax::Attribute) << attrString;
+ else
+ WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", attr);
+
+ const char *formString = FormEncodingString(form);
+ if (formString)
+ OS << " [" << formString << ']';
+ else
+ OS << format(" [DW_FORM_Unknown_%x]", form);
+
+ DWARFFormValue formValue(form);
+
+ if (!formValue.extractValue(u->getDebugInfoExtractor(), offset_ptr, u))
+ return;
+
+ OS << "\t(";
+
+ const char *Name = nullptr;
+ std::string File;
+ auto Color = syntax::Enumerator;
+ if (attr == DW_AT_decl_file || attr == DW_AT_call_file) {
+ Color = syntax::String;
+ if (const auto *LT = u->getContext().getLineTableForUnit(u))
+ if (LT->getFileNameByIndex(
+ formValue.getAsUnsignedConstant().getValue(),
+ u->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
+ File = '"' + File + '"';
+ Name = File.c_str();
+ }
+ } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant())
+ Name = AttributeValueString(attr, *Val);
+
+ if (Name)
+ WithColor(OS, Color) << Name;
+ else if (attr == DW_AT_decl_line || attr == DW_AT_call_line)
+ OS << *formValue.getAsUnsignedConstant();
+ else
+ formValue.dump(OS, u);
+
+ // We have dumped the attribute raw value. For some attributes
+ // having both the raw value and the pretty-printed value is
+ // interesting. These attributes are handled below.
+ if (attr == DW_AT_specification || attr == DW_AT_abstract_origin) {
+ Optional<uint64_t> Ref = formValue.getAsReference(u);
+ if (Ref.hasValue()) {
+ uint32_t RefOffset = Ref.getValue();
+ DWARFDebugInfoEntryMinimal DIE;
+ if (const DWARFUnit *RefU = findUnitAndExtractFast(DIE, u, &RefOffset))
+ if (const char *Name = DIE.getName(RefU, DINameKind::LinkageName))
+ OS << " \"" << Name << '\"';
+ }
+ } else if (attr == DW_AT_APPLE_property_attribute) {
+ if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant())
+ dumpApplePropertyAttribute(OS, *OptVal);
+ } else if (attr == DW_AT_ranges) {
+ dumpRanges(OS, getAddressRanges(u), u->getAddressByteSize(),
+ sizeof(BaseIndent)+indent+4);
+ }
+
+ OS << ")\n";
+}
+
+bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U,
+ uint32_t *OffsetPtr) {
+ Offset = *OffsetPtr;
+ DataExtractor DebugInfoData = U->getDebugInfoExtractor();
+ uint32_t UEndOffset = U->getNextUnitOffset();
+ if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
+ return false;
+ uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
+ if (0 == AbbrCode) {
+ // NULL debug tag entry.
+ AbbrevDecl = nullptr;
+ return true;
+ }
+ AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode);
+ if (nullptr == AbbrevDecl) {
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ ArrayRef<uint8_t> FixedFormSizes = DWARFFormValue::getFixedFormSizes(
+ U->getAddressByteSize(), U->getVersion());
+ assert(FixedFormSizes.size() > 0);
+
+ // Skip all data in the .debug_info for the attributes
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ uint16_t Form = AttrSpec.Form;
+
+ uint8_t FixedFormSize =
+ (Form < FixedFormSizes.size()) ? FixedFormSizes[Form] : 0;
+ if (FixedFormSize)
+ *OffsetPtr += FixedFormSize;
+ else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) {
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DWARFDebugInfoEntryMinimal::isSubprogramDIE() const {
+ return getTag() == DW_TAG_subprogram;
+}
+
+bool DWARFDebugInfoEntryMinimal::isSubroutineDIE() const {
+ uint32_t Tag = getTag();
+ return Tag == DW_TAG_subprogram ||
+ Tag == DW_TAG_inlined_subroutine;
+}
+
+bool DWARFDebugInfoEntryMinimal::getAttributeValue(
+ const DWARFUnit *U, const uint16_t Attr, DWARFFormValue &FormValue) const {
+ if (!AbbrevDecl)
+ return false;
+
+ uint32_t AttrIdx = AbbrevDecl->findAttributeIndex(Attr);
+ if (AttrIdx == -1U)
+ return false;
+
+ DataExtractor DebugInfoData = U->getDebugInfoExtractor();
+ uint32_t DebugInfoOffset = getOffset();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ DebugInfoData.getULEB128(&DebugInfoOffset);
+
+ // Skip preceding attribute values.
+ for (uint32_t i = 0; i < AttrIdx; ++i) {
+ DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(i),
+ DebugInfoData, &DebugInfoOffset, U);
+ }
+
+ FormValue = DWARFFormValue(AbbrevDecl->getFormByIndex(AttrIdx));
+ return FormValue.extractValue(DebugInfoData, &DebugInfoOffset, U);
+}
+
+const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
+ const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const {
+ DWARFFormValue FormValue;
+ if (!getAttributeValue(U, Attr, FormValue))
+ return FailValue;
+ Optional<const char *> Result = FormValue.getAsCString(U);
+ return Result.hasValue() ? Result.getValue() : FailValue;
+}
+
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress(
+ const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
+ DWARFFormValue FormValue;
+ if (!getAttributeValue(U, Attr, FormValue))
+ return FailValue;
+ Optional<uint64_t> Result = FormValue.getAsAddress(U);
+ return Result.hasValue() ? Result.getValue() : FailValue;
+}
+
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant(
+ const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
+ DWARFFormValue FormValue;
+ if (!getAttributeValue(U, Attr, FormValue))
+ return FailValue;
+ Optional<uint64_t> Result = FormValue.getAsUnsignedConstant();
+ return Result.hasValue() ? Result.getValue() : FailValue;
+}
+
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(
+ const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
+ DWARFFormValue FormValue;
+ if (!getAttributeValue(U, Attr, FormValue))
+ return FailValue;
+ Optional<uint64_t> Result = FormValue.getAsReference(U);
+ return Result.hasValue() ? Result.getValue() : FailValue;
+}
+
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSectionOffset(
+ const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const {
+ DWARFFormValue FormValue;
+ if (!getAttributeValue(U, Attr, FormValue))
+ return FailValue;
+ Optional<uint64_t> Result = FormValue.getAsSectionOffset();
+ return Result.hasValue() ? Result.getValue() : FailValue;
+}
+
+uint64_t
+DWARFDebugInfoEntryMinimal::getRangesBaseAttribute(const DWARFUnit *U,
+ uint64_t FailValue) const {
+ uint64_t Result =
+ getAttributeValueAsSectionOffset(U, DW_AT_ranges_base, -1ULL);
+ if (Result != -1ULL)
+ return Result;
+ return getAttributeValueAsSectionOffset(U, DW_AT_GNU_ranges_base, FailValue);
+}
+
+bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U,
+ uint64_t &LowPC,
+ uint64_t &HighPC) const {
+ LowPC = getAttributeValueAsAddress(U, DW_AT_low_pc, -1ULL);
+ if (LowPC == -1ULL)
+ return false;
+ HighPC = getAttributeValueAsAddress(U, DW_AT_high_pc, -1ULL);
+ if (HighPC == -1ULL) {
+ // Since DWARF4, DW_AT_high_pc may also be of class constant, in which case
+ // it represents function size.
+ HighPC = getAttributeValueAsUnsignedConstant(U, DW_AT_high_pc, -1ULL);
+ if (HighPC != -1ULL)
+ HighPC += LowPC;
+ }
+ return (HighPC != -1ULL);
+}
+
+DWARFAddressRangesVector
+DWARFDebugInfoEntryMinimal::getAddressRanges(const DWARFUnit *U) const {
+ if (isNULL())
+ return DWARFAddressRangesVector();
+ // Single range specified by low/high PC.
+ uint64_t LowPC, HighPC;
+ if (getLowAndHighPC(U, LowPC, HighPC)) {
+ return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC));
+ }
+ // Multiple ranges from .debug_ranges section.
+ uint32_t RangesOffset =
+ getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U);
+ if (RangesOffset != -1U) {
+ DWARFDebugRangeList RangeList;
+ if (U->extractRangeList(RangesOffset, RangeList))
+ return RangeList.getAbsoluteRanges(U->getBaseAddress());
+ }
+ return DWARFAddressRangesVector();
+}
+
+void DWARFDebugInfoEntryMinimal::collectChildrenAddressRanges(
+ const DWARFUnit *U, DWARFAddressRangesVector& Ranges) const {
+ if (isNULL())
+ return;
+ if (isSubprogramDIE()) {
+ const auto &DIERanges = getAddressRanges(U);
+ Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
+ }
+
+ const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
+ while (Child) {
+ Child->collectChildrenAddressRanges(U, Ranges);
+ Child = Child->getSibling();
+ }
+}
+
+bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
+ const DWARFUnit *U, const uint64_t Address) const {
+ for (const auto& R : getAddressRanges(U)) {
+ if (R.first <= Address && Address < R.second)
+ return true;
+ }
+ return false;
+}
+
+const char *
+DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFUnit *U,
+ DINameKind Kind) const {
+ if (!isSubroutineDIE())
+ return nullptr;
+ return getName(U, Kind);
+}
+
+const char *
+DWARFDebugInfoEntryMinimal::getName(const DWARFUnit *U,
+ DINameKind Kind) const {
+ if (Kind == DINameKind::None)
+ return nullptr;
+ // Try to get mangled name only if it was asked for.
+ if (Kind == DINameKind::LinkageName) {
+ if (const char *name =
+ getAttributeValueAsString(U, DW_AT_MIPS_linkage_name, nullptr))
+ return name;
+ if (const char *name =
+ getAttributeValueAsString(U, DW_AT_linkage_name, nullptr))
+ return name;
+ }
+ if (const char *name = getAttributeValueAsString(U, DW_AT_name, nullptr))
+ return name;
+ // Try to get name from specification DIE.
+ uint32_t spec_ref =
+ getAttributeValueAsReference(U, DW_AT_specification, -1U);
+ if (spec_ref != -1U) {
+ DWARFDebugInfoEntryMinimal spec_die;
+ if (const DWARFUnit *RefU = findUnitAndExtractFast(spec_die, U, &spec_ref)) {
+ if (const char *name = spec_die.getName(RefU, Kind))
+ return name;
+ }
+ }
+ // Try to get name from abstract origin DIE.
+ uint32_t abs_origin_ref =
+ getAttributeValueAsReference(U, DW_AT_abstract_origin, -1U);
+ if (abs_origin_ref != -1U) {
+ DWARFDebugInfoEntryMinimal abs_origin_die;
+ if (const DWARFUnit *RefU = findUnitAndExtractFast(abs_origin_die, U,
+ &abs_origin_ref)) {
+ if (const char *name = abs_origin_die.getName(RefU, Kind))
+ return name;
+ }
+ }
+ return nullptr;
+}
+
+void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFUnit *U,
+ uint32_t &CallFile,
+ uint32_t &CallLine,
+ uint32_t &CallColumn) const {
+ CallFile = getAttributeValueAsUnsignedConstant(U, DW_AT_call_file, 0);
+ CallLine = getAttributeValueAsUnsignedConstant(U, DW_AT_call_line, 0);
+ CallColumn = getAttributeValueAsUnsignedConstant(U, DW_AT_call_column, 0);
+}
+
+DWARFDebugInfoEntryInlinedChain
+DWARFDebugInfoEntryMinimal::getInlinedChainForAddress(
+ const DWARFUnit *U, const uint64_t Address) const {
+ DWARFDebugInfoEntryInlinedChain InlinedChain;
+ InlinedChain.U = U;
+ if (isNULL())
+ return InlinedChain;
+ for (const DWARFDebugInfoEntryMinimal *DIE = this; DIE; ) {
+ // Append current DIE to inlined chain only if it has correct tag
+ // (e.g. it is not a lexical block).
+ if (DIE->isSubroutineDIE()) {
+ InlinedChain.DIEs.push_back(*DIE);
+ }
+ // Try to get child which also contains provided address.
+ const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild();
+ while (Child) {
+ if (Child->addressRangeContainsAddress(U, Address)) {
+ // Assume there is only one such child.
+ break;
+ }
+ Child = Child->getSibling();
+ }
+ DIE = Child;
+ }
+ // Reverse the obtained chain to make the root of inlined chain last.
+ std::reverse(InlinedChain.DIEs.begin(), InlinedChain.DIEs.end());
+ return InlinedChain;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 000000000000..b63af6a64ee4
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,698 @@
+//===-- DWARFDebugLine.cpp ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+using namespace llvm;
+using namespace dwarf;
+typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
+
+DWARFDebugLine::Prologue::Prologue() {
+ clear();
+}
+
+void DWARFDebugLine::Prologue::clear() {
+ TotalLength = Version = PrologueLength = 0;
+ MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
+ OpcodeBase = 0;
+ StandardOpcodeLengths.clear();
+ IncludeDirectories.clear();
+ FileNames.clear();
+}
+
+void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
+ OS << "Line table prologue:\n"
+ << format(" total_length: 0x%8.8x\n", TotalLength)
+ << format(" version: %u\n", Version)
+ << format(" prologue_length: 0x%8.8x\n", PrologueLength)
+ << format(" min_inst_length: %u\n", MinInstLength)
+ << format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
+ << format(" default_is_stmt: %u\n", DefaultIsStmt)
+ << format(" line_base: %i\n", LineBase)
+ << format(" line_range: %u\n", LineRange)
+ << format(" opcode_base: %u\n", OpcodeBase);
+
+ for (uint32_t i = 0; i < StandardOpcodeLengths.size(); ++i)
+ OS << format("standard_opcode_lengths[%s] = %u\n", LNStandardString(i+1),
+ StandardOpcodeLengths[i]);
+
+ if (!IncludeDirectories.empty())
+ for (uint32_t i = 0; i < IncludeDirectories.size(); ++i)
+ OS << format("include_directories[%3u] = '", i+1)
+ << IncludeDirectories[i] << "'\n";
+
+ if (!FileNames.empty()) {
+ OS << " Dir Mod Time File Len File Name\n"
+ << " ---- ---------- ---------- -----------"
+ "----------------\n";
+ for (uint32_t i = 0; i < FileNames.size(); ++i) {
+ const FileNameEntry& fileEntry = FileNames[i];
+ OS << format("file_names[%3u] %4" PRIu64 " ", i+1, fileEntry.DirIdx)
+ << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ",
+ fileEntry.ModTime, fileEntry.Length)
+ << fileEntry.Name << '\n';
+ }
+ }
+}
+
+bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data,
+ uint32_t *offset_ptr) {
+ const uint32_t prologue_offset = *offset_ptr;
+
+ clear();
+ TotalLength = debug_line_data.getU32(offset_ptr);
+ Version = debug_line_data.getU16(offset_ptr);
+ if (Version < 2)
+ return false;
+
+ PrologueLength = debug_line_data.getU32(offset_ptr);
+ const uint32_t end_prologue_offset = PrologueLength + *offset_ptr;
+ MinInstLength = debug_line_data.getU8(offset_ptr);
+ if (Version >= 4)
+ MaxOpsPerInst = debug_line_data.getU8(offset_ptr);
+ DefaultIsStmt = debug_line_data.getU8(offset_ptr);
+ LineBase = debug_line_data.getU8(offset_ptr);
+ LineRange = debug_line_data.getU8(offset_ptr);
+ OpcodeBase = debug_line_data.getU8(offset_ptr);
+
+ StandardOpcodeLengths.reserve(OpcodeBase - 1);
+ for (uint32_t i = 1; i < OpcodeBase; ++i) {
+ uint8_t op_len = debug_line_data.getU8(offset_ptr);
+ StandardOpcodeLengths.push_back(op_len);
+ }
+
+ while (*offset_ptr < end_prologue_offset) {
+ const char *s = debug_line_data.getCStr(offset_ptr);
+ if (s && s[0])
+ IncludeDirectories.push_back(s);
+ else
+ break;
+ }
+
+ while (*offset_ptr < end_prologue_offset) {
+ const char *name = debug_line_data.getCStr(offset_ptr);
+ if (name && name[0]) {
+ FileNameEntry fileEntry;
+ fileEntry.Name = name;
+ fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr);
+ fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr);
+ fileEntry.Length = debug_line_data.getULEB128(offset_ptr);
+ FileNames.push_back(fileEntry);
+ } else {
+ break;
+ }
+ }
+
+ if (*offset_ptr != end_prologue_offset) {
+ fprintf(stderr, "warning: parsing line table prologue at 0x%8.8x should"
+ " have ended at 0x%8.8x but it ended at 0x%8.8x\n",
+ prologue_offset, end_prologue_offset, *offset_ptr);
+ return false;
+ }
+ return true;
+}
+
+DWARFDebugLine::Row::Row(bool default_is_stmt) {
+ reset(default_is_stmt);
+}
+
+void DWARFDebugLine::Row::postAppend() {
+ BasicBlock = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::reset(bool default_is_stmt) {
+ Address = 0;
+ Line = 1;
+ Column = 0;
+ File = 1;
+ Isa = 0;
+ Discriminator = 0;
+ IsStmt = default_is_stmt;
+ BasicBlock = false;
+ EndSequence = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
+ OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column)
+ << format(" %6u %3u %13u ", File, Isa, Discriminator)
+ << (IsStmt ? " is_stmt" : "")
+ << (BasicBlock ? " basic_block" : "")
+ << (PrologueEnd ? " prologue_end" : "")
+ << (EpilogueBegin ? " epilogue_begin" : "")
+ << (EndSequence ? " end_sequence" : "")
+ << '\n';
+}
+
+DWARFDebugLine::Sequence::Sequence() {
+ reset();
+}
+
+void DWARFDebugLine::Sequence::reset() {
+ LowPC = 0;
+ HighPC = 0;
+ FirstRowIndex = 0;
+ LastRowIndex = 0;
+ Empty = true;
+}
+
+DWARFDebugLine::LineTable::LineTable() {
+ clear();
+}
+
+void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const {
+ Prologue.dump(OS);
+ OS << '\n';
+
+ if (!Rows.empty()) {
+ OS << "Address Line Column File ISA Discriminator Flags\n"
+ << "------------------ ------ ------ ------ --- ------------- "
+ "-------------\n";
+ for (const Row &R : Rows) {
+ R.dump(OS);
+ }
+ }
+}
+
+void DWARFDebugLine::LineTable::clear() {
+ Prologue.clear();
+ Rows.clear();
+ Sequences.clear();
+}
+
+DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
+ : LineTable(LT), RowNumber(0) {
+ resetRowAndSequence();
+}
+
+void DWARFDebugLine::ParsingState::resetRowAndSequence() {
+ Row.reset(LineTable->Prologue.DefaultIsStmt);
+ Sequence.reset();
+}
+
+void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) {
+ if (Sequence.Empty) {
+ // Record the beginning of instruction sequence.
+ Sequence.Empty = false;
+ Sequence.LowPC = Row.Address;
+ Sequence.FirstRowIndex = RowNumber;
+ }
+ ++RowNumber;
+ LineTable->appendRow(Row);
+ if (Row.EndSequence) {
+ // Record the end of instruction sequence.
+ Sequence.HighPC = Row.Address;
+ Sequence.LastRowIndex = RowNumber;
+ if (Sequence.isValid())
+ LineTable->appendSequence(Sequence);
+ Sequence.reset();
+ }
+ Row.postAppend();
+}
+
+const DWARFDebugLine::LineTable *
+DWARFDebugLine::getLineTable(uint32_t offset) const {
+ LineTableConstIter pos = LineTableMap.find(offset);
+ if (pos != LineTableMap.end())
+ return &pos->second;
+ return nullptr;
+}
+
+const DWARFDebugLine::LineTable *
+DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data,
+ uint32_t offset) {
+ std::pair<LineTableIter, bool> pos =
+ LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable()));
+ LineTable *LT = &pos.first->second;
+ if (pos.second) {
+ if (!LT->parse(debug_line_data, RelocMap, &offset))
+ return nullptr;
+ }
+ return LT;
+}
+
+bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
+ const RelocAddrMap *RMap,
+ uint32_t *offset_ptr) {
+ const uint32_t debug_line_offset = *offset_ptr;
+
+ clear();
+
+ if (!Prologue.parse(debug_line_data, offset_ptr)) {
+ // Restore our offset and return false to indicate failure!
+ *offset_ptr = debug_line_offset;
+ return false;
+ }
+
+ const uint32_t end_offset = debug_line_offset + Prologue.TotalLength +
+ sizeof(Prologue.TotalLength);
+
+ ParsingState State(this);
+
+ while (*offset_ptr < end_offset) {
+ uint8_t opcode = debug_line_data.getU8(offset_ptr);
+
+ if (opcode == 0) {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ uint32_t ext_offset = *offset_ptr;
+ uint64_t len = debug_line_data.getULEB128(offset_ptr);
+ uint32_t arg_size = len - (*offset_ptr - ext_offset);
+
+ uint8_t sub_opcode = debug_line_data.getU8(offset_ptr);
+ switch (sub_opcode) {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ State.Row.EndSequence = true;
+ State.appendRowToMatrix(*offset_ptr);
+ State.resetRowAndSequence();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // relocatable address. All of the other statement program opcodes
+ // that affect the address register add a delta to it. This instruction
+ // stores a relocatable value into it instead.
+ {
+ // If this address is in our relocation map, apply the relocation.
+ RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr);
+ if (AI != RMap->end()) {
+ const std::pair<uint8_t, int64_t> &R = AI->second;
+ State.Row.Address =
+ debug_line_data.getAddress(offset_ptr) + R.second;
+ } else
+ State.Row.Address = debug_line_data.getAddress(offset_ptr);
+ }
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number
+ // representing the directory index of the directory in which the file
+ // was found. The third is an unsigned LEB128 number representing the
+ // time of last modification of the file. The fourth is an unsigned
+ // LEB128 number representing the length in bytes of the file. The time
+ // and length fields may contain LEB128(0) if the information is not
+ // available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry fileEntry;
+ fileEntry.Name = debug_line_data.getCStr(offset_ptr);
+ fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr);
+ fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr);
+ fileEntry.Length = debug_line_data.getULEB128(offset_ptr);
+ Prologue.FileNames.push_back(fileEntry);
+ }
+ break;
+
+ case DW_LNE_set_discriminator:
+ State.Row.Discriminator = debug_line_data.getULEB128(offset_ptr);
+ break;
+
+ default:
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ (*offset_ptr) += arg_size;
+ break;
+ }
+ } else if (opcode < Prologue.OpcodeBase) {
+ switch (opcode) {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers. Then set
+ // the basic_block register to false.
+ State.appendRowToMatrix(*offset_ptr);
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ State.Row.Address +=
+ debug_line_data.getULEB128(offset_ptr) * Prologue.MinInstLength;
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ State.Row.Line += debug_line_data.getSLEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ State.Row.File = debug_line_data.getULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ State.Row.Column = debug_line_data.getULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ State.Row.IsStmt = !State.Row.IsStmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.BasicBlock = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint8_t adjust_opcode = 255 - Prologue.OpcodeBase;
+ uint64_t addr_offset =
+ (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength;
+ State.Row.Address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ State.Row.Address += debug_line_data.getU16(offset_ptr);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ State.Row.PrologueEnd = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.EpilogueBegin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ State.Row.Isa = debug_line_data.getULEB128(offset_ptr);
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ assert(opcode - 1U < Prologue.StandardOpcodeLengths.size());
+ uint8_t opcode_length = Prologue.StandardOpcodeLengths[opcode - 1];
+ for (uint8_t i = 0; i < opcode_length; ++i)
+ debug_line_data.getULEB128(offset_ptr);
+ }
+ break;
+ }
+ } else {
+ // Special Opcodes
+
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) +
+ // (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) *
+ // minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ uint8_t adjust_opcode = opcode - Prologue.OpcodeBase;
+ uint64_t addr_offset =
+ (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength;
+ int32_t line_offset =
+ Prologue.LineBase + (adjust_opcode % Prologue.LineRange);
+ State.Row.Line += line_offset;
+ State.Row.Address += addr_offset;
+ State.appendRowToMatrix(*offset_ptr);
+ }
+ }
+
+ if (!State.Sequence.Empty) {
+ fprintf(stderr, "warning: last sequence in debug line table is not"
+ "terminated!\n");
+ }
+
+ // Sort all sequences so that address lookup will work faster.
+ if (!Sequences.empty()) {
+ std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC);
+ // Note: actually, instruction address ranges of sequences should not
+ // overlap (in shared objects and executables). If they do, the address
+ // lookup would still work, though, but result would be ambiguous.
+ // We don't report warning in this case. For example,
+ // sometimes .so compiled from multiple object files contains a few
+ // rudimentary sequences for address ranges [0x0, 0xsomething).
+ }
+
+ return end_offset;
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const {
+ uint32_t unknown_index = UINT32_MAX;
+ if (Sequences.empty())
+ return unknown_index;
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence sequence;
+ sequence.LowPC = address;
+ SequenceIter first_seq = Sequences.begin();
+ SequenceIter last_seq = Sequences.end();
+ SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
+ DWARFDebugLine::Sequence::orderByLowPC);
+ DWARFDebugLine::Sequence found_seq;
+ if (seq_pos == last_seq) {
+ found_seq = Sequences.back();
+ } else if (seq_pos->LowPC == address) {
+ found_seq = *seq_pos;
+ } else {
+ if (seq_pos == first_seq)
+ return unknown_index;
+ found_seq = *(seq_pos - 1);
+ }
+ if (!found_seq.containsPC(address))
+ return unknown_index;
+ // Search for instruction address in the rows describing the sequence.
+ // Rows are stored in a vector, so we may use arithmetical operations with
+ // iterators.
+ DWARFDebugLine::Row row;
+ row.Address = address;
+ RowIter first_row = Rows.begin() + found_seq.FirstRowIndex;
+ RowIter last_row = Rows.begin() + found_seq.LastRowIndex;
+ RowIter row_pos = std::lower_bound(first_row, last_row, row,
+ DWARFDebugLine::Row::orderByAddress);
+ if (row_pos == last_row) {
+ return found_seq.LastRowIndex - 1;
+ }
+ uint32_t index = found_seq.FirstRowIndex + (row_pos - first_row);
+ if (row_pos->Address > address) {
+ if (row_pos == first_row)
+ return unknown_index;
+ else
+ index--;
+ }
+ return index;
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRange(
+ uint64_t address, uint64_t size, std::vector<uint32_t> &result) const {
+ if (Sequences.empty())
+ return false;
+ uint64_t end_addr = address + size;
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence sequence;
+ sequence.LowPC = address;
+ SequenceIter first_seq = Sequences.begin();
+ SequenceIter last_seq = Sequences.end();
+ SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
+ DWARFDebugLine::Sequence::orderByLowPC);
+ if (seq_pos == last_seq || seq_pos->LowPC != address) {
+ if (seq_pos == first_seq)
+ return false;
+ seq_pos--;
+ }
+ if (!seq_pos->containsPC(address))
+ return false;
+
+ SequenceIter start_pos = seq_pos;
+
+ // Add the rows from the first sequence to the vector, starting with the
+ // index we just calculated
+
+ while (seq_pos != last_seq && seq_pos->LowPC < end_addr) {
+ DWARFDebugLine::Sequence cur_seq = *seq_pos;
+ uint32_t first_row_index;
+ uint32_t last_row_index;
+ if (seq_pos == start_pos) {
+ // For the first sequence, we need to find which row in the sequence is the
+ // first in our range. Rows are stored in a vector, so we may use
+ // arithmetical operations with iterators.
+ DWARFDebugLine::Row row;
+ row.Address = address;
+ RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex;
+ RowIter last_row = Rows.begin() + cur_seq.LastRowIndex;
+ RowIter row_pos = std::upper_bound(first_row, last_row, row,
+ DWARFDebugLine::Row::orderByAddress);
+ // The 'row_pos' iterator references the first row that is greater than
+ // our start address. Unless that's the first row, we want to start at
+ // the row before that.
+ first_row_index = cur_seq.FirstRowIndex + (row_pos - first_row);
+ if (row_pos != first_row)
+ --first_row_index;
+ } else
+ first_row_index = cur_seq.FirstRowIndex;
+
+ // For the last sequence in our range, we need to figure out the last row in
+ // range. For all other sequences we can go to the end of the sequence.
+ if (cur_seq.HighPC > end_addr) {
+ DWARFDebugLine::Row row;
+ row.Address = end_addr;
+ RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex;
+ RowIter last_row = Rows.begin() + cur_seq.LastRowIndex;
+ RowIter row_pos = std::upper_bound(first_row, last_row, row,
+ DWARFDebugLine::Row::orderByAddress);
+ // The 'row_pos' iterator references the first row that is greater than
+ // our end address. The row before that is the last row we want.
+ last_row_index = cur_seq.FirstRowIndex + (row_pos - first_row) - 1;
+ } else
+ // Contrary to what you might expect, DWARFDebugLine::SequenceLastRowIndex
+ // isn't a valid index within the current sequence. It's that plus one.
+ last_row_index = cur_seq.LastRowIndex - 1;
+
+ for (uint32_t i = first_row_index; i <= last_row_index; ++i) {
+ result.push_back(i);
+ }
+
+ ++seq_pos;
+ }
+
+ return true;
+}
+
+bool
+DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
+ const char *CompDir,
+ FileLineInfoKind Kind,
+ std::string &Result) const {
+ if (FileIndex == 0 || FileIndex > Prologue.FileNames.size() ||
+ Kind == FileLineInfoKind::None)
+ return false;
+ const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
+ const char *FileName = Entry.Name;
+ if (Kind != FileLineInfoKind::AbsoluteFilePath ||
+ sys::path::is_absolute(FileName)) {
+ Result = FileName;
+ return true;
+ }
+
+ SmallString<16> FilePath;
+ uint64_t IncludeDirIndex = Entry.DirIdx;
+ const char *IncludeDir = "";
+ // Be defensive about the contents of Entry.
+ if (IncludeDirIndex > 0 &&
+ IncludeDirIndex <= Prologue.IncludeDirectories.size())
+ IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1];
+
+ // We may still need to append compilation directory of compile unit.
+ // We know that FileName is not absolute, the only way to have an
+ // absolute path at this point would be if IncludeDir is absolute.
+ if (CompDir && Kind == FileLineInfoKind::AbsoluteFilePath &&
+ sys::path::is_relative(IncludeDir))
+ sys::path::append(FilePath, CompDir);
+
+ // sys::path::append skips empty strings.
+ sys::path::append(FilePath, IncludeDir, FileName);
+ Result = FilePath.str();
+ return true;
+}
+
+bool
+DWARFDebugLine::LineTable::getFileLineInfoForAddress(uint64_t Address,
+ const char *CompDir,
+ FileLineInfoKind Kind,
+ DILineInfo &Result) const {
+ // Get the index of row we're looking for in the line table.
+ uint32_t RowIndex = lookupAddress(Address);
+ if (RowIndex == -1U)
+ return false;
+ // Take file number and line/column from the row.
+ const auto &Row = Rows[RowIndex];
+ if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName))
+ return false;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ return true;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
new file mode 100644
index 000000000000..cd6fbefd05dd
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -0,0 +1,127 @@
+//===-- DWARFDebugLoc.cpp -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFDebugLoc::dump(raw_ostream &OS) const {
+ for (const LocationList &L : Locations) {
+ OS << format("0x%8.8x: ", L.Offset);
+ const unsigned Indent = 12;
+ for (const Entry &E : L.Entries) {
+ if (&E != L.Entries.begin())
+ OS.indent(Indent);
+ OS << "Beginning address offset: " << format("0x%016" PRIx64, E.Begin)
+ << '\n';
+ OS.indent(Indent) << " Ending address offset: "
+ << format("0x%016" PRIx64, E.End) << '\n';
+ OS.indent(Indent) << " Location description: ";
+ for (unsigned char Loc : E.Loc) {
+ OS << format("%2.2x ", Loc);
+ }
+ OS << "\n\n";
+ }
+ }
+}
+
+void DWARFDebugLoc::parse(DataExtractor data, unsigned AddressSize) {
+ uint32_t Offset = 0;
+ while (data.isValidOffset(Offset+AddressSize-1)) {
+ Locations.resize(Locations.size() + 1);
+ LocationList &Loc = Locations.back();
+ Loc.Offset = Offset;
+ // 2.6.2 Location Lists
+ // A location list entry consists of:
+ while (true) {
+ Entry E;
+ RelocAddrMap::const_iterator AI = RelocMap.find(Offset);
+ // 1. A beginning address offset. ...
+ E.Begin = data.getUnsigned(&Offset, AddressSize);
+ if (AI != RelocMap.end())
+ E.Begin += AI->second.second;
+
+ AI = RelocMap.find(Offset);
+ // 2. An ending address offset. ...
+ E.End = data.getUnsigned(&Offset, AddressSize);
+ if (AI != RelocMap.end())
+ E.End += AI->second.second;
+
+ // 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)
+ break;
+
+ unsigned Bytes = data.getU16(&Offset);
+ // A single location description describing the location of the object...
+ StringRef str = data.getData().substr(Offset, Bytes);
+ Offset += Bytes;
+ E.Loc.append(str.begin(), str.end());
+ Loc.Entries.push_back(std::move(E));
+ }
+ }
+ if (data.isValidOffset(Offset))
+ llvm::errs() << "error: failed to consume entire .debug_loc section\n";
+}
+
+void DWARFDebugLocDWO::parse(DataExtractor data) {
+ uint32_t Offset = 0;
+ while (data.isValidOffset(Offset)) {
+ Locations.resize(Locations.size() + 1);
+ LocationList &Loc = Locations.back();
+ Loc.Offset = Offset;
+ dwarf::LocationListEntry Kind;
+ while ((Kind = static_cast<dwarf::LocationListEntry>(
+ data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list_entry) {
+
+ if (Kind != dwarf::DW_LLE_start_length_entry) {
+ llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind
+ << " not implemented\n";
+ return;
+ }
+
+ Entry E;
+
+ E.Start = data.getULEB128(&Offset);
+ E.Length = data.getU32(&Offset);
+
+ unsigned Bytes = data.getU16(&Offset);
+ // A single location description describing the location of the object...
+ StringRef str = data.getData().substr(Offset, Bytes);
+ Offset += Bytes;
+ E.Loc.resize(str.size());
+ std::copy(str.begin(), str.end(), E.Loc.begin());
+
+ Loc.Entries.push_back(std::move(E));
+ }
+ }
+}
+
+void DWARFDebugLocDWO::dump(raw_ostream &OS) const {
+ for (const LocationList &L : Locations) {
+ OS << format("0x%8.8x: ", L.Offset);
+ const unsigned Indent = 12;
+ for (const Entry &E : L.Entries) {
+ if (&E != L.Entries.begin())
+ OS.indent(Indent);
+ OS << "Beginning address index: " << E.Start << '\n';
+ OS.indent(Indent) << " Length: " << E.Length << '\n';
+ OS.indent(Indent) << " Location description: ";
+ for (unsigned char Loc : E.Loc)
+ OS << format("%2.2x ", Loc);
+ OS << "\n\n";
+ }
+ }
+}
+
diff --git a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
new file mode 100644
index 000000000000..d5df6885f5e9
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -0,0 +1,69 @@
+//===-- DWARFDebugRangesList.cpp ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFDebugRangeList::clear() {
+ Offset = -1U;
+ AddressSize = 0;
+ Entries.clear();
+}
+
+bool DWARFDebugRangeList::extract(DataExtractor data, uint32_t *offset_ptr) {
+ clear();
+ if (!data.isValidOffset(*offset_ptr))
+ return false;
+ AddressSize = data.getAddressSize();
+ if (AddressSize != 4 && AddressSize != 8)
+ return false;
+ Offset = *offset_ptr;
+ while (true) {
+ RangeListEntry entry;
+ uint32_t prev_offset = *offset_ptr;
+ entry.StartAddress = data.getAddress(offset_ptr);
+ entry.EndAddress = data.getAddress(offset_ptr);
+ // Check that both values were extracted correctly.
+ if (*offset_ptr != prev_offset + 2 * AddressSize) {
+ clear();
+ return false;
+ }
+ if (entry.isEndOfListEntry())
+ break;
+ Entries.push_back(entry);
+ }
+ return true;
+}
+
+void DWARFDebugRangeList::dump(raw_ostream &OS) const {
+ for (const RangeListEntry &RLE : Entries) {
+ const char *format_str = (AddressSize == 4
+ ? "%08x %08" PRIx64 " %08" PRIx64 "\n"
+ : "%08x %016" PRIx64 " %016" PRIx64 "\n");
+ OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
+ }
+ OS << format("%08x <End of list>\n", Offset);
+}
+
+DWARFAddressRangesVector
+DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const {
+ DWARFAddressRangesVector Res;
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
+ BaseAddress = RLE.EndAddress;
+ } else {
+ Res.push_back(std::make_pair(BaseAddress + RLE.StartAddress,
+ BaseAddress + RLE.EndAddress));
+ }
+ }
+ return Res;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp
new file mode 100644
index 000000000000..53a676efaf3f
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,589 @@
+//===-- DWARFFormValue.cpp ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntaxHighlighting.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <climits>
+using namespace llvm;
+using namespace dwarf;
+using namespace syntax;
+
+namespace {
+uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) {
+ // FIXME: Support DWARF64.
+ return (Version == 2) ? AddrSize : 4;
+}
+
+template <uint8_t AddrSize, uint8_t RefAddrSize>
+ArrayRef<uint8_t> makeFixedFormSizesArrayRef() {
+ static const uint8_t sizes[] = {
+ 0, // 0x00 unused
+ AddrSize, // 0x01 DW_FORM_addr
+ 0, // 0x02 unused
+ 0, // 0x03 DW_FORM_block2
+ 0, // 0x04 DW_FORM_block4
+ 2, // 0x05 DW_FORM_data2
+ 4, // 0x06 DW_FORM_data4
+ 8, // 0x07 DW_FORM_data8
+ 0, // 0x08 DW_FORM_string
+ 0, // 0x09 DW_FORM_block
+ 0, // 0x0a DW_FORM_block1
+ 1, // 0x0b DW_FORM_data1
+ 1, // 0x0c DW_FORM_flag
+ 0, // 0x0d DW_FORM_sdata
+ 4, // 0x0e DW_FORM_strp
+ 0, // 0x0f DW_FORM_udata
+ RefAddrSize, // 0x10 DW_FORM_ref_addr
+ 1, // 0x11 DW_FORM_ref1
+ 2, // 0x12 DW_FORM_ref2
+ 4, // 0x13 DW_FORM_ref4
+ 8, // 0x14 DW_FORM_ref8
+ 0, // 0x15 DW_FORM_ref_udata
+ 0, // 0x16 DW_FORM_indirect
+ 4, // 0x17 DW_FORM_sec_offset
+ 0, // 0x18 DW_FORM_exprloc
+ 0, // 0x19 DW_FORM_flag_present
+ };
+ return makeArrayRef(sizes);
+}
+}
+
+ArrayRef<uint8_t> DWARFFormValue::getFixedFormSizes(uint8_t AddrSize,
+ uint16_t Version) {
+ uint8_t RefAddrSize = getRefAddrSize(AddrSize, Version);
+ if (AddrSize == 4 && RefAddrSize == 4)
+ return makeFixedFormSizesArrayRef<4, 4>();
+ if (AddrSize == 4 && RefAddrSize == 8)
+ return makeFixedFormSizesArrayRef<4, 8>();
+ if (AddrSize == 8 && RefAddrSize == 4)
+ return makeFixedFormSizesArrayRef<8, 4>();
+ if (AddrSize == 8 && RefAddrSize == 8)
+ return makeFixedFormSizesArrayRef<8, 8>();
+ return None;
+}
+
+static const DWARFFormValue::FormClass DWARF4FormClasses[] = {
+ DWARFFormValue::FC_Unknown, // 0x0
+ DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr
+ DWARFFormValue::FC_Unknown, // 0x02 unused
+ DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2
+ DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4
+ DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2
+ // --- These can be FC_SectionOffset in DWARF3 and below:
+ DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4
+ DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8
+ // ---
+ DWARFFormValue::FC_String, // 0x08 DW_FORM_string
+ DWARFFormValue::FC_Block, // 0x09 DW_FORM_block
+ DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1
+ DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1
+ DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag
+ DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata
+ DWARFFormValue::FC_String, // 0x0e DW_FORM_strp
+ DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata
+ DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr
+ DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1
+ DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2
+ DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4
+ DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8
+ DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata
+ DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect
+ DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset
+ DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc
+ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present
+};
+
+bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
+ // First, check DWARF4 form classes.
+ if (Form < ArrayRef<FormClass>(DWARF4FormClasses).size() &&
+ DWARF4FormClasses[Form] == FC)
+ return true;
+ // Check more forms from DWARF4 and DWARF5 proposals.
+ switch (Form) {
+ case DW_FORM_ref_sig8:
+ case DW_FORM_GNU_ref_alt:
+ return (FC == FC_Reference);
+ case DW_FORM_GNU_addr_index:
+ return (FC == FC_Address);
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_strp_alt:
+ return (FC == FC_String);
+ }
+ // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset.
+ // Don't check for DWARF version here, as some producers may still do this
+ // by mistake.
+ return (Form == DW_FORM_data4 || Form == DW_FORM_data8) &&
+ FC == FC_SectionOffset;
+}
+
+bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr,
+ const DWARFUnit *cu) {
+ bool indirect = false;
+ bool is_block = false;
+ Value.data = nullptr;
+ // Read the value for the form into value and follow and DW_FORM_indirect
+ // instances we run into
+ do {
+ indirect = false;
+ switch (Form) {
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr: {
+ if (!cu)
+ return false;
+ uint16_t AddrSize =
+ (Form == DW_FORM_addr)
+ ? cu->getAddressByteSize()
+ : getRefAddrSize(cu->getAddressByteSize(), cu->getVersion());
+ RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr);
+ if (AI != cu->getRelocMap()->end()) {
+ const std::pair<uint8_t, int64_t> &R = AI->second;
+ Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second;
+ } else
+ Value.uval = data.getUnsigned(offset_ptr, AddrSize);
+ break;
+ }
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ Value.uval = data.getULEB128(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_block1:
+ Value.uval = data.getU8(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_block2:
+ Value.uval = data.getU16(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_block4:
+ Value.uval = data.getU32(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ Value.uval = data.getU8(offset_ptr);
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ Value.uval = data.getU16(offset_ptr);
+ break;
+ case DW_FORM_data4:
+ case DW_FORM_ref4: {
+ Value.uval = data.getU32(offset_ptr);
+ if (!cu)
+ break;
+ RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4);
+ if (AI != cu->getRelocMap()->end())
+ Value.uval += AI->second.second;
+ break;
+ }
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ Value.uval = data.getU64(offset_ptr);
+ break;
+ case DW_FORM_sdata:
+ Value.sval = data.getSLEB128(offset_ptr);
+ break;
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ Value.uval = data.getULEB128(offset_ptr);
+ break;
+ case DW_FORM_string:
+ Value.cstr = data.getCStr(offset_ptr);
+ break;
+ case DW_FORM_indirect:
+ Form = data.getULEB128(offset_ptr);
+ indirect = true;
+ break;
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt: {
+ // FIXME: This is 64-bit for DWARF64.
+ Value.uval = data.getU32(offset_ptr);
+ if (!cu)
+ break;
+ RelocAddrMap::const_iterator AI =
+ cu->getRelocMap()->find(*offset_ptr - 4);
+ if (AI != cu->getRelocMap()->end())
+ Value.uval += AI->second.second;
+ break;
+ }
+ case DW_FORM_flag_present:
+ Value.uval = 1;
+ break;
+ case DW_FORM_ref_sig8:
+ Value.uval = data.getU64(offset_ptr);
+ break;
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ Value.uval = data.getULEB128(offset_ptr);
+ break;
+ default:
+ return false;
+ }
+ } while (indirect);
+
+ if (is_block) {
+ StringRef str = data.getData().substr(*offset_ptr, Value.uval);
+ Value.data = nullptr;
+ if (!str.empty()) {
+ Value.data = reinterpret_cast<const uint8_t *>(str.data());
+ *offset_ptr += Value.uval;
+ }
+ }
+
+ return true;
+}
+
+bool
+DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr,
+ const DWARFUnit *cu) const {
+ return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, cu);
+}
+
+bool
+DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data,
+ uint32_t *offset_ptr, const DWARFUnit *cu) {
+ bool indirect = false;
+ do {
+ switch (form) {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc:
+ case DW_FORM_block: {
+ uint64_t size = debug_info_data.getULEB128(offset_ptr);
+ *offset_ptr += size;
+ return true;
+ }
+ case DW_FORM_block1: {
+ uint8_t size = debug_info_data.getU8(offset_ptr);
+ *offset_ptr += size;
+ return true;
+ }
+ case DW_FORM_block2: {
+ uint16_t size = debug_info_data.getU16(offset_ptr);
+ *offset_ptr += size;
+ return true;
+ }
+ case DW_FORM_block4: {
+ uint32_t size = debug_info_data.getU32(offset_ptr);
+ *offset_ptr += size;
+ return true;
+ }
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.getCStr(offset_ptr);
+ return true;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ *offset_ptr += cu->getAddressByteSize();
+ return true;
+ case DW_FORM_ref_addr:
+ *offset_ptr += getRefAddrSize(cu->getAddressByteSize(), cu->getVersion());
+ return true;
+
+ // 0 byte values - implied from the form.
+ case DW_FORM_flag_present:
+ return true;
+
+ // 1 byte values
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ *offset_ptr += 1;
+ return true;
+
+ // 2 byte values
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ *offset_ptr += 2;
+ return true;
+
+ // 4 byte values
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ *offset_ptr += 4;
+ return true;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ debug_info_data.getULEB128(offset_ptr);
+ return true;
+
+ case DW_FORM_indirect:
+ indirect = true;
+ form = debug_info_data.getULEB128(offset_ptr);
+ break;
+
+ // FIXME: 4 for DWARF32, 8 for DWARF64.
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ *offset_ptr += 4;
+ return true;
+
+ default:
+ return false;
+ }
+ } while (indirect);
+ return true;
+}
+
+void
+DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const {
+ uint64_t uvalue = Value.uval;
+ bool cu_relative_offset = false;
+
+ switch (Form) {
+ case DW_FORM_addr: OS << format("0x%016" PRIx64, uvalue); break;
+ case DW_FORM_GNU_addr_index: {
+ OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue);
+ uint64_t Address;
+ if (cu->getAddrOffsetSectionItem(uvalue, Address))
+ OS << format("0x%016" PRIx64, Address);
+ else
+ OS << "<no .debug_addr section>";
+ break;
+ }
+ case DW_FORM_flag_present: OS << "true"; break;
+ case DW_FORM_flag:
+ case DW_FORM_data1: OS << format("0x%02x", (uint8_t)uvalue); break;
+ case DW_FORM_data2: OS << format("0x%04x", (uint16_t)uvalue); break;
+ case DW_FORM_data4: OS << format("0x%08x", (uint32_t)uvalue); break;
+ case DW_FORM_ref_sig8:
+ case DW_FORM_data8: OS << format("0x%016" PRIx64, uvalue); break;
+ case DW_FORM_string:
+ OS << '"';
+ OS.write_escaped(Value.cstr);
+ OS << '"';
+ break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (uvalue > 0) {
+ switch (Form) {
+ case DW_FORM_exprloc:
+ case DW_FORM_block: OS << format("<0x%" PRIx64 "> ", uvalue); break;
+ case DW_FORM_block1: OS << format("<0x%2.2x> ", (uint8_t)uvalue); break;
+ case DW_FORM_block2: OS << format("<0x%4.4x> ", (uint16_t)uvalue); break;
+ case DW_FORM_block4: OS << format("<0x%8.8x> ", (uint32_t)uvalue); break;
+ default: break;
+ }
+
+ const uint8_t* data_ptr = Value.data;
+ if (data_ptr) {
+ // uvalue contains size of block
+ const uint8_t* end_data_ptr = data_ptr + uvalue;
+ while (data_ptr < end_data_ptr) {
+ OS << format("%2.2x ", *data_ptr);
+ ++data_ptr;
+ }
+ }
+ else
+ OS << "NULL";
+ }
+ break;
+
+ case DW_FORM_sdata: OS << Value.sval; break;
+ case DW_FORM_udata: OS << Value.uval; break;
+ case DW_FORM_strp: {
+ OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
+ dumpString(OS, cu);
+ break;
+ }
+ case DW_FORM_GNU_str_index: {
+ OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue);
+ dumpString(OS, cu);
+ break;
+ }
+ case DW_FORM_GNU_strp_alt: {
+ OS << format("alt indirect string, offset: 0x%" PRIx64 "", uvalue);
+ dumpString(OS, cu);
+ break;
+ }
+ case DW_FORM_ref_addr:
+ OS << format("0x%016" PRIx64, uvalue);
+ break;
+ case DW_FORM_ref1:
+ cu_relative_offset = true;
+ OS << format("cu + 0x%2.2x", (uint8_t)uvalue);
+ break;
+ case DW_FORM_ref2:
+ cu_relative_offset = true;
+ OS << format("cu + 0x%4.4x", (uint16_t)uvalue);
+ break;
+ case DW_FORM_ref4:
+ cu_relative_offset = true;
+ OS << format("cu + 0x%4.4x", (uint32_t)uvalue);
+ break;
+ case DW_FORM_ref8:
+ cu_relative_offset = true;
+ OS << format("cu + 0x%8.8" PRIx64, uvalue);
+ break;
+ case DW_FORM_ref_udata:
+ cu_relative_offset = true;
+ OS << format("cu + 0x%" PRIx64, uvalue);
+ break;
+ case DW_FORM_GNU_ref_alt:
+ OS << format("<alt 0x%" PRIx64 ">", uvalue);
+ break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling
+ // this function
+ case DW_FORM_indirect:
+ OS << "DW_FORM_indirect";
+ break;
+
+ // Should be formatted to 64-bit for DWARF64.
+ case DW_FORM_sec_offset:
+ OS << format("0x%08x", (uint32_t)uvalue);
+ break;
+
+ default:
+ OS << format("DW_FORM(0x%4.4x)", Form);
+ break;
+ }
+
+ if (cu_relative_offset) {
+ OS << " => {";
+ WithColor(OS, syntax::Address).get()
+ << format("0x%8.8" PRIx64, uvalue + (cu ? cu->getOffset() : 0));
+ OS << "}";
+ }
+}
+
+void DWARFFormValue::dumpString(raw_ostream &OS, const DWARFUnit *U) const {
+ Optional<const char *> DbgStr = getAsCString(U);
+ if (DbgStr.hasValue()) {
+ raw_ostream &COS = WithColor(OS, syntax::String);
+ COS << '"';
+ COS.write_escaped(DbgStr.getValue());
+ COS << '"';
+ }
+}
+
+Optional<const char *> DWARFFormValue::getAsCString(const DWARFUnit *U) const {
+ if (!isFormClass(FC_String))
+ return None;
+ if (Form == DW_FORM_string)
+ return Value.cstr;
+ // FIXME: Add support for DW_FORM_GNU_strp_alt
+ if (Form == DW_FORM_GNU_strp_alt || U == nullptr)
+ return None;
+ uint32_t Offset = Value.uval;
+ if (Form == DW_FORM_GNU_str_index) {
+ uint32_t StrOffset;
+ if (!U->getStringOffsetSectionItem(Offset, StrOffset))
+ return None;
+ Offset = StrOffset;
+ }
+ if (const char *Str = U->getStringExtractor().getCStr(&Offset)) {
+ return Str;
+ }
+ return None;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsAddress(const DWARFUnit *U) const {
+ if (!isFormClass(FC_Address))
+ return None;
+ if (Form == DW_FORM_GNU_addr_index) {
+ uint32_t Index = Value.uval;
+ uint64_t Result;
+ if (!U || !U->getAddrOffsetSectionItem(Index, Result))
+ return None;
+ return Result;
+ }
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReference(const DWARFUnit *U) const {
+ if (!isFormClass(FC_Reference))
+ return None;
+ switch (Form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ if (!U)
+ return None;
+ return Value.uval + U->getOffset();
+ case DW_FORM_ref_addr:
+ return Value.uval;
+ // FIXME: Add proper support for DW_FORM_ref_sig8 and DW_FORM_GNU_ref_alt.
+ default:
+ return None;
+ }
+}
+
+Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const {
+ if (!isFormClass(FC_SectionOffset))
+ return None;
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag))
+ || Form == DW_FORM_sdata)
+ return None;
+ return Value.uval;
+}
+
+Optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+ (Form == DW_FORM_udata && uint64_t(LLONG_MAX) < Value.uval))
+ return None;
+ switch (Form) {
+ case DW_FORM_data4:
+ return int32_t(Value.uval);
+ case DW_FORM_data2:
+ return int16_t(Value.uval);
+ case DW_FORM_data1:
+ return int8_t(Value.uval);
+ case DW_FORM_sdata:
+ case DW_FORM_data8:
+ default:
+ return Value.sval;
+ }
+}
+
+Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const {
+ if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc))
+ return None;
+ return ArrayRef<uint8_t>(Value.data, Value.uval);
+}
+
diff --git a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
new file mode 100644
index 000000000000..766e8ac16f0c
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
@@ -0,0 +1,40 @@
+//===-- DWARFTypeUnit.cpp -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+bool DWARFTypeUnit::extractImpl(DataExtractor debug_info,
+ uint32_t *offset_ptr) {
+ if (!DWARFUnit::extractImpl(debug_info, offset_ptr))
+ return false;
+ TypeHash = debug_info.getU64(offset_ptr);
+ TypeOffset = debug_info.getU32(offset_ptr);
+ return TypeOffset < getLength();
+}
+
+void DWARFTypeUnit::dump(raw_ostream &OS) {
+ OS << format("0x%08x", getOffset()) << ": Type Unit:"
+ << " length = " << format("0x%08x", getLength())
+ << " version = " << format("0x%04x", getVersion())
+ << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
+ << " addr_size = " << format("0x%02x", getAddressByteSize())
+ << " type_signature = " << format("0x%16" PRIx64, TypeHash)
+ << " type_offset = " << format("0x%04x", TypeOffset)
+ << " (next unit at " << format("0x%08x", getNextUnitOffset())
+ << ")\n";
+
+ if (const DWARFDebugInfoEntryMinimal *TU = getUnitDIE(false))
+ TU->dump(OS, this, -1U);
+ else
+ OS << "<type unit can't be parsed!>\n\n";
+}
diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp
new file mode 100644
index 000000000000..348476d72b60
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -0,0 +1,377 @@
+//===-- DWARFUnit.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Path.h"
+#include <cstdio>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) {
+ parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(),
+ C.getStringSection(), StringRef(), C.getAddrSection(),
+ C.isLittleEndian());
+}
+
+void DWARFUnitSectionBase::parseDWO(DWARFContext &C,
+ const DWARFSection &DWOSection) {
+ parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(),
+ C.getStringDWOSection(), C.getStringOffsetDWOSection(),
+ C.getAddrSection(), C.isLittleEndian());
+}
+
+DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
+ const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
+ StringRef SOS, StringRef AOS, bool LE,
+ const DWARFUnitSectionBase &UnitSection)
+ : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS),
+ StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
+ isLittleEndian(LE), UnitSection(UnitSection) {
+ clear();
+}
+
+DWARFUnit::~DWARFUnit() {
+}
+
+bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index,
+ uint64_t &Result) const {
+ uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize;
+ if (AddrOffsetSection.size() < Offset + AddrSize)
+ return false;
+ DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize);
+ Result = DA.getAddress(&Offset);
+ return true;
+}
+
+bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index,
+ uint32_t &Result) const {
+ // FIXME: string offset section entries are 8-byte for DWARF64.
+ const uint32_t ItemSize = 4;
+ uint32_t Offset = Index * ItemSize;
+ if (StringOffsetSection.size() < Offset + ItemSize)
+ return false;
+ DataExtractor DA(StringOffsetSection, isLittleEndian, 0);
+ Result = DA.getU32(&Offset);
+ return true;
+}
+
+bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
+ Length = debug_info.getU32(offset_ptr);
+ Version = debug_info.getU16(offset_ptr);
+ uint64_t AbbrOffset = debug_info.getU32(offset_ptr);
+ AddrSize = debug_info.getU8(offset_ptr);
+
+ bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
+ bool VersionOK = DWARFContext::isSupportedVersion(Version);
+ bool AddrSizeOK = AddrSize == 4 || AddrSize == 8;
+
+ if (!LengthOK || !VersionOK || !AddrSizeOK)
+ return false;
+
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset);
+ return Abbrevs != nullptr;
+}
+
+bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
+ clear();
+
+ Offset = *offset_ptr;
+
+ if (debug_info.isValidOffset(*offset_ptr)) {
+ if (extractImpl(debug_info, offset_ptr))
+ return true;
+
+ // reset the offset to where we tried to parse from if anything went wrong
+ *offset_ptr = Offset;
+ }
+
+ return false;
+}
+
+bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const {
+ // Require that compile unit is extracted.
+ assert(DieArray.size() > 0);
+ DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize);
+ uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+ return RangeList.extract(RangesData, &ActualRangeListOffset);
+}
+
+void DWARFUnit::clear() {
+ Offset = 0;
+ Length = 0;
+ Version = 0;
+ Abbrevs = nullptr;
+ AddrSize = 0;
+ BaseAddr = 0;
+ RangeSectionBase = 0;
+ AddrOffsetSectionBase = 0;
+ clearDIEs(false);
+ DWO.reset();
+}
+
+const char *DWARFUnit::getCompilationDir() {
+ extractDIEsIfNeeded(true);
+ if (DieArray.empty())
+ return nullptr;
+ return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr);
+}
+
+uint64_t DWARFUnit::getDWOId() {
+ extractDIEsIfNeeded(true);
+ const uint64_t FailValue = -1ULL;
+ if (DieArray.empty())
+ return FailValue;
+ return DieArray[0]
+ .getAttributeValueAsUnsignedConstant(this, DW_AT_GNU_dwo_id, FailValue);
+}
+
+void DWARFUnit::setDIERelations() {
+ if (DieArray.size() <= 1)
+ return;
+
+ std::vector<DWARFDebugInfoEntryMinimal *> ParentChain;
+ DWARFDebugInfoEntryMinimal *SiblingChain = nullptr;
+ for (auto &DIE : DieArray) {
+ if (SiblingChain) {
+ SiblingChain->setSibling(&DIE);
+ }
+ if (const DWARFAbbreviationDeclaration *AbbrDecl =
+ DIE.getAbbreviationDeclarationPtr()) {
+ // Normal DIE.
+ if (AbbrDecl->hasChildren()) {
+ ParentChain.push_back(&DIE);
+ SiblingChain = nullptr;
+ } else {
+ SiblingChain = &DIE;
+ }
+ } else {
+ // NULL entry terminates the sibling chain.
+ SiblingChain = ParentChain.back();
+ ParentChain.pop_back();
+ }
+ }
+ assert(SiblingChain == nullptr || SiblingChain == &DieArray[0]);
+ assert(ParentChain.empty());
+}
+
+void DWARFUnit::extractDIEsToVector(
+ bool AppendCUDie, bool AppendNonCUDies,
+ std::vector<DWARFDebugInfoEntryMinimal> &Dies) const {
+ if (!AppendCUDie && !AppendNonCUDies)
+ return;
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ uint32_t DIEOffset = Offset + getHeaderSize();
+ uint32_t NextCUOffset = getNextUnitOffset();
+ DWARFDebugInfoEntryMinimal DIE;
+ uint32_t Depth = 0;
+ bool IsCUDie = true;
+
+ while (DIEOffset < NextCUOffset && DIE.extractFast(this, &DIEOffset)) {
+ if (IsCUDie) {
+ if (AppendCUDie)
+ Dies.push_back(DIE);
+ if (!AppendNonCUDies)
+ break;
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so let's pre-reserve the needed memory for
+ // our DIE entries accordingly.
+ Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
+ IsCUDie = false;
+ } else {
+ Dies.push_back(DIE);
+ }
+
+ if (const DWARFAbbreviationDeclaration *AbbrDecl =
+ DIE.getAbbreviationDeclarationPtr()) {
+ // Normal DIE
+ if (AbbrDecl->hasChildren())
+ ++Depth;
+ } else {
+ // NULL DIE.
+ if (Depth > 0)
+ --Depth;
+ if (Depth == 0)
+ break; // We are done with this compile unit!
+ }
+ }
+
+ // Give a little bit of info if we encounter corrupt DWARF (our offset
+ // should always terminate at or before the start of the next compilation
+ // unit header).
+ if (DIEOffset > NextCUOffset)
+ fprintf(stderr, "warning: DWARF compile unit extends beyond its "
+ "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), DIEOffset);
+}
+
+size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
+ if ((CUDieOnly && DieArray.size() > 0) ||
+ DieArray.size() > 1)
+ return 0; // Already parsed.
+
+ bool HasCUDie = DieArray.size() > 0;
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+
+ if (DieArray.empty())
+ return 0;
+
+ // If CU DIE was just parsed, copy several attribute values from it.
+ if (!HasCUDie) {
+ uint64_t BaseAddr =
+ DieArray[0].getAttributeValueAsAddress(this, DW_AT_low_pc, -1ULL);
+ if (BaseAddr == -1ULL)
+ BaseAddr = DieArray[0].getAttributeValueAsAddress(this, DW_AT_entry_pc, 0);
+ setBaseAddress(BaseAddr);
+ AddrOffsetSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
+ this, DW_AT_GNU_addr_base, 0);
+ RangeSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
+ this, DW_AT_ranges_base, 0);
+ // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
+ // skeleton CU DIE, so that DWARF users not aware of it are not broken.
+ }
+
+ setDIERelations();
+ return DieArray.size();
+}
+
+DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath)
+ : DWOFile(), DWOContext(), DWOU(nullptr) {
+ auto Obj = object::ObjectFile::createObjectFile(DWOPath);
+ if (!Obj)
+ return;
+ DWOFile = std::move(Obj.get());
+ DWOContext.reset(
+ cast<DWARFContext>(new DWARFContextInMemory(*DWOFile.getBinary())));
+ if (DWOContext->getNumDWOCompileUnits() > 0)
+ DWOU = DWOContext->getDWOCompileUnitAtIndex(0);
+}
+
+bool DWARFUnit::parseDWO() {
+ if (DWO.get())
+ return false;
+ extractDIEsIfNeeded(true);
+ if (DieArray.empty())
+ return false;
+ const char *DWOFileName =
+ DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, nullptr);
+ if (!DWOFileName)
+ return false;
+ const char *CompilationDir =
+ DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr);
+ SmallString<16> AbsolutePath;
+ if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) {
+ sys::path::append(AbsolutePath, CompilationDir);
+ }
+ sys::path::append(AbsolutePath, DWOFileName);
+ DWO = llvm::make_unique<DWOHolder>(AbsolutePath);
+ DWARFUnit *DWOCU = DWO->getUnit();
+ // Verify that compile unit in .dwo file is valid.
+ if (!DWOCU || DWOCU->getDWOId() != getDWOId()) {
+ DWO.reset();
+ return false;
+ }
+ // Share .debug_addr and .debug_ranges section with compile unit in .dwo
+ DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
+ uint32_t DWORangesBase = DieArray[0].getRangesBaseAttribute(this, 0);
+ DWOCU->setRangesSection(RangeSection, DWORangesBase);
+ return true;
+}
+
+void DWARFUnit::clearDIEs(bool KeepCUDie) {
+ if (DieArray.size() > (unsigned)KeepCUDie) {
+ // std::vectors never get any smaller when resized to a smaller size,
+ // or when clear() or erase() are called, the size will report that it
+ // is smaller, but the memory allocated remains intact (call capacity()
+ // to see this). So we need to create a temporary vector and swap the
+ // contents which will cause just the internal pointers to be swapped
+ // so that when temporary vector goes out of scope, it will destroy the
+ // contents.
+ std::vector<DWARFDebugInfoEntryMinimal> TmpArray;
+ DieArray.swap(TmpArray);
+ // Save at least the compile unit DIE
+ if (KeepCUDie)
+ DieArray.push_back(TmpArray.front());
+ }
+}
+
+void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
+ const auto *U = getUnitDIE();
+ if (U == nullptr)
+ return;
+ // First, check if unit DIE describes address ranges for the whole unit.
+ const auto &CUDIERanges = U->getAddressRanges(this);
+ if (!CUDIERanges.empty()) {
+ CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
+ return;
+ }
+
+ // This function is usually called if there in no .debug_aranges section
+ // in order to produce a compile unit level set of address ranges that
+ // is accurate. If the DIEs weren't parsed, then we don't want all dies for
+ // all compile units to stay loaded when they weren't needed. So we can end
+ // up parsing the DWARF and then throwing them all away to keep memory usage
+ // down.
+ const bool ClearDIEs = extractDIEsIfNeeded(false) > 1;
+ DieArray[0].collectChildrenAddressRanges(this, CURanges);
+
+ // Collect address ranges from DIEs in .dwo if necessary.
+ bool DWOCreated = parseDWO();
+ if (DWO.get())
+ DWO->getUnit()->collectAddressRanges(CURanges);
+ if (DWOCreated)
+ DWO.reset();
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed.
+ if (ClearDIEs)
+ clearDIEs(true);
+}
+
+const DWARFDebugInfoEntryMinimal *
+DWARFUnit::getSubprogramForAddress(uint64_t Address) {
+ extractDIEsIfNeeded(false);
+ for (const DWARFDebugInfoEntryMinimal &DIE : DieArray) {
+ if (DIE.isSubprogramDIE() &&
+ DIE.addressRangeContainsAddress(this, Address)) {
+ return &DIE;
+ }
+ }
+ return nullptr;
+}
+
+DWARFDebugInfoEntryInlinedChain
+DWARFUnit::getInlinedChainForAddress(uint64_t Address) {
+ // First, find a subprogram that contains the given address (the root
+ // of inlined chain).
+ const DWARFUnit *ChainCU = nullptr;
+ const DWARFDebugInfoEntryMinimal *SubprogramDIE =
+ getSubprogramForAddress(Address);
+ if (SubprogramDIE) {
+ ChainCU = this;
+ } else {
+ // Try to look for subprogram DIEs in the DWO file.
+ parseDWO();
+ if (DWO.get()) {
+ SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address);
+ if (SubprogramDIE)
+ ChainCU = DWO->getUnit();
+ }
+ }
+
+ // Get inlined chain rooted at this subprogram DIE.
+ if (!SubprogramDIE)
+ return DWARFDebugInfoEntryInlinedChain();
+ return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address);
+}
diff --git a/lib/DebugInfo/DWARF/LLVMBuild.txt b/lib/DebugInfo/DWARF/LLVMBuild.txt
new file mode 100644
index 000000000000..9f8b1047ef6b
--- /dev/null
+++ b/lib/DebugInfo/DWARF/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./lib/DebugInfo/DWARF/LLVMBuild.txt ----------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = DebugInfoDWARF
+parent = DebugInfo
+required_libraries = Object Support
diff --git a/lib/DebugInfo/DWARF/Makefile b/lib/DebugInfo/DWARF/Makefile
new file mode 100644
index 000000000000..863337353d0a
--- /dev/null
+++ b/lib/DebugInfo/DWARF/Makefile
@@ -0,0 +1,14 @@
+##===- lib/DebugInfo/DWARF/Makefile ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME = LLVMDebugInfoDWARF
+BUILD_ARCHIVE := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
new file mode 100644
index 000000000000..a6b4c6549ca4
--- /dev/null
+++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
@@ -0,0 +1,37 @@
+//===-- SyntaxHighlighting.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntaxHighlighting.h"
+#include "llvm/Support/CommandLine.h"
+using namespace llvm;
+using namespace dwarf;
+using namespace syntax;
+
+static cl::opt<cl::boolOrDefault>
+ UseColor("color",
+ cl::desc("use colored syntax highlighting (default=autodetect)"),
+ cl::init(cl::BOU_UNSET));
+
+WithColor::WithColor(llvm::raw_ostream &OS, enum HighlightColor Type) : OS(OS) {
+ // Detect color from terminal type unless the user passed the --color option.
+ if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE) {
+ switch (Type) {
+ case Address: OS.changeColor(llvm::raw_ostream::YELLOW); break;
+ case String: OS.changeColor(llvm::raw_ostream::GREEN); break;
+ case Tag: OS.changeColor(llvm::raw_ostream::BLUE); break;
+ case Attribute: OS.changeColor(llvm::raw_ostream::CYAN); break;
+ case Enumerator: OS.changeColor(llvm::raw_ostream::MAGENTA); break;
+ }
+ }
+}
+
+WithColor::~WithColor() {
+ if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE)
+ OS.resetColor();
+}
diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/lib/DebugInfo/DWARF/SyntaxHighlighting.h
new file mode 100644
index 000000000000..946a31308aa1
--- /dev/null
+++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.h
@@ -0,0 +1,39 @@
+//===-- SyntaxHighlighting.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H
+#define LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace dwarf {
+namespace syntax {
+
+// Symbolic names for various syntax elements.
+enum HighlightColor { Address, String, Tag, Attribute, Enumerator };
+
+/// An RAII object that temporarily switches an output stream to a
+/// specific color.
+class WithColor {
+ llvm::raw_ostream &OS;
+
+public:
+ /// To be used like this: WithColor(OS, syntax::String) << "text";
+ WithColor(llvm::raw_ostream &OS, enum HighlightColor Type);
+ ~WithColor();
+
+ llvm::raw_ostream& get() { return OS; }
+ operator llvm::raw_ostream& () { return OS; }
+};
+}
+}
+}
+
+#endif
diff --git a/lib/DebugInfo/DWARF/module.modulemap b/lib/DebugInfo/DWARF/module.modulemap
new file mode 100644
index 000000000000..c2f624fd4b6c
--- /dev/null
+++ b/lib/DebugInfo/DWARF/module.modulemap
@@ -0,0 +1 @@
+module DebugInfoDWARF { requires cplusplus umbrella "." module * { export * } }