diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo')
29 files changed, 5074 insertions, 0 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DIContext.cpp b/contrib/llvm/lib/DebugInfo/DIContext.cpp new file mode 100644 index 000000000000..49a44097d3e2 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DIContext.cpp @@ -0,0 +1,18 @@ +//===-- DIContext.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/DIContext.h" +#include "DWARFContext.h" +using namespace llvm; + +DIContext::~DIContext() {} + +DIContext *DIContext::getDWARFContext(object::ObjectFile *Obj) { + return new DWARFContextInMemory(Obj); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARFAbbreviationDeclaration.cpp new file mode 100644 index 000000000000..f46fd58a63b0 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/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 "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; + Attributes.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; + Attributes.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 (unsigned i = 0, e = Attributes.size(); i != e; ++i) { + OS << '\t'; + const char *attrString = AttributeString(Attributes[i].Attr); + if (attrString) + OS << attrString; + else + OS << format("DW_AT_Unknown_%x", Attributes[i].Attr); + OS << '\t'; + const char *formString = FormEncodingString(Attributes[i].Form); + if (formString) + OS << formString; + else + OS << format("DW_FORM_Unknown_%x", Attributes[i].Form); + OS << '\n'; + } + OS << '\n'; +} + +uint32_t +DWARFAbbreviationDeclaration::findAttributeIndex(uint16_t attr) const { + for (uint32_t i = 0, e = Attributes.size(); i != e; ++i) { + if (Attributes[i].Attr == attr) + return i; + } + return -1U; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFAbbreviationDeclaration.h b/contrib/llvm/lib/DebugInfo/DWARFAbbreviationDeclaration.h new file mode 100644 index 000000000000..e9b072eb86d8 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFAbbreviationDeclaration.h @@ -0,0 +1,55 @@ +//===-- DWARFAbbreviationDeclaration.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_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#define LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataExtractor.h" + +namespace llvm { + +class raw_ostream; + +class DWARFAbbreviationDeclaration { + uint32_t Code; + uint32_t Tag; + bool HasChildren; + + struct AttributeSpec { + AttributeSpec(uint16_t Attr, uint16_t Form) : Attr(Attr), Form(Form) {} + uint16_t Attr; + uint16_t Form; + }; + SmallVector<AttributeSpec, 8> Attributes; +public: + DWARFAbbreviationDeclaration(); + + uint32_t getCode() const { return Code; } + uint32_t getTag() const { return Tag; } + bool hasChildren() const { return HasChildren; } + uint32_t getNumAttributes() const { return Attributes.size(); } + uint16_t getAttrByIndex(uint32_t idx) const { + return idx < Attributes.size() ? Attributes[idx].Attr : 0; + } + uint16_t getFormByIndex(uint32_t idx) const { + return idx < Attributes.size() ? Attributes[idx].Form : 0; + } + + uint32_t findAttributeIndex(uint16_t attr) const; + bool extract(DataExtractor Data, uint32_t* OffsetPtr); + void dump(raw_ostream &OS) const; + +private: + void clear(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.cpp new file mode 100644 index 000000000000..33869d8c998e --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.cpp @@ -0,0 +1,32 @@ +//===-- DWARFCompileUnit.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "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"; + + const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false); + assert(CU && "Null Compile Unit?"); + CU->dump(OS, this, -1U); +} + +// VTable anchor. +DWARFCompileUnit::~DWARFCompileUnit() { +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.h b/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.h new file mode 100644 index 000000000000..1c9573b0b4b7 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFCompileUnit.h @@ -0,0 +1,30 @@ +//===-- DWARFCompileUnit.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_DEBUGINFO_DWARFCOMPILEUNIT_H +#define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H + +#include "DWARFUnit.h" + +namespace llvm { + +class DWARFCompileUnit : public DWARFUnit { +public: + DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE) + : DWARFUnit(DA, IS, AS, RS, SS, SOS, AOS, M, LE) {} + void dump(raw_ostream &OS); + // VTable anchor. + ~DWARFCompileUnit() LLVM_OVERRIDE; +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARFContext.cpp new file mode 100644 index 000000000000..e47719025c80 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFContext.cpp @@ -0,0 +1,719 @@ +//===-- DWARFContext.cpp --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFContext.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/STLExtras.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; + +typedef DWARFDebugLine::LineTable DWARFLineTable; + +DWARFContext::~DWARFContext() { + DeleteContainerPointers(CUs); + DeleteContainerPointers(TUs); + DeleteContainerPointers(DWOCUs); +} + +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; + 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"; + } +} + +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_Info) { + OS << "\n.debug_info contents:\n"; + for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) + getCompileUnitAtIndex(i)->dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_Types) { + OS << "\n.debug_types contents:\n"; + for (unsigned i = 0, e = getNumTypeUnits(); i != e; ++i) + getTypeUnitAtIndex(i)->dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_Loc) { + OS << "\n.debug_loc contents:\n"; + getDebugLoc()->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 (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { + DWARFCompileUnit *cu = getCompileUnitAtIndex(i); + savedAddressByteSize = cu->getAddressByteSize(); + unsigned stmtOffset = + cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( + cu, DW_AT_stmt_list, -1U); + if (stmtOffset != -1U) { + DataExtractor lineData(getLineSection().Data, isLittleEndian(), + savedAddressByteSize); + DWARFDebugLine::DumpingState state(OS); + DWARFDebugLine::parseStatementTable(lineData, &getLineSection().Relocs, &stmtOffset, state); + } + } + } + + 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_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_AbbrevDwo) { + const DWARFDebugAbbrev *D = getDebugAbbrevDWO(); + if (D) { + OS << "\n.debug_abbrev.dwo contents:\n"; + getDebugAbbrevDWO()->dump(OS); + } + } + + if (DumpType == DIDT_All || DumpType == DIDT_InfoDwo) + if (getNumDWOCompileUnits()) { + OS << "\n.debug_info.dwo contents:\n"; + for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i) + getDWOCompileUnitAtIndex(i)->dump(OS); + } + + if (DumpType == DIDT_All || DumpType == DIDT_StrDwo) + if (!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_StrOffsetsDwo) + if (!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)); + } + } +} + +const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { + if (Abbrev) + return Abbrev.get(); + + DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0); + + Abbrev.reset(new DWARFDebugAbbrev()); + Abbrev->parse(abbrData); + return Abbrev.get(); +} + +const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { + if (AbbrevDWO) + return AbbrevDWO.get(); + + DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0); + AbbrevDWO.reset(new DWARFDebugAbbrev()); + AbbrevDWO->parse(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 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::getLineTableForCompileUnit(DWARFCompileUnit *cu) { + if (!Line) + Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); + + unsigned stmtOffset = + cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( + cu, DW_AT_stmt_list, -1U); + if (stmtOffset == -1U) + return 0; // 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(), + cu->getAddressByteSize()); + return Line->getOrParseLineTable(lineData, stmtOffset); +} + +void DWARFContext::parseCompileUnits() { + uint32_t offset = 0; + const DataExtractor &DIData = DataExtractor(getInfoSection().Data, + isLittleEndian(), 0); + while (DIData.isValidOffset(offset)) { + OwningPtr<DWARFCompileUnit> CU(new DWARFCompileUnit( + getDebugAbbrev(), getInfoSection().Data, getAbbrevSection(), + getRangeSection(), getStringSection(), StringRef(), getAddrSection(), + &getInfoSection().Relocs, isLittleEndian())); + if (!CU->extract(DIData, &offset)) { + break; + } + CUs.push_back(CU.take()); + offset = CUs.back()->getNextUnitOffset(); + } +} + +void DWARFContext::parseTypeUnits() { + const std::map<object::SectionRef, Section> &Sections = getTypesSections(); + for (std::map<object::SectionRef, Section>::const_iterator + I = Sections.begin(), + E = Sections.end(); + I != E; ++I) { + uint32_t offset = 0; + const DataExtractor &DIData = + DataExtractor(I->second.Data, isLittleEndian(), 0); + while (DIData.isValidOffset(offset)) { + OwningPtr<DWARFTypeUnit> TU(new DWARFTypeUnit( + getDebugAbbrev(), I->second.Data, getAbbrevSection(), + getRangeSection(), getStringSection(), StringRef(), getAddrSection(), + &I->second.Relocs, isLittleEndian())); + if (!TU->extract(DIData, &offset)) + break; + TUs.push_back(TU.take()); + offset = TUs.back()->getNextUnitOffset(); + } + } +} + +void DWARFContext::parseDWOCompileUnits() { + uint32_t offset = 0; + const DataExtractor &DIData = + DataExtractor(getInfoDWOSection().Data, isLittleEndian(), 0); + while (DIData.isValidOffset(offset)) { + OwningPtr<DWARFCompileUnit> DWOCU(new DWARFCompileUnit( + getDebugAbbrevDWO(), getInfoDWOSection().Data, getAbbrevDWOSection(), + getRangeDWOSection(), getStringDWOSection(), + getStringOffsetDWOSection(), getAddrSection(), + &getInfoDWOSection().Relocs, isLittleEndian())); + if (!DWOCU->extract(DIData, &offset)) { + break; + } + DWOCUs.push_back(DWOCU.take()); + offset = DWOCUs.back()->getNextUnitOffset(); + } +} + +namespace { + struct OffsetComparator { + bool operator()(const DWARFCompileUnit *LHS, + const DWARFCompileUnit *RHS) const { + return LHS->getOffset() < RHS->getOffset(); + } + bool operator()(const DWARFCompileUnit *LHS, uint32_t RHS) const { + return LHS->getOffset() < RHS; + } + bool operator()(uint32_t LHS, const DWARFCompileUnit *RHS) const { + return LHS < RHS->getOffset(); + } + }; +} + +DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t Offset) { + if (CUs.empty()) + parseCompileUnits(); + + DWARFCompileUnit **CU = + std::lower_bound(CUs.begin(), CUs.end(), Offset, OffsetComparator()); + if (CU != CUs.end()) { + return *CU; + } + return 0; +} + +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 getFileNameForCompileUnit(DWARFCompileUnit *CU, + const DWARFLineTable *LineTable, + uint64_t FileIndex, + bool NeedsAbsoluteFilePath, + std::string &FileName) { + if (CU == 0 || + LineTable == 0 || + !LineTable->getFileNameByIndex(FileIndex, NeedsAbsoluteFilePath, + FileName)) + return false; + if (NeedsAbsoluteFilePath && sys::path::is_relative(FileName)) { + // We may still need to append compilation directory of compile unit. + SmallString<16> AbsolutePath; + if (const char *CompilationDir = CU->getCompilationDir()) { + sys::path::append(AbsolutePath, CompilationDir); + } + sys::path::append(AbsolutePath, FileName); + FileName = AbsolutePath.str(); + } + return true; +} + +static bool getFileLineInfoForCompileUnit(DWARFCompileUnit *CU, + const DWARFLineTable *LineTable, + uint64_t Address, + bool NeedsAbsoluteFilePath, + std::string &FileName, + uint32_t &Line, uint32_t &Column) { + if (CU == 0 || LineTable == 0) + return false; + // Get the index of row we're looking for in the line table. + uint32_t RowIndex = LineTable->lookupAddress(Address); + if (RowIndex == -1U) + return false; + // Take file number and line/column from the row. + const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; + if (!getFileNameForCompileUnit(CU, LineTable, Row.File, + NeedsAbsoluteFilePath, FileName)) + return false; + Line = Row.Line; + Column = Row.Column; + return true; +} + +DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, + DILineInfoSpecifier Specifier) { + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return DILineInfo(); + std::string FileName = "<invalid>"; + std::string FunctionName = "<invalid>"; + uint32_t Line = 0; + uint32_t Column = 0; + if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { + // 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) { + const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.U)) + FunctionName = Name; + } + } + if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { + const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); + const bool NeedsAbsoluteFilePath = + Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); + getFileLineInfoForCompileUnit(CU, LineTable, Address, + NeedsAbsoluteFilePath, + FileName, Line, Column); + } + return DILineInfo(StringRef(FileName), StringRef(FunctionName), + Line, Column); +} + +DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, + uint64_t Size, + DILineInfoSpecifier Specifier) { + DILineInfoTable Lines; + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Lines; + + std::string FunctionName = "<invalid>"; + if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { + // 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) { + const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; + if (const char *Name = TopFunctionDIE.getSubroutineName(InlinedChain.U)) + FunctionName = Name; + } + } + + // If the Specifier says we don't need FileLineInfo, just + // return the top-most function at the starting address. + if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { + Lines.push_back( + std::make_pair(Address, DILineInfo("<invalid>", FunctionName, 0, 0))); + return Lines; + } + + const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); + const bool NeedsAbsoluteFilePath = + Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); + + // 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; + + uint32_t NumRows = RowVector.size(); + for (uint32_t i = 0; i < NumRows; ++i) { + uint32_t RowIndex = RowVector[i]; + // Take file number and line/column from the row. + const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; + std::string FileName = "<invalid>"; + getFileNameForCompileUnit(CU, LineTable, Row.File, + NeedsAbsoluteFilePath, FileName); + Lines.push_back(std::make_pair( + Row.Address, DILineInfo(FileName, FunctionName, Row.Line, Row.Column))); + } + + return Lines; +} + +DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, + DILineInfoSpecifier Specifier) { + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return DIInliningInfo(); + + const DWARFDebugInfoEntryInlinedChain &InlinedChain = + CU->getInlinedChainForAddress(Address); + if (InlinedChain.DIEs.size() == 0) + return DIInliningInfo(); + + DIInliningInfo InliningInfo; + uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; + const DWARFLineTable *LineTable = 0; + for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { + const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; + std::string FileName = "<invalid>"; + std::string FunctionName = "<invalid>"; + uint32_t Line = 0; + uint32_t Column = 0; + // Get function name if necessary. + if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { + if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) + FunctionName = Name; + } + if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { + const bool NeedsAbsoluteFilePath = + Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); + if (i == 0) { + // For the topmost frame, initialize the line table of this + // compile unit and fetch file/line info from it. + LineTable = getLineTableForCompileUnit(CU); + // For the topmost routine, get file/line info from line table. + getFileLineInfoForCompileUnit(CU, LineTable, Address, + NeedsAbsoluteFilePath, + FileName, Line, Column); + } else { + // Otherwise, use call file, call line and call column from + // previous DIE in inlined chain. + getFileNameForCompileUnit(CU, LineTable, CallFile, + NeedsAbsoluteFilePath, FileName); + Line = CallLine; + Column = CallColumn; + } + // Get call file/line/column of a current DIE. + if (i + 1 < n) { + FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, + CallColumn); + } + } + DILineInfo Frame(StringRef(FileName), StringRef(FunctionName), + Line, Column); + 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(object::ObjectFile *Obj) : + IsLittleEndian(Obj->isLittleEndian()), + AddressSize(Obj->getBytesInAddress()) { + error_code ec; + for (object::section_iterator i = Obj->begin_sections(), + e = Obj->end_sections(); + i != e; i.increment(ec)) { + StringRef name; + i->getName(name); + StringRef data; + i->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; + OwningPtr<MemoryBuffer> UncompressedSection; + if (zlib::uncompress(data, UncompressedSection, OriginalSize) != + zlib::StatusOK) + continue; + // Make data point to uncompressed section contents and save its contents. + name = name.substr(1); + data = UncompressedSection->getBuffer(); + UncompressedSections.push_back(UncompressedSection.take()); + } + + StringRef *Section = + 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_str.dwo", &StringDWOSection) + .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) + .Case("debug_addr", &AddrSection) + // Any more debug info sections go here. + .Default(0); + if (Section) { + *Section = 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[*i].Data = data; + } + + section_iterator RelocatedSection = i->getRelocatedSection(); + if (RelocatedSection == Obj->end_sections()) + continue; + + StringRef RelSecName; + RelocatedSection->getName(RelSecName); + 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) + .Default(0); + if (!Map) { + if (RelSecName != "debug_types") + continue; + // Find debug_types relocs by section rather than name as there are + // multiple, comdat grouped, debug_types sections. + Map = &TypesSections[*RelocatedSection].Relocs; + } + + if (i->begin_relocations() != i->end_relocations()) { + uint64_t SectionSize; + RelocatedSection->getSize(SectionSize); + for (object::relocation_iterator reloc_i = i->begin_relocations(), + reloc_e = i->end_relocations(); + reloc_i != reloc_e; reloc_i.increment(ec)) { + uint64_t Address; + reloc_i->getOffset(Address); + uint64_t Type; + reloc_i->getType(Type); + uint64_t SymAddr = 0; + // ELF relocations may need the symbol address + if (Obj->isELF()) { + object::symbol_iterator Sym = reloc_i->getSymbol(); + Sym->getAddress(SymAddr); + } + + object::RelocVisitor V(Obj->getFileFormatName()); + // The section address is always 0 for debug sections. + object::RelocToApply R(V.visit(Type, *reloc_i, 0, SymAddr)); + if (V.error()) { + SmallString<32> Name; + error_code ec(reloc_i->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))); + } + } + } +} + +DWARFContextInMemory::~DWARFContextInMemory() { + DeleteContainerPointers(UncompressedSections); +} + +void DWARFContextInMemory::anchor() { } diff --git a/contrib/llvm/lib/DebugInfo/DWARFContext.h b/contrib/llvm/lib/DebugInfo/DWARFContext.h new file mode 100644 index 000000000000..03863ab8b1e2 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFContext.h @@ -0,0 +1,241 @@ +//===-- DWARFContext.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_DEBUGINFO_DWARFCONTEXT_H +#define LLVM_DEBUGINFO_DWARFCONTEXT_H + +#include "DWARFCompileUnit.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugFrame.h" +#include "DWARFDebugLine.h" +#include "DWARFDebugLoc.h" +#include "DWARFDebugRangeList.h" +#include "DWARFTypeUnit.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/DIContext.h" + +namespace llvm { + +/// DWARFContext +/// This data structure is the top level entity that deals with dwarf debug +/// information parsing. The actual data is supplied through pure virtual +/// methods that a concrete implementation provides. +class DWARFContext : public DIContext { + SmallVector<DWARFCompileUnit *, 1> CUs; + SmallVector<DWARFTypeUnit *, 1> TUs; + OwningPtr<DWARFDebugAbbrev> Abbrev; + OwningPtr<DWARFDebugLoc> Loc; + OwningPtr<DWARFDebugAranges> Aranges; + OwningPtr<DWARFDebugLine> Line; + OwningPtr<DWARFDebugFrame> DebugFrame; + + SmallVector<DWARFCompileUnit *, 1> DWOCUs; + OwningPtr<DWARFDebugAbbrev> AbbrevDWO; + + DWARFContext(DWARFContext &) LLVM_DELETED_FUNCTION; + DWARFContext &operator=(DWARFContext &) LLVM_DELETED_FUNCTION; + + /// Read compile units from the debug_info section and store them in CUs. + void parseCompileUnits(); + + /// Read type units from the debug_types sections and store them in CUs. + void parseTypeUnits(); + + /// Read compile units from the debug_info.dwo section and store them in + /// DWOCUs. + void parseDWOCompileUnits(); + +public: + struct Section { + StringRef Data; + RelocAddrMap Relocs; + }; + + DWARFContext() : DIContext(CK_DWARF) {} + virtual ~DWARFContext(); + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == CK_DWARF; + } + + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All); + + /// Get the number of compile units in this context. + unsigned getNumCompileUnits() { + if (CUs.empty()) + parseCompileUnits(); + return CUs.size(); + } + + /// Get the number of compile units in this context. + unsigned getNumTypeUnits() { + if (TUs.empty()) + parseTypeUnits(); + return TUs.size(); + } + + /// Get the number of compile units in the DWO context. + unsigned getNumDWOCompileUnits() { + if (DWOCUs.empty()) + parseDWOCompileUnits(); + return DWOCUs.size(); + } + + /// Get the compile unit at the specified index for this compile unit. + DWARFCompileUnit *getCompileUnitAtIndex(unsigned index) { + if (CUs.empty()) + parseCompileUnits(); + return CUs[index]; + } + + /// Get the type unit at the specified index for this compile unit. + DWARFTypeUnit *getTypeUnitAtIndex(unsigned index) { + if (TUs.empty()) + parseTypeUnits(); + return TUs[index]; + } + + /// Get the compile unit at the specified index for the DWO compile units. + DWARFCompileUnit *getDWOCompileUnitAtIndex(unsigned index) { + if (DWOCUs.empty()) + parseDWOCompileUnits(); + return DWOCUs[index]; + } + + /// Get a pointer to the parsed DebugAbbrev object. + const DWARFDebugAbbrev *getDebugAbbrev(); + + /// Get a pointer to the parsed DebugLoc object. + const DWARFDebugLoc *getDebugLoc(); + + /// Get a pointer to the parsed dwo abbreviations object. + const DWARFDebugAbbrev *getDebugAbbrevDWO(); + + /// Get a pointer to the parsed DebugAranges object. + const DWARFDebugAranges *getDebugAranges(); + + /// Get a pointer to the parsed frame information object. + const DWARFDebugFrame *getDebugFrame(); + + /// Get a pointer to a parsed line table corresponding to a compile unit. + const DWARFDebugLine::LineTable * + getLineTableForCompileUnit(DWARFCompileUnit *cu); + + virtual DILineInfo getLineInfoForAddress(uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()); + virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, + uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier()); + virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()); + + virtual bool isLittleEndian() const = 0; + virtual uint8_t getAddressSize() const = 0; + virtual const Section &getInfoSection() = 0; + virtual const std::map<object::SectionRef, Section> &getTypesSections() = 0; + virtual StringRef getAbbrevSection() = 0; + virtual const Section &getLocSection() = 0; + virtual StringRef getARangeSection() = 0; + virtual StringRef getDebugFrameSection() = 0; + virtual const Section &getLineSection() = 0; + virtual StringRef getStringSection() = 0; + virtual StringRef getRangeSection() = 0; + virtual StringRef getPubNamesSection() = 0; + virtual StringRef getPubTypesSection() = 0; + virtual StringRef getGnuPubNamesSection() = 0; + virtual StringRef getGnuPubTypesSection() = 0; + + // Sections for DWARF5 split dwarf proposal. + virtual const Section &getInfoDWOSection() = 0; + virtual StringRef getAbbrevDWOSection() = 0; + virtual StringRef getStringDWOSection() = 0; + virtual StringRef getStringOffsetDWOSection() = 0; + virtual StringRef getRangeDWOSection() = 0; + virtual StringRef getAddrSection() = 0; + + static bool isSupportedVersion(unsigned version) { + return version == 2 || version == 3 || version == 4; + } +private: + /// Return the compile unit that includes an offset (relative to .debug_info). + DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); + + /// Return the compile unit which contains instruction with provided + /// address. + DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); +}; + +/// DWARFContextInMemory is the simplest possible implementation of a +/// DWARFContext. It assumes all content is available in memory and stores +/// pointers to it. +class DWARFContextInMemory : public DWARFContext { + virtual void anchor(); + bool IsLittleEndian; + uint8_t AddressSize; + Section InfoSection; + std::map<object::SectionRef, Section> TypesSections; + StringRef AbbrevSection; + Section LocSection; + StringRef ARangeSection; + StringRef DebugFrameSection; + Section LineSection; + StringRef StringSection; + StringRef RangeSection; + StringRef PubNamesSection; + StringRef PubTypesSection; + StringRef GnuPubNamesSection; + StringRef GnuPubTypesSection; + + // Sections for DWARF5 split dwarf proposal. + Section InfoDWOSection; + StringRef AbbrevDWOSection; + StringRef StringDWOSection; + StringRef StringOffsetDWOSection; + StringRef RangeDWOSection; + StringRef AddrSection; + + SmallVector<MemoryBuffer*, 4> UncompressedSections; + +public: + DWARFContextInMemory(object::ObjectFile *); + ~DWARFContextInMemory(); + virtual bool isLittleEndian() const { return IsLittleEndian; } + virtual uint8_t getAddressSize() const { return AddressSize; } + virtual const Section &getInfoSection() { return InfoSection; } + virtual const std::map<object::SectionRef, Section> &getTypesSections() { + return TypesSections; + } + virtual StringRef getAbbrevSection() { return AbbrevSection; } + virtual const Section &getLocSection() { return LocSection; } + virtual StringRef getARangeSection() { return ARangeSection; } + virtual StringRef getDebugFrameSection() { return DebugFrameSection; } + virtual const Section &getLineSection() { return LineSection; } + virtual StringRef getStringSection() { return StringSection; } + virtual StringRef getRangeSection() { return RangeSection; } + virtual StringRef getPubNamesSection() { return PubNamesSection; } + virtual StringRef getPubTypesSection() { return PubTypesSection; } + virtual StringRef getGnuPubNamesSection() { return GnuPubNamesSection; } + virtual StringRef getGnuPubTypesSection() { return GnuPubTypesSection; } + + // Sections for DWARF5 split dwarf proposal. + virtual const Section &getInfoDWOSection() { return InfoDWOSection; } + virtual StringRef getAbbrevDWOSection() { return AbbrevDWOSection; } + virtual StringRef getStringDWOSection() { return StringDWOSection; } + virtual StringRef getStringOffsetDWOSection() { + return StringOffsetDWOSection; + } + virtual StringRef getRangeDWOSection() { return RangeDWOSection; } + virtual StringRef getAddrSection() { + return AddrSection; + } +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.cpp new file mode 100644 index 000000000000..6e6c37e30945 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.cpp @@ -0,0 +1,106 @@ +//===-- DWARFDebugAbbrev.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugAbbrev.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +bool DWARFAbbreviationDeclarationSet::extract(DataExtractor data, + uint32_t* offset_ptr) { + const uint32_t beginOffset = *offset_ptr; + Offset = beginOffset; + clear(); + DWARFAbbreviationDeclaration abbrevDeclaration; + uint32_t prevAbbrAode = 0; + while (abbrevDeclaration.extract(data, offset_ptr)) { + Decls.push_back(abbrevDeclaration); + if (IdxOffset == 0) { + IdxOffset = abbrevDeclaration.getCode(); + } else { + if (prevAbbrAode + 1 != abbrevDeclaration.getCode()) + IdxOffset = UINT32_MAX;// Out of order indexes, we can't do O(1) lookups + } + prevAbbrAode = abbrevDeclaration.getCode(); + } + return beginOffset != *offset_ptr; +} + +void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { + for (unsigned i = 0, e = Decls.size(); i != e; ++i) + Decls[i].dump(OS); +} + +const DWARFAbbreviationDeclaration* +DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(uint32_t abbrCode) + const { + if (IdxOffset == UINT32_MAX) { + DWARFAbbreviationDeclarationCollConstIter pos; + DWARFAbbreviationDeclarationCollConstIter end = Decls.end(); + for (pos = Decls.begin(); pos != end; ++pos) { + if (pos->getCode() == abbrCode) + return &(*pos); + } + } else { + uint32_t idx = abbrCode - IdxOffset; + if (idx < Decls.size()) + return &Decls[idx]; + } + return NULL; +} + +DWARFDebugAbbrev::DWARFDebugAbbrev() : + AbbrevCollMap(), + PrevAbbrOffsetPos(AbbrevCollMap.end()) {} + + +void DWARFDebugAbbrev::parse(DataExtractor data) { + uint32_t offset = 0; + + while (data.isValidOffset(offset)) { + uint32_t initial_cu_offset = offset; + DWARFAbbreviationDeclarationSet abbrevDeclSet; + + if (abbrevDeclSet.extract(data, &offset)) + AbbrevCollMap[initial_cu_offset] = abbrevDeclSet; + else + break; + } + PrevAbbrOffsetPos = AbbrevCollMap.end(); +} + +void DWARFDebugAbbrev::dump(raw_ostream &OS) const { + if (AbbrevCollMap.empty()) { + OS << "< EMPTY >\n"; + return; + } + + DWARFAbbreviationDeclarationCollMapConstIter pos; + for (pos = AbbrevCollMap.begin(); pos != AbbrevCollMap.end(); ++pos) { + OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", pos->first); + pos->second.dump(OS); + } +} + +const DWARFAbbreviationDeclarationSet* +DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t cu_abbr_offset) const { + DWARFAbbreviationDeclarationCollMapConstIter end = AbbrevCollMap.end(); + DWARFAbbreviationDeclarationCollMapConstIter pos; + if (PrevAbbrOffsetPos != end && + PrevAbbrOffsetPos->first == cu_abbr_offset) { + return &(PrevAbbrOffsetPos->second); + } else { + pos = AbbrevCollMap.find(cu_abbr_offset); + PrevAbbrOffsetPos = pos; + } + + if (pos != AbbrevCollMap.end()) + return &(pos->second); + return NULL; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.h b/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.h new file mode 100644 index 000000000000..c7c0436866c4 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugAbbrev.h @@ -0,0 +1,73 @@ +//===-- DWARFDebugAbbrev.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_DEBUGINFO_DWARFDEBUGABBREV_H +#define LLVM_DEBUGINFO_DWARFDEBUGABBREV_H + +#include "DWARFAbbreviationDeclaration.h" +#include <list> +#include <map> +#include <vector> + +namespace llvm { + +typedef std::vector<DWARFAbbreviationDeclaration> + DWARFAbbreviationDeclarationColl; +typedef DWARFAbbreviationDeclarationColl::iterator + DWARFAbbreviationDeclarationCollIter; +typedef DWARFAbbreviationDeclarationColl::const_iterator + DWARFAbbreviationDeclarationCollConstIter; + +class DWARFAbbreviationDeclarationSet { + uint32_t Offset; + uint32_t IdxOffset; + std::vector<DWARFAbbreviationDeclaration> Decls; + public: + DWARFAbbreviationDeclarationSet() + : Offset(0), IdxOffset(0) {} + + DWARFAbbreviationDeclarationSet(uint32_t offset, uint32_t idxOffset) + : Offset(offset), IdxOffset(idxOffset) {} + + void clear() { + IdxOffset = 0; + Decls.clear(); + } + uint32_t getOffset() const { return Offset; } + void dump(raw_ostream &OS) const; + bool extract(DataExtractor data, uint32_t* offset_ptr); + + const DWARFAbbreviationDeclaration * + getAbbreviationDeclaration(uint32_t abbrCode) const; +}; + +class DWARFDebugAbbrev { +public: + typedef std::map<uint64_t, DWARFAbbreviationDeclarationSet> + DWARFAbbreviationDeclarationCollMap; + typedef DWARFAbbreviationDeclarationCollMap::iterator + DWARFAbbreviationDeclarationCollMapIter; + typedef DWARFAbbreviationDeclarationCollMap::const_iterator + DWARFAbbreviationDeclarationCollMapConstIter; + +private: + DWARFAbbreviationDeclarationCollMap AbbrevCollMap; + mutable DWARFAbbreviationDeclarationCollMapConstIter PrevAbbrOffsetPos; + +public: + DWARFDebugAbbrev(); + const DWARFAbbreviationDeclarationSet * + getAbbreviationDeclarationSet(uint64_t cu_abbr_offset) const; + void dump(raw_ostream &OS) const; + void parse(DataExtractor data); +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.cpp new file mode 100644 index 000000000000..229376e4a1c7 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.cpp @@ -0,0 +1,102 @@ +//===-- DWARFDebugArangeSet.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "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; + + assert(sizeof(arangeDescriptor.Address) == sizeof(arangeDescriptor.Length)); + 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 (DescriptorConstIter pos = ArangeDescriptors.begin(), + end = ArangeDescriptors.end(); pos != end; ++pos) + OS << format("[0x%*.*" PRIx64 " -", hex_width, hex_width, pos->Address) + << format(" 0x%*.*" PRIx64 ")\n", + hex_width, hex_width, pos->getEndAddress()); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.h b/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.h new file mode 100644 index 000000000000..49a713201d1f --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugArangeSet.h @@ -0,0 +1,70 @@ +//===-- DWARFDebugArangeSet.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_DEBUGINFO_DWARFDEBUGARANGESET_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H + +#include "llvm/Support/DataExtractor.h" +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugArangeSet { +public: + struct Header { + // The total length of the entries for that set, not including the length + // field itself. + uint32_t Length; + // The offset from the beginning of the .debug_info section of the + // compilation unit entry referenced by the table. + uint32_t CuOffset; + // The DWARF version number. + uint16_t Version; + // The size in bytes of an address on the target architecture. For segmented + // addressing, this is the size of the offset portion of the address. + uint8_t AddrSize; + // The size in bytes of a segment descriptor on the target architecture. + // If the target system uses a flat address space, this value is 0. + uint8_t SegSize; + }; + + struct Descriptor { + uint64_t Address; + uint64_t Length; + uint64_t getEndAddress() const { return Address + Length; } + }; + +private: + typedef std::vector<Descriptor> DescriptorColl; + typedef DescriptorColl::const_iterator DescriptorConstIter; + + uint32_t Offset; + Header HeaderData; + DescriptorColl ArangeDescriptors; + +public: + DWARFDebugArangeSet() { clear(); } + void clear(); + bool extract(DataExtractor data, uint32_t *offset_ptr); + void dump(raw_ostream &OS) const; + + uint32_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; } + uint32_t getNumDescriptors() const { return ArangeDescriptors.size(); } + const Descriptor *getDescriptor(uint32_t i) const { + if (i < ArangeDescriptors.size()) + return &ArangeDescriptors[i]; + return NULL; + } +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp new file mode 100644 index 000000000000..591d4bde7124 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp @@ -0,0 +1,152 @@ +//===-- 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 "DWARFDebugAranges.h" +#include "DWARFCompileUnit.h" +#include "DWARFContext.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +using namespace llvm; + +void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { + if (!DebugArangesData.isValidOffset(0)) + return; + uint32_t Offset = 0; + typedef std::vector<DWARFDebugArangeSet> RangeSetColl; + RangeSetColl Sets; + DWARFDebugArangeSet Set; + uint32_t TotalRanges = 0; + + while (Set.extract(DebugArangesData, &Offset)) { + Sets.push_back(Set); + TotalRanges += Set.getNumDescriptors(); + } + if (TotalRanges == 0) + return; + + Aranges.reserve(TotalRanges); + for (RangeSetColl::const_iterator I = Sets.begin(), E = Sets.end(); I != E; + ++I) { + uint32_t CUOffset = I->getCompileUnitDIEOffset(); + + for (uint32_t i = 0, n = I->getNumDescriptors(); i < n; ++i) { + const DWARFDebugArangeSet::Descriptor *ArangeDescPtr = + I->getDescriptor(i); + uint64_t LowPC = ArangeDescPtr->Address; + uint64_t HighPC = LowPC + ArangeDescPtr->Length; + appendRange(CUOffset, LowPC, HighPC); + } + } +} + +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 (uint32_t i = 0, n = CTX->getNumCompileUnits(); i < n; ++i) { + if (DWARFCompileUnit *CU = CTX->getCompileUnitAtIndex(i)) { + uint32_t CUOffset = CU->getOffset(); + if (ParsedCUOffsets.insert(CUOffset).second) + CU->buildAddressRangeTable(this, true, CUOffset); + } + } + + sortAndMinimize(); +} + +void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC, + uint64_t HighPC) { + if (!Aranges.empty()) { + if (Aranges.back().CUOffset == CUOffset && + Aranges.back().HighPC() == LowPC) { + Aranges.back().setHighPC(HighPC); + return; + } + } + Aranges.push_back(Range(LowPC, HighPC, CUOffset)); +} + +void DWARFDebugAranges::sortAndMinimize() { + const size_t orig_arange_size = Aranges.size(); + // Size of one? If so, no sorting is needed + if (orig_arange_size <= 1) + return; + // Sort our address range entries + std::stable_sort(Aranges.begin(), Aranges.end()); + + // Most address ranges are contiguous from function to function + // so our new ranges will likely be smaller. We calculate the size + // of the new ranges since although std::vector objects can be resized, + // the will never reduce their allocated block size and free any excesss + // memory, so we might as well start a brand new collection so it is as + // small as possible. + + // First calculate the size of the new minimal arange vector + // so we don't have to do a bunch of re-allocations as we + // copy the new minimal stuff over to the new collection. + size_t minimal_size = 1; + for (size_t i = 1; i < orig_arange_size; ++i) { + if (!Range::SortedOverlapCheck(Aranges[i-1], Aranges[i])) + ++minimal_size; + } + + // If the sizes are the same, then no consecutive aranges can be + // combined, we are done. + if (minimal_size == orig_arange_size) + return; + + // Else, make a new RangeColl that _only_ contains what we need. + RangeColl minimal_aranges; + minimal_aranges.resize(minimal_size); + uint32_t j = 0; + minimal_aranges[j] = Aranges[0]; + for (size_t i = 1; i < orig_arange_size; ++i) { + if (Range::SortedOverlapCheck(minimal_aranges[j], Aranges[i])) { + minimal_aranges[j].setHighPC(Aranges[i].HighPC()); + } else { + // Only increment j if we aren't merging + minimal_aranges[++j] = Aranges[i]; + } + } + assert(j+1 == minimal_size); + + // Now swap our new minimal aranges into place. The local + // minimal_aranges will then contian the old big collection + // which will get freed. + minimal_aranges.swap(Aranges); +} + +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/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.h b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.h new file mode 100644 index 000000000000..35ad8e53d63d --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.h @@ -0,0 +1,84 @@ +//===-- DWARFDebugAranges.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_DEBUGINFO_DWARFDEBUGARANGES_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGES_H + +#include "DWARFDebugArangeSet.h" +#include "llvm/ADT/DenseSet.h" +#include <list> + +namespace llvm { + +class DWARFContext; + +class DWARFDebugAranges { +public: + void clear() { + Aranges.clear(); + ParsedCUOffsets.clear(); + } + + void generate(DWARFContext *CTX); + + // Use appendRange multiple times and then call sortAndMinimize. + void appendRange(uint32_t CUOffset, uint64_t LowPC, uint64_t HighPC); + + uint32_t findAddress(uint64_t Address) const; + +private: + void extract(DataExtractor DebugArangesData); + void sortAndMinimize(); + + struct Range { + explicit Range(uint64_t LowPC = -1ULL, uint64_t HighPC = -1ULL, + uint32_t CUOffset = -1U) + : LowPC(LowPC), Length(HighPC - LowPC), CUOffset(CUOffset) {} + + void setHighPC(uint64_t HighPC) { + if (HighPC == -1ULL || HighPC <= LowPC) + Length = 0; + else + Length = HighPC - LowPC; + } + uint64_t HighPC() const { + if (Length) + return LowPC + Length; + return -1ULL; + } + bool containsAddress(uint64_t Address) const { + return LowPC <= Address && Address < HighPC(); + } + + bool operator <(const Range &other) const { + return LowPC < other.LowPC; + } + + static bool SortedOverlapCheck(const Range &Left, const Range &Right) { + if (Left.CUOffset != Right.CUOffset) + return false; + return Left.HighPC() >= Right.LowPC; + } + + uint64_t LowPC; // Start of address range. + uint32_t Length; // End of address range (not including this address). + uint32_t CUOffset; // Offset of the compile unit or die. + }; + + typedef std::vector<Range> RangeColl; + typedef RangeColl::const_iterator RangeCollIterator; + typedef DenseSet<uint32_t> ParsedCUOffsetColl; + + RangeColl Aranges; + ParsedCUOffsetColl ParsedCUOffsets; +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.cpp new file mode 100644 index 000000000000..3efe6a1ebd30 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.cpp @@ -0,0 +1,391 @@ +//===-- 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 "DWARFDebugFrame.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Dwarf.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, DataExtractor D, uint64_t Offset, uint64_t Length) + : Kind(K), Data(D), 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 our data + /// stream, 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(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 The data stream holding the section from which the entry was + /// parsed. + DataExtractor Data; + + /// \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(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: + // 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!"); + } + } + } +} + + +void FrameEntry::dumpInstructions(raw_ostream &OS) const { + // TODO: at the moment only instruction names are dumped. Expand this to + // dump operands as well. + for (std::vector<Instruction>::const_iterator I = Instructions.begin(), + E = Instructions.end(); + I != E; ++I) { + uint8_t Opcode = I->Opcode; + if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) + Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; + OS << " " << CallFrameString(Opcode) << ":\n"; + } +} + + +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(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version, + SmallString<8> Augmentation, uint64_t CodeAlignmentFactor, + int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister) + : FrameEntry(FK_CIE, D, Offset, Length), Version(Version), + Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister) {} + + ~CIE() { + } + + void dumpHeader(raw_ostream &OS) const { + 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"; + 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 v3 + uint8_t Version; + SmallString<8> Augmentation; + 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(DataExtractor D, uint64_t Offset, uint64_t Length, + int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange) + : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset), + InitialLocation(InitialLocation), AddressRange(AddressRange), + LinkedCIE(NULL) {} + + ~FDE() { + } + + void dumpHeader(raw_ostream &OS) const { + 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); + if (LinkedCIE) { + OS << format("%p\n", LinkedCIE); + } + } + + 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; +}; +} // end anonymous namespace + + +DWARFDebugFrame::DWARFDebugFrame() { +} + + +DWARFDebugFrame::~DWARFDebugFrame() { + for (EntryVector::iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + delete *I; + } +} + + +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; + + 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); + + FrameEntry *Entry = 0; + if (IsCIE) { + // Note: this is specifically DWARFv3 CIE header structure. It was + // changed in DWARFv4. We currently don't support reading DWARFv4 + // here because LLVM itself does not emit it (and LLDB doesn't + // support it either). + uint8_t Version = Data.getU8(&Offset); + const char *Augmentation = Data.getCStr(&Offset); + uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); + int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); + uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); + + Entry = new CIE(Data, StartOffset, Length, Version, + StringRef(Augmentation), CodeAlignmentFactor, + DataAlignmentFactor, ReturnAddressRegister); + } else { + // FDE + uint64_t CIEPointer = Id; + uint64_t InitialLocation = Data.getAddress(&Offset); + uint64_t AddressRange = Data.getAddress(&Offset); + + Entry = new FDE(Data, StartOffset, Length, CIEPointer, + InitialLocation, AddressRange); + } + + assert(Entry && "Expected Entry to be populated with CIE or FDE"); + Entry->parseInstructions(&Offset, EndStructureOffset); + + if (Offset == EndStructureOffset) { + // Entry instrucitons parsed successfully. + Entries.push_back(Entry); + } else { + std::string Str; + raw_string_ostream OS(Str); + OS << format("Parsing entry instructions at %lx failed", + Entry->getOffset()); + report_fatal_error(Str); + } + } +} + + +void DWARFDebugFrame::dump(raw_ostream &OS) const { + OS << "\n"; + for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + FrameEntry *Entry = *I; + Entry->dumpHeader(OS); + Entry->dumpInstructions(OS); + OS << "\n"; + } +} + diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.h b/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.h new file mode 100644 index 000000000000..48b8d63a5a64 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugFrame.h @@ -0,0 +1,46 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGFRAME_H +#define LLVM_DEBUGINFO_DWARFDEBUGFRAME_H + +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + + +namespace llvm { + +class FrameEntry; + + +/// \brief A parsed .debug_frame section +/// +class DWARFDebugFrame { +public: + DWARFDebugFrame(); + ~DWARFDebugFrame(); + + /// \brief Dump the section data into the given stream. + void dump(raw_ostream &OS) const; + + /// \brief Parse the section from raw data. + /// data is assumed to be pointing to the beginning of the section. + void parse(DataExtractor Data); + +private: + typedef std::vector<FrameEntry *> EntryVector; + EntryVector Entries; +}; + + +} // namespace llvm + +#endif + diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp new file mode 100644 index 000000000000..babfd2ece067 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -0,0 +1,340 @@ +//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugInfoEntry.h" +#include "DWARFCompileUnit.h" +#include "DWARFContext.h" +#include "DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARFFormValue.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; + +void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, const 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); + + OS << format("\n0x%8.8x: ", Offset); + if (abbrCode) { + if (AbbrevDecl) { + const char *tagString = TagString(getTag()); + if (tagString) + OS.indent(indent) << tagString; + else + OS.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. + const uint32_t numAttributes = AbbrevDecl->getNumAttributes(); + for (uint32_t i = 0; i != numAttributes; ++i) { + uint16_t attr = AbbrevDecl->getAttrByIndex(i); + uint16_t form = AbbrevDecl->getFormByIndex(i); + dumpAttribute(OS, u, &offset, attr, 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"; + } + } +} + +void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, + const DWARFUnit *u, + uint32_t *offset_ptr, + uint16_t attr, uint16_t form, + unsigned indent) const { + OS << " "; + OS.indent(indent+2); + const char *attrString = AttributeString(attr); + if (attrString) + OS << attrString; + else + OS << 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("; + formValue.dump(OS, u); + 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 = NULL; + return true; + } + AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); + if (0 == 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 (uint32_t i = 0, n = AbbrevDecl->getNumAttributes(); i < n; ++i) { + uint16_t Form = AbbrevDecl->getFormByIndex(i); + + 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; +} + +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); +} + +void DWARFDebugInfoEntryMinimal::buildAddressRangeTable( + const DWARFUnit *U, DWARFDebugAranges *DebugAranges, + uint32_t UOffsetInAranges) const { + if (AbbrevDecl) { + if (isSubprogramDIE()) { + uint64_t LowPC, HighPC; + if (getLowAndHighPC(U, LowPC, HighPC)) + DebugAranges->appendRange(UOffsetInAranges, LowPC, HighPC); + // FIXME: try to append ranges from .debug_ranges section. + } + + const DWARFDebugInfoEntryMinimal *Child = getFirstChild(); + while (Child) { + Child->buildAddressRangeTable(U, DebugAranges, UOffsetInAranges); + Child = Child->getSibling(); + } + } +} + +bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress( + const DWARFUnit *U, const uint64_t Address) const { + if (isNULL()) + return false; + uint64_t LowPC, HighPC; + if (getLowAndHighPC(U, LowPC, HighPC)) + return (LowPC <= Address && Address <= HighPC); + // Try to get address 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.containsAddress(U->getBaseAddress(), Address); + } + return false; +} + +const char * +DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFUnit *U) const { + if (!isSubroutineDIE()) + return 0; + // Try to get mangled name if possible. + if (const char *name = + getAttributeValueAsString(U, DW_AT_MIPS_linkage_name, 0)) + return name; + if (const char *name = getAttributeValueAsString(U, DW_AT_linkage_name, 0)) + return name; + if (const char *name = getAttributeValueAsString(U, DW_AT_name, 0)) + 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 (spec_die.extractFast(U, &spec_ref)) { + if (const char *name = spec_die.getSubroutineName(U)) + 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 (abs_origin_die.extractFast(U, &abs_origin_ref)) { + if (const char *name = abs_origin_die.getSubroutineName(U)) + return name; + } + } + return 0; +} + +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/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.h b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.h new file mode 100644 index 000000000000..aa61056332ef --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugInfoEntry.h @@ -0,0 +1,179 @@ +//===-- DWARFDebugInfoEntry.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_DEBUGINFO_DWARFDEBUGINFOENTRY_H +#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H + +#include "DWARFAbbreviationDeclaration.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +class DWARFDebugAranges; +class DWARFCompileUnit; +class DWARFUnit; +class DWARFContext; +class DWARFFormValue; +struct DWARFDebugInfoEntryInlinedChain; + +/// DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data. +class DWARFDebugInfoEntryMinimal { + /// Offset within the .debug_info of the start of this entry. + uint32_t Offset; + + /// How many to subtract from "this" to get the parent. + /// If zero this die has no parent. + uint32_t ParentIdx; + + /// How many to add to "this" to get the sibling. + uint32_t SiblingIdx; + + const DWARFAbbreviationDeclaration *AbbrevDecl; +public: + DWARFDebugInfoEntryMinimal() + : Offset(0), ParentIdx(0), SiblingIdx(0), AbbrevDecl(0) {} + + void dump(raw_ostream &OS, const DWARFUnit *u, unsigned recurseDepth, + unsigned indent = 0) const; + void dumpAttribute(raw_ostream &OS, const DWARFUnit *u, uint32_t *offset_ptr, + uint16_t attr, uint16_t form, unsigned indent = 0) const; + + /// Extracts a debug info entry, which is a child of a given unit, + /// starting at a given offset. If DIE can't be extracted, returns false and + /// doesn't change OffsetPtr. + bool extractFast(const DWARFUnit *U, uint32_t *OffsetPtr); + + uint32_t getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : 0; } + bool isNULL() const { return AbbrevDecl == 0; } + + /// Returns true if DIE represents a subprogram (not inlined). + bool isSubprogramDIE() const; + /// Returns true if DIE represents a subprogram or an inlined + /// subroutine. + bool isSubroutineDIE() const; + + uint32_t getOffset() const { return Offset; } + uint32_t getNumAttributes() const { + return !isNULL() ? AbbrevDecl->getNumAttributes() : 0; + } + bool hasChildren() const { return !isNULL() && AbbrevDecl->hasChildren(); } + + // We know we are kept in a vector of contiguous entries, so we know + // our parent will be some index behind "this". + DWARFDebugInfoEntryMinimal *getParent() { + return ParentIdx > 0 ? this - ParentIdx : 0; + } + const DWARFDebugInfoEntryMinimal *getParent() const { + return ParentIdx > 0 ? this - ParentIdx : 0; + } + // We know we are kept in a vector of contiguous entries, so we know + // our sibling will be some index after "this". + DWARFDebugInfoEntryMinimal *getSibling() { + return SiblingIdx > 0 ? this + SiblingIdx : 0; + } + const DWARFDebugInfoEntryMinimal *getSibling() const { + return SiblingIdx > 0 ? this + SiblingIdx : 0; + } + // We know we are kept in a vector of contiguous entries, so we know + // we don't need to store our child pointer, if we have a child it will + // be the next entry in the list... + DWARFDebugInfoEntryMinimal *getFirstChild() { + return hasChildren() ? this + 1 : 0; + } + const DWARFDebugInfoEntryMinimal *getFirstChild() const { + return hasChildren() ? this + 1 : 0; + } + + void setParent(DWARFDebugInfoEntryMinimal *parent) { + if (parent) { + // We know we are kept in a vector of contiguous entries, so we know + // our parent will be some index behind "this". + ParentIdx = this - parent; + } else + ParentIdx = 0; + } + void setSibling(DWARFDebugInfoEntryMinimal *sibling) { + if (sibling) { + // We know we are kept in a vector of contiguous entries, so we know + // our sibling will be some index after "this". + SiblingIdx = sibling - this; + sibling->setParent(getParent()); + } else + SiblingIdx = 0; + } + + const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const { + return AbbrevDecl; + } + + bool getAttributeValue(const DWARFUnit *U, const uint16_t Attr, + DWARFFormValue &FormValue) const; + + const char *getAttributeValueAsString(const DWARFUnit *U, const uint16_t Attr, + const char *FailValue) const; + + uint64_t getAttributeValueAsAddress(const DWARFUnit *U, const uint16_t Attr, + uint64_t FailValue) const; + + uint64_t getAttributeValueAsUnsignedConstant(const DWARFUnit *U, + const uint16_t Attr, + uint64_t FailValue) const; + + uint64_t getAttributeValueAsReference(const DWARFUnit *U, const uint16_t Attr, + uint64_t FailValue) const; + + uint64_t getAttributeValueAsSectionOffset(const DWARFUnit *U, + const uint16_t Attr, + uint64_t FailValue) const; + + /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU. + /// Returns true if both attributes are present. + bool getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC, + uint64_t &HighPC) const; + + void buildAddressRangeTable(const DWARFUnit *U, + DWARFDebugAranges *DebugAranges, + uint32_t CUOffsetInAranges) const; + + bool addressRangeContainsAddress(const DWARFUnit *U, + const uint64_t Address) const; + + /// If a DIE represents a subprogram (or inlined subroutine), + /// returns its mangled name (or short name, if mangled is missing). + /// This name may be fetched from specification or abstract origin + /// for this subprogram. Returns null if no name is found. + const char *getSubroutineName(const DWARFUnit *U) const; + + /// Retrieves values of DW_AT_call_file, DW_AT_call_line and + /// DW_AT_call_column from DIE (or zeroes if they are missing). + void getCallerFrame(const DWARFUnit *U, uint32_t &CallFile, + uint32_t &CallLine, uint32_t &CallColumn) const; + + /// Get inlined chain for a given address, rooted at the current DIE. + /// Returns empty chain if address is not contained in address range + /// of current DIE. + DWARFDebugInfoEntryInlinedChain + getInlinedChainForAddress(const DWARFUnit *U, const uint64_t Address) const; +}; + +/// DWARFDebugInfoEntryInlinedChain - represents a chain of inlined_subroutine +/// DIEs, (possibly ending with subprogram DIE), all of which are contained +/// in some concrete inlined instance tree. Address range for each DIE +/// (except the last DIE) in this chain is contained in address +/// range for next DIE in the chain. +struct DWARFDebugInfoEntryInlinedChain { + DWARFDebugInfoEntryInlinedChain() : U(0) {} + SmallVector<DWARFDebugInfoEntryMinimal, 4> DIEs; + const DWARFUnit *U; +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugLine.cpp new file mode 100644 index 000000000000..13d09dd298b9 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugLine.cpp @@ -0,0 +1,628 @@ +//===-- DWARFDebugLine.cpp ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "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; + +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("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'; + } + } +} + +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; + 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 ", File, Isa) + << (IsStmt ? " is_stmt" : "") + << (BasicBlock ? " basic_block" : "") + << (PrologueEnd ? " prologue_end" : "") + << (EpilogueBegin ? " epilogue_begin" : "") + << (EndSequence ? " end_sequence" : "") + << '\n'; +} + +void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const { + Prologue.dump(OS); + OS << '\n'; + + if (!Rows.empty()) { + OS << "Address Line Column File ISA Flags\n" + << "------------------ ------ ------ ------ --- -------------\n"; + for (std::vector<Row>::const_iterator pos = Rows.begin(), + end = Rows.end(); pos != end; ++pos) + pos->dump(OS); + } +} + +DWARFDebugLine::State::~State() {} + +void DWARFDebugLine::State::appendRowToMatrix(uint32_t offset) { + if (Sequence::Empty) { + // Record the beginning of instruction sequence. + Sequence::Empty = false; + Sequence::LowPC = Address; + Sequence::FirstRowIndex = row; + } + ++row; // Increase the row number. + LineTable::appendRow(*this); + if (EndSequence) { + // Record the end of instruction sequence. + Sequence::HighPC = Address; + Sequence::LastRowIndex = row; + if (Sequence::isValid()) + LineTable::appendSequence(*this); + Sequence::reset(); + } + Row::postAppend(); +} + +void DWARFDebugLine::State::finalize() { + row = DoneParsingLineTable; + if (!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). + } +} + +DWARFDebugLine::DumpingState::~DumpingState() {} + +void DWARFDebugLine::DumpingState::finalize() { + LineTable::dump(OS); +} + +const DWARFDebugLine::LineTable * +DWARFDebugLine::getLineTable(uint32_t offset) const { + LineTableConstIter pos = LineTableMap.find(offset); + if (pos != LineTableMap.end()) + return &pos->second; + return 0; +} + +const DWARFDebugLine::LineTable * +DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data, + uint32_t offset) { + std::pair<LineTableIter, bool> pos = + LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable())); + if (pos.second) { + // Parse and cache the line table for at this offset. + State state; + if (!parseStatementTable(debug_line_data, RelocMap, &offset, state)) + return 0; + pos.first->second = state; + } + return &pos.first->second; +} + +bool +DWARFDebugLine::parsePrologue(DataExtractor debug_line_data, + uint32_t *offset_ptr, Prologue *prologue) { + const uint32_t prologue_offset = *offset_ptr; + + prologue->clear(); + prologue->TotalLength = debug_line_data.getU32(offset_ptr); + prologue->Version = debug_line_data.getU16(offset_ptr); + if (prologue->Version != 2) + return false; + + prologue->PrologueLength = debug_line_data.getU32(offset_ptr); + const uint32_t end_prologue_offset = prologue->PrologueLength + *offset_ptr; + prologue->MinInstLength = debug_line_data.getU8(offset_ptr); + prologue->DefaultIsStmt = debug_line_data.getU8(offset_ptr); + prologue->LineBase = debug_line_data.getU8(offset_ptr); + prologue->LineRange = debug_line_data.getU8(offset_ptr); + prologue->OpcodeBase = debug_line_data.getU8(offset_ptr); + + prologue->StandardOpcodeLengths.reserve(prologue->OpcodeBase-1); + for (uint32_t i = 1; i < prologue->OpcodeBase; ++i) { + uint8_t op_len = debug_line_data.getU8(offset_ptr); + prologue->StandardOpcodeLengths.push_back(op_len); + } + + while (*offset_ptr < end_prologue_offset) { + const char *s = debug_line_data.getCStr(offset_ptr); + if (s && s[0]) + prologue->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); + prologue->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; +} + +bool +DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data, + const RelocAddrMap *RMap, + uint32_t *offset_ptr, State &state) { + const uint32_t debug_line_offset = *offset_ptr; + + Prologue *prologue = &state.Prologue; + + if (!parsePrologue(debug_line_data, offset_ptr, prologue)) { + // 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); + + state.reset(); + + 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.EndSequence = true; + state.appendRowToMatrix(*offset_ptr); + state.reset(); + 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.Address = debug_line_data.getAddress(offset_ptr) + R.second; + } else + state.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; + + 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.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.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.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.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.IsStmt = !state.IsStmt; + break; + + case DW_LNS_set_basic_block: + // Takes no arguments. Set the basic_block register of the + // state machine to true + state.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.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.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.PrologueEnd = true; + break; + + case DW_LNS_set_epilogue_begin: + // Takes no arguments. Set the basic_block register of the + // state machine to true + state.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.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.Line += line_offset; + state.Address += addr_offset; + state.appendRowToMatrix(*offset_ptr); + } + } + + state.finalize(); + + 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, + bool NeedsAbsoluteFilePath, + std::string &Result) const { + if (FileIndex == 0 || FileIndex > Prologue.FileNames.size()) + return false; + const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; + const char *FileName = Entry.Name; + if (!NeedsAbsoluteFilePath || + sys::path::is_absolute(FileName)) { + Result = FileName; + return true; + } + SmallString<16> FilePath; + uint64_t IncludeDirIndex = Entry.DirIdx; + // Be defensive about the contents of Entry. + if (IncludeDirIndex > 0 && + IncludeDirIndex <= Prologue.IncludeDirectories.size()) { + const char *IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1]; + sys::path::append(FilePath, IncludeDir); + } + sys::path::append(FilePath, FileName); + Result = FilePath.str(); + return true; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugLine.h b/contrib/llvm/lib/DebugInfo/DWARFDebugLine.h new file mode 100644 index 000000000000..2990756bd7c9 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugLine.h @@ -0,0 +1,254 @@ +//===-- DWARFDebugLine.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_DEBUGINFO_DWARFDEBUGLINE_H +#define LLVM_DEBUGINFO_DWARFDEBUGLINE_H + +#include "DWARFRelocMap.h" +#include "llvm/Support/DataExtractor.h" +#include <map> +#include <string> +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugLine { +public: + DWARFDebugLine(const RelocAddrMap* LineInfoRelocMap) : RelocMap(LineInfoRelocMap) {} + struct FileNameEntry { + FileNameEntry() : Name(0), DirIdx(0), ModTime(0), Length(0) {} + + const char *Name; + uint64_t DirIdx; + uint64_t ModTime; + uint64_t Length; + }; + + struct Prologue { + Prologue() + : TotalLength(0), Version(0), PrologueLength(0), MinInstLength(0), + DefaultIsStmt(0), LineBase(0), LineRange(0), OpcodeBase(0) {} + + // The size in bytes of the statement information for this compilation unit + // (not including the total_length field itself). + uint32_t TotalLength; + // Version identifier for the statement information format. + uint16_t Version; + // The number of bytes following the prologue_length field to the beginning + // of the first byte of the statement program itself. + uint32_t PrologueLength; + // The size in bytes of the smallest target machine instruction. Statement + // program opcodes that alter the address register first multiply their + // operands by this value. + uint8_t MinInstLength; + // The initial value of theis_stmtregister. + uint8_t DefaultIsStmt; + // This parameter affects the meaning of the special opcodes. See below. + int8_t LineBase; + // This parameter affects the meaning of the special opcodes. See below. + uint8_t LineRange; + // The number assigned to the first special opcode. + uint8_t OpcodeBase; + std::vector<uint8_t> StandardOpcodeLengths; + std::vector<const char*> IncludeDirectories; + std::vector<FileNameEntry> FileNames; + + // Length of the prologue in bytes. + uint32_t getLength() const { + return PrologueLength + sizeof(TotalLength) + sizeof(Version) + + sizeof(PrologueLength); + } + // Length of the line table data in bytes (not including the prologue). + uint32_t getStatementTableLength() const { + return TotalLength + sizeof(TotalLength) - getLength(); + } + int32_t getMaxLineIncrementForSpecialOpcode() const { + return LineBase + (int8_t)LineRange - 1; + } + void dump(raw_ostream &OS) const; + void clear() { + TotalLength = Version = PrologueLength = 0; + MinInstLength = LineBase = LineRange = OpcodeBase = 0; + StandardOpcodeLengths.clear(); + IncludeDirectories.clear(); + FileNames.clear(); + } + }; + + // Standard .debug_line state machine structure. + struct Row { + Row(bool default_is_stmt = false) { reset(default_is_stmt); } + /// Called after a row is appended to the matrix. + void postAppend(); + void reset(bool default_is_stmt); + void dump(raw_ostream &OS) const; + + static bool orderByAddress(const Row& LHS, const Row& RHS) { + return LHS.Address < RHS.Address; + } + + // The program-counter value corresponding to a machine instruction + // generated by the compiler. + uint64_t Address; + // An unsigned integer indicating a source line number. Lines are numbered + // beginning at 1. The compiler may emit the value 0 in cases where an + // instruction cannot be attributed to any source line. + uint32_t Line; + // An unsigned integer indicating a column number within a source line. + // Columns are numbered beginning at 1. The value 0 is reserved to indicate + // that a statement begins at the 'left edge' of the line. + uint16_t Column; + // An unsigned integer indicating the identity of the source file + // corresponding to a machine instruction. + uint16_t File; + // An unsigned integer whose value encodes the applicable instruction set + // architecture for the current instruction. + uint8_t Isa; + // A boolean indicating that the current instruction is the beginning of a + // statement. + uint8_t IsStmt:1, + // A boolean indicating that the current instruction is the + // beginning of a basic block. + BasicBlock:1, + // A boolean indicating that the current address is that of the + // first byte after the end of a sequence of target machine + // instructions. + EndSequence:1, + // A boolean indicating that the current address is one (of possibly + // many) where execution should be suspended for an entry breakpoint + // of a function. + PrologueEnd:1, + // A boolean indicating that the current address is one (of possibly + // many) where execution should be suspended for an exit breakpoint + // of a function. + EpilogueBegin:1; + }; + + // Represents a series of contiguous machine instructions. Line table for each + // compilation unit may consist of multiple sequences, which are not + // guaranteed to be in the order of ascending instruction address. + struct Sequence { + // Sequence describes instructions at address range [LowPC, HighPC) + // and is described by line table rows [FirstRowIndex, LastRowIndex). + uint64_t LowPC; + uint64_t HighPC; + unsigned FirstRowIndex; + unsigned LastRowIndex; + bool Empty; + + Sequence() { reset(); } + void reset() { + LowPC = 0; + HighPC = 0; + FirstRowIndex = 0; + LastRowIndex = 0; + Empty = true; + } + static bool orderByLowPC(const Sequence& LHS, const Sequence& RHS) { + return LHS.LowPC < RHS.LowPC; + } + bool isValid() const { + return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex); + } + bool containsPC(uint64_t pc) const { + return (LowPC <= pc && pc < HighPC); + } + }; + + struct LineTable { + void appendRow(const DWARFDebugLine::Row &state) { Rows.push_back(state); } + void appendSequence(const DWARFDebugLine::Sequence &sequence) { + Sequences.push_back(sequence); + } + void clear() { + Prologue.clear(); + Rows.clear(); + Sequences.clear(); + } + + // Returns the index of the row with file/line info for a given address, + // or -1 if there is no such row. + uint32_t lookupAddress(uint64_t address) const; + + bool lookupAddressRange(uint64_t address, + uint64_t size, + std::vector<uint32_t>& result) const; + + // Extracts filename by its index in filename table in prologue. + // Returns true on success. + bool getFileNameByIndex(uint64_t FileIndex, + bool NeedsAbsoluteFilePath, + std::string &Result) const; + + void dump(raw_ostream &OS) const; + + struct Prologue Prologue; + typedef std::vector<Row> RowVector; + typedef RowVector::const_iterator RowIter; + typedef std::vector<Sequence> SequenceVector; + typedef SequenceVector::const_iterator SequenceIter; + RowVector Rows; + SequenceVector Sequences; + }; + + struct State : public Row, public Sequence, public LineTable { + // Special row codes. + enum { + StartParsingLineTable = 0, + DoneParsingLineTable = -1 + }; + + State() : row(StartParsingLineTable) {} + virtual ~State(); + + virtual void appendRowToMatrix(uint32_t offset); + virtual void finalize(); + virtual void reset() { + Row::reset(Prologue.DefaultIsStmt); + Sequence::reset(); + } + + // The row number that starts at zero for the prologue, and increases for + // each row added to the matrix. + unsigned row; + }; + + struct DumpingState : public State { + DumpingState(raw_ostream &OS) : OS(OS) {} + virtual ~DumpingState(); + virtual void finalize(); + private: + raw_ostream &OS; + }; + + static bool parsePrologue(DataExtractor debug_line_data, uint32_t *offset_ptr, + Prologue *prologue); + /// Parse a single line table (prologue and all rows). + static bool parseStatementTable(DataExtractor debug_line_data, + const RelocAddrMap *RMap, + uint32_t *offset_ptr, State &state); + + const LineTable *getLineTable(uint32_t offset) const; + const LineTable *getOrParseLineTable(DataExtractor debug_line_data, + uint32_t offset); + +private: + typedef std::map<uint32_t, LineTable> LineTableMapTy; + typedef LineTableMapTy::iterator LineTableIter; + typedef LineTableMapTy::const_iterator LineTableConstIter; + + const RelocAddrMap *RelocMap; + LineTableMapTy LineTableMap; +}; + +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.cpp new file mode 100644 index 000000000000..3895ffa8d7a7 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.cpp @@ -0,0 +1,74 @@ +//===-- DWARFDebugLoc.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugLoc.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void DWARFDebugLoc::dump(raw_ostream &OS) const { + for (LocationLists::const_iterator I = Locations.begin(), E = Locations.end(); I != E; ++I) { + OS << format("0x%8.8x: ", I->Offset); + const unsigned Indent = 12; + for (SmallVectorImpl<Entry>::const_iterator I2 = I->Entries.begin(), E2 = I->Entries.end(); I2 != E2; ++I2) { + if (I2 != I->Entries.begin()) + OS.indent(Indent); + OS << "Beginning address offset: " << format("0x%016" PRIx64, I2->Begin) + << '\n'; + OS.indent(Indent) << " Ending address offset: " + << format("0x%016" PRIx64, I2->End) << '\n'; + OS.indent(Indent) << " Location description: "; + for (SmallVectorImpl<unsigned char>::const_iterator I3 = I2->Loc.begin(), E3 = I2->Loc.end(); I3 != E3; ++I3) { + OS << format("%2.2x ", *I3); + } + OS << "\n\n"; + } + } +} + +void DWARFDebugLoc::parse(DataExtractor data, unsigned AddressSize) { + uint32_t Offset = 0; + while (data.isValidOffset(Offset)) { + 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.reserve(str.size()); + std::copy(str.begin(), str.end(), std::back_inserter(E.Loc)); + Loc.Entries.push_back(llvm_move(E)); + } + } +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.h b/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.h new file mode 100644 index 000000000000..d31aaaa12737 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugLoc.h @@ -0,0 +1,60 @@ +//===-- DWARFDebugLoc.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_DEBUGINFO_DWARFDEBUGLOC_H +#define LLVM_DEBUGINFO_DWARFDEBUGLOC_H + +#include "DWARFRelocMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataExtractor.h" + +namespace llvm { + +class raw_ostream; + +class DWARFDebugLoc { + /// A single location within a location list. + struct Entry { + /// The beginning address of the instruction range. + uint64_t Begin; + /// The ending address of the instruction range. + uint64_t End; + /// The location of the variable within the specified range. + SmallVector<unsigned char, 4> Loc; + }; + + /// A list of locations that contain one variable. + struct LocationList { + /// The beginning offset where this location list is stored in the debug_loc + /// section. + unsigned Offset; + /// All the locations in which the variable is stored. + SmallVector<Entry, 2> Entries; + }; + + typedef SmallVector<LocationList, 4> LocationLists; + + /// A list of all the variables in the debug_loc section, each one describing + /// the locations in which the variable is stored. + LocationLists Locations; + + /// A map used to resolve binary relocations. + const RelocAddrMap &RelocMap; + +public: + DWARFDebugLoc(const RelocAddrMap &LocRelocMap) : RelocMap(LocRelocMap) {} + /// Print the location lists found within the debug_loc section. + void dump(raw_ostream &OS) const; + /// Parse the debug_loc section accessible via the 'data' parameter using the + /// specified address size to interpret the address ranges. + void parse(DataExtractor data, unsigned AddressSize); +}; +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.cpp new file mode 100644 index 000000000000..1806beee7285 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.cpp @@ -0,0 +1,67 @@ +//===-- DWARFDebugRangesList.cpp ------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "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 (int i = 0, n = Entries.size(); i != n; ++i) { + const char *format_str = (AddressSize == 4 + ? "%08x %08" PRIx64 " %08" PRIx64 "\n" + : "%08x %016" PRIx64 " %016" PRIx64 "\n"); + OS << format(format_str, Offset, Entries[i].StartAddress, + Entries[i].EndAddress); + } + OS << format("%08x <End of list>\n", Offset); +} + +bool DWARFDebugRangeList::containsAddress(uint64_t BaseAddress, + uint64_t Address) const { + for (int i = 0, n = Entries.size(); i != n; ++i) { + if (Entries[i].isBaseAddressSelectionEntry(AddressSize)) + BaseAddress = Entries[i].EndAddress; + else if (Entries[i].containsAddress(BaseAddress, Address)) + return true; + } + return false; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.h b/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.h new file mode 100644 index 000000000000..4e34a916f4a3 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugRangeList.h @@ -0,0 +1,78 @@ +//===-- DWARFDebugRangeList.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_DEBUGINFO_DWARFDEBUGRANGELIST_H +#define LLVM_DEBUGINFO_DWARFDEBUGRANGELIST_H + +#include "llvm/Support/DataExtractor.h" +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugRangeList { +public: + struct RangeListEntry { + // A beginning address offset. This address offset has the size of an + // address and is relative to the applicable base address of the + // compilation unit referencing this range list. It marks the beginning + // of an address range. + uint64_t StartAddress; + // An ending address offset. This address offset again has the size of + // an address and is relative to the applicable base address of the + // compilation unit referencing this range list. It marks the first + // address past the end of the address range. The ending address must + // be greater than or equal to the beginning address. + uint64_t EndAddress; + // The end of any given range 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. + bool isEndOfListEntry() const { + return (StartAddress == 0) && (EndAddress == 0); + } + // A base address selection entry consists of: + // 1. The value of the largest representable address offset + // (for example, 0xffffffff when the size of an address is 32 bits). + // 2. An address, which defines the appropriate base address for + // use in interpreting the beginning and ending address offsets of + // subsequent entries of the location list. + bool isBaseAddressSelectionEntry(uint8_t AddressSize) const { + assert(AddressSize == 4 || AddressSize == 8); + if (AddressSize == 4) + return StartAddress == -1U; + else + return StartAddress == -1ULL; + } + bool containsAddress(uint64_t BaseAddress, uint64_t Address) const { + return (BaseAddress + StartAddress <= Address) && + (Address < BaseAddress + EndAddress); + } + }; + +private: + // Offset in .debug_ranges section. + uint32_t Offset; + uint8_t AddressSize; + std::vector<RangeListEntry> Entries; + +public: + DWARFDebugRangeList() { clear(); } + void clear(); + void dump(raw_ostream &OS) const; + bool extract(DataExtractor data, uint32_t *offset_ptr); + /// containsAddress - Returns true if range list contains the given + /// address. Has to be passed base address of the compile unit that + /// references this range list. + bool containsAddress(uint64_t BaseAddress, uint64_t Address) const; +}; + +} // namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGRANGELIST_H diff --git a/contrib/llvm/lib/DebugInfo/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARFFormValue.cpp new file mode 100644 index 000000000000..da71fb3d1161 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFFormValue.cpp @@ -0,0 +1,549 @@ +//===-- DWARFFormValue.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/DWARFFormValue.h" +#include "DWARFCompileUnit.h" +#include "DWARFContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +using namespace llvm; +using namespace dwarf; + +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 DW_FORM_ref_sig8 from DWARF4. + if (Form == DW_FORM_ref_sig8) + return (FC == FC_Reference); + // Check for some DWARF5 forms. + if (Form == DW_FORM_GNU_addr_index) + return (FC == FC_Address); + if (Form == DW_FORM_GNU_str_index) + 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. + if ((Form == DW_FORM_data4 || Form == DW_FORM_data8) && + FC == FC_SectionOffset) + return true; + return false; +} + +bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, + const DWARFUnit *cu) { + bool indirect = false; + bool is_block = false; + Value.data = NULL; + // 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: { + 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: { + RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); + Value.uval = data.getU32(offset_ptr); + 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_strp: { + 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.getU32(offset_ptr) + R.second; + } else + Value.uval = data.getU32(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: { + // FIXME: This is 64-bit for DWARF64. + 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.getU32(offset_ptr) + R.second; + } else + Value.uval = data.getU32(offset_ptr); + 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 = NULL; + 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_strp: + 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: + *offset_ptr += 4; + return true; + + default: + return false; + } + } while (indirect); + return true; +} + +void +DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { + DataExtractor debug_str_data(cu->getStringSection(), true, 0); + DataExtractor debug_str_offset_data(cu->getStringOffsetSection(), true, 0); + 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); + Optional<const char *> DbgStr = getAsCString(cu); + if (DbgStr.hasValue()) { + OS << '"'; + OS.write_escaped(DbgStr.getValue()); + OS << '"'; + } + break; + } + case DW_FORM_GNU_str_index: { + OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); + Optional<const char *> DbgStr = getAsCString(cu); + if (DbgStr.hasValue()) { + OS << '"'; + OS.write_escaped(DbgStr.getValue()); + OS << '"'; + } + 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; + + // 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 << format(" => {0x%8.8" PRIx64 "}", uvalue + (cu ? cu->getOffset() : 0)); +} + +Optional<const char *> DWARFFormValue::getAsCString(const DWARFUnit *U) const { + if (!isFormClass(FC_String)) + return None; + if (Form == DW_FORM_string) + return Value.cstr; + if (U == 0) + 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 == 0 || !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 == 0) + return None; + return Value.uval + U->getOffset(); + case DW_FORM_ref_addr: + return Value.uval; + // FIXME: Add proper support for DW_FORM_ref_sig8 + default: + return Value.uval; + } +} + +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) || Form == DW_FORM_sdata) + return None; + return Value.uval; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFRelocMap.h b/contrib/llvm/lib/DebugInfo/DWARFRelocMap.h new file mode 100644 index 000000000000..6929e367b84c --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFRelocMap.h @@ -0,0 +1,22 @@ +//===-- DWARFRelocMap.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_DEBUGINFO_DWARFRELOCMAP_H +#define LLVM_DEBUGINFO_DWARFRELOCMAP_H + +#include "llvm/ADT/DenseMap.h" + +namespace llvm { + +typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t> > RelocAddrMap; + +} // namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFRELOCMAP_H + diff --git a/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.cpp new file mode 100644 index 000000000000..303bf707067d --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.cpp @@ -0,0 +1,39 @@ +//===-- DWARFTypeUnit.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "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"; + + const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false); + assert(CU && "Null Compile Unit?"); + CU->dump(OS, this, -1U); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.h b/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.h new file mode 100644 index 000000000000..7a0dab204d0a --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFTypeUnit.h @@ -0,0 +1,35 @@ +//===-- DWARFTypeUnit.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_DEBUGINFO_DWARFTYPEUNIT_H +#define LLVM_DEBUGINFO_DWARFTYPEUNIT_H + +#include "DWARFUnit.h" + +namespace llvm { + +class DWARFTypeUnit : public DWARFUnit { +private: + uint64_t TypeHash; + uint32_t TypeOffset; +public: + DWARFTypeUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE) + : DWARFUnit(DA, IS, AS, RS, SS, SOS, AOS, M, LE) {} + uint32_t getSize() const LLVM_OVERRIDE { return DWARFUnit::getSize() + 12; } + void dump(raw_ostream &OS); +protected: + bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) LLVM_OVERRIDE; +}; + +} + +#endif + diff --git a/contrib/llvm/lib/DebugInfo/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARFUnit.cpp new file mode 100644 index 000000000000..5167eb947c41 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFUnit.cpp @@ -0,0 +1,365 @@ +//===-- DWARFUnit.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFUnit.h" +#include "DWARFContext.h" +#include "llvm/DebugInfo/DWARFFormValue.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Path.h" +#include <cstdio> + +using namespace llvm; +using namespace dwarf; + +DWARFUnit::DWARFUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE) + : Abbrev(DA), InfoSection(IS), AbbrevSection(AS), RangeSection(RS), + StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), + RelocMap(M), isLittleEndian(LE) { + 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 abbrOffsetOK = AbbrevSection.size() > abbrOffset; + bool addrSizeOK = AddrSize == 4 || AddrSize == 8; + + if (!lengthOK || !versionOK || !addrSizeOK || !abbrOffsetOK) + return false; + + Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset); + return true; +} + +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 = 0; + AddrSize = 0; + BaseAddr = 0; + RangeSectionBase = 0; + AddrOffsetSectionBase = 0; + clearDIEs(false); + DWO.reset(); +} + +const char *DWARFUnit::getCompilationDir() { + extractDIEsIfNeeded(true); + if (DieArray.empty()) + return 0; + return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); +} + +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.empty()) + return; + DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); + DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); + DWARFDebugInfoEntryMinimal *curr_die; + // We purposely are skipping the last element in the array in the loop below + // so that we can always have a valid next item + for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { + // Since our loop doesn't include the last element, we can always + // safely access the next die in the array. + DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; + + const DWARFAbbreviationDeclaration *curr_die_abbrev = + curr_die->getAbbreviationDeclarationPtr(); + + if (curr_die_abbrev) { + // Normal DIE + if (curr_die_abbrev->hasChildren()) + next_die->setParent(curr_die); + else + curr_die->setSibling(next_die); + } else { + // NULL DIE that terminates a sibling chain + DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); + if (parent) + parent->setSibling(next_die); + } + } + + // Since we skipped the last element, we need to fix it up! + if (die_array_begin < die_array_end) + curr_die->setParent(die_array_begin); +} + +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 Offset = getFirstDIEOffset(); + uint32_t NextCUOffset = getNextUnitOffset(); + DWARFDebugInfoEntryMinimal DIE; + uint32_t Depth = 0; + bool IsCUDie = true; + + while (Offset < NextCUOffset && DIE.extractFast(this, &Offset)) { + 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); + } + + const DWARFAbbreviationDeclaration *AbbrDecl = + DIE.getAbbreviationDeclarationPtr(); + if (AbbrDecl) { + // 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 (Offset > NextCUOffset) + fprintf(stderr, "warning: DWARF compile unit extends beyond its " + "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), Offset); +} + +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_GNU_ranges_base, 0); + } + + setDIERelations(); + return DieArray.size(); +} + +DWARFUnit::DWOHolder::DWOHolder(object::ObjectFile *DWOFile) + : DWOFile(DWOFile), + DWOContext(cast<DWARFContext>(DIContext::getDWARFContext(DWOFile))), + DWOU(0) { + if (DWOContext->getNumDWOCompileUnits() > 0) + DWOU = DWOContext->getDWOCompileUnitAtIndex(0); +} + +bool DWARFUnit::parseDWO() { + if (DWO.get() != 0) + return false; + extractDIEsIfNeeded(true); + if (DieArray.empty()) + return false; + const char *DWOFileName = + DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, 0); + if (DWOFileName == 0) + return false; + const char *CompilationDir = + DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0); + SmallString<16> AbsolutePath; + if (sys::path::is_relative(DWOFileName) && CompilationDir != 0) { + sys::path::append(AbsolutePath, CompilationDir); + } + sys::path::append(AbsolutePath, DWOFileName); + object::ObjectFile *DWOFile = + object::ObjectFile::createObjectFile(AbsolutePath); + if (!DWOFile) + return false; + // Reset DWOHolder. + DWO.reset(new DWOHolder(DWOFile)); + DWARFUnit *DWOCU = DWO->getUnit(); + // Verify that compile unit in .dwo file is valid. + if (DWOCU == 0 || DWOCU->getDWOId() != getDWOId()) { + DWO.reset(); + return false; + } + // Share .debug_addr and .debug_ranges section with compile unit in .dwo + DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); + DWOCU->setRangesSection(RangeSection, RangeSectionBase); + 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::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed, + uint32_t CUOffsetInAranges) { + // 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 clear_dies = extractDIEsIfNeeded(false) > 1 && + clear_dies_if_already_not_parsed; + DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges); + bool DWOCreated = parseDWO(); + if (DWO.get()) { + // If there is a .dwo file for this compile unit, then skeleton CU DIE + // doesn't have children, and we should instead build address range table + // from DIEs in the .debug_info.dwo section of .dwo file. + DWO->getUnit()->buildAddressRangeTable( + debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges); + } + if (DWOCreated && clear_dies_if_already_not_parsed) + DWO.reset(); + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed. + if (clear_dies) + clearDIEs(true); +} + +const DWARFDebugInfoEntryMinimal * +DWARFUnit::getSubprogramForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + for (size_t i = 0, n = DieArray.size(); i != n; i++) + if (DieArray[i].isSubprogramDIE() && + DieArray[i].addressRangeContainsAddress(this, Address)) { + return &DieArray[i]; + } + return 0; +} + +DWARFDebugInfoEntryInlinedChain +DWARFUnit::getInlinedChainForAddress(uint64_t Address) { + // First, find a subprogram that contains the given address (the root + // of inlined chain). + const DWARFUnit *ChainCU = 0; + 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/contrib/llvm/lib/DebugInfo/DWARFUnit.h b/contrib/llvm/lib/DebugInfo/DWARFUnit.h new file mode 100644 index 000000000000..bd768a6bce4c --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFUnit.h @@ -0,0 +1,168 @@ +//===-- DWARFUnit.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_DEBUGINFO_DWARFUNIT_H +#define LLVM_DEBUGINFO_DWARFUNIT_H + +#include "llvm/ADT/OwningPtr.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFDebugRangeList.h" +#include "DWARFRelocMap.h" +#include <vector> + +namespace llvm { + +namespace object { +class ObjectFile; +} + +class DWARFDebugAbbrev; +class StringRef; +class raw_ostream; + +class DWARFUnit { + const DWARFDebugAbbrev *Abbrev; + StringRef InfoSection; + StringRef AbbrevSection; + StringRef RangeSection; + uint32_t RangeSectionBase; + StringRef StringSection; + StringRef StringOffsetSection; + StringRef AddrOffsetSection; + uint32_t AddrOffsetSectionBase; + const RelocAddrMap *RelocMap; + bool isLittleEndian; + + uint32_t Offset; + uint32_t Length; + uint16_t Version; + const DWARFAbbreviationDeclarationSet *Abbrevs; + uint8_t AddrSize; + uint64_t BaseAddr; + // The compile unit debug information entry items. + std::vector<DWARFDebugInfoEntryMinimal> DieArray; + + class DWOHolder { + OwningPtr<object::ObjectFile> DWOFile; + OwningPtr<DWARFContext> DWOContext; + DWARFUnit *DWOU; + public: + DWOHolder(object::ObjectFile *DWOFile); + DWARFUnit *getUnit() const { return DWOU; } + }; + OwningPtr<DWOHolder> DWO; + +protected: + virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); + +public: + + DWARFUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, + StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, + const RelocAddrMap *M, bool LE); + + virtual ~DWARFUnit(); + + StringRef getStringSection() const { return StringSection; } + StringRef getStringOffsetSection() const { return StringOffsetSection; } + void setAddrOffsetSection(StringRef AOS, uint32_t Base) { + AddrOffsetSection = AOS; + AddrOffsetSectionBase = Base; + } + void setRangesSection(StringRef RS, uint32_t Base) { + RangeSection = RS; + RangeSectionBase = Base; + } + + bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const; + // FIXME: Result should be uint64_t in DWARF64. + bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const; + + DataExtractor getDebugInfoExtractor() const { + return DataExtractor(InfoSection, isLittleEndian, AddrSize); + } + DataExtractor getStringExtractor() const { + return DataExtractor(StringSection, false, 0); + } + + const RelocAddrMap *getRelocMap() const { return RelocMap; } + + bool extract(DataExtractor debug_info, uint32_t* offset_ptr); + + /// extractRangeList - extracts the range list referenced by this compile + /// unit from .debug_ranges section. Returns true on success. + /// Requires that compile unit is already extracted. + bool extractRangeList(uint32_t RangeListOffset, + DWARFDebugRangeList &RangeList) const; + void clear(); + uint32_t getOffset() const { return Offset; } + /// Size in bytes of the compile unit header. + virtual uint32_t getSize() const { return 11; } + uint32_t getFirstDIEOffset() const { return Offset + getSize(); } + uint32_t getNextUnitOffset() const { return Offset + Length + 4; } + /// Size in bytes of the .debug_info data associated with this compile unit. + size_t getDebugInfoSize() const { return Length + 4 - getSize(); } + uint32_t getLength() const { return Length; } + uint16_t getVersion() const { return Version; } + const DWARFAbbreviationDeclarationSet *getAbbreviations() const { + return Abbrevs; + } + uint8_t getAddressByteSize() const { return AddrSize; } + uint64_t getBaseAddress() const { return BaseAddr; } + + void setBaseAddress(uint64_t base_addr) { + BaseAddr = base_addr; + } + + const DWARFDebugInfoEntryMinimal * + getCompileUnitDIE(bool extract_cu_die_only = true) { + extractDIEsIfNeeded(extract_cu_die_only); + return DieArray.empty() ? NULL : &DieArray[0]; + } + + const char *getCompilationDir(); + uint64_t getDWOId(); + + void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed, + uint32_t CUOffsetInAranges); + + /// getInlinedChainForAddress - fetches inlined chain for a given address. + /// Returns empty chain if there is no subprogram containing address. The + /// chain is valid as long as parsed compile unit DIEs are not cleared. + DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(uint64_t Address); + +private: + /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it + /// hasn't already been done. Returns the number of DIEs parsed at this call. + size_t extractDIEsIfNeeded(bool CUDieOnly); + /// extractDIEsToVector - Appends all parsed DIEs to a vector. + void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, + std::vector<DWARFDebugInfoEntryMinimal> &DIEs) const; + /// setDIERelations - We read in all of the DIE entries into our flat list + /// of DIE entries and now we need to go back through all of them and set the + /// parent, sibling and child pointers for quick DIE navigation. + void setDIERelations(); + /// clearDIEs - Clear parsed DIEs to keep memory usage low. + void clearDIEs(bool KeepCUDie); + + /// parseDWO - Parses .dwo file for current compile unit. Returns true if + /// it was actually constructed. + bool parseDWO(); + + /// getSubprogramForAddress - Returns subprogram DIE with address range + /// encompassing the provided address. The pointer is alive as long as parsed + /// compile unit DIEs are not cleared. + const DWARFDebugInfoEntryMinimal *getSubprogramForAddress(uint64_t Address); +}; + +} + +#endif |