mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
DWARF: Add basic support for line tables.
The llvm-dwarfdump output isn't very verbose yet. llvm-svn: 139771
This commit is contained in:
parent
2109f34467
commit
ceca872d69
@ -7,6 +7,7 @@ add_llvm_library(LLVMDebugInfo
|
||||
DWARFDebugArangeSet.cpp
|
||||
DWARFDebugAranges.cpp
|
||||
DWARFDebugInfoEntry.cpp
|
||||
DWARFDebugLine.cpp
|
||||
DWARFFormValue.cpp
|
||||
)
|
||||
|
||||
|
@ -25,6 +25,10 @@ void DWARFContext::dump(raw_ostream &OS) {
|
||||
DWARFDebugArangeSet set;
|
||||
while (set.extract(arangesData, &offset))
|
||||
set.dump(OS);
|
||||
|
||||
OS << "\n.debug_lines contents:\n";
|
||||
DataExtractor lineData(getLineSection(), isLittleEndian(), 8);
|
||||
DWARFDebugLine::dump(lineData, OS);
|
||||
}
|
||||
|
||||
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
|
||||
@ -51,6 +55,17 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() {
|
||||
return Aranges.get();
|
||||
}
|
||||
|
||||
const DWARFDebugLine *DWARFContext::getDebugLine() {
|
||||
if (Line)
|
||||
return Line.get();
|
||||
|
||||
DataExtractor lineData(getLineSection(), isLittleEndian(), 0);
|
||||
|
||||
Line.reset(new DWARFDebugLine());
|
||||
Line->parse(lineData);
|
||||
return Line.get();
|
||||
}
|
||||
|
||||
void DWARFContext::parseCompileUnits() {
|
||||
uint32_t offset = 0;
|
||||
const DataExtractor &debug_info_data = DataExtractor(getInfoSection(),
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "DWARFCompileUnit.h"
|
||||
#include "DWARFDebugAranges.h"
|
||||
#include "DWARFDebugLine.h"
|
||||
#include "llvm/DebugInfo/DIContext.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -28,6 +29,7 @@ class DWARFContext : public DIContext {
|
||||
SmallVector<DWARFCompileUnit, 1> CUs;
|
||||
OwningPtr<DWARFDebugAbbrev> Abbrev;
|
||||
OwningPtr<DWARFDebugAranges> Aranges;
|
||||
OwningPtr<DWARFDebugLine> Line;
|
||||
|
||||
DWARFContext(DWARFContext &); // = delete
|
||||
DWARFContext &operator=(DWARFContext &); // = delete
|
||||
@ -57,6 +59,9 @@ public:
|
||||
/// Get a pointer to the parsed DebugAranges object.
|
||||
const DWARFDebugAranges *getDebugAranges();
|
||||
|
||||
/// Get a pointer to the parsed DWARFDebugLine object.
|
||||
const DWARFDebugLine *getDebugLine();
|
||||
|
||||
bool isLittleEndian() const { return IsLittleEndian; }
|
||||
|
||||
virtual StringRef getInfoSection() = 0;
|
||||
|
491
lib/DebugInfo/DWARFDebugLine.cpp
Normal file
491
lib/DebugInfo/DWARFDebugLine.cpp
Normal file
@ -0,0 +1,491 @@
|
||||
//===-- 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/raw_ostream.h"
|
||||
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] %4u ", i+1, fileEntry.DirIdx)
|
||||
<< format("0x%8.8x 0x%8.8x ", 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.16llx %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);
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFDebugLine::State::appendRowToMatrix(uint32_t offset) {
|
||||
++row; // Increase the row number.
|
||||
LineTable::appendRow(*this);
|
||||
Row::postAppend();
|
||||
}
|
||||
|
||||
void DWARFDebugLine::parse(const DataExtractor debug_line_data) {
|
||||
LineTableMap.clear();
|
||||
uint32_t offset = 0;
|
||||
State state;
|
||||
while (debug_line_data.isValidOffset(offset)) {
|
||||
const uint32_t debug_line_offset = offset;
|
||||
|
||||
if (parseStatementTable(debug_line_data, &offset, state)) {
|
||||
// Make sure we don't don't loop infinitely
|
||||
if (offset <= debug_line_offset)
|
||||
break;
|
||||
|
||||
LineTableMap[debug_line_offset] = state;
|
||||
state.reset();
|
||||
}
|
||||
else
|
||||
++offset; // Try next byte in line table
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFDebugLine::DumpingState::finalize(uint32_t offset) {
|
||||
LineTable::dump(OS);
|
||||
}
|
||||
|
||||
void DWARFDebugLine::dump(const DataExtractor debug_line_data, raw_ostream &OS){
|
||||
uint32_t offset = 0;
|
||||
DumpingState state(OS);
|
||||
while (debug_line_data.isValidOffset(offset)) {
|
||||
const uint32_t debug_line_offset = offset;
|
||||
|
||||
if (parseStatementTable(debug_line_data, &offset, state)) {
|
||||
// Make sure we don't don't loop infinitely
|
||||
if (offset <= debug_line_offset)
|
||||
break;
|
||||
|
||||
state.reset();
|
||||
}
|
||||
else
|
||||
++offset; // Try next byte in line table
|
||||
}
|
||||
}
|
||||
|
||||
const DWARFDebugLine::LineTable *
|
||||
DWARFDebugLine::getLineTable(uint32_t offset) const {
|
||||
LineTableConstIter pos = LineTableMap.find(offset);
|
||||
if (pos != LineTableMap.end())
|
||||
return &pos->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 ad 0x%8.8x\n",
|
||||
prologue_offset, end_prologue_offset, *offset_ptr);
|
||||
}
|
||||
return end_prologue_offset;
|
||||
}
|
||||
|
||||
bool
|
||||
DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
|
||||
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);
|
||||
|
||||
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.
|
||||
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 - 1 < 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(*offset_ptr);
|
||||
|
||||
return end_offset;
|
||||
}
|
||||
|
||||
static bool findMatchingAddress(const DWARFDebugLine::Row& row1,
|
||||
const DWARFDebugLine::Row& row2) {
|
||||
return row1.Address < row2.Address;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DWARFDebugLine::LineTable::lookupAddress(uint64_t address,
|
||||
uint64_t cu_high_pc) const {
|
||||
uint32_t index = UINT32_MAX;
|
||||
if (!Rows.empty()) {
|
||||
// Use the lower_bound algorithm to perform a binary search since we know
|
||||
// that our line table data is ordered by address.
|
||||
DWARFDebugLine::Row row;
|
||||
row.Address = address;
|
||||
typedef std::vector<Row>::const_iterator iterator;
|
||||
iterator begin_pos = Rows.begin();
|
||||
iterator end_pos = Rows.end();
|
||||
iterator pos = std::lower_bound(begin_pos, end_pos, row,
|
||||
findMatchingAddress);
|
||||
if (pos == end_pos) {
|
||||
if (address < cu_high_pc)
|
||||
return Rows.size()-1;
|
||||
} else {
|
||||
// Rely on fact that we are using a std::vector and we can do
|
||||
// pointer arithmetic to find the row index (which will be one less
|
||||
// that what we found since it will find the first position after
|
||||
// the current address) since std::vector iterators are just
|
||||
// pointers to the container type.
|
||||
index = pos - begin_pos;
|
||||
if (pos->Address > address) {
|
||||
if (index > 0)
|
||||
--index;
|
||||
else
|
||||
index = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
return index; // Failed to find address.
|
||||
}
|
195
lib/DebugInfo/DWARFDebugLine.h
Normal file
195
lib/DebugInfo/DWARFDebugLine.h
Normal file
@ -0,0 +1,195 @@
|
||||
//===-- 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 "llvm/Support/DataExtractor.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
class DWARFDebugLine {
|
||||
public:
|
||||
struct FileNameEntry {
|
||||
FileNameEntry() : DirIdx(0), ModTime(0), Length(0) {}
|
||||
|
||||
std::string 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<std::string> 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();
|
||||
}
|
||||
bool getFile(uint32_t file_idx, std::string& file, std::string& dir) const;
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
struct LineTable {
|
||||
void appendRow(const DWARFDebugLine::Row &state) { Rows.push_back(state); }
|
||||
void clear() {
|
||||
Prologue.clear();
|
||||
Rows.clear();
|
||||
}
|
||||
|
||||
uint32_t lookupAddress(uint64_t address, uint64_t cu_high_pc) const;
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
struct Prologue Prologue;
|
||||
std::vector<Row> Rows;
|
||||
};
|
||||
|
||||
struct State : public Row, public LineTable {
|
||||
// Special row codes.
|
||||
enum {
|
||||
StartParsingLineTable = 0,
|
||||
DoneParsingLineTable = -1
|
||||
};
|
||||
|
||||
State() : row(0) {}
|
||||
|
||||
virtual void appendRowToMatrix(uint32_t offset);
|
||||
virtual void finalize(uint32_t offset) { row = DoneParsingLineTable; }
|
||||
virtual void reset() { Row::reset(Prologue.DefaultIsStmt); }
|
||||
|
||||
// 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 void finalize(uint32_t offset);
|
||||
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,
|
||||
uint32_t *offset_ptr, State &state);
|
||||
|
||||
/// Parse all information in the debug_line_data into an internal
|
||||
/// representation.
|
||||
void parse(DataExtractor debug_line_data);
|
||||
void parseIfNeeded(DataExtractor debug_line_data) {
|
||||
if (LineTableMap.empty())
|
||||
parse(debug_line_data);
|
||||
}
|
||||
static void dump(DataExtractor debug_line_data, raw_ostream &OS);
|
||||
const LineTable *getLineTable(uint32_t offset) const;
|
||||
|
||||
protected:
|
||||
typedef std::map<uint32_t, LineTable> LineTableMapTy;
|
||||
typedef LineTableMapTy::iterator LineTableIter;
|
||||
typedef LineTableMapTy::const_iterator LineTableConstIter;
|
||||
|
||||
LineTableMapTy LineTableMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -79,7 +79,8 @@ static void DumpInput(const StringRef &Filename) {
|
||||
OwningPtr<DIContext> dictx(DIContext::getDWARFContext(/*FIXME*/true,
|
||||
DebugInfoSection,
|
||||
DebugAbbrevSection,
|
||||
DebugArangesSection));
|
||||
DebugArangesSection,
|
||||
DebugLineSection));
|
||||
dictx->dump(outs());
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user