1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
//===-- 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/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;
using namespace dwarf;
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);
OS << "\n.debug_lines contents:\n";
for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) {
DWARFCompileUnit *cu = getCompileUnitAtIndex(i);
unsigned stmtOffset =
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
-1U);
if (stmtOffset != -1U) {
DataExtractor lineData(getLineSection(), isLittleEndian(),
cu->getAddressByteSize());
DWARFDebugLine::DumpingState state(OS);
DWARFDebugLine::parseStatementTable(lineData, &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;
}
}
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 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);
return Aranges.get();
}
const DWARFDebugLine::LineTable *
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 DWARFDebugLine::LineTable *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 &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();
break;
}
offset = CUs.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 *i = std::lower_bound(CUs.begin(), CUs.end(), offset,
OffsetComparator());
if (i != CUs.end())
return &*i;
return 0;
}
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address) {
// First, get the offset of the compile unit.
uint32_t cuOffset = getDebugAranges()->findAddress(address);
// Retrieve the compile unit.
DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset);
if (!cu)
return DILineInfo("<invalid>", 0, 0);
// Get the line table for this compile unit.
const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
if (!lineTable)
return DILineInfo("<invalid>", 0, 0);
// Get the index of the row we're looking for in the line table.
uint64_t hiPC =
cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_high_pc,
-1ULL);
uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
if (rowIndex == -1U)
return DILineInfo("<invalid>", 0, 0);
// From here, contruct the DILineInfo.
const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
const std::string &fileName = lineTable->Prologue.FileNames[row.File-1].Name;
return DILineInfo(fileName.c_str(), row.Line, row.Column);
}
|