+2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * 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 <andrew.burgess@embecosm.com>
* dwarf2read.c (lnp_state_machine::record_line): Include
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;
-}
\f
/* 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
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. */
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
+2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.dwarf2/dw2-inline-stepping.c: New file.
+ * gdb.dwarf2/dw2-inline-stepping.exp: New file.
+
2020-01-24 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.base/maint.exp: Update line table parsing test.
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+/* 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 */
--- /dev/null
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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'"
+}