[PATCH 2/2] gdb: Preserve is-stmt lines when switch between files
Bernd Edlinger
bernd.edlinger@hotmail.de
Sun Apr 5 00:04:34 GMT 2020
On 4/5/20 12:23 AM, Andrew Burgess wrote:
> * Bernd Edlinger <bernd.edlinger@hotmail.de> [2020-04-04 20:07:52 +0200]:
>
>> Sorry, Andrew,
>>
>> please hold this one.
>>
>> This will definitely break all the step over inline
>> stuff that was already working.
>
> By all I assume you only mean gdb.cp/step-and-next-inline.exp, which I
> specifically talk about in the commit message.
>
> The DWARF produced in that test is horribly broken, I was tempted to
> drop the whole test, but a few parts do still work, and hopefully if
> GCC gets fixed we'll be back in business.
>
DWARF is broken by design, I said that already.
But I think there is no reason why the test case cannot
work.
Maybe I overlooked something, but that is what I think
in the moment.
> As I mentioned in the GCC bug report, if I hack GDB to "fix" the DWARF
> produced by GCC, then that test passes fine with no regressions with
> this patch as is.
>
In the moment, my approach is leave GCC as is, and teach
GDB to make as much sense as possible out of the DWARF info
as it is, we have a lot of backward compatibility to maintain.
Even if the DWARF is eventually fixed it must be a new dwarf
revision v6 or so.
Bernd.
> All other tests still pass with this patch - admittedly there's not
> much testing the inline behaviour, but there are a few.
>
> If you know of a case with valid DWARF that is broken by this test
> then I'm all ears. With the setup I used for the tests in this patch
> it's actually pretty easy to synthesis test of inline functions, so
> all you really need to do is describe a test you think will break and
> I can knock up a test case for it reasonably quickly.
>
>>
>> Can we please go to the drawing board before we continue
>> from here?
>
> Sure. I posted my thoughts just now.
>
> Thanks,
> Andrew
>
>>
>>
>> Thanks
>> Bernd.
>>
>> On 4/4/20 12:21 AM, Andrew Burgess wrote:
>>> 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.
>>> ---
>>> gdb/ChangeLog | 10 ++
>>> gdb/dwarf2/read.c | 47 +++++-
>>> gdb/testsuite/ChangeLog | 11 ++
>>> gdb/testsuite/gdb.cp/step-and-next-inline.exp | 7 +
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp | 156 ++++++++++++++++++
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp | 179 ++++++++++++++++++++
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp | 192 ++++++++++++++++++++++
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c | 46 ++++++
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header.c | 24 +++
>>> gdb/testsuite/gdb.dwarf2/dw2-inline-header.h | 24 +++
>>> 10 files changed, 693 insertions(+), 3 deletions(-)
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header.c
>>> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-inline-header.h
>>>
>>> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
>>> index f94c66b4f1b..261c8455424 100644
>>> --- a/gdb/dwarf2/read.c
>>> +++ b/gdb/dwarf2/read.c
>>> @@ -19327,6 +19327,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;
>>>
>>> @@ -19520,14 +19529,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;
>>>
>>> @@ -19546,6 +19575,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,
>>> @@ -19565,6 +19603,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_addr = 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..c683dc4bb8a
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
>>> @@ -0,0 +1,192 @@
>>> +# 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