From: Andrew Burgess <andrew.burgess@embecosm.com>
To: Bernd Edlinger <bernd.edlinger@hotmail.de>
Cc: Tom Tromey <tom@tromey.com>,
gdb-patches@sourceware.org, Alexandre Oliva <oliva@gnu.org>
Subject: Re: [PATCH 2/2] gdb: Preserve is-stmt lines when switch between files
Date: Wed, 27 May 2020 14:10:22 +0100 [thread overview]
Message-ID: <20200527131022.GW3522@embecosm.com> (raw)
In-Reply-To: <20200520182658.GU3522@embecosm.com>
Below is an updated version of the previous work in progress patch.
I'm posting it here so there's a record, however, I don't think this
patch should be merged into upstream. While working on this solution
the problems with it became apparent to me. I've tried to describe my
issues with this approach in the commit message of the patch.
It is now my intention to merge the patch I posted here:
https://sourceware.org/pipermail/gdb-patches/2020-May/168611.html
which I'll do in a couple of days unless anyone would like to discuss
this further.
Thanks,
Andrew
---
commit 79719063c19b3906fda9d9e7fa0b8c009716b53a
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Wed May 20 19:16:05 2020 +0100
gdb: Don't delete empty lines when changing symtabs
***** NOT FOR MERGING INTO UPSTREAM *****
This patch is based on the work of Bernd Edlinger here:
https://sourceware.org/pipermail/gdb-patches/2020-May/168591.html
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.
In order to understand the solution presented here, we must first
remind ourselves why we delete line table entries that occur at the
same address as an END marker.
The problem this (deleting lines) is trying to solve is that if the
last real line within a line table is empty (maybe due to
optimisation) then the line will be at the same address as the end
marker. If the user tries to place a breakpoint at this address then
we actually end up with a breakpoint at whatever is _after_ the
location of that empty line, which is likely some other random
function.
However, when a line table switches subfiles we also insert end
markers, this is because the GDB internal line table is split
per-subfile, so the end markers allow us to see and "end" for the line
just before the switch. Without this, the line table entry just
before the we switch subfiles would appear to extend over the entire
region covered by the subfile we switch too.
If we further consider the end markers inserted for switching
subfiles, there are two common cases when this can occur, these are,
first when one file is fully included inside another, and secondly
when a function from one (header) file is inlined within a function
in a different file.
In the first of these situations GDB is exposed to the same risk as
for the classic end marker case, if the last line before the subfile
switch is empty, then when we switch subfiles we should be deleting
the empty line, otherwise a user placing a breakpoint on this line,
will end up with a breakpoint in a potentially different function.
However, for the case of the inlined function the argument for
deleting lines is harder to make, indeed if we consider a function
inlined from another file compared to a function inlined from within
the same file then it is obvious that in the case where the inlined
callee is within the same file there will be no subfile switch, and
hence no end of sequence markers inserted, and as a consequence no
deleted line entries.
It is tempting then to think that, when we switch subfiles as part of
an inlined function we would like to preserve line table entries where
possible.
The problem is how to distinguish between the case of an inlined
function subfile switch, and a general inclusion subfile switch?
Though I'm sure we can solve this problem, I think it is worth
considering if this is even a problem worth solving.
First, the act of deleting line table entries only occurs when entries
in the original debug information "pile up" and occur at the same
address, consider this imagined input line table:
| Addr | File | Line | Stmt |
|------|------|------|------|
| 1 | 1 | 10 | Y |
| 2 | 2 | 100 | Y |
| 3 | 1 | 11 | Y |
In this case no entries will be deleted, as every line table item
occurs at a separate address. Compare it to this:
| Addr | File | Line | Stmt |
|------|------|------|------|
| 1 | 1 | 10 | Y |
| 1 | 2 | 100 | Y |
| 2 | 1 | 11 | Y |
Here, the switch to subfile 2 will cause the line item from subfile
1 (also at address 1) to be deleted. This kind of makes sense, the
debug is claiming the address 1 represents both file 1, line 10 and
file 2, line 100. If we stop at this address which line should GDB
report? If the same situation was imagined within a single subfile,
like this:
| Addr | File | Line | Stmt |
|------|------|------|------|
| 1 | 1 | 10 | Y |
| 1 | 1 | 100 | Y |
| 2 | 1 | 11 | Y |
GDB would report line 100 at address 1, and line 11 at address 2. By
deleting the line in the two subfile case we get the same behaviour,
but we protect against the empty line at the end of a subfile
problem.
It is for this reason, that I think this commit should not be merged
with GDB.
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. Also the possibility of extending
GDB to handle GCC's broken debug information has been discussed.
gdb/ChangeLog:
* buildsym.c (buildsym_compunit::record_line): Extend header
comment. Add some static assertions. Handle different end of
sequence types.
* buildsym.h (struct buildsym_compunit) <end_of_sequence>: New
constant.
<change_of_subfile>: New constant.
* dwarf2/read.c (dwarf_finish_line): Add extra parameter, use this
to decide which end of sequence marker to send through as the line
number.
(lnp_state_machine::record_line): Pass extra parameter to
dwarf_finish_line.
* symtab.c (find_pc_sect_line): The previous line is better if it
was marked is-stmt, and the new possible best is not.
* symtab.h (struct linetable_entry) <line>: Extend comment.
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/buildsym.c b/gdb/buildsym.c
index 33bf6523e90..37fec4f53b6 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -663,7 +663,42 @@ buildsym_compunit::pop_subfile ()
}
\f
/* Add a linetable entry for line number LINE and address PC to the
- line vector for SUBFILE. */
+ line vector for SUBFILE.
+
+ Pass the constant end_of_sequence for LINE when an end of sequence
+ marker is encountered in the original debug information. If this case
+ any previous line table entries already at this address will be deleted,
+ these lines are by definition empty, and attempting to place a
+ breakpoint at this address will result in a breakpoint being placed on
+ whatever is next in the executable, which is never going to be the
+ correct behaviour.
+
+ Alternatively, pass the constant change_of_subfile for LINE to indicate
+ that the original debug line table switched to a different subfile.
+ This still results in an end of sequence marker being placed in GDB's
+ internal line table, but in this case we don't delete previous line
+ entries at this address. This case arises from two common situations,
+ the most common is inlined functions, in this case the switching between
+ subfiles occurs within a single function. If a real line entry and a
+ subfile switch occur at the same address we don't want to delete the
+ real line entry in this case as we end up loosing too much useful debug
+ information.
+
+ The other situation where a subfile switch is commonly seen is when one
+ source file is included into another, in this case the original line
+ table will include information for one subfile before switching to the
+ second subfile. If the last line of the last function in the first
+ subfile is at the same address as the subfile switch then it is possible
+ that a breakpoint placed on this line would actually be placed in the
+ subsequent function by mistake.
+
+ We could improve on this second situation by entering all end of
+ sequence markers here without deleting any line table entries, then
+ cross check the line table with the list of function blocks, we would
+ then delete any line table entries that occurred at an end of sequence
+ marker that was also at the end of a function. Right now we don't do
+ this, and live with the (small) risk of a breakpoint being misplaced;
+ the benefit of preserving the extra line table entries is worth it. */
void
buildsym_compunit::record_line (struct subfile *subfile, int line,
@@ -671,6 +706,13 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
{
struct linetable_entry *e;
+ /* The END_OF_SEQUENCE must be 0 as the constant 0 is used when
+ processing the line table as the magic end of sequence marker. The
+ CHANGE_OF_SUBFILE marker must be less than 0 as any value greater than
+ 0 is an actual line number. */
+ gdb_static_assert (buildsym_compunit::end_of_sequence == 0);
+ gdb_static_assert (buildsym_compunit::change_of_subfile < 0);
+
/* Make sure line vector exists and is big enough. */
if (!subfile->line_vector)
{
@@ -705,7 +747,7 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
end of sequence markers. All we lose is the ability to set
breakpoints at some lines which contain no instructions
anyway. */
- if (line == 0)
+ if (line == buildsym_compunit::end_of_sequence)
{
while (subfile->line_vector->nitems > 0)
{
@@ -715,8 +757,11 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
subfile->line_vector->nitems--;
}
}
+ else if (line == buildsym_compunit::change_of_subfile)
+ line = buildsym_compunit::end_of_sequence;
e = subfile->line_vector->item + subfile->line_vector->nitems++;
+ gdb_assert (line >= 0);
e->line = line;
e->is_stmt = is_stmt ? 1 : 0;
e->pc = pc;
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index c768a4c2dae..3e22d0b4494 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -190,6 +190,14 @@ struct buildsym_compunit
void record_line (struct subfile *subfile, int line, CORE_ADDR pc,
bool is_stmt);
+ /* These two constants can be passed to RECORD_LINE as the value of LINE
+ to indicate special events in the line table. END_OF_SEQUENCE marks
+ an actual end of sequence marked in the original debug's line table,
+ while CHANGE_OF_SUBFILE indicates an end marker due to switching
+ between subfiles. */
+ static const int end_of_sequence = 0;
+ static const int change_of_subfile = -1;
+
struct compunit_symtab *get_compunit_symtab ()
{
return m_compunit_symtab;
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ec3844188ee..ed0f247b6a1 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -20067,7 +20067,7 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
static void
dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
- CORE_ADDR address, struct dwarf2_cu *cu)
+ CORE_ADDR address, struct dwarf2_cu *cu, bool end_sequence)
{
if (subfile == NULL)
return;
@@ -20080,7 +20080,10 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
paddress (gdbarch, address));
}
- dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu);
+ int lineno = (end_sequence
+ ? buildsym_compunit::end_of_sequence
+ : buildsym_compunit::change_of_subfile);
+ dwarf_record_line_1 (gdbarch, subfile, lineno, address, true, cu);
}
void
@@ -20113,7 +20116,8 @@ lnp_state_machine::record_line (bool end_sequence)
|| end_sequence)
{
dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
- m_currently_recording_lines ? m_cu : nullptr);
+ m_currently_recording_lines ? m_cu : nullptr,
+ end_sequence);
}
if (!end_sequence)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5c4e282c024..f6ebae45b27 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3254,7 +3254,9 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
save prev if it represents the end of a function (i.e. line number
0) instead of a real line. */
- if (prev && prev->line && (!best || prev->pc > best->pc))
+ if (prev && prev->line && (!best || prev->pc > best->pc
+ || (prev->pc == best->pc && !best->is_stmt
+ && prev->is_stmt)))
{
best = prev;
best_symtab = iter_s;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 9972e8125ba..62bedb45de7 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1306,7 +1306,10 @@ struct rust_vtable_symbol : public symbol
struct linetable_entry
{
- /* The line number for this entry. */
+ /* The line number for this entry. This should be a value greater than
+ 0 to indicate an actual line number, or the magic value 0 is used to
+ indicate the end of a sequence of linetable_entry structures in a
+ list. */
int line;
/* True if this PC is a good location to place a breakpoint for LINE. */
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..dc7ec929236
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
@@ -0,0 +1,186 @@
+# 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:
+#
+# | | | | | Inline | Inline |
+# | Addr | File | Line | Stmt | Rng A | Rng B |
+# |------|------|------|------|--------|--------|
+# | 1 | 1 | 16 | Y | | |
+# | 2 | 1 | 17 | Y | | |
+# | 3 | 2 | 21 | Y | X | |
+# | 4 | 2 | 22 | Y | X | |
+# | 4 | 1 | 18 | N | X | |
+# | 5 | 2 | 23 | N | X | X |
+# | 6 | 1 | 24 | Y | | |
+# | 7 | 1 | END | Y | | |
+# |------|------|------|------|--------|--------|
+#
+# Places a brekpoint at file 2, line 22. Previously GDB would discard
+# 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.
+#
+# The two inlined subroutine ranges 'A' and 'B' represent two possible
+# ways that a compiler might represent this siuatio in the DWARF.
+#
+# Range 'B' is something that has been seen in the wild using GCC 8.2.
+# In this case the compilers range information is clearly wrong, but
+# this shouldn't impact the main point of the test.
+#
+# Range 'A' is a hypothetical case of how the compiler might choose to
+# represent this range, this has never been seen in the wild, but is
+# an improved debug experiece over range 'B'. However, if we ever run
+# in to the situation where GDB can support the range 'A' test, or
+# support some real DWARF seen in the wild, then the range 'A' case
+# should be dropped in favour of supporting real world cases. This is
+# included here as it "just worked" once the range 'B' case was
+# working.
+
+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
+}
+
+# Prepare and run the test.
+proc do_test { start_label func_name tag } {
+ global srcfile srcfile2 srcfile3 srcfile4 testfile
+
+ standard_testfile dw2-inline-header-lbls.c dw2-inline-header-${tag}.S \
+ dw2-inline-header.c dw2-inline-header.h
+
+ set build_options {nodebug optimize=-O1}
+
+ set asm_file [standard_output_file $srcfile2]
+ Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4 testfile
+ upvar build_options build_options
+ upvar start_label start_label
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main $build_options
+
+ 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 $start_label addr}
+ {high_pc line_label_6 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}-${tag} \
+ [list $srcfile $asm_file] $build_options] } {
+ 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 $func_name at \[^\r\n\]+${srcfile4}:22\\y.*" \
+ "info breakpoints, $tag"
+}
+
+do_test line_label_3 "callee" "range-a"
+do_test line_label_5 "main" "range-b"
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..9f09f353273
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
@@ -0,0 +1,189 @@
+# 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 | Inline |
+# |------|------|------|------|--------|
+# | 1 | 1 | 16 | Y | |
+# | 2 | 1 | 17 | Y | |
+# | 3 | 2 | 21 | Y | X |
+# | 4 | 2 | 22 | Y | X |
+# | 4 | 1 | 18 | N | X |
+# | 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.
+#
+# This test is designed to test GDB's internal behaviour with respect
+# to discarding particular line table entries. GCC and DWARF are
+# starting to introduce the idea of line table views. As the views
+# information becomes better supported within GDB it is likely that
+# this will become out of date. This is fine, the test will have
+# served its purpose by that point and can be deleted.
+#
+# [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 build_options {nodebug optimize=-O1}
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4
+ global build_options
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main $build_options
+
+ 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_3 addr}
+ {high_pc line_label_5 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] $build_options] } {
+ 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 main 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..a3820f16d57
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
@@ -0,0 +1,193 @@
+# 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 | Inline |
+# |------|------|------|------|--------|
+# | 1 | 1 | 16 | Y | |
+# | 2 | 1 | 17 | Y | |
+# | 3 | 2 | 21 | Y | X |
+# | 4 | 2 | 22 | Y | X |
+# | 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 build_options {nodebug optimize=-O1}
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile3 srcfile4
+ global build_options
+ declare_labels lines_label callee_subprog_label
+
+ get_func_info main $build_options
+
+ 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_3 addr}
+ {high_pc line_label_5 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] $build_options] } {
+ 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 */
next prev parent reply other threads:[~2020-05-27 13:10 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-05 11:37 [PATCH 0/2] Line table is_stmt support Andrew Burgess
2020-02-05 11:37 ` [PATCH 1/2] gdb/testsuite: Add is-stmt support to the DWARF compiler Andrew Burgess
2020-02-05 11:37 ` [PATCH 2/2] gdb: Add support for tracking the DWARF line table is-stmt field Andrew Burgess
2020-02-05 17:55 ` Bernd Edlinger
2020-02-10 18:30 ` Bernd Edlinger
2020-02-11 13:57 ` Andrew Burgess
2020-02-14 20:05 ` Bernd Edlinger
2020-03-05 18:01 ` Bernd Edlinger
2020-03-08 12:50 ` [PATCHv2 0/2] Line table is_stmt support Andrew Burgess
2020-03-08 14:39 ` Bernd Edlinger
2020-03-10 23:01 ` Andrew Burgess
2020-03-11 6:50 ` Simon Marchi
2020-03-11 11:28 ` Andrew Burgess
2020-03-11 13:27 ` Simon Marchi
2020-04-03 22:21 ` [PATCH 0/2] More regression fixing from is-stmt patches Andrew Burgess
2020-04-03 22:21 ` [PATCH 1/2] gdb/testsuite: Move helper function into lib/dwarf.exp Andrew Burgess
2020-04-06 20:18 ` Tom Tromey
2020-04-14 11:18 ` Andrew Burgess
2020-04-03 22:21 ` [PATCH 2/2] gdb: Preserve is-stmt lines when switch between files Andrew Burgess
2020-04-04 18:07 ` Bernd Edlinger
2020-04-04 19:59 ` Bernd Edlinger
2020-04-04 22:23 ` Andrew Burgess
2020-04-05 0:04 ` Bernd Edlinger
2020-04-05 0:47 ` Bernd Edlinger
2020-04-05 8:55 ` Bernd Edlinger
2020-04-11 3:52 ` Bernd Edlinger
2020-04-12 17:13 ` Bernd Edlinger
2020-04-14 11:28 ` Andrew Burgess
2020-04-14 11:37 ` Bernd Edlinger
2020-04-14 11:41 ` Bernd Edlinger
2020-04-14 13:08 ` Andrew Burgess
2020-04-16 17:18 ` Andrew Burgess
2020-04-22 21:13 ` Tom Tromey
2020-04-25 7:06 ` Bernd Edlinger
2020-04-27 10:34 ` Andrew Burgess
2020-05-14 20:18 ` Tom Tromey
2020-05-14 22:39 ` Andrew Burgess
2020-05-15 3:35 ` Bernd Edlinger
2020-05-15 14:46 ` Andrew Burgess
2020-05-16 8:12 ` Bernd Edlinger
2020-05-17 17:26 ` Bernd Edlinger
2020-05-20 18:26 ` Andrew Burgess
2020-05-27 13:10 ` Andrew Burgess [this message]
2020-06-01 9:05 ` Andrew Burgess
2020-03-08 12:50 ` [PATCHv2 1/2] gdb/testsuite: Add is-stmt support to the DWARF compiler Andrew Burgess
2020-03-08 12:50 ` [PATCHv2 2/2] gdb: Add support for tracking the DWARF line table is-stmt field Andrew Burgess
2020-03-16 20:57 ` Tom Tromey
2020-03-16 22:37 ` Bernd Edlinger
2020-03-17 12:47 ` Tom Tromey
2020-03-17 18:23 ` Tom Tromey
2020-03-17 18:51 ` Bernd Edlinger
2020-03-17 18:56 ` Andrew Burgess
2020-03-17 20:18 ` Tom Tromey
2020-03-17 22:21 ` Andrew Burgess
2020-03-23 17:30 ` [PATCH 0/3] Keep duplicate line table entries Andrew Burgess
2020-03-23 17:30 ` [PATCH 1/3] gdb/testsuite: Add compiler options parameter to function_range helper Andrew Burgess
2020-04-01 18:31 ` Tom Tromey
2020-03-23 17:30 ` [PATCH 2/3] gdb/testsuite: Add support for DW_LNS_set_file to DWARF compiler Andrew Burgess
2020-04-01 18:32 ` Tom Tromey
2020-03-23 17:30 ` [PATCH 3/3] gdb: Don't remove duplicate entries from the line table Andrew Burgess
2020-04-01 18:34 ` Tom Tromey
2020-06-01 13:26 ` [PATCH 2/2] gdb: Add support for tracking the DWARF line table is-stmt field Pedro Alves
2020-02-06 9:01 ` Luis Machado
2020-02-11 15:39 ` Andrew Burgess
2020-02-09 21:07 ` [PATCH] Fix range end handling of inlined subroutines Bernd Edlinger
2020-02-10 21:48 ` Andrew Burgess
2020-02-22 6:39 ` [PATCHv2] " Bernd Edlinger
2020-03-08 14:57 ` [PATCHv3] " Bernd Edlinger
2020-03-11 22:02 ` Andrew Burgess
2020-03-12 18:21 ` Bernd Edlinger
2020-03-12 18:27 ` Christian Biesinger
2020-03-13 8:03 ` Bernd Edlinger
2020-03-17 22:27 ` Andrew Burgess
2020-03-19 1:33 ` Bernd Edlinger
2020-03-21 20:31 ` Bernd Edlinger
2020-03-23 17:53 ` Andrew Burgess
2020-03-23 20:58 ` Bernd Edlinger
2020-06-01 14:28 ` Pedro Alves
2020-03-13 12:47 ` [PATCHv4] " Bernd Edlinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200527131022.GW3522@embecosm.com \
--to=andrew.burgess@embecosm.com \
--cc=bernd.edlinger@hotmail.de \
--cc=gdb-patches@sourceware.org \
--cc=oliva@gnu.org \
--cc=tom@tromey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox