[DWARF parser] Cleanup code in DWARFDebugLine.

Streamline parsing and dumping line tables:
Prefer composition to multiple inheritance in DWARFDebugLine::ParsingState.
Get rid of the weird concept of "DumpingState" structure.

was:
  DWARFDebugLine::DumpingState state(OS);
  DWARFDebugLine::parseStatementTable(..., state);
now:
  DWARFDebugLine::LineTable LineTable;
  LineTable.parse(...);
  LineTable.dump(OS);

No functionality change.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207599 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alexey Samsonov
2014-04-30 00:09:19 +00:00
parent 9902128e2a
commit 1ea858937c
3 changed files with 112 additions and 128 deletions

View File

@@ -192,50 +192,34 @@ void DWARFDebugLine::LineTable::clear() {
Sequences.clear();
}
DWARFDebugLine::State::~State() {}
DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
: LineTable(LT), RowNumber(0) {
resetRowAndSequence();
}
void DWARFDebugLine::State::appendRowToMatrix(uint32_t offset) {
if (Sequence::Empty) {
void DWARFDebugLine::ParsingState::resetRowAndSequence() {
Row.reset(LineTable->Prologue.DefaultIsStmt);
Sequence.reset();
}
void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) {
if (Sequence.Empty) {
// Record the beginning of instruction sequence.
Sequence::Empty = false;
Sequence::LowPC = Address;
Sequence::FirstRowIndex = row;
Sequence.Empty = false;
Sequence.LowPC = Row.Address;
Sequence.FirstRowIndex = RowNumber;
}
++row; // Increase the row number.
LineTable::appendRow(*this);
if (EndSequence) {
++RowNumber;
LineTable->appendRow(Row);
if (Row.EndSequence) {
// Record the end of instruction sequence.
Sequence::HighPC = Address;
Sequence::LastRowIndex = row;
if (Sequence::isValid())
LineTable::appendSequence(*this);
Sequence::reset();
Sequence.HighPC = Row.Address;
Sequence.LastRowIndex = RowNumber;
if (Sequence.isValid())
LineTable->appendSequence(Sequence);
Sequence.reset();
}
Row::postAppend();
}
void DWARFDebugLine::State::finalize() {
row = DoneParsingLineTable;
if (!Sequence::Empty) {
fprintf(stderr, "warning: last sequence in debug line table is not"
"terminated!\n");
}
// Sort all sequences so that address lookup will work faster.
if (!Sequences.empty()) {
std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC);
// Note: actually, instruction address ranges of sequences should not
// overlap (in shared objects and executables). If they do, the address
// lookup would still work, though, but result would be ambiguous.
// We don't report warning in this case. For example,
// sometimes .so compiled from multiple object files contains a few
// rudimentary sequences for address ranges [0x0, 0xsomething).
}
}
DWARFDebugLine::DumpingState::~DumpingState() {}
void DWARFDebugLine::DumpingState::finalize() {
LineTable::dump(OS);
Row.postAppend();
}
const DWARFDebugLine::LineTable *
@@ -251,33 +235,31 @@ DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data,
uint32_t offset) {
std::pair<LineTableIter, bool> pos =
LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable()));
LineTable *LT = &pos.first->second;
if (pos.second) {
// Parse and cache the line table for at this offset.
State state;
if (!parseStatementTable(debug_line_data, RelocMap, &offset, state))
if (!LT->parse(debug_line_data, RelocMap, &offset))
return nullptr;
pos.first->second = state;
}
return &pos.first->second;
return LT;
}
bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
const RelocAddrMap *RMap,
uint32_t *offset_ptr, State &state) {
bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
const RelocAddrMap *RMap,
uint32_t *offset_ptr) {
const uint32_t debug_line_offset = *offset_ptr;
Prologue *prologue = &state.Prologue;
clear();
if (!prologue->parse(debug_line_data, offset_ptr)) {
if (!Prologue.parse(debug_line_data, offset_ptr)) {
// 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);
const uint32_t end_offset = debug_line_offset + Prologue.TotalLength +
sizeof(Prologue.TotalLength);
state.reset();
ParsingState State(this);
while (*offset_ptr < end_offset) {
uint8_t opcode = debug_line_data.getU8(offset_ptr);
@@ -299,9 +281,9 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// 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();
State.Row.EndSequence = true;
State.appendRowToMatrix(*offset_ptr);
State.resetRowAndSequence();
break;
case DW_LNE_set_address:
@@ -316,9 +298,10 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr);
if (AI != RMap->end()) {
const std::pair<uint8_t, int64_t> &R = AI->second;
state.Address = debug_line_data.getAddress(offset_ptr) + R.second;
State.Row.Address =
debug_line_data.getAddress(offset_ptr) + R.second;
} else
state.Address = debug_line_data.getAddress(offset_ptr);
State.Row.Address = debug_line_data.getAddress(offset_ptr);
}
break;
@@ -349,12 +332,12 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
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);
Prologue.FileNames.push_back(fileEntry);
}
break;
case DW_LNE_set_discriminator:
state.Discriminator = debug_line_data.getULEB128(offset_ptr);
State.Row.Discriminator = debug_line_data.getULEB128(offset_ptr);
break;
default:
@@ -363,52 +346,52 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
(*offset_ptr) += arg_size;
break;
}
} else if (opcode < prologue->OpcodeBase) {
} 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);
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;
State.Row.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);
State.Row.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);
State.Row.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);
State.Row.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;
State.Row.IsStmt = !State.Row.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;
State.Row.BasicBlock = true;
break;
case DW_LNS_const_add_pc:
@@ -424,10 +407,10 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// 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;
uint8_t adjust_opcode = 255 - Prologue.OpcodeBase;
uint64_t addr_offset =
(adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength;
State.Row.Address += addr_offset;
}
break;
@@ -441,25 +424,25 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// 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);
State.Row.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;
State.Row.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;
State.Row.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);
State.Row.Isa = debug_line_data.getULEB128(offset_ptr);
break;
default:
@@ -467,9 +450,9 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// of such opcodes because they are specified in the prologue
// as a multiple of LEB128 operands for each opcode.
{
assert(opcode - 1U < prologue->StandardOpcodeLengths.size());
uint8_t opcode_length = prologue->StandardOpcodeLengths[opcode - 1];
for (uint8_t i=0; i<opcode_length; ++i)
assert(opcode - 1U < 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;
@@ -508,18 +491,32 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
//
// 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);
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.Row.Line += line_offset;
State.Row.Address += addr_offset;
State.appendRowToMatrix(*offset_ptr);
}
}
state.finalize();
if (!State.Sequence.Empty) {
fprintf(stderr, "warning: last sequence in debug line table is not"
"terminated!\n");
}
// Sort all sequences so that address lookup will work faster.
if (!Sequences.empty()) {
std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC);
// Note: actually, instruction address ranges of sequences should not
// overlap (in shared objects and executables). If they do, the address
// lookup would still work, though, but result would be ambiguous.
// We don't report warning in this case. For example,
// sometimes .so compiled from multiple object files contains a few
// rudimentary sequences for address ranges [0x0, 0xsomething).
}
return end_offset;
}