#include <algorithm>
using namespace llvm;
using namespace dwarf;
+typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
DWARFDebugLine::Prologue::Prologue() {
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) {
- // Record the beginning of instruction sequence.
- Sequence::Empty = false;
- Sequence::LowPC = Address;
- Sequence::FirstRowIndex = row;
- }
- ++row; // Increase the row number.
- LineTable::appendRow(*this);
- if (EndSequence) {
- // Record the end of instruction sequence.
- Sequence::HighPC = Address;
- Sequence::LastRowIndex = row;
- if (Sequence::isValid())
- LineTable::appendSequence(*this);
- Sequence::reset();
- }
- Row::postAppend();
+void DWARFDebugLine::ParsingState::resetRowAndSequence() {
+ Row.reset(LineTable->Prologue.DefaultIsStmt);
+ Sequence.reset();
}
-void DWARFDebugLine::State::finalize() {
- row = DoneParsingLineTable;
- if (!Sequence::Empty) {
- fprintf(stderr, "warning: last sequence in debug line table is not"
- "terminated!\n");
+void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) {
+ if (Sequence.Empty) {
+ // Record the beginning of instruction sequence.
+ Sequence.Empty = false;
+ Sequence.LowPC = Row.Address;
+ Sequence.FirstRowIndex = RowNumber;
}
- // 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).
+ ++RowNumber;
+ LineTable->appendRow(Row);
+ if (Row.EndSequence) {
+ // Record the end of instruction sequence.
+ Sequence.HighPC = Row.Address;
+ Sequence.LastRowIndex = RowNumber;
+ if (Sequence.isValid())
+ LineTable->appendSequence(Sequence);
+ Sequence.reset();
}
-}
-
-DWARFDebugLine::DumpingState::~DumpingState() {}
-
-void DWARFDebugLine::DumpingState::finalize() {
- LineTable::dump(OS);
+ Row.postAppend();
}
const DWARFDebugLine::LineTable *
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);
// 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:
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;
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:
(*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:
// 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;
// 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:
// 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;
//
// 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;
}
bool
DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
- bool NeedsAbsoluteFilePath,
+ const char *CompDir,
+ FileLineInfoKind Kind,
std::string &Result) const {
- if (FileIndex == 0 || FileIndex > Prologue.FileNames.size())
+ if (FileIndex == 0 || FileIndex > Prologue.FileNames.size() ||
+ Kind == FileLineInfoKind::None)
return false;
const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
const char *FileName = Entry.Name;
- if (!NeedsAbsoluteFilePath ||
+ if (Kind != FileLineInfoKind::AbsoluteFilePath ||
sys::path::is_absolute(FileName)) {
Result = FileName;
return true;
}
+
SmallString<16> FilePath;
uint64_t IncludeDirIndex = Entry.DirIdx;
+ const char *IncludeDir = "";
// Be defensive about the contents of Entry.
if (IncludeDirIndex > 0 &&
- IncludeDirIndex <= Prologue.IncludeDirectories.size()) {
- const char *IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1];
- sys::path::append(FilePath, IncludeDir);
- }
- sys::path::append(FilePath, FileName);
+ IncludeDirIndex <= Prologue.IncludeDirectories.size())
+ IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1];
+
+ // We may still need to append compilation directory of compile unit.
+ // We know that FileName is not absolute, the only way to have an
+ // absolute path at this point would be if IncludeDir is absolute.
+ if (CompDir && Kind == FileLineInfoKind::AbsoluteFilePath &&
+ sys::path::is_relative(IncludeDir))
+ sys::path::append(FilePath, CompDir);
+
+ // sys::path::append skips empty strings.
+ sys::path::append(FilePath, IncludeDir, FileName);
Result = FilePath.str();
return true;
}
+
+bool
+DWARFDebugLine::LineTable::getFileLineInfoForAddress(uint64_t Address,
+ const char *CompDir,
+ FileLineInfoKind Kind,
+ DILineInfo &Result) const {
+ // Get the index of row we're looking for in the line table.
+ uint32_t RowIndex = lookupAddress(Address);
+ if (RowIndex == -1U)
+ return false;
+ // Take file number and line/column from the row.
+ const auto &Row = Rows[RowIndex];
+ if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName))
+ return false;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ return true;
+}