#include "DWARFContext.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include <algorithm>
using namespace llvm;
using namespace dwarf;
+using namespace object;
-void DWARFContext::dump(raw_ostream &OS) {
- OS << ".debug_abbrev contents:\n";
- getDebugAbbrev()->dump(OS);
+typedef DWARFDebugLine::LineTable DWARFLineTable;
- OS << "\n.debug_info contents:\n";
- for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i)
- getCompileUnitAtIndex(i)->dump(OS);
+static void dumpPubSection(raw_ostream &OS, StringRef Name, StringRef Data,
+ bool LittleEndian, bool GnuStyle) {
+ OS << "\n." << Name << " contents:\n";
+ DataExtractor pubNames(Data, LittleEndian, 0);
+ uint32_t offset = 0;
+ while (pubNames.isValidOffset(offset)) {
+ OS << "length = " << format("0x%08x", pubNames.getU32(&offset));
+ OS << " version = " << format("0x%04x", pubNames.getU16(&offset));
+ OS << " unit_offset = " << format("0x%08x", pubNames.getU32(&offset));
+ OS << " unit_size = " << format("0x%08x", pubNames.getU32(&offset)) << '\n';
+ if (GnuStyle)
+ OS << "Offset Linkage Kind Name\n";
+ else
+ OS << "Offset Name\n";
+
+ while (offset < Data.size()) {
+ uint32_t dieRef = pubNames.getU32(&offset);
+ if (dieRef == 0)
+ break;
+ OS << format("0x%8.8x ", dieRef);
+ if (GnuStyle) {
+ PubIndexEntryDescriptor desc(pubNames.getU8(&offset));
+ OS << format("%-8s", dwarf::GDBIndexEntryLinkageString(desc.Linkage))
+ << ' ' << format("%-8s", dwarf::GDBIndexEntryKindString(desc.Kind))
+ << ' ';
+ }
+ OS << '\"' << pubNames.getCStr(&offset) << "\"\n";
+ }
+ }
+}
+
+void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
+ if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
+ OS << ".debug_abbrev contents:\n";
+ getDebugAbbrev()->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo)
+ if (const DWARFDebugAbbrev *D = getDebugAbbrevDWO()) {
+ OS << "\n.debug_abbrev.dwo contents:\n";
+ D->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Info) {
+ OS << "\n.debug_info contents:\n";
+ for (const auto &CU : compile_units())
+ CU->dump(OS);
+ }
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_InfoDwo) &&
+ getNumDWOCompileUnits()) {
+ OS << "\n.debug_info.dwo contents:\n";
+ for (const auto &DWOCU : dwo_compile_units())
+ DWOCU->dump(OS);
+ }
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) {
+ OS << "\n.debug_types contents:\n";
+ for (const auto &TU : type_units())
+ TU->dump(OS);
+ }
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_TypesDwo) &&
+ getNumDWOTypeUnits()) {
+ OS << "\n.debug_types.dwo contents:\n";
+ for (const auto &DWOTU : dwo_type_units())
+ DWOTU->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Loc) {
+ OS << "\n.debug_loc contents:\n";
+ getDebugLoc()->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) {
+ OS << "\n.debug_loc.dwo contents:\n";
+ getDebugLocDWO()->dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
+ OS << "\n.debug_frame contents:\n";
+ getDebugFrame()->dump(OS);
+ }
- OS << "\n.debug_aranges contents:\n";
- DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
uint32_t offset = 0;
- DWARFDebugArangeSet set;
- while (set.extract(arangesData, &offset))
- set.dump(OS);
+ 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;
- OS << "\n.debug_lines contents:\n";
- for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) {
- DWARFCompileUnit *cu = getCompileUnitAtIndex(i);
- savedAddressByteSize = cu->getAddressByteSize();
- unsigned stmtOffset =
- cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
- -1U);
- if (stmtOffset != -1U) {
- DataExtractor lineData(getLineSection(), isLittleEndian(),
- savedAddressByteSize);
- DWARFDebugLine::DumpingState state(OS);
- DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state);
+ if (DumpType == DIDT_All || DumpType == DIDT_Line) {
+ OS << "\n.debug_line contents:\n";
+ for (const auto &CU : compile_units()) {
+ savedAddressByteSize = CU->getAddressByteSize();
+ unsigned stmtOffset =
+ CU->getCompileUnitDIE()->getAttributeValueAsSectionOffset(
+ CU.get(), 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);
+ }
}
}
- OS << "\n.debug_str contents:\n";
- DataExtractor strData(getStringSection(), isLittleEndian(), 0);
- offset = 0;
- uint32_t lastOffset = 0;
- while (const char *s = strData.getCStr(&offset)) {
- OS << format("0x%8.8x: \"%s\"\n", lastOffset, s);
- lastOffset = offset;
+ if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) {
+ OS << "\n.debug_line.dwo contents:\n";
+ unsigned stmtOffset = 0;
+ DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(),
+ savedAddressByteSize);
+ DWARFDebugLine::DumpingState state(OS);
+ while (DWARFDebugLine::parsePrologue(lineData, &stmtOffset, &state.Prologue))
+ state.finalize();
+ }
+
+ 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;
+ }
}
- 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_StrDwo) &&
+ !getStringDWOSection().empty()) {
+ OS << "\n.debug_str.dwo contents:\n";
+ DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0);
+ offset = 0;
+ uint32_t strDWOOffset = 0;
+ while (const char *s = strDWOData.getCStr(&offset)) {
+ OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
+ strDWOOffset = offset;
+ }
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Ranges) {
+ OS << "\n.debug_ranges contents:\n";
+ // In fact, different compile units may have different address byte
+ // sizes, but for simplicity we just use the address byte size of the last
+ // compile unit (there is no easy and fast way to associate address range
+ // list and the compile unit it describes).
+ DataExtractor rangesData(getRangeSection(), isLittleEndian(),
+ savedAddressByteSize);
+ offset = 0;
+ DWARFDebugRangeList rangeList;
+ while (rangeList.extract(rangesData, &offset))
+ rangeList.dump(OS);
+ }
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Pubnames)
+ dumpPubSection(OS, "debug_pubnames", getPubNamesSection(),
+ isLittleEndian(), false);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes)
+ dumpPubSection(OS, "debug_pubtypes", getPubTypesSection(),
+ isLittleEndian(), false);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames)
+ dumpPubSection(OS, "debug_gnu_pubnames", getGnuPubNamesSection(),
+ isLittleEndian(), true /* GnuStyle */);
+
+ if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes)
+ dumpPubSection(OS, "debug_gnu_pubtypes", getGnuPubTypesSection(),
+ isLittleEndian(), true /* GnuStyle */);
+
+ if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) &&
+ !getStringOffsetDWOSection().empty()) {
+ OS << "\n.debug_str_offsets.dwo contents:\n";
+ DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(),
+ 0);
+ offset = 0;
+ uint64_t size = getStringOffsetDWOSection().size();
+ while (offset < size) {
+ OS << format("0x%8.8x: ", offset);
+ OS << format("%8.8x\n", strOffsetExt.getU32(&offset));
+ }
+ }
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
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 DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
+ if (LocDWO)
+ return LocDWO.get();
+
+ DataExtractor LocData(getLocDWOSection().Data, isLittleEndian(), 0);
+ LocDWO.reset(new DWARFDebugLocDWO());
+ LocDWO->parse(LocData);
+ return LocDWO.get();
+}
+
const DWARFDebugAranges *DWARFContext::getDebugAranges() {
if (Aranges)
return Aranges.get();
- DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
-
Aranges.reset(new DWARFDebugAranges());
- Aranges->extract(arangesData);
- if (Aranges->isEmpty()) // No aranges in file, generate them from the DIEs.
- Aranges->generate(this);
+ Aranges->generate(this);
return Aranges.get();
}
-const DWARFDebugLine::LineTable *
+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());
+ Line.reset(new DWARFDebugLine(&getLineSection().Relocs));
unsigned stmtOffset =
- cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
- -1U);
+ 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 DWARFDebugLine::LineTable *lt = Line->getLineTable(stmtOffset))
+ if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
return lt;
// We have to parse it first.
- DataExtractor lineData(getLineSection(), isLittleEndian(),
+ DataExtractor lineData(getLineSection().Data, isLittleEndian(),
cu->getAddressByteSize());
return Line->getOrParseLineTable(lineData, stmtOffset);
}
void DWARFContext::parseCompileUnits() {
+ if (!CUs.empty())
+ return;
uint32_t offset = 0;
- const DataExtractor &debug_info_data = DataExtractor(getInfoSection(),
- isLittleEndian(), 0);
- while (debug_info_data.isValidOffset(offset)) {
- CUs.push_back(DWARFCompileUnit(*this));
- if (!CUs.back().extract(debug_info_data, &offset)) {
- CUs.pop_back();
+ const DataExtractor &DIData = DataExtractor(getInfoSection().Data,
+ isLittleEndian(), 0);
+ while (DIData.isValidOffset(offset)) {
+ std::unique_ptr<DWARFCompileUnit> CU(new DWARFCompileUnit(
+ getDebugAbbrev(), getInfoSection().Data, getAbbrevSection(),
+ getRangeSection(), getStringSection(), StringRef(), getAddrSection(),
+ &getInfoSection().Relocs, isLittleEndian()));
+ if (!CU->extract(DIData, &offset)) {
break;
}
+ CUs.push_back(std::move(CU));
+ offset = CUs.back()->getNextUnitOffset();
+ }
+}
- offset = CUs.back().getNextCompileUnitOffset();
+void DWARFContext::parseTypeUnits() {
+ if (!TUs.empty())
+ return;
+ for (const auto &I : getTypesSections()) {
+ uint32_t offset = 0;
+ const DataExtractor &DIData =
+ DataExtractor(I.second.Data, isLittleEndian(), 0);
+ while (DIData.isValidOffset(offset)) {
+ std::unique_ptr<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(std::move(TU));
+ offset = TUs.back()->getNextUnitOffset();
+ }
+ }
+}
+
+void DWARFContext::parseDWOCompileUnits() {
+ if (!DWOCUs.empty())
+ return;
+ uint32_t offset = 0;
+ const DataExtractor &DIData =
+ DataExtractor(getInfoDWOSection().Data, isLittleEndian(), 0);
+ while (DIData.isValidOffset(offset)) {
+ std::unique_ptr<DWARFCompileUnit> DWOCU(new DWARFCompileUnit(
+ getDebugAbbrevDWO(), getInfoDWOSection().Data, getAbbrevDWOSection(),
+ getRangeDWOSection(), getStringDWOSection(),
+ getStringOffsetDWOSection(), getAddrSection(),
+ &getInfoDWOSection().Relocs, isLittleEndian()));
+ if (!DWOCU->extract(DIData, &offset)) {
+ break;
+ }
+ DWOCUs.push_back(std::move(DWOCU));
+ offset = DWOCUs.back()->getNextUnitOffset();
+ }
+}
+
+void DWARFContext::parseDWOTypeUnits() {
+ if (!DWOTUs.empty())
+ return;
+ for (const auto &I : getTypesDWOSections()) {
+ uint32_t offset = 0;
+ const DataExtractor &DIData =
+ DataExtractor(I.second.Data, isLittleEndian(), 0);
+ while (DIData.isValidOffset(offset)) {
+ std::unique_ptr<DWARFTypeUnit> TU(new DWARFTypeUnit(
+ getDebugAbbrevDWO(), I.second.Data, getAbbrevDWOSection(),
+ getRangeDWOSection(), getStringDWOSection(),
+ getStringOffsetDWOSection(), getAddrSection(), &I.second.Relocs,
+ isLittleEndian()));
+ if (!TU->extract(DIData, &offset))
+ break;
+ DWOTUs.push_back(std::move(TU));
+ offset = DWOTUs.back()->getNextUnitOffset();
+ }
}
}
namespace {
struct OffsetComparator {
- bool operator()(const DWARFCompileUnit &LHS,
- const DWARFCompileUnit &RHS) const {
- return LHS.getOffset() < RHS.getOffset();
+
+ bool operator()(const std::unique_ptr<DWARFCompileUnit> &LHS,
+ const std::unique_ptr<DWARFCompileUnit> &RHS) const {
+ return LHS->getOffset() < RHS->getOffset();
}
- bool operator()(const DWARFCompileUnit &LHS, uint32_t RHS) const {
- return LHS.getOffset() < RHS;
+ bool operator()(const std::unique_ptr<DWARFCompileUnit> &LHS,
+ uint32_t RHS) const {
+ return LHS->getOffset() < RHS;
}
- bool operator()(uint32_t LHS, const DWARFCompileUnit &RHS) const {
- return LHS < RHS.getOffset();
+ bool operator()(uint32_t LHS,
+ const std::unique_ptr<DWARFCompileUnit> &RHS) const {
+ return LHS < RHS->getOffset();
}
};
}
-DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t offset) {
- if (CUs.empty())
- parseCompileUnits();
+DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t Offset) {
+ parseCompileUnits();
- DWARFCompileUnit *i = std::lower_bound(CUs.begin(), CUs.end(), offset,
- OffsetComparator());
- if (i != CUs.end())
- return &*i;
+ std::unique_ptr<DWARFCompileUnit> *CU =
+ std::lower_bound(CUs.begin(), CUs.end(), Offset, OffsetComparator());
+ if (CU != CUs.end()) {
+ return CU->get();
+ }
return 0;
}
-DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address,
- DILineInfoSpecifier specifier) {
+DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
// First, get the offset of the compile unit.
- uint32_t cuOffset = getDebugAranges()->findAddress(address);
+ uint32_t CUOffset = getDebugAranges()->findAddress(Address);
// Retrieve the compile unit.
- DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset);
- if (!cu)
+ 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();
- SmallString<16> fileName("<invalid>");
- SmallString<16> functionName("<invalid>");
- uint32_t line = 0;
- uint32_t column = 0;
- if (specifier.needs(DILineInfoSpecifier::FunctionName)) {
- const DWARFDebugInfoEntryMinimal *function_die =
- cu->getFunctionDIEForAddress(address);
- if (function_die) {
- if (const char *name = function_die->getSubprogramName(cu))
- functionName = name;
- }
- }
- if (specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
- // Get the line table for this compile unit.
- const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
- if (lineTable) {
- // Get the index of the row we're looking for in the line table.
- uint32_t rowIndex = lineTable->lookupAddress(address);
- if (rowIndex != -1U) {
- const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
- // Take file/line info from the line table.
- const DWARFDebugLine::FileNameEntry &fileNameEntry =
- lineTable->Prologue.FileNames[row.File - 1];
- fileName = fileNameEntry.Name;
- if (specifier.needs(DILineInfoSpecifier::AbsoluteFilePath) &&
- sys::path::is_relative(fileName.str())) {
- // Append include directory of file (if it is present in line table)
- // and compilation directory of compile unit to make path absolute.
- const char *includeDir = 0;
- if (uint64_t includeDirIndex = fileNameEntry.DirIdx) {
- includeDir = lineTable->Prologue
- .IncludeDirectories[includeDirIndex - 1];
- }
- SmallString<16> absFileName;
- if (includeDir == 0 || sys::path::is_relative(includeDir)) {
- if (const char *compilationDir = cu->getCompilationDir())
- sys::path::append(absFileName, compilationDir);
- }
- if (includeDir) {
- sys::path::append(absFileName, includeDir);
+ 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;
+
+ for (uint32_t RowIndex : RowVector) {
+ // 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()) {
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef name;
+ Section.getName(name);
+ StringRef data;
+ Section.getContents(data);
+
+ name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
+
+ // Check if debug info section is compressed with zlib.
+ if (name.startswith("zdebug_")) {
+ uint64_t OriginalSize;
+ if (!zlib::isAvailable() ||
+ !consumeCompressedDebugSectionHeader(data, OriginalSize))
+ continue;
+ UncompressedSections.resize(UncompressedSections.size() + 1);
+ if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) !=
+ zlib::StatusOK) {
+ UncompressedSections.pop_back();
+ continue;
+ }
+ // Make data point to uncompressed section contents and save its contents.
+ name = name.substr(1);
+ data = UncompressedSections.back();
+ }
+
+ StringRef *SectionData =
+ StringSwitch<StringRef *>(name)
+ .Case("debug_info", &InfoSection.Data)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_loc", &LocSection.Data)
+ .Case("debug_line", &LineSection.Data)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_pubtypes", &PubTypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case("debug_info.dwo", &InfoDWOSection.Data)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_loc.dwo", &LocDWOSection.Data)
+ .Case("debug_line.dwo", &LineDWOSection.Data)
+ .Case("debug_str.dwo", &StringDWOSection)
+ .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
+ .Case("debug_addr", &AddrSection)
+ // Any more debug info sections go here.
+ .Default(0);
+ if (SectionData) {
+ *SectionData = data;
+ if (name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangeDWOSection = data;
+ }
+ } else if (name == "debug_types") {
+ // Find debug_types data by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ TypesSections[Section].Data = data;
+ } else if (name == "debug_types.dwo") {
+ TypesDWOSections[Section].Data = data;
+ }
+
+ section_iterator RelocatedSection = Section.getRelocatedSection();
+ if (RelocatedSection == Obj->section_end())
+ continue;
+
+ StringRef RelSecName;
+ 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) {
+ // Find debug_types relocs by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ if (RelSecName == "debug_types")
+ Map = &TypesSections[*RelocatedSection].Relocs;
+ else if (RelSecName == "debug_types.dwo")
+ Map = &TypesDWOSections[*RelocatedSection].Relocs;
+ else
+ continue;
+ }
+
+ if (Section.relocation_begin() != Section.relocation_end()) {
+ uint64_t SectionSize;
+ RelocatedSection->getSize(SectionSize);
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ uint64_t Address;
+ Reloc.getOffset(Address);
+ uint64_t Type;
+ Reloc.getType(Type);
+ uint64_t SymAddr = 0;
+ // ELF relocations may need the symbol address
+ if (Obj->isELF()) {
+ object::symbol_iterator Sym = Reloc.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, 0, SymAddr));
+ if (V.error()) {
+ SmallString<32> Name;
+ error_code ec(Reloc.getTypeName(Name));
+ if (ec) {
+ errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n";
}
- sys::path::append(absFileName, fileName.str());
- fileName = absFileName;
+ 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;
}
- line = row.Line;
- column = row.Column;
+ 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)));
}
}
}
- return DILineInfo(fileName, functionName, line, column);
}
void DWARFContextInMemory::anchor() { }