llvm-6502/lib/DebugInfo/DWARFContext.cpp
Eric Christopher 82de10a34c Extend the dumping infrastructure to deal with additional
sections for debug info. These are some of the dwo sections from the
DWARF5 split debug info proposal. Update the fission-cu.ll testcase
to show what we should be able to dump more of now.

Work in progress: Ultimately the relocations will be gone for the
dwo section and the strings will be a different form (as well as
the rest of the sections will be included).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171428 91177308-0d34-0410-b5e6-96231b3b80d8
2013-01-02 23:52:13 +00:00

445 lines
16 KiB
C++

//===-- 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/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;
using namespace dwarf;
typedef DWARFDebugLine::LineTable DWARFLineTable;
void DWARFContext::dump(raw_ostream &OS) {
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);
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);
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);
}
}
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;
}
}
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 DWARFDebugAranges *DWARFContext::getDebugAranges() {
if (Aranges)
return Aranges.get();
DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
Aranges.reset(new DWARFDebugAranges());
Aranges->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.
Aranges->generate(this);
return Aranges.get();
}
const DWARFLineTable *
DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) {
if (!Line)
Line.reset(new DWARFDebugLine());
unsigned stmtOffset =
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(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(), isLittleEndian(),
cu->getAddressByteSize());
return Line->getOrParseLineTable(lineData, stmtOffset);
}
void DWARFContext::parseCompileUnits() {
uint32_t offset = 0;
const DataExtractor &DIData = DataExtractor(getInfoSection(),
isLittleEndian(), 0);
while (DIData.isValidOffset(offset)) {
CUs.push_back(DWARFCompileUnit(getDebugAbbrev(), getInfoSection(),
getAbbrevSection(), getRangeSection(),
getStringSection(), &infoRelocMap(),
isLittleEndian()));
if (!CUs.back().extract(DIData, &offset)) {
CUs.pop_back();
break;
}
offset = CUs.back().getNextCompileUnitOffset();
}
}
void DWARFContext::parseDWOCompileUnits() {
uint32_t offset = 0;
const DataExtractor &DIData = DataExtractor(getInfoDWOSection(),
isLittleEndian(), 0);
while (DIData.isValidOffset(offset)) {
DWOCUs.push_back(DWARFCompileUnit(getDebugAbbrevDWO(), getInfoDWOSection(),
getAbbrevDWOSection(),
getRangeDWOSection(),
getStringDWOSection(),
&infoDWORelocMap(),
isLittleEndian()));
if (!DWOCUs.back().extract(DIData, &offset)) {
DWOCUs.pop_back();
break;
}
offset = DWOCUs.back().getNextCompileUnitOffset();
}
}
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 DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
CU->getInlinedChainForAddress(Address);
if (InlinedChain.size() > 0) {
const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0];
if (const char *Name = TopFunctionDIE.getSubroutineName(CU))
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);
}
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier) {
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
if (!CU)
return DIInliningInfo();
const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
CU->getInlinedChainForAddress(Address);
if (InlinedChain.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.size(); i != n; i++) {
const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain[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(CU))
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(CU, CallFile, CallLine, CallColumn);
}
}
DILineInfo Frame(StringRef(FileName), StringRef(FunctionName),
Line, Column);
InliningInfo.addFrame(Frame);
}
return InliningInfo;
}
DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
IsLittleEndian(true /* FIXME */) {
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.
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") {
// 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;
// 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
continue;
if (i->begin_relocations() != i->end_relocations()) {
uint64_t SectionSize;
i->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->getAddress(Address);
uint64_t Type;
reloc_i->getType(Type);
object::RelocVisitor V(Obj->getFileFormatName());
// The section address is always 0 for debug sections.
object::RelocToApply R(V.visit(Type, *reloc_i));
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)));
}
}
}
}
void DWARFContextInMemory::anchor() { }