[gdb/symtab] Fix line-table end-of-sequence sorting Consider test-case gdb.dwarf2/dw2-ranges-base.exp. It has a line-table for dw2-ranges-base.c like this: ... Line Number Statements: [0x0000014e] Extended opcode 2: set Address to 0x4004ba [0x00000159] Advance Line by 10 to 11 [0x0000015b] Copy [0x0000015c] Advance PC by 12 to 0x4004c6 [0x0000015e] Advance Line by 19 to 30 [0x00000160] Copy [0x00000161] Extended opcode 1: End of Sequence [0x00000164] Extended opcode 2: set Address to 0x4004ae [0x0000016f] Advance Line by 20 to 21 [0x00000171] Copy [0x00000172] Advance PC by 12 to 0x4004ba [0x00000174] Advance Line by 29 to 50 [0x00000176] Copy [0x00000177] Extended opcode 1: End of Sequence [0x0000017a] Extended opcode 2: set Address to 0x4004a7 [0x00000185] Advance Line by 30 to 31 [0x00000187] Copy [0x00000188] Advance PC by 7 to 0x4004ae [0x0000018a] Advance Line by 39 to 70 [0x0000018c] Copy [0x0000018d] Extended opcode 1: End of Sequence ... The Copy followed by End-of-Sequence is as specified in the dwarf assembly, but incorrect. F.i., consider: ... [0x0000015c] Advance PC by 12 to 0x4004c6 [0x0000015e] Advance Line by 19 to 30 [0x00000160] Copy [0x00000161] Extended opcode 1: End of Sequence ... Both the Copy and the End-of-Sequence append a row to the matrix using the same addres: 0x4004c6. The Copy declares a target instruction at that address. The End-of-Sequence declares that the sequence ends before that address. It's a contradiction that the target instruction is both part of the sequence (according to Copy) and not part of the sequence (according to End-of-Sequence). The offending Copy is skipped though by buildsym_compunit::record_line for unrelated reasons. So, if we disable the sorting in buildsym_compunit::end_symtab_with_blockvector, we have: ... INDEX LINE ADDRESS IS-STMT 0 11 0x00000000004004ba Y 1 END 0x00000000004004c6 Y 2 21 0x00000000004004ae Y 3 END 0x00000000004004ba Y 4 31 0x00000000004004a7 Y 5 END 0x00000000004004ae Y ... but if we re-enable the sorting, we have: ... INDEX LINE ADDRESS IS-STMT 0 31 0x00000000004004a7 Y 1 21 0x00000000004004ae Y 2 END 0x00000000004004ae Y 3 11 0x00000000004004ba Y 4 END 0x00000000004004ba Y 5 END 0x00000000004004c6 Y ... which has both: - the contradictory order for the same-address pairs 1/2 and 3/4, as well as - a non-sensical pair of ENDs, while we'd like: ... INDEX LINE ADDRESS IS-STMT 0 31 0x00000000004004a7 Y 1 END 0x00000000004004ae Y 2 21 0x00000000004004ae Y 3 END 0x00000000004004ba Y 4 11 0x00000000004004ba Y 5 END 0x00000000004004c6 Y ... This is a regression since commit 3d92a3e313 "gdb: Don't reorder line table entries too much when sorting", that introduced sorting on address while keeping entries with the same address in pre-sort order, which leads to incorrect results if one of the entries is an End-Of-Sequence. Fix this by handling End-Of-Sequence entries in the sorting function. Tested on x86_64-linux. gdb/ChangeLog: 2020-06-06 Tom de Vries * buildsym.c (buildsym_compunit::end_symtab_with_blockvector): Handle End-Of-Sequence in lte_is_less_than. gdb/testsuite/ChangeLog: 2020-06-06 Tom de Vries * gdb.dwarf2/dw2-ranges-base.exp: Test line-table order. --- gdb/buildsym.c | 4 ++++ gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 33bf6523e9..76f0b54ff6 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -943,6 +943,10 @@ buildsym_compunit::end_symtab_with_blockvector (struct block *static_block, = [] (const linetable_entry &ln1, const linetable_entry &ln2) -> bool { + if (ln1.pc == ln2.pc + && ((ln1.line == 0) != (ln2.line == 0))) + return ln1.line == 0 ? true : false; + return (ln1.pc < ln2.pc); }; diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp index 92f8f6cecb..39281a8857 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp @@ -144,12 +144,26 @@ gdb_test "info line frame3" \ # Ensure that the line table correctly tracks the end of sequence markers. set end_seq_count 0 +set prev -1 +set seq_count 0 gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \ "count END markers in line table" { -re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" { + if { $prev != -1 } { + gdb_assert "$prev == 1" \ + "prev of normal entry at $seq_count is end marker" + } + set prev 0 + incr seq_count exp_continue } -re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" { + if { $prev != -1 } { + gdb_assert "$prev == 0" \ + "prev of end marker at $seq_count is normal entry" + } + set prev 1 + incr seq_count incr end_seq_count exp_continue }