[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

@@ -130,8 +130,9 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
if (stmtOffset != -1U) { if (stmtOffset != -1U) {
DataExtractor lineData(getLineSection().Data, isLittleEndian(), DataExtractor lineData(getLineSection().Data, isLittleEndian(),
savedAddressByteSize); savedAddressByteSize);
DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::LineTable LineTable;
DWARFDebugLine::parseStatementTable(lineData, &getLineSection().Relocs, &stmtOffset, state); LineTable.parse(lineData, &getLineSection().Relocs, &stmtOffset);
LineTable.dump(OS);
} }
} }
} }
@@ -141,9 +142,11 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
unsigned stmtOffset = 0; unsigned stmtOffset = 0;
DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(), DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(),
savedAddressByteSize); savedAddressByteSize);
DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::LineTable LineTable;
while (state.Prologue.parse(lineData, &stmtOffset)) while (LineTable.Prologue.parse(lineData, &stmtOffset)) {
state.finalize(); LineTable.dump(OS);
LineTable.clear();
}
} }
if (DumpType == DIDT_All || DumpType == DIDT_Str) { if (DumpType == DIDT_All || DumpType == DIDT_Str) {

View File

@@ -192,50 +192,34 @@ void DWARFDebugLine::LineTable::clear() {
Sequences.clear(); Sequences.clear();
} }
DWARFDebugLine::State::~State() {} DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
: LineTable(LT), RowNumber(0) {
resetRowAndSequence();
}
void DWARFDebugLine::State::appendRowToMatrix(uint32_t offset) { void DWARFDebugLine::ParsingState::resetRowAndSequence() {
if (Sequence::Empty) { Row.reset(LineTable->Prologue.DefaultIsStmt);
Sequence.reset();
}
void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) {
if (Sequence.Empty) {
// Record the beginning of instruction sequence. // Record the beginning of instruction sequence.
Sequence::Empty = false; Sequence.Empty = false;
Sequence::LowPC = Address; Sequence.LowPC = Row.Address;
Sequence::FirstRowIndex = row; Sequence.FirstRowIndex = RowNumber;
} }
++row; // Increase the row number. ++RowNumber;
LineTable::appendRow(*this); LineTable->appendRow(Row);
if (EndSequence) { if (Row.EndSequence) {
// Record the end of instruction sequence. // Record the end of instruction sequence.
Sequence::HighPC = Address; Sequence.HighPC = Row.Address;
Sequence::LastRowIndex = row; Sequence.LastRowIndex = RowNumber;
if (Sequence::isValid()) if (Sequence.isValid())
LineTable::appendSequence(*this); LineTable->appendSequence(Sequence);
Sequence::reset(); Sequence.reset();
} }
Row::postAppend(); 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);
} }
const DWARFDebugLine::LineTable * const DWARFDebugLine::LineTable *
@@ -251,33 +235,31 @@ DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data,
uint32_t offset) { uint32_t offset) {
std::pair<LineTableIter, bool> pos = std::pair<LineTableIter, bool> pos =
LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable())); LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable()));
LineTable *LT = &pos.first->second;
if (pos.second) { if (pos.second) {
// Parse and cache the line table for at this offset. if (!LT->parse(debug_line_data, RelocMap, &offset))
State state;
if (!parseStatementTable(debug_line_data, RelocMap, &offset, state))
return nullptr; return nullptr;
pos.first->second = state;
} }
return &pos.first->second; return LT;
} }
bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data, bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data,
const RelocAddrMap *RMap, const RelocAddrMap *RMap,
uint32_t *offset_ptr, State &state) { uint32_t *offset_ptr) {
const uint32_t debug_line_offset = *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! // Restore our offset and return false to indicate failure!
*offset_ptr = debug_line_offset; *offset_ptr = debug_line_offset;
return false; return false;
} }
const uint32_t end_offset = debug_line_offset + prologue->TotalLength + const uint32_t end_offset = debug_line_offset + Prologue.TotalLength +
sizeof(prologue->TotalLength); sizeof(Prologue.TotalLength);
state.reset(); ParsingState State(this);
while (*offset_ptr < end_offset) { while (*offset_ptr < end_offset) {
uint8_t opcode = debug_line_data.getU8(offset_ptr); 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 // with a DW_LNE_end_sequence instruction which creates a row whose
// address is that of the byte after the last target machine instruction // address is that of the byte after the last target machine instruction
// of the sequence. // of the sequence.
state.EndSequence = true; State.Row.EndSequence = true;
state.appendRowToMatrix(*offset_ptr); State.appendRowToMatrix(*offset_ptr);
state.reset(); State.resetRowAndSequence();
break; break;
case DW_LNE_set_address: case DW_LNE_set_address:
@@ -316,9 +298,10 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr); RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr);
if (AI != RMap->end()) { if (AI != RMap->end()) {
const std::pair<uint8_t, int64_t> &R = AI->second; 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 } else
state.Address = debug_line_data.getAddress(offset_ptr); State.Row.Address = debug_line_data.getAddress(offset_ptr);
} }
break; break;
@@ -349,12 +332,12 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr);
fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr);
fileEntry.Length = 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; break;
case DW_LNE_set_discriminator: case DW_LNE_set_discriminator:
state.Discriminator = debug_line_data.getULEB128(offset_ptr); State.Row.Discriminator = debug_line_data.getULEB128(offset_ptr);
break; break;
default: default:
@@ -363,52 +346,52 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
(*offset_ptr) += arg_size; (*offset_ptr) += arg_size;
break; break;
} }
} else if (opcode < prologue->OpcodeBase) { } else if (opcode < Prologue.OpcodeBase) {
switch (opcode) { switch (opcode) {
// Standard Opcodes // Standard Opcodes
case DW_LNS_copy: case DW_LNS_copy:
// Takes no arguments. Append a row to the matrix using the // Takes no arguments. Append a row to the matrix using the
// current values of the state-machine registers. Then set // current values of the state-machine registers. Then set
// the basic_block register to false. // the basic_block register to false.
state.appendRowToMatrix(*offset_ptr); State.appendRowToMatrix(*offset_ptr);
break; break;
case DW_LNS_advance_pc: case DW_LNS_advance_pc:
// Takes a single unsigned LEB128 operand, multiplies it by the // Takes a single unsigned LEB128 operand, multiplies it by the
// min_inst_length field of the prologue, and adds the // min_inst_length field of the prologue, and adds the
// result to the address register of the state machine. // result to the address register of the state machine.
state.Address += debug_line_data.getULEB128(offset_ptr) * State.Row.Address +=
prologue->MinInstLength; debug_line_data.getULEB128(offset_ptr) * Prologue.MinInstLength;
break; break;
case DW_LNS_advance_line: case DW_LNS_advance_line:
// Takes a single signed LEB128 operand and adds that value to // Takes a single signed LEB128 operand and adds that value to
// the line register of the state machine. // 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; break;
case DW_LNS_set_file: case DW_LNS_set_file:
// Takes a single unsigned LEB128 operand and stores it in the file // Takes a single unsigned LEB128 operand and stores it in the file
// register of the state machine. // register of the state machine.
state.File = debug_line_data.getULEB128(offset_ptr); State.Row.File = debug_line_data.getULEB128(offset_ptr);
break; break;
case DW_LNS_set_column: case DW_LNS_set_column:
// Takes a single unsigned LEB128 operand and stores it in the // Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine. // column register of the state machine.
state.Column = debug_line_data.getULEB128(offset_ptr); State.Row.Column = debug_line_data.getULEB128(offset_ptr);
break; break;
case DW_LNS_negate_stmt: case DW_LNS_negate_stmt:
// Takes no arguments. Set the is_stmt register of the state // Takes no arguments. Set the is_stmt register of the state
// machine to the logical negation of its current value. // machine to the logical negation of its current value.
state.IsStmt = !state.IsStmt; State.Row.IsStmt = !State.Row.IsStmt;
break; break;
case DW_LNS_set_basic_block: case DW_LNS_set_basic_block:
// Takes no arguments. Set the basic_block register of the // Takes no arguments. Set the basic_block register of the
// state machine to true // state machine to true
state.BasicBlock = true; State.Row.BasicBlock = true;
break; break;
case DW_LNS_const_add_pc: 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 // than twice that range will it need to use both DW_LNS_advance_pc
// and a special opcode, requiring three or more bytes. // and a special opcode, requiring three or more bytes.
{ {
uint8_t adjust_opcode = 255 - prologue->OpcodeBase; uint8_t adjust_opcode = 255 - Prologue.OpcodeBase;
uint64_t addr_offset = (adjust_opcode / prologue->LineRange) * uint64_t addr_offset =
prologue->MinInstLength; (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength;
state.Address += addr_offset; State.Row.Address += addr_offset;
} }
break; break;
@@ -441,25 +424,25 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// judge when the computation of a special opcode overflows and // judge when the computation of a special opcode overflows and
// requires the use of DW_LNS_advance_pc. Such assemblers, however, // requires the use of DW_LNS_advance_pc. Such assemblers, however,
// can use DW_LNS_fixed_advance_pc instead, sacrificing compression. // 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; break;
case DW_LNS_set_prologue_end: case DW_LNS_set_prologue_end:
// Takes no arguments. Set the prologue_end register of the // Takes no arguments. Set the prologue_end register of the
// state machine to true // state machine to true
state.PrologueEnd = true; State.Row.PrologueEnd = true;
break; break;
case DW_LNS_set_epilogue_begin: case DW_LNS_set_epilogue_begin:
// Takes no arguments. Set the basic_block register of the // Takes no arguments. Set the basic_block register of the
// state machine to true // state machine to true
state.EpilogueBegin = true; State.Row.EpilogueBegin = true;
break; break;
case DW_LNS_set_isa: case DW_LNS_set_isa:
// Takes a single unsigned LEB128 operand and stores it in the // Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine. // column register of the state machine.
state.Isa = debug_line_data.getULEB128(offset_ptr); State.Row.Isa = debug_line_data.getULEB128(offset_ptr);
break; break;
default: default:
@@ -467,9 +450,9 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// of such opcodes because they are specified in the prologue // of such opcodes because they are specified in the prologue
// as a multiple of LEB128 operands for each opcode. // as a multiple of LEB128 operands for each opcode.
{ {
assert(opcode - 1U < prologue->StandardOpcodeLengths.size()); assert(opcode - 1U < Prologue.StandardOpcodeLengths.size());
uint8_t opcode_length = prologue->StandardOpcodeLengths[opcode - 1]; uint8_t opcode_length = Prologue.StandardOpcodeLengths[opcode - 1];
for (uint8_t i=0; i<opcode_length; ++i) for (uint8_t i = 0; i < opcode_length; ++i)
debug_line_data.getULEB128(offset_ptr); debug_line_data.getULEB128(offset_ptr);
} }
break; break;
@@ -508,18 +491,32 @@ bool DWARFDebugLine::parseStatementTable(DataExtractor debug_line_data,
// //
// line increment = line_base + (adjusted opcode % line_range) // line increment = line_base + (adjusted opcode % line_range)
uint8_t adjust_opcode = opcode - prologue->OpcodeBase; uint8_t adjust_opcode = opcode - Prologue.OpcodeBase;
uint64_t addr_offset = (adjust_opcode / prologue->LineRange) * uint64_t addr_offset =
prologue->MinInstLength; (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength;
int32_t line_offset = prologue->LineBase + int32_t line_offset =
(adjust_opcode % prologue->LineRange); Prologue.LineBase + (adjust_opcode % Prologue.LineRange);
state.Line += line_offset; State.Row.Line += line_offset;
state.Address += addr_offset; State.Row.Address += addr_offset;
state.appendRowToMatrix(*offset_ptr); 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; return end_offset;
} }

View File

@@ -185,6 +185,10 @@ public:
void dump(raw_ostream &OS) const; void dump(raw_ostream &OS) const;
void clear(); void clear();
/// Parse prologue and all rows.
bool parse(DataExtractor debug_line_data, const RelocAddrMap *RMap,
uint32_t *offset_ptr);
struct Prologue Prologue; struct Prologue Prologue;
typedef std::vector<Row> RowVector; typedef std::vector<Row> RowVector;
typedef RowVector::const_iterator RowIter; typedef RowVector::const_iterator RowIter;
@@ -194,46 +198,26 @@ public:
SequenceVector Sequences; SequenceVector Sequences;
}; };
struct State : public Row, public Sequence, public LineTable {
// Special row codes.
enum {
StartParsingLineTable = 0,
DoneParsingLineTable = -1
};
State() : row(StartParsingLineTable) {}
virtual ~State();
virtual void appendRowToMatrix(uint32_t offset);
virtual void finalize();
virtual void reset() {
Row::reset(Prologue.DefaultIsStmt);
Sequence::reset();
}
// 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 ~DumpingState();
void finalize() override;
private:
raw_ostream &OS;
};
/// Parse a single line table (prologue and all rows).
static bool parseStatementTable(DataExtractor debug_line_data,
const RelocAddrMap *RMap,
uint32_t *offset_ptr, State &state);
const LineTable *getLineTable(uint32_t offset) const; const LineTable *getLineTable(uint32_t offset) const;
const LineTable *getOrParseLineTable(DataExtractor debug_line_data, const LineTable *getOrParseLineTable(DataExtractor debug_line_data,
uint32_t offset); uint32_t offset);
private: private:
struct ParsingState {
ParsingState(struct LineTable *LT);
void resetRowAndSequence();
void appendRowToMatrix(uint32_t offset);
// Line table we're currently parsing.
struct LineTable *LineTable;
// The row number that starts at zero for the prologue, and increases for
// each row added to the matrix.
unsigned RowNumber;
struct Row Row;
struct Sequence Sequence;
};
typedef std::map<uint32_t, LineTable> LineTableMapTy; typedef std::map<uint32_t, LineTable> LineTableMapTy;
typedef LineTableMapTy::iterator LineTableIter; typedef LineTableMapTy::iterator LineTableIter;
typedef LineTableMapTy::const_iterator LineTableConstIter; typedef LineTableMapTy::const_iterator LineTableConstIter;