mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
[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:
parent
9902128e2a
commit
1ea858937c
@ -130,8 +130,9 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
|
||||
if (stmtOffset != -1U) {
|
||||
DataExtractor lineData(getLineSection().Data, isLittleEndian(),
|
||||
savedAddressByteSize);
|
||||
DWARFDebugLine::DumpingState state(OS);
|
||||
DWARFDebugLine::parseStatementTable(lineData, &getLineSection().Relocs, &stmtOffset, state);
|
||||
DWARFDebugLine::LineTable LineTable;
|
||||
LineTable.parse(lineData, &getLineSection().Relocs, &stmtOffset);
|
||||
LineTable.dump(OS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,9 +142,11 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
|
||||
unsigned stmtOffset = 0;
|
||||
DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(),
|
||||
savedAddressByteSize);
|
||||
DWARFDebugLine::DumpingState state(OS);
|
||||
while (state.Prologue.parse(lineData, &stmtOffset))
|
||||
state.finalize();
|
||||
DWARFDebugLine::LineTable LineTable;
|
||||
while (LineTable.Prologue.parse(lineData, &stmtOffset)) {
|
||||
LineTable.dump(OS);
|
||||
LineTable.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Str) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -185,6 +185,10 @@ public:
|
||||
void dump(raw_ostream &OS) const;
|
||||
void clear();
|
||||
|
||||
/// Parse prologue and all rows.
|
||||
bool parse(DataExtractor debug_line_data, const RelocAddrMap *RMap,
|
||||
uint32_t *offset_ptr);
|
||||
|
||||
struct Prologue Prologue;
|
||||
typedef std::vector<Row> RowVector;
|
||||
typedef RowVector::const_iterator RowIter;
|
||||
@ -194,46 +198,26 @@ public:
|
||||
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 *getOrParseLineTable(DataExtractor debug_line_data,
|
||||
uint32_t offset);
|
||||
|
||||
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 LineTableMapTy::iterator LineTableIter;
|
||||
typedef LineTableMapTy::const_iterator LineTableConstIter;
|
||||
|
Loading…
Reference in New Issue
Block a user