llvm.org GIT mirror llvm / 351f83b
Fix the representation of debug line table in DebugInfo LLVM library, and "instruction address -> file/line" lookup. Instead of plain collection of rows, debug line table for compilation unit is now treated as the number of row ranges, describing sequences (series of contiguous machine instructions). The sequences are not always listed in the order of increasing address, so previously used std::lower_bound() sometimes produced wrong results. Now the instruction address lookup consists of two stages: finding the correct sequence, and searching for address in range of rows for this sequence. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161414 91177308-0d34-0410-b5e6-96231b3b80d8 Alexey Samsonov 7 years ago
5 changed file(s) with 147 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
166166 const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
167167 if (lineTable) {
168168 // Get the index of the row we're looking for in the line table.
169 uint64_t hiPC = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(
170 cu, DW_AT_high_pc, -1ULL);
171 uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
169 uint32_t rowIndex = lineTable->lookupAddress(address);
172170 if (rowIndex != -1U) {
173171 const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
174172 // Take file/line info from the line table.
9494 DWARFDebugLine::State::~State() {}
9595
9696 void DWARFDebugLine::State::appendRowToMatrix(uint32_t offset) {
97 if (Sequence::Empty) {
98 // Record the beginning of instruction sequence.
99 Sequence::Empty = false;
100 Sequence::LowPC = Address;
101 Sequence::FirstRowIndex = row;
102 }
97103 ++row; // Increase the row number.
98104 LineTable::appendRow(*this);
105 if (EndSequence) {
106 // Record the end of instruction sequence.
107 Sequence::HighPC = Address;
108 Sequence::LastRowIndex = row;
109 if (Sequence::isValid())
110 LineTable::appendSequence(*this);
111 Sequence::reset();
112 }
99113 Row::postAppend();
100114 }
101115
116 void DWARFDebugLine::State::finalize() {
117 row = DoneParsingLineTable;
118 if (!Sequence::Empty) {
119 fprintf(stderr, "warning: last sequence in debug line table is not"
120 "terminated!\n");
121 }
122 // Sort all sequences so that address lookup will work faster.
123 if (!Sequences.empty()) {
124 std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC);
125 // Note: actually, instruction address ranges of sequences should not
126 // overlap (in shared objects and executables). If they do, the address
127 // lookup would still work, though, but result would be ambiguous.
128 // We don't report warning in this case. For example,
129 // sometimes .so compiled from multiple object files contains a few
130 // rudimentary sequences for address ranges [0x0, 0xsomething).
131 }
132 }
133
102134 DWARFDebugLine::DumpingState::~DumpingState() {}
103135
104 void DWARFDebugLine::DumpingState::finalize(uint32_t offset) {
136 void DWARFDebugLine::DumpingState::finalize() {
105137 LineTable::dump(OS);
106138 }
107139
179211 fprintf(stderr, "warning: parsing line table prologue at 0x%8.8x should"
180212 " have ended at 0x%8.8x but it ended ad 0x%8.8x\n",
181213 prologue_offset, end_prologue_offset, *offset_ptr);
182 }
183 return end_prologue_offset;
214 return false;
215 }
216 return true;
184217 }
185218
186219 bool
429462 }
430463 }
431464
432 state.finalize(*offset_ptr);
465 state.finalize();
433466
434467 return end_offset;
435468 }
436469
437 static bool findMatchingAddress(const DWARFDebugLine::Row& row1,
438 const DWARFDebugLine::Row& row2) {
439 return row1.Address < row2.Address;
440 }
441
442470 uint32_t
443 DWARFDebugLine::LineTable::lookupAddress(uint64_t address,
444 uint64_t cu_high_pc) const {
445 uint32_t index = UINT32_MAX;
446 if (!Rows.empty()) {
447 // Use the lower_bound algorithm to perform a binary search since we know
448 // that our line table data is ordered by address.
449 DWARFDebugLine::Row row;
450 row.Address = address;
451 typedef std::vector::const_iterator iterator;
452 iterator begin_pos = Rows.begin();
453 iterator end_pos = Rows.end();
454 iterator pos = std::lower_bound(begin_pos, end_pos, row,
455 findMatchingAddress);
456 if (pos == end_pos) {
457 if (address < cu_high_pc)
458 return Rows.size()-1;
459 } else {
460 // Rely on fact that we are using a std::vector and we can do
461 // pointer arithmetic to find the row index (which will be one less
462 // that what we found since it will find the first position after
463 // the current address) since std::vector iterators are just
464 // pointers to the container type.
465 index = pos - begin_pos;
466 if (pos->Address > address) {
467 if (index > 0)
468 --index;
469 else
470 index = UINT32_MAX;
471 }
472 }
473 }
474 return index; // Failed to find address.
475 }
471 DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const {
472 uint32_t unknown_index = UINT32_MAX;
473 if (Sequences.empty())
474 return unknown_index;
475 // First, find an instruction sequence containing the given address.
476 DWARFDebugLine::Sequence sequence;
477 sequence.LowPC = address;
478 SequenceIter first_seq = Sequences.begin();
479 SequenceIter last_seq = Sequences.end();
480 SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
481 DWARFDebugLine::Sequence::orderByLowPC);
482 DWARFDebugLine::Sequence found_seq;
483 if (seq_pos == last_seq) {
484 found_seq = Sequences.back();
485 } else if (seq_pos->LowPC == address) {
486 found_seq = *seq_pos;
487 } else {
488 if (seq_pos == first_seq)
489 return unknown_index;
490 found_seq = *(seq_pos - 1);
491 }
492 if (!found_seq.containsPC(address))
493 return unknown_index;
494 // Search for instruction address in the rows describing the sequence.
495 // Rows are stored in a vector, so we may use arithmetical operations with
496 // iterators.
497 DWARFDebugLine::Row row;
498 row.Address = address;
499 RowIter first_row = Rows.begin() + found_seq.FirstRowIndex;
500 RowIter last_row = Rows.begin() + found_seq.LastRowIndex;
501 RowIter row_pos = std::lower_bound(first_row, last_row, row,
502 DWARFDebugLine::Row::orderByAddress);
503 if (row_pos == last_row) {
504 return found_seq.LastRowIndex - 1;
505 }
506 uint32_t index = found_seq.FirstRowIndex + (row_pos - first_row);
507 if (row_pos->Address > address) {
508 if (row_pos == first_row)
509 return unknown_index;
510 else
511 index--;
512 }
513 return index;
514 }
8686 void postAppend();
8787 void reset(bool default_is_stmt);
8888 void dump(raw_ostream &OS) const;
89
90 static bool orderByAddress(const Row& LHS, const Row& RHS) {
91 return LHS.Address < RHS.Address;
92 }
8993
9094 // The program-counter value corresponding to a machine instruction
9195 // generated by the compiler.
124128 EpilogueBegin:1;
125129 };
126130
131 // Represents a series of contiguous machine instructions. Line table for each
132 // compilation unit may consist of multiple sequences, which are not
133 // guaranteed to be in the order of ascending instruction address.
134 struct Sequence {
135 // Sequence describes instructions at address range [LowPC, HighPC)
136 // and is described by line table rows [FirstRowIndex, LastRowIndex).
137 uint64_t LowPC;
138 uint64_t HighPC;
139 unsigned FirstRowIndex;
140 unsigned LastRowIndex;
141 bool Empty;
142
143 Sequence() { reset(); }
144 void reset() {
145 LowPC = 0;
146 HighPC = 0;
147 FirstRowIndex = 0;
148 LastRowIndex = 0;
149 Empty = true;
150 }
151 static bool orderByLowPC(const Sequence& LHS, const Sequence& RHS) {
152 return LHS.LowPC < RHS.LowPC;
153 }
154 bool isValid() const {
155 return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex);
156 }
157 bool containsPC(uint64_t pc) const {
158 return (LowPC <= pc && pc < HighPC);
159 }
160 };
161
127162 struct LineTable {
128163 void appendRow(const DWARFDebugLine::Row &state) { Rows.push_back(state); }
164 void appendSequence(const DWARFDebugLine::Sequence &sequence) {
165 Sequences.push_back(sequence);
166 }
129167 void clear() {
130168 Prologue.clear();
131169 Rows.clear();
132 }
133
134 uint32_t lookupAddress(uint64_t address, uint64_t cu_high_pc) const;
170 Sequences.clear();
171 }
172
173 // Returns the index of the row with file/line info for a given address,
174 // or -1 if there is no such row.
175 uint32_t lookupAddress(uint64_t address) const;
135176 void dump(raw_ostream &OS) const;
136177
137178 struct Prologue Prologue;
138 std::vector Rows;
139 };
140
141 struct State : public Row, public LineTable {
179 typedef std::vector RowVector;
180 typedef RowVector::const_iterator RowIter;
181 typedef std::vector SequenceVector;
182 typedef SequenceVector::const_iterator SequenceIter;
183 RowVector Rows;
184 SequenceVector Sequences;
185 };
186
187 struct State : public Row, public Sequence, public LineTable {
142188 // Special row codes.
143189 enum {
144190 StartParsingLineTable = 0,
149195 virtual ~State();
150196
151197 virtual void appendRowToMatrix(uint32_t offset);
152 virtual void finalize(uint32_t offset) { row = DoneParsingLineTable; }
153 virtual void reset() { Row::reset(Prologue.DefaultIsStmt); }
198 virtual void finalize();
199 virtual void reset() {
200 Row::reset(Prologue.DefaultIsStmt);
201 Sequence::reset();
202 }
154203
155204 // The row number that starts at zero for the prologue, and increases for
156205 // each row added to the matrix.
160209 struct DumpingState : public State {
161210 DumpingState(raw_ostream &OS) : OS(OS) {}
162211 virtual ~DumpingState();
163 virtual void finalize(uint32_t offset);
212 virtual void finalize();
164213 private:
165214 raw_ostream &OS;
166215 };
1313 RUN: --address=0x573 --functions | FileCheck %s -check-prefix INCLUDE_TEST_1
1414 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test3.elf-x86-64 \
1515 RUN: --address=0x56d --functions | FileCheck %s -check-prefix INCLUDE_TEST_2
16 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test4.elf-x86-64 \
17 RUN: --address=0x55c --functions \
18 RUN: | FileCheck %s -check-prefix MANY_SEQ_IN_LINE_TABLE
1619
1720 MAIN: main
1821 MAIN-NEXT: /tmp/dbginfo{{[/\\]}}dwarfdump-test.cc:16:10
3740
3841 INCLUDE_TEST_2: _Z3do1v
3942 INCLUDE_TEST_2-NEXT: /tmp/include{{[/\\]}}decl.h:5:0
43
44 MANY_SEQ_IN_LINE_TABLE: _Z1cv
45 MANY_SEQ_IN_LINE_TABLE-NEXT: /tmp/dbginfo/sequences{{[/\\]}}c.cc:2:0