diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 82eea3254c..5dd516538a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2020-01-24 Andrew Burgess + + * buildsym.c (lte_is_less_than): Delete. + (buildsym_compunit::end_symtab_with_blockvector): Create local + lambda function to sort line table entries, and use + std::stable_sort instead of std::sort. + * symtab.c (find_pc_sect_line): Skip backward over end of sequence + markers when looking for a previous line. + 2020-01-24 Andrew Burgess * dwarf2read.c (lnp_state_machine::record_line): Include diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 5b2a92c75a..4965b552b3 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -719,23 +719,6 @@ buildsym_compunit::record_line (struct subfile *subfile, int line, e->pc = pc; } -/* Needed in order to sort line tables from IBM xcoff files. Sigh! */ - -static bool -lte_is_less_than (const linetable_entry &ln1, const linetable_entry &ln2) -{ - /* Note: this code does not assume that CORE_ADDRs can fit in ints. - Please keep it that way. */ - if (ln1.pc < ln2.pc) - return true; - - if (ln1.pc > ln2.pc) - return false; - - /* If pc equal, sort by line. I'm not sure whether this is optimum - behavior (see comment at struct linetable in symtab.h). */ - return ln1.line < ln2.line; -} /* Subroutine of end_symtab to simplify it. Look for a subfile that matches the main source file's basename. If there is only one, and @@ -953,14 +936,23 @@ buildsym_compunit::end_symtab_with_blockvector (struct block *static_block, linetablesize = sizeof (struct linetable) + subfile->line_vector->nitems * sizeof (struct linetable_entry); - /* Like the pending blocks, the line table may be - scrambled in reordered executables. Sort it if - OBJF_REORDERED is true. */ + const auto lte_is_less_than + = [] (const linetable_entry &ln1, + const linetable_entry &ln2) -> bool + { + return (ln1.pc < ln2.pc); + }; + + /* Like the pending blocks, the line table may be scrambled in + reordered executables. Sort it if OBJF_REORDERED is true. It + is important to preserve the order of lines at the same + address, as this maintains the inline function caller/callee + relationships, this is why std::stable_sort is used. */ if (m_objfile->flags & OBJF_REORDERED) - std::sort (subfile->line_vector->item, - subfile->line_vector->item - + subfile->line_vector->nitems, - lte_is_less_than); + std::stable_sort (subfile->line_vector->item, + subfile->line_vector->item + + subfile->line_vector->nitems, + lte_is_less_than); } /* Allocate a symbol table if necessary. */ diff --git a/gdb/symtab.c b/gdb/symtab.c index d5ba249ced..f456f4d852 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -3222,7 +3222,12 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) struct linetable_entry *last = item + len; item = std::upper_bound (first, last, pc, pc_compare); if (item != first) - prev = item - 1; /* Found a matching item. */ + { + /* Found a matching item. Skip backwards over any end of + sequence markers. */ + for (prev = item - 1; prev->line == 0 && prev != first; prev--) + /* Nothing. */; + } /* At this point, prev points at the line whose start addr is <= pc, and item points at the next line. If we ran off the end of the linetable diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1a1bc44ccb..07853155db 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-01-24 Andrew Burgess + + * gdb.dwarf2/dw2-inline-stepping.c: New file. + * gdb.dwarf2/dw2-inline-stepping.exp: New file. + 2020-01-24 Andrew Burgess * gdb.base/maint.exp: Update line table parsing test. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.c new file mode 100644 index 0000000000..c32e3d0b3e --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.c @@ -0,0 +1,45 @@ +/* Copyright 2019-2020 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* This test relies on foo being inlined into main and bar not being + inlined. The test is checking GDB's behaviour as we single step from + main through foo and into bar. */ + +volatile int global_var; + +int __attribute__ ((noinline)) +bar () +{ /* bar prologue */ + asm ("bar_label: .globl bar_label"); + return global_var; /* bar return global_var */ +} /* bar end */ + +static inline int __attribute__ ((always_inline)) +foo () +{ /* foo prologue */ + return bar (); /* foo call bar */ +} /* foo end */ + +int +main () +{ /* main prologue */ + int ans; + asm ("main_label: .globl main_label"); + global_var = 0; /* main set global_var */ + asm ("main_label2: .globl main_label2"); + ans = foo (); /* main call foo */ + asm ("main_label3: .globl main_label3"); + return ans; +} /* main end */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.exp new file mode 100644 index 0000000000..81a678243d --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-stepping.exp @@ -0,0 +1,146 @@ +# Copyright 2019-2020 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This test shows the importance of not corrupting the order of line +# table information. When multiple lines are given for the same +# address the compiler usually lists these in the order in which we +# would expect to encounter them. When stepping through nested inline +# frames the last line given for an address is assumed by GDB to be +# the most inner frame, and this is what GDB displays. +# +# If we corrupt the order of the line table entries then GDB will +# display the wrong line as being the inner most frame. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# The .c files use __attribute__. +if [get_compiler_info] { + return -1 +} +if !$gcc_compiled { + return 0 +} + +standard_testfile dw2-inline-stepping.c dw2-inline-stepping.S + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile srcfile2 + declare_labels ranges_label lines_label foo_prog + + lassign [function_range main [list ${srcdir}/${subdir}/$srcfile]] \ + main_start main_len + set main_end "$main_start + $main_len" + lassign [function_range bar [list ${srcdir}/${subdir}/$srcfile]] \ + bar_start bar_len + set bar_end "$bar_start + $bar_len" + + set call_line [gdb_get_line_number "main call foo"] + + cu {} { + compile_unit { + {language @DW_LANG_C} + {name dw2-inline-stepping.c} + {low_pc 0 addr} + {stmt_list ${lines_label} DW_FORM_sec_offset} + {ranges ${ranges_label} DW_FORM_sec_offset} + } { + subprogram { + {external 1 flag} + {name bar} + {low_pc $bar_start addr} + {high_pc "$bar_start + $bar_len" addr} + } + foo_prog: subprogram { + {name foo} + {inline 3 data1} + } + subprogram { + {external 1 flag} + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_len" addr} + } { + inlined_subroutine { + {abstract_origin %$foo_prog} + {low_pc main_label2 addr} + {high_pc main_label3 addr} + {call_file 1 data1} + {call_line $call_line data1} + } + } + } + } + + lines {version 2} lines_label { + include_dir "${srcdir}/${subdir}" + file_name "$srcfile" 1 + + program { + {DW_LNE_set_address $main_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "main prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address main_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "main set global_var"] - [gdb_get_line_number "main prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "main call foo"] - [gdb_get_line_number "main set global_var"]]} + {DW_LNS_copy} + {DW_LNE_set_address main_label2} + {DW_LNS_advance_line [expr [gdb_get_line_number "foo call bar"] - [gdb_get_line_number "main call foo"]]} + {DW_LNS_copy} + {DW_LNE_set_address $main_end} + {DW_LNE_end_sequence} + + {DW_LNE_set_address $bar_start} + {DW_LNS_advance_line [expr [gdb_get_line_number "bar prologue"] - 1]} + {DW_LNS_copy} + {DW_LNE_set_address bar_label} + {DW_LNS_advance_line [expr [gdb_get_line_number "bar return global_var"] - [gdb_get_line_number "bar prologue"]]} + {DW_LNS_copy} + {DW_LNE_set_address $bar_end} + {DW_LNE_end_sequence} + } + } + + ranges {is_64 [is_64_target]} { + ranges_label: sequence { + {range {${main_start}} ${main_end}} + {range {${bar_start}} ${bar_end}} + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +set patterns [list "main call foo" \ + "foo call bar" \ + "bar return global_var"] +foreach p $patterns { + gdb_test "step" "/\\* $p \\*/" \ + "step to '$p'" +}