[PATCH 2/2] gdb: Preserve is-stmt lines when switch between files
Andrew Burgess
andrew.burgess@embecosm.com
Tue Apr 14 11:28:41 GMT 2020
Bernd,
As requested, rebased version of this patch for your feedback. Sorry
for the delay, I took a short break over Easter.
Apologies for the previous build failure the fix you found was the
only issue, and was caused by a last second choice to rename
'm_stmt_at_addr' to 'm_stmt_at_address', combined with me making a
dumb mistake generating the patch from a slightly broken tree. Please
be assured the patch was fully tested before I did the rename.
The trailing blank lines I have no excuse for.
Changes since previous version:
- Rebase
- Fix m_stmt_at_addr typo
- Delete some trailing blank lines.
I look forward to hearing your thoughts.
Thanks,
Andrew
---
commit cf4bab4672356e190b166e063d2539ddad5eb542
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Fri Apr 3 20:32:38 2020 +0100
gdb: Preserve is-stmt lines when switch between files
After the is-stmt support commit:
commit 8c95582da858ac981f689a6f599acacb8c5c490f
Date: Mon Dec 30 21:04:51 2019 +0000
gdb: Add support for tracking the DWARF line table is-stmt field
A regression was observed where a breakpoint could no longer be placed
in some cases.
Consider a line table like this:
File 1: test.c
File 2: test.h
| Addr | File | Line | Stmt |
|------|------|------|------|
| 1 | 1 | 16 | Y |
| 2 | 1 | 17 | Y |
| 3 | 2 | 21 | Y |
| 4 | 2 | 22 | Y |
| 4 | 1 | 18 | N |
| 5 | 2 | 23 | N |
| 6 | 1 | 24 | Y |
| 7 | 1 | END | Y |
|------|------|------|------|
Before the is-stmt patch GDB would ignore any non-stmt lines, so GDB
built two line table structures:
File 1 File 2
------ ------
| Addr | Line | | Addr | Line |
|------|------| |------|------|
| 1 | 16 | | 3 | 21 |
| 2 | 17 | | 4 | 22 |
| 3 | END | | 6 | END |
| 6 | 24 | |------|------|
| 7 | END |
|------|------|
After the is-stmt patch GDB now records non-stmt lines, so the
generated line table structures look like this:
File 1 File 2
------ ------
| Addr | Line | Stmt | | Addr | Line | Stmt |
|------|------|------| |------|------|------|
| 1 | 16 | Y | | 3 | 21 | Y |
| 2 | 17 | Y | | 4 | 22 | Y |
| 3 | END | Y | | 4 | END | Y |
| 4 | 18 | N | | 5 | 23 | N |
| 5 | END | Y | | 6 | END | Y |
| 6 | 24 | Y | |------|------|------|
| 7 | END | Y |
|------|------|------|
The problem is that in 'File 2', end END marker at address 4 causes
the previous line table entry to be discarded, so we actually end up
with this:
File 2
------
| Addr | Line | Stmt |
|------|------|------|
| 3 | 21 | Y |
| 4 | END | Y |
| 5 | 23 | N |
| 6 | END | Y |
|------|------|------|
When a user tries to place a breakpoint in file 2 at line 22, this is
no longer possible.
The solution I propose here is that we ignore line table entries that
would trigger a change of file if:
1. The new line being added is at the same address as the previous
line, and
2. We have previously seen an is-stmt line at the current address.
The result of this is that GDB switches file, and knows that some line
entry (or entries) are going to be discarded, prefer to keep is-stmt
lines and discard non-stmt lines.
After this commit the lines tables are now:
File 1 File 2
------ ------
| Addr | Line | Stmt | | Addr | Line | Stmt |
|------|------|------| |------|------|------|
| 1 | 16 | Y | | 3 | 21 | Y |
| 2 | 17 | Y | | 4 | 22 | Y |
| 3 | END | Y | | 5 | 23 | N |
| 5 | END | Y | | 6 | END | Y |
| 6 | 24 | Y | |------|------|------|
| 7 | END | Y |
|------|------|------|
We've lost the non-stmt entry for file 1, line 18, but retained the
is-stmt entry for file 2, line 22. The user can now place a
breakpoint at that location.
One problem that came from this commit was the test
gdb.cp/step-and-next-inline.exp, which broke in several places. After
looking at this test again I think that in some cases this test was
only ever passing by pure luck. The debug GCC is producing for this
test is pretty broken. I raised this GCC bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
for this and disabled one entire half of the test. There are still
some cases in here that do pass, and if/when GCC is fixed it would be
great to enable this test again.
gdb/ChangeLog:
* dwarf2/read.c (class lnp_state_machine) <m_last_address>: New
member variable.
<m_stmt_at_address>: New member variable.
(lnp_state_machine::record_line): Don't record some lines, update
tracking of is_stmt at the same address.
(lnp_state_machine::lnp_state_machine): Initialise new member
variables.
gdb/testsuite/ChangeLog:
* gdb.cp/step-and-next-inline.exp (do_test): Skip all tests in the
use_header case.
* gdb.dwarf2/dw2-inline-header-1.exp: New file.
* gdb.dwarf2/dw2-inline-header-2.exp: New file.
* gdb.dwarf2/dw2-inline-header-3.exp: New file.
* gdb.dwarf2/dw2-inline-header-lbls.c: New file.
* gdb.dwarf2/dw2-inline-header.c: New file.
* gdb.dwarf2/dw2-inline-header.h: New file.
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index da702205c60..36e8b24a29a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -19508,6 +19508,15 @@ class lnp_state_machine
/* The last file a line number was recorded for. */
struct subfile *m_last_subfile = NULL;
+ /* The address of the last line entry. */
+ CORE_ADDR m_last_address;
+
+ /* Set to true when a previous line at the same address (using
+ m_last_address) had m_is_stmt true. This is reset to false when a
+ line entry at a new address (m_address different to m_last_address) is
+ processed. */
+ bool m_stmt_at_address = false;
+
/* When true, record the lines we decode. */
bool m_currently_recording_lines = false;
@@ -19701,14 +19710,34 @@ lnp_state_machine::record_line (bool end_sequence)
fe->included_p = 1;
if (m_record_lines_p)
{
- if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
- || end_sequence)
+ /* When we switch files we insert an end maker in the first file,
+ switch to the second file and add a new line entry. The
+ problem is that the end marker inserted in the first file will
+ discard any previous line entries at the same address. If the
+ line entries in the first file are marked as is-stmt, while
+ the new line in the second file is non-stmt, then this means
+ the end marker will discard is-stmt lines so we can have a
+ non-stmt line. This means that there are less addresses at
+ which the user can insert a breakpoint.
+
+ To improve this we track the last address in m_last_address,
+ and whether we have seen an is-stmt at this address. Then
+ when switching files, if we have seen a stmt at the current
+ address, and we are switching to create a non-stmt line, then
+ discard the new line. */
+ bool file_changed
+ = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
+ bool ignore_this_line
+ = (file_changed && !end_sequence && m_last_address == m_address
+ && !m_is_stmt && m_stmt_at_address);
+
+ if ((file_changed && !ignore_this_line) || end_sequence)
{
dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
m_currently_recording_lines ? m_cu : nullptr);
}
- if (!end_sequence)
+ if (!end_sequence && !ignore_this_line)
{
bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
@@ -19727,6 +19756,15 @@ lnp_state_machine::record_line (bool end_sequence)
}
}
}
+
+ /* Track whether we have seen any m_is_stmt true at m_address in case we
+ have multiple line table entries all at m_address. */
+ if (m_last_address != m_address)
+ {
+ m_stmt_at_address = false;
+ m_last_address = m_address;
+ }
+ m_stmt_at_address |= m_is_stmt;
}
lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -19746,6 +19784,9 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
m_address = gdbarch_adjust_dwarf2_line (arch, 0, 0);
m_is_stmt = lh->default_is_stmt;
m_discriminator = 0;
+
+ m_last_address = m_address;
+ m_stmt_at_address = false;
}
void
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 3733fa75570..a95e21194f9 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -24,6 +24,13 @@ if { ![supports_statement_frontiers] } {
proc do_test { use_header } {
global srcfile testfile
+ if { $use_header } {
+ # This test will not pass due to poor debug information
+ # generated by GCC (at least upto 10.x). See
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
+ return
+ }
+
set options {c++ debug nowarnings optimize=-O2\ -gstatement-frontiers}
if { $use_header } {
lappend options additional_flags=-DUSE_NEXT_INLINE_H
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
new file mode 100644
index 00000000000..6a1e990002c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
@@ -0,0 +1,156 @@
+# Copyright 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/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1 | 1 | 16 | Y |
+# | 2 | 1 | 17 | Y |
+# | 3 | 2 | 21 | Y |
+# | 4 | 2 | 22 | Y |
+# | 4 | 1 | 18 | N |
+# | 5 | 2 | 23 | N |
+# | 6 | 1 | 24 | Y |
+# | 7 | 1 | END | Y |
+# |------|------|------|------|
+#
+# Places a brekpoint at file 2, line 22. Previously GDB would discrad
+# the line table entry for this line due to switching files for the
+# file 1, line 18 non-statement line. After patching however, GDB now
+# discards the file 1, line 18 entry instead, and the breakpoint at
+# line 22 should succeed.
+
+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-header-lbls.c dw2-inline-header.S \
+ dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main
+
+ cu {} {
+ compile_unit {
+ {producer "gcc" }
+ {language @DW_LANG_C}
+ {name ${srcfile3}}
+ {low_pc 0 addr}
+ {stmt_list ${lines_label} DW_FORM_sec_offset}
+ } {
+ callee_subprog_label: subprogram {
+ {external 1 flag}
+ {name callee}
+ {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 %$callee_subprog_label}
+ {low_pc line_label_1 addr}
+ {high_pc line_label_7 addr}
+ {call_file 1 data1}
+ {call_line 18 data1}
+ }
+ }
+ }
+ }
+
+ lines {version 2 default_is_stmt 1} lines_label {
+ include_dir "${srcdir}/${subdir}"
+ file_name "$srcfile3" 1
+ file_name "$srcfile4" 1
+
+ program {
+ {DW_LNE_set_address line_label_1}
+ {DW_LNS_advance_line 15}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_2}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_set_file 2}
+ {DW_LNE_set_address line_label_3}
+ {DW_LNS_advance_line 4}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_4}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_advance_line -4}
+ {DW_LNS_set_file 1}
+ {DW_LNS_negate_stmt}
+ {DW_LNS_copy}
+
+ {DW_LNS_set_file 2}
+ {DW_LNE_set_address line_label_5}
+ {DW_LNS_advance_line 5}
+ {DW_LNS_copy}
+
+ {DW_LNS_negate_stmt}
+ {DW_LNS_set_file 1}
+ {DW_LNE_set_address line_label_6}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_7}
+ {DW_LNE_end_sequence}
+ }
+ }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected. It should
+# appear at the requested line. When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+ ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
new file mode 100644
index 00000000000..46499919a8b
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
@@ -0,0 +1,179 @@
+# Copyright 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/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1 | 1 | 16 | Y |
+# | 2 | 1 | 17 | Y |
+# | 3 | 2 | 21 | Y |
+# | 4 | 2 | 22 | Y |
+# | 4 | 1 | 18 | N |
+# | 5 | 1 | 19 | Y |
+# | 6 | 1 | 20 | Y |
+# | 7 | 1 | END | Y |
+# |------|------|------|------|
+#
+#
+# Place the first brekpoint at file 2, line 22 and a second breakpoint
+# at file 1, line 19. A third breakpoint is placed at file 1, line
+# 18, but as this line table entry will have been discarded[1] the
+# third breakpoint will actually be placed at the same location as the
+# second breakpoint.
+#
+# [1] The entry for file 1, line 18 is discarded because it is at the
+# same address as the previous entry, but the previous entry is-stmt,
+# while line 18 is a non-stmt.
+
+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-header-lbls.c dw2-inline-header.S \
+ dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main
+
+ cu {} {
+ compile_unit {
+ {producer "gcc" }
+ {language @DW_LANG_C}
+ {name ${srcfile3}}
+ {low_pc 0 addr}
+ {stmt_list ${lines_label} DW_FORM_sec_offset}
+ } {
+ callee_subprog_label: subprogram {
+ {external 1 flag}
+ {name callee}
+ {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 %$callee_subprog_label}
+ {low_pc line_label_1 addr}
+ {high_pc line_label_7 addr}
+ {call_file 1 data1}
+ {call_line 18 data1}
+ }
+ }
+ }
+ }
+
+ lines {version 2 default_is_stmt 1} lines_label {
+ include_dir "${srcdir}/${subdir}"
+ file_name "$srcfile3" 1
+ file_name "$srcfile4" 1
+
+ program {
+ {DW_LNE_set_address line_label_1}
+ {DW_LNS_advance_line 15}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_2}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_set_file 2}
+ {DW_LNE_set_address line_label_3}
+ {DW_LNS_advance_line 4}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_4}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_advance_line -4}
+ {DW_LNS_set_file 1}
+ {DW_LNS_negate_stmt}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_5}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_negate_stmt}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_6}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_7}
+ {DW_LNE_end_sequence}
+ }
+ }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected. It should
+# appear at the requested line. When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+ ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*" \
+ "check for breakpoint at ${srcfile4}"
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile3}:19"
+
+# Check that the breakpoint was placed where we expected. It should
+# appear at the requested line. When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+ ".* in callee at \[^\r\n\]+${srcfile3}:19\\y.*" \
+ "check for breakpoint at ${srcfile3}"
+
+# Line table entry for line 18 will have been discarded, so this
+# brekpoint will be at the same location as line 19.
+gdb_test "break ${srcfile3}:18" \
+ "Note: breakpoint $decimal also set at pc $hex.*"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
new file mode 100644
index 00000000000..161a1fc2aea
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
@@ -0,0 +1,190 @@
+# Copyright 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/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1 | 1 | 16 | Y |
+# | 2 | 1 | 17 | Y |
+# | 3 | 2 | 21 | Y |
+# | 4 | 2 | 22 | Y |
+# | 4 | 1 | 18 | N |
+# | 5 | 1 | 19 | N |
+# | 6 | 1 | 20 | Y |
+# | 7 | 1 | END | Y |
+# |------|------|------|------|
+#
+# Break at file 2, line 22, then single instruction step forward. We
+# should pass through line 19 and then encounter line 20.
+#
+# Currently we don't expect GDB to see file 1, line 18, as this is a
+# non-stmt line in a different file at the same address as the
+# previous is-stmt line.
+
+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-header-lbls.c dw2-inline-header.S \
+ dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main
+
+ cu {} {
+ compile_unit {
+ {producer "gcc" }
+ {language @DW_LANG_C}
+ {name ${srcfile3}}
+ {low_pc 0 addr}
+ {stmt_list ${lines_label} DW_FORM_sec_offset}
+ } {
+ callee_subprog_label: subprogram {
+ {external 1 flag}
+ {name callee}
+ {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 %$callee_subprog_label}
+ {low_pc line_label_1 addr}
+ {high_pc line_label_7 addr}
+ {call_file 1 data1}
+ {call_line 18 data1}
+ }
+ }
+ }
+ }
+
+ lines {version 2 default_is_stmt 1} lines_label {
+ include_dir "${srcdir}/${subdir}"
+ file_name "$srcfile3" 1
+ file_name "$srcfile4" 1
+
+ program {
+ {DW_LNE_set_address line_label_1}
+ {DW_LNS_advance_line 15}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_2}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_set_file 2}
+ {DW_LNE_set_address line_label_3}
+ {DW_LNS_advance_line 4}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_4}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNS_advance_line -4}
+ {DW_LNS_set_file 1}
+ {DW_LNS_negate_stmt}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_5}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_6}
+ {DW_LNS_advance_line 1}
+ {DW_LNS_negate_stmt}
+ {DW_LNS_copy}
+
+ {DW_LNE_set_address line_label_7}
+ {DW_LNE_end_sequence}
+ }
+ }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected. It should
+# appear at the requested line. When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+ ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*"
+
+gdb_continue_to_breakpoint "${srcfile4}:22" \
+ ".* ${srcfile4} : 22 .*"
+
+# Now single instruction step forward. Eventually we should hit
+# ${srcfile3}:20, but before we do we should hit the non-statement
+# line ${srcfile3}:19.
+#
+# We don't know how many instructions we'll need to step, but 100
+# should be enough for everyone (surely), and this stops us looping
+# forever if something goes wrong.
+set found_line_19 0
+set found_line_20 0
+set keep_going 1
+for { set i 0 } { $i < 100 && $keep_going } { incr i } {
+ set keep_going 0
+ gdb_test_multiple "stepi" "stepi ${i}" {
+ -re "${srcfile3} : 19 .*${gdb_prompt} " {
+ set found_line_19 1
+ set keep_going 1
+ }
+
+ -re "${srcfile3} : 20 .*${gdb_prompt} " {
+ set found_line_20 1
+ }
+
+ -re "${srcfile4} : 22 .*${gdb_prompt} " {
+ # Not left line 22 yet.
+ set keep_going 1
+ }
+ }
+}
+
+gdb_assert { $found_line_19 && $found_line_20 } \
+ "found line 19 and 20"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c
new file mode 100644
index 00000000000..a1b7b17cbeb
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c
@@ -0,0 +1,46 @@
+/* Copyright 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/>. */
+
+/* Used to insert labels with which we can build a fake line table. */
+#define LL(N) asm ("line_label_" #N ": .globl line_label_" #N)
+
+volatile int var;
+volatile int bar;
+
+/* Generate some code to take up some space. */
+#define FILLER do { \
+ var = 99; \
+} while (0)
+
+int
+main ()
+{ /* main prologue */
+ asm ("main_label: .globl main_label");
+ LL (1); // F1, Ln 16
+ FILLER;
+ LL (2); // F1, Ln 17
+ FILLER;
+ LL (3); // F2, Ln 21
+ FILLER;
+ LL (4); // F2, Ln 22 // F1, Ln 18, !S
+ FILLER;
+ LL (5); // F1, Ln 19 !S
+ FILLER;
+ LL (6); // F1, Ln 20
+ FILLER;
+ LL (7);
+ FILLER;
+ return 0; /* main end */
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c
new file mode 100644
index 00000000000..a8331268a09
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c
@@ -0,0 +1,24 @@
+/* Copyright 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/>. */
+
+/* dw2-inline-header.c : 16 */
+/* dw2-inline-header.c : 17 */
+/* dw2-inline-header.c : 18 */
+/* dw2-inline-header.c : 19 */
+/* dw2-inline-header.c : 20 */
+/* dw2-inline-header.c : 21 */
+/* dw2-inline-header.c : 22 */
+/* dw2-inline-header.c : 23 */
+/* dw2-inline-header.c : 24 */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h
new file mode 100644
index 00000000000..7233acbcd76
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h
@@ -0,0 +1,24 @@
+/* Copyright 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/>. */
+
+/* dw2-inline-header.h : 16 */
+/* dw2-inline-header.h : 17 */
+/* dw2-inline-header.h : 18 */
+/* dw2-inline-header.h : 19 */
+/* dw2-inline-header.h : 20 */
+/* dw2-inline-header.h : 21 */
+/* dw2-inline-header.h : 22 */
+/* dw2-inline-header.h : 23 */
+/* dw2-inline-header.h : 24 */
More information about the Gdb-patches
mailing list