#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"
typedef DWARFDebugLine::LineTable DWARFLineTable;
-void DWARFContext::dump(raw_ostream &OS) {
- OS << ".debug_abbrev contents:\n";
- getDebugAbbrev()->dump(OS);
+void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
+ if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
+ OS << ".debug_abbrev contents:\n";
+ getDebugAbbrev()->dump(OS);
+ }
- 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_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_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_line 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 (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, &lineRelocMap(), &stmtOffset, state);
+ }
}
}
- 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_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);
-
- OS << "\n.debug_abbrev.dwo contents:\n";
- getDebugAbbrevDWO()->dump(OS);
-
- OS << "\n.debug_info.dwo contents:\n";
- for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i)
- getDWOCompileUnitAtIndex(i)->dump(OS);
-
- 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) {
+ OS << "\n.debug_pubnames contents:\n";
+ DataExtractor pubNames(getPubNamesSection(), isLittleEndian(), 0);
+ offset = 0;
+ OS << "Length: " << pubNames.getU32(&offset) << "\n";
+ OS << "Version: " << pubNames.getU16(&offset) << "\n";
+ OS << "Offset in .debug_info: " << pubNames.getU32(&offset) << "\n";
+ OS << "Size: " << pubNames.getU32(&offset) << "\n";
+ OS << "\n Offset Name\n";
+ while (offset < getPubNamesSection().size()) {
+ uint32_t n = pubNames.getU32(&offset);
+ if (n == 0)
+ break;
+ OS << format("%8x ", n);
+ OS << pubNames.getCStr(&offset) << "\n";
+ }
}
+
+ 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() {
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());
+ Line.reset(new DWARFDebugLine(&lineRelocMap()));
unsigned stmtOffset =
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
while (DIData.isValidOffset(offset)) {
CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(),
getAbbrevSection(), getRangeSection(),
- getStringSection(), "",
+ getStringSection(), StringRef(),
+ getAddrSection(),
&infoRelocMap(),
isLittleEndian()));
if (!CUs.back().extract(DIData, &offset)) {
getRangeDWOSection(),
getStringDWOSection(),
getStringOffsetDWOSection(),
+ getAddrSection(),
&infoDWORelocMap(),
isLittleEndian()));
if (!DWOCUs.back().extract(DIData, &offset)) {
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 DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
+ CU->getInlinedChainForAddress(Address);
+ if (InlinedChain.size() > 0) {
+ const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0];
+ if (const char *Name = TopFunctionDIE.getSubroutineName(CU))
+ FunctionName = Name;
+ }
+ }
+
+ StringRef FuncNameRef = StringRef(FunctionName);
+
+ // 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(StringRef("<invalid>"),
+ FuncNameRef, 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(StringRef(FileName),
+ FuncNameRef, Row.Line, Row.Column)));
+ }
+
+ return Lines;
+}
+
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier) {
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
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(true /* FIXME */) {
+ IsLittleEndian(Obj->isLittleEndian()),
+ AddressSize(Obj->getBytesInAddress()) {
error_code ec;
for (object::section_iterator i = Obj->begin_sections(),
e = Obj->end_sections();
i->getContents(data);
name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes.
- if (name == "debug_info")
- InfoSection = data;
- else if (name == "debug_abbrev")
- AbbrevSection = data;
- else if (name == "debug_line")
- LineSection = data;
- else if (name == "debug_aranges")
- ARangeSection = data;
- else if (name == "debug_str")
- StringSection = data;
- else if (name == "debug_ranges") {
+
+ // 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)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_line", &LineSection)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_info.dwo", &InfoDWOSection)
+ .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)
+ continue;
+ *Section = data;
+ if (name == "debug_ranges") {
// FIXME: Use the other dwo range section when we emit it.
RangeDWOSection = data;
- RangeSection = data;
}
- else if (name == "debug_info.dwo")
- InfoDWOSection = data;
- else if (name == "debug_abbrev.dwo")
- AbbrevDWOSection = data;
- else if (name == "debug_str.dwo")
- StringDWOSection = data;
- else if (name == "debug_str_offsets.dwo")
- StringOffsetDWOSection = data;
- // Any more debug info sections go here.
- else
- continue;
- // TODO: For now only handle relocations for the debug_info section.
- RelocAddrMap *Map;
- if (name == "debug_info")
- Map = &InfoRelocMap;
- else if (name == "debug_info.dwo")
- Map = &InfoDWORelocMap;
- else
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(name)
+ .Case("debug_info", &InfoRelocMap)
+ .Case("debug_info.dwo", &InfoDWORelocMap)
+ .Case("debug_line", &LineRelocMap)
+ .Default(0);
+ if (!Map)
continue;
if (i->begin_relocations() != i->end_relocations()) {
reloc_e = i->end_relocations();
reloc_i != reloc_e; reloc_i.increment(ec)) {
uint64_t Address;
- reloc_i->getAddress(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::SymbolRef Sym;
+ reloc_i->getSymbol(Sym);
+ 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));
+ object::RelocToApply R(V.visit(Type, *reloc_i, 0, SymAddr));
if (V.error()) {
SmallString<32> Name;
error_code ec(reloc_i->getTypeName(Name));
}
}
+DWARFContextInMemory::~DWARFContextInMemory() {
+ DeleteContainerPointers(UncompressedSections);
+}
+
void DWARFContextInMemory::anchor() { }