[PATCH 2/2] gdb: Preserve is-stmt lines when switch between files

Bernd Edlinger bernd.edlinger@hotmail.de
Tue Apr 14 11:37:56 GMT 2020



On 4/14/20 1:28 PM, Andrew Burgess wrote:
> 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.
> 

Did you look at fixing the subrouting ranges.
My patch depends entirely on correct range info.

It is probably not very difficult for you to fix.


Thanks
Bernd.

> 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