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

Message ID 6e9b21a0002164cec014dfe4d94d816a376989b4.1585952198.git.andrew.burgess@embecosm.com
State New
Headers show
Series
  • More regression fixing from is-stmt patches
Related show

Commit Message

Andrew Burgess April 3, 2020, 10:21 p.m.
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

-- 
2.14.5

Comments

Bernd Edlinger April 4, 2020, 6:07 p.m. | #1
Sorry, Andrew,

please hold this one.

This will definitely break all the step over inline
stuff that was already working.

Can we please go to the drawing board before we continue
from here?


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 */

>
Bernd Edlinger April 4, 2020, 7:59 p.m. | #2
Andrew,

I think my other patch that is still in your review queue
is able to solve most if not all of the regressions,

see https://marc.info/?l=gdb-patches&m=158602983106559&w=2

I may have overlooked something, but I believe that is
at least a different fix that is focused only on the inline
functions.

What do you think?


Bernd.

On 4/4/20 8:07 PM, Bernd Edlinger wrote:
> Sorry, Andrew,

> 

> please hold this one.

> 

> This will definitely break all the step over inline

> stuff that was already working.

> 

> Can we please go to the drawing board before we continue

> from here?

> 

> 

> 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 */

>>
Andrew Burgess April 4, 2020, 10:23 p.m. | #3
* 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.

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.

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 */

> >
Bernd Edlinger April 5, 2020, 12:04 a.m. | #4
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 */

>>>
Bernd Edlinger April 5, 2020, 12:47 a.m. | #5
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.

> 

> 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.

> 

> 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.

> 


Yes, I really need a test case with your dwarf magic, that duplicates
the aarch64 test case, which fails on current trunk.
And gets fixed if I am right :-)


Thanks
Bernd.

>>

>> 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 */

>>>
Bernd Edlinger April 5, 2020, 8:55 a.m. | #6
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.

> 

> 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.

> 

> 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:

>>>


I was aware that this may happen, I pointed that out already
twice at least.  My initial patch used this effect entirely,
but I tossed it, when I saw, how nice your patch worked.


Thanks
Bernd.


>>>   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 */

>>>
Bernd Edlinger April 11, 2020, 3:52 a.m. | #7
Andrew,

Just, a minor nit:

/home/ed/gnu/binutils-gdb/.git/rebase-apply/patch:665: new blank line at EOF.

I am trying to find out which patch is better.
So I applied your patch, an try to see where the differences are.


Please be patient..


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 */

>
Bernd Edlinger April 12, 2020, 5:13 p.m. | #8
On 4/11/20 5:52 AM, Bernd Edlinger wrote:
> Andrew,

> 

> Just, a minor nit:

> 

> /home/ed/gnu/binutils-gdb/.git/rebase-apply/patch:665: new blank line at EOF.


Hmm, I hope you did not think that is me beginning to be insane, that was just the
incomprehensible output of "git am" on your patch part 2/2, funny isn't it?

I think that means:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
index c683dc4..161a1fc 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
@@ -188,5 +188,3 @@ for { set i 0 } { $i < 100 && $keep_going } { incr i } {
 
 gdb_assert { $found_line_19 && $found_line_20 } \
     "found line 19 and 20"
-
-
-- 

Another bit I had to fix in order to make it compile

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index a146ed1..36e8b24 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -19786,7 +19786,7 @@ class lnp_state_machine
   m_discriminator = 0;
 
   m_last_address = m_address;
-  m_stmt_at_addr = false;
+  m_stmt_at_address = false;
 }
 
 void

Which makes me wonder if you compiled that at all, what you sent to me.
Or if that was actually a different version than intended, so please
double-check that.

If that is the case, please re-submit your test case patches as extra
patch files, and the code change also extra, since I intend to use
your test cases in my patch, and not having to dissect the patches
would be great.

And in order to compare the test results better, I restored the
step-and-next-inline.exp test:

diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index a95e211..e3a5793 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -24,13 +24,6 @@ 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
@@ -59,37 +52,20 @@ proc do_test { use_header } {
     gdb_test "step" ".*" "step into get_alias_set"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 1"
-    # It's possible that this first failure (when not using a header
-    # file) is GCC's fault, though the remaining failures would best
-    # be fixed by adding location views support (though it could be
-    # that some easier heuristic could be figured out).  Still, it is
-    # not certain that the first failure wouldn't also be fixed by
-    # having location view support, so for now it is tagged as such.
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" ".*TREE_TYPE.*" "next step 1"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2"
     gdb_test "next" ".*TREE_TYPE.*" "next step 2"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3"
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" ".*TREE_TYPE.*" "next step 3"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 4"
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" "return 0.*" "next step 4"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 5"
 
-    if {!$use_header} {
-	# With the debug from GCC 10.x (and earlier) GDB is currently
-	# unable to successfully complete the following tests when we
-	# are not using a header file.
-	kfail symtab/25507 "stepping tests"
-	return
-    }
-
     clean_restart ${executable}
 
     if ![runto_main] {


> 

> I am trying to find out which patch is better.

> So I applied your patch, an try to see where the differences are.

> 

> 

> Please be patient..

> 


Hmm, okay, I compared the two patches now.

First please don't take that personally :-)
but I think mine is a tiny bit better, because it
fixes the step-and-next-inline test case entirely.

And fixes your test case also almost completely:
 /gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.cp/step-and-next-inline.exp ...
 PASS: gdb.cp/step-and-next-inline.exp: no_header: in get_alias_set pass 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: in inline 1 pass 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: in inline 2 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: in inline 1 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: in inline 2 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: in inline 3 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: in main
 PASS: gdb.cp/step-and-next-inline.exp: no_header: in main pass 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: next step 1
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: next step 1
 PASS: gdb.cp/step-and-next-inline.exp: no_header: next step 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: next step 3
-PASS: gdb.cp/step-and-next-inline.exp: no_header: next step 4
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: next step 3
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: next step 4
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 1
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 1 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 2 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: not in inline 2 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 3
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 3 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 4
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 4 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: no_header: not in inline 5
-PASS: gdb.cp/step-and-next-inline.exp: no_header: step 1
-PASS: gdb.cp/step-and-next-inline.exp: no_header: step 2
-PASS: gdb.cp/step-and-next-inline.exp: no_header: step 3
-PASS: gdb.cp/step-and-next-inline.exp: no_header: step 4
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: step 1
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: step 2
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: step 3
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: step 4
 PASS: gdb.cp/step-and-next-inline.exp: no_header: step 5
 PASS: gdb.cp/step-and-next-inline.exp: no_header: step 6
-PASS: gdb.cp/step-and-next-inline.exp: no_header: step 7
+FAIL: gdb.cp/step-and-next-inline.exp: no_header: step 7
 PASS: gdb.cp/step-and-next-inline.exp: no_header: step into get_alias_set
 PASS: gdb.cp/step-and-next-inline.exp: no_header: step into get_alias_set pass 2
 PASS: gdb.cp/step-and-next-inline.exp: use_header: in get_alias_set pass 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: in inline 1 pass 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: in inline 2 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: in inline 1 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: in inline 2 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: use_header: in inline 3 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: use_header: in main
 PASS: gdb.cp/step-and-next-inline.exp: use_header: in main pass 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: next step 1
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: next step 1
 PASS: gdb.cp/step-and-next-inline.exp: use_header: next step 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: next step 3
-PASS: gdb.cp/step-and-next-inline.exp: use_header: next step 4
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: next step 3
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: next step 4
 PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 1
-PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 1 pass 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 2 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: not in inline 1 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: not in inline 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: not in inline 2 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 3
 PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 3 pass 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 4
-PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 4 pass 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: not in inline 4
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: not in inline 4 pass 2
 PASS: gdb.cp/step-and-next-inline.exp: use_header: not in inline 5
-PASS: gdb.cp/step-and-next-inline.exp: use_header: step 1
-PASS: gdb.cp/step-and-next-inline.exp: use_header: step 2
-PASS: gdb.cp/step-and-next-inline.exp: use_header: step 3
-PASS: gdb.cp/step-and-next-inline.exp: use_header: step 4
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: step 1
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: step 2
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: step 3
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: step 4
 PASS: gdb.cp/step-and-next-inline.exp: use_header: step 5
 PASS: gdb.cp/step-and-next-inline.exp: use_header: step 6
-PASS: gdb.cp/step-and-next-inline.exp: use_header: step 7
+FAIL: gdb.cp/step-and-next-inline.exp: use_header: step 7
 PASS: gdb.cp/step-and-next-inline.exp: use_header: step into get_alias_set
 PASS: gdb.cp/step-and-next-inline.exp: use_header: step into get_alias_set pass 2
 /gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.cp/subtypes.exp ...
@@ -52391,7 +52381,7 @@
 PASS: gdb.dwarf2/dw2-inline-header-2.exp: check for breakpoint at dw2-inline-header.c
 PASS: gdb.dwarf2/dw2-inline-header-2.exp: check for breakpoint at dw2-inline-header.h
 /gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp ...
-FAIL: gdb.dwarf2/dw2-inline-header-3.exp: continue to breakpoint: dw2-inline-header.h:22
+PASS: gdb.dwarf2/dw2-inline-header-3.exp: continue to breakpoint: dw2-inline-header.h:22
 PASS: gdb.dwarf2/dw2-inline-header-3.exp: found line 19 and 20
 PASS: gdb.dwarf2/dw2-inline-header-3.exp: info breakpoints

So if it would be a socker game that would be 26:1 :-/

Regarding the one test where my patch is still able to be improved,
gdb.dwarf2/dw2-inline-header-3.exp: continue to breakpoint: dw2-inline-header.h:22

I think the issue there is that dw2-inline-header.h:22
and dw2-inline-header.c:18 is at the same adress.
To me it appears a bit arbitrary, which of the two lines the stack trace shows,
but on the other hand, if there is a breakpoint on dw2-inline-header.h:22
that is a clear indication that the user want to see  dw2-inline-header.h:22
while if there is a breakpoint on dw2-inline-header.c:18 the user would
certainly want to see dw2-inline-header.c:18 even if both are only different
views of the same address.  Yes.  I wonder if we can choose the SAL entry
which is presented, in a was that prefers SAL where there is a breakpoint.
That can't be impossible given all we alread achieved in this cursade ;-)
for better debug experience, don't you agree?

Looking at the debug info in the test case, I see a wrong subroutine
range here:

 <2><52>: Abbrev Number: 5 (DW_TAG_inlined_subroutine)
    <53>   DW_AT_abstract_origin: <0x31>
    <57>   DW_AT_low_pc      : 0x401122
    <5f>   DW_AT_high_pc     : 0x40115e
    <67>   DW_AT_call_file   : 1
    <68>   DW_AT_call_line   : 18

See the line table the subroutine is from 0x401136 to 0x401140:

  [0x000000ba]  Set File Name to entry 2 in the File Name Table
  [0x000000bc]  Extended opcode 2: set Address to 0x401136
  [0x000000c7]  Advance Line by 4 to 21
  [0x000000c9]  Copy
  [0x000000ca]  Extended opcode 2: set Address to 0x401140
  [0x000000d5]  Advance Line by 1 to 22
  [0x000000d7]  Copy
  [0x000000d8]  Advance Line by -4 to 18
  [0x000000da]  Set File Name to entry 1 in the File Name Table


with that wrong subroutine table I think my patch cas not a chance
to give correct results.  Could you please fix the subroutine
table, and then we see what I have to fix on my patch in order
to make it pass?

Also please check the subroutine entries on the other
dw2-inline-header tests, if the subroutine range info have similar
problems, I need correct ranges, otherwise my patch is unable to
produce correct output.


Thanks
Bernd.
Andrew Burgess April 14, 2020, 11:28 a.m. | #9
Bernd,

As requested, rebased version of this patch for your feedback.  Sorry
for the delay, I took a short break over Easter.

Apologies for the previous build failure the fix you found was the
only issue, and was caused by a last second choice to rename
'm_stmt_at_addr' to 'm_stmt_at_address', combined with me making a
dumb mistake generating the patch from a slightly broken tree.  Please
be assured the patch was fully tested before I did the rename.

The trailing blank lines I have no excuse for.

Changes since previous version:

  - Rebase
  - Fix m_stmt_at_addr typo
  - Delete some trailing blank lines.

I look forward to hearing your thoughts.

Thanks,
Andrew

---

commit cf4bab4672356e190b166e063d2539ddad5eb542
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Fri Apr 3 20:32:38 2020 +0100

    gdb: Preserve is-stmt lines when switch between files
    
    After the is-stmt support commit:
    
      commit 8c95582da858ac981f689a6f599acacb8c5c490f
      Date:   Mon Dec 30 21:04:51 2019 +0000
    
          gdb: Add support for tracking the DWARF line table is-stmt field
    
    A regression was observed where a breakpoint could no longer be placed
    in some cases.
    
    Consider a line table like this:
    
      File 1: test.c
      File 2: test.h
    
      | Addr | File | Line | Stmt |
      |------|------|------|------|
      | 1    | 1    | 16   | Y    |
      | 2    | 1    | 17   | Y    |
      | 3    | 2    | 21   | Y    |
      | 4    | 2    | 22   | Y    |
      | 4    | 1    | 18   | N    |
      | 5    | 2    | 23   | N    |
      | 6    | 1    | 24   | Y    |
      | 7    | 1    | END  | Y    |
      |------|------|------|------|
    
    Before the is-stmt patch GDB would ignore any non-stmt lines, so GDB
    built two line table structures:
    
      File 1                 File 2
      ------                 ------
    
      | Addr | Line |        | Addr | Line |
      |------|------|        |------|------|
      | 1    | 16   |        | 3    | 21   |
      | 2    | 17   |        | 4    | 22   |
      | 3    | END  |        | 6    | END  |
      | 6    | 24   |        |------|------|
      | 7    | END  |
      |------|------|
    
    After the is-stmt patch GDB now records non-stmt lines, so the
    generated line table structures look like this:
    
      File 1                   File 2
      ------                   ------
    
      | Addr | Line | Stmt |  | Addr | Line | Stmt |
      |------|------|------|  |------|------|------|
      | 1    | 16   | Y    |  | 3    | 21   | Y    |
      | 2    | 17   | Y    |  | 4    | 22   | Y    |
      | 3    | END  | Y    |  | 4    | END  | Y    |
      | 4    | 18   | N    |  | 5    | 23   | N    |
      | 5    | END  | Y    |  | 6    | END  | Y    |
      | 6    | 24   | Y    |  |------|------|------|
      | 7    | END  | Y    |
      |------|------|------|
    
    The problem is that in 'File 2', end END marker at address 4 causes
    the previous line table entry to be discarded, so we actually end up
    with this:
    
      File 2
      ------
    
      | Addr | Line | Stmt |
      |------|------|------|
      | 3    | 21   | Y    |
      | 4    | END  | Y    |
      | 5    | 23   | N    |
      | 6    | END  | Y    |
      |------|------|------|
    
    When a user tries to place a breakpoint in file 2 at line 22, this is
    no longer possible.
    
    The solution I propose here is that we ignore line table entries that
    would trigger a change of file if:
    
      1. The new line being added is at the same address as the previous
      line, and
    
      2. We have previously seen an is-stmt line at the current address.
    
    The result of this is that GDB switches file, and knows that some line
    entry (or entries) are going to be discarded, prefer to keep is-stmt
    lines and discard non-stmt lines.
    
    After this commit the lines tables are now:
    
      File 1                   File 2
      ------                   ------
    
      | Addr | Line | Stmt |  | Addr | Line | Stmt |
      |------|------|------|  |------|------|------|
      | 1    | 16   | Y    |  | 3    | 21   | Y    |
      | 2    | 17   | Y    |  | 4    | 22   | Y    |
      | 3    | END  | Y    |  | 5    | 23   | N    |
      | 5    | END  | Y    |  | 6    | END  | Y    |
      | 6    | 24   | Y    |  |------|------|------|
      | 7    | END  | Y    |
      |------|------|------|
    
    We've lost the non-stmt entry for file 1, line 18, but retained the
    is-stmt entry for file 2, line 22.  The user can now place a
    breakpoint at that location.
    
    One problem that came from this commit was the test
    gdb.cp/step-and-next-inline.exp, which broke in several places.  After
    looking at this test again I think that in some cases this test was
    only ever passing by pure luck.  The debug GCC is producing for this
    test is pretty broken.  I raised this GCC bug:
    
      https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
    
    for this and disabled one entire half of the test.  There are still
    some cases in here that do pass, and if/when GCC is fixed it would be
    great to enable this test again.
    
    gdb/ChangeLog:
    
            * dwarf2/read.c (class lnp_state_machine) <m_last_address>: New
            member variable.
            <m_stmt_at_address>: New member variable.
            (lnp_state_machine::record_line): Don't record some lines, update
            tracking of is_stmt at the same address.
            (lnp_state_machine::lnp_state_machine): Initialise new member
            variables.
    
    gdb/testsuite/ChangeLog:
    
            * gdb.cp/step-and-next-inline.exp (do_test): Skip all tests in the
            use_header case.
            * gdb.dwarf2/dw2-inline-header-1.exp: New file.
            * gdb.dwarf2/dw2-inline-header-2.exp: New file.
            * gdb.dwarf2/dw2-inline-header-3.exp: New file.
            * gdb.dwarf2/dw2-inline-header-lbls.c: New file.
            * gdb.dwarf2/dw2-inline-header.c: New file.
            * gdb.dwarf2/dw2-inline-header.h: New file.

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index da702205c60..36e8b24a29a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -19508,6 +19508,15 @@ class lnp_state_machine
   /* The last file a line number was recorded for.  */
   struct subfile *m_last_subfile = NULL;
 
+  /* The address of the last line entry.  */
+  CORE_ADDR m_last_address;
+
+  /* Set to true when a previous line at the same address (using
+     m_last_address) had m_is_stmt true.  This is reset to false when a
+     line entry at a new address (m_address different to m_last_address) is
+     processed.  */
+  bool m_stmt_at_address = false;
+
   /* When true, record the lines we decode.  */
   bool m_currently_recording_lines = false;
 
@@ -19701,14 +19710,34 @@ lnp_state_machine::record_line (bool end_sequence)
       fe->included_p = 1;
       if (m_record_lines_p)
 	{
-	  if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
-	      || end_sequence)
+	  /* When we switch files we insert an end maker in the first file,
+	     switch to the second file and add a new line entry.  The
+	     problem is that the end marker inserted in the first file will
+	     discard any previous line entries at the same address.  If the
+	     line entries in the first file are marked as is-stmt, while
+	     the new line in the second file is non-stmt, then this means
+	     the end marker will discard is-stmt lines so we can have a
+	     non-stmt line.  This means that there are less addresses at
+	     which the user can insert a breakpoint.
+
+	     To improve this we track the last address in m_last_address,
+	     and whether we have seen an is-stmt at this address.  Then
+	     when switching files, if we have seen a stmt at the current
+	     address, and we are switching to create a non-stmt line, then
+	     discard the new line.  */
+	  bool file_changed
+	    = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
+	  bool ignore_this_line
+	    = (file_changed && !end_sequence && m_last_address == m_address
+	       && !m_is_stmt && m_stmt_at_address);
+
+	  if ((file_changed && !ignore_this_line) || end_sequence)
 	    {
 	      dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
 				 m_currently_recording_lines ? m_cu : nullptr);
 	    }
 
-	  if (!end_sequence)
+	  if (!end_sequence && !ignore_this_line)
 	    {
 	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -19727,6 +19756,15 @@ lnp_state_machine::record_line (bool end_sequence)
 	    }
 	}
     }
+
+  /* Track whether we have seen any m_is_stmt true at m_address in case we
+     have multiple line table entries all at m_address.  */
+  if (m_last_address != m_address)
+    {
+      m_stmt_at_address = false;
+      m_last_address = m_address;
+    }
+  m_stmt_at_address |= m_is_stmt;
 }
 
 lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -19746,6 +19784,9 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
   m_address = gdbarch_adjust_dwarf2_line (arch, 0, 0);
   m_is_stmt = lh->default_is_stmt;
   m_discriminator = 0;
+
+  m_last_address = m_address;
+  m_stmt_at_address = false;
 }
 
 void
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 3733fa75570..a95e21194f9 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -24,6 +24,13 @@ if { ![supports_statement_frontiers] } {
 proc do_test { use_header } {
     global srcfile testfile
 
+    if { $use_header } {
+	# This test will not pass due to poor debug information
+	# generated by GCC (at least upto 10.x).  See
+	# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
+	return
+    }
+
     set options {c++ debug nowarnings optimize=-O2\ -gstatement-frontiers}
     if { $use_header } {
 	lappend options additional_flags=-DUSE_NEXT_INLINE_H
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
new file mode 100644
index 00000000000..6a1e990002c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
@@ -0,0 +1,156 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1    | 1    | 16   | Y    |
+# | 2    | 1    | 17   | Y    |
+# | 3    | 2    | 21   | Y    |
+# | 4    | 2    | 22   | Y    |
+# | 4    | 1    | 18   | N    |
+# | 5    | 2    | 23   | N    |
+# | 6    | 1    | 24   | Y    |
+# | 7    | 1    | END  | Y    |
+# |------|------|------|------|
+#
+# Places a brekpoint at file 2, line 22.  Previously GDB would discrad
+# the line table entry for this line due to switching files for the
+# file 1, line 18 non-statement line.  After patching however, GDB now
+# discards the file 1, line 18 entry instead, and the breakpoint at
+# line 22 should succeed.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# The .c files use __attribute__.
+if [get_compiler_info] {
+    return -1
+}
+if !$gcc_compiled {
+    return 0
+}
+
+standard_testfile dw2-inline-header-lbls.c dw2-inline-header.S \
+    dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global srcdir subdir srcfile srcfile3 srcfile4
+    declare_labels lines_label callee_subprog_label
+
+    get_func_info main
+
+    cu {} {
+	compile_unit {
+	    {producer "gcc" }
+	    {language @DW_LANG_C}
+	    {name ${srcfile3}}
+	    {low_pc 0 addr}
+	    {stmt_list ${lines_label} DW_FORM_sec_offset}
+	} {
+	    callee_subprog_label: subprogram {
+		{external 1 flag}
+		{name callee}
+		{inline 3 data1}
+	    }
+	    subprogram {
+		{external 1 flag}
+		{name main}
+		{low_pc $main_start addr}
+		{high_pc "$main_start + $main_len" addr}
+	    } {
+		inlined_subroutine {
+		    {abstract_origin %$callee_subprog_label}
+		    {low_pc line_label_1 addr}
+		    {high_pc line_label_7 addr}
+		    {call_file 1 data1}
+		    {call_line 18 data1}
+		}
+	    }
+	}
+    }
+
+    lines {version 2 default_is_stmt 1} lines_label {
+	include_dir "${srcdir}/${subdir}"
+	file_name "$srcfile3" 1
+	file_name "$srcfile4" 1
+
+	program {
+	    {DW_LNE_set_address line_label_1}
+	    {DW_LNS_advance_line 15}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_2}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_set_file 2}
+	    {DW_LNE_set_address line_label_3}
+	    {DW_LNS_advance_line 4}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_4}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_advance_line -4}
+	    {DW_LNS_set_file 1}
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_set_file 2}
+	    {DW_LNE_set_address line_label_5}
+	    {DW_LNS_advance_line 5}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_set_file 1}
+	    {DW_LNE_set_address line_label_6}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_7}
+	    {DW_LNE_end_sequence}
+	}
+    }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected.  It should
+# appear at the requested line.  When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+    ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
new file mode 100644
index 00000000000..46499919a8b
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
@@ -0,0 +1,179 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1    | 1    | 16   | Y    |
+# | 2    | 1    | 17   | Y    |
+# | 3    | 2    | 21   | Y    |
+# | 4    | 2    | 22   | Y    |
+# | 4    | 1    | 18   | N    |
+# | 5    | 1    | 19   | Y    |
+# | 6    | 1    | 20   | Y    |
+# | 7    | 1    | END  | Y    |
+# |------|------|------|------|
+#
+#
+# Place the first brekpoint at file 2, line 22 and a second breakpoint
+# at file 1, line 19.  A third breakpoint is placed at file 1, line
+# 18, but as this line table entry will have been discarded[1] the
+# third breakpoint will actually be placed at the same location as the
+# second breakpoint.
+#
+# [1] The entry for file 1, line 18 is discarded because it is at the
+# same address as the previous entry, but the previous entry is-stmt,
+# while line 18 is a non-stmt.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# The .c files use __attribute__.
+if [get_compiler_info] {
+    return -1
+}
+if !$gcc_compiled {
+    return 0
+}
+
+standard_testfile dw2-inline-header-lbls.c dw2-inline-header.S \
+    dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global srcdir subdir srcfile srcfile3 srcfile4
+    declare_labels lines_label callee_subprog_label
+
+    get_func_info main
+
+    cu {} {
+	compile_unit {
+	    {producer "gcc" }
+	    {language @DW_LANG_C}
+	    {name ${srcfile3}}
+	    {low_pc 0 addr}
+	    {stmt_list ${lines_label} DW_FORM_sec_offset}
+	} {
+	    callee_subprog_label: subprogram {
+		{external 1 flag}
+		{name callee}
+		{inline 3 data1}
+	    }
+	    subprogram {
+		{external 1 flag}
+		{name main}
+		{low_pc $main_start addr}
+		{high_pc "$main_start + $main_len" addr}
+	    } {
+		inlined_subroutine {
+		    {abstract_origin %$callee_subprog_label}
+		    {low_pc line_label_1 addr}
+		    {high_pc line_label_7 addr}
+		    {call_file 1 data1}
+		    {call_line 18 data1}
+		}
+	    }
+	}
+    }
+
+    lines {version 2 default_is_stmt 1} lines_label {
+	include_dir "${srcdir}/${subdir}"
+	file_name "$srcfile3" 1
+	file_name "$srcfile4" 1
+
+	program {
+	    {DW_LNE_set_address line_label_1}
+	    {DW_LNS_advance_line 15}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_2}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_set_file 2}
+	    {DW_LNE_set_address line_label_3}
+	    {DW_LNS_advance_line 4}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_4}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_advance_line -4}
+	    {DW_LNS_set_file 1}
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_5}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_6}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_7}
+	    {DW_LNE_end_sequence}
+	}
+    }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected.  It should
+# appear at the requested line.  When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+    ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*" \
+    "check for breakpoint at ${srcfile4}"
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile3}:19"
+
+# Check that the breakpoint was placed where we expected.  It should
+# appear at the requested line.  When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+    ".* in callee at \[^\r\n\]+${srcfile3}:19\\y.*" \
+    "check for breakpoint at ${srcfile3}"
+
+# Line table entry for line 18 will have been discarded, so this
+# brekpoint will be at the same location as line 19.
+gdb_test "break ${srcfile3}:18" \
+    "Note: breakpoint $decimal also set at pc $hex.*"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
new file mode 100644
index 00000000000..161a1fc2aea
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp
@@ -0,0 +1,190 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Setup a line table where:
+#
+# | Addr | File | Line | Stmt |
+# |------|------|------|------|
+# | 1    | 1    | 16   | Y    |
+# | 2    | 1    | 17   | Y    |
+# | 3    | 2    | 21   | Y    |
+# | 4    | 2    | 22   | Y    |
+# | 4    | 1    | 18   | N    |
+# | 5    | 1    | 19   | N    |
+# | 6    | 1    | 20   | Y    |
+# | 7    | 1    | END  | Y    |
+# |------|------|------|------|
+#
+# Break at file 2, line 22, then single instruction step forward.  We
+# should pass through line 19 and then encounter line 20.
+#
+# Currently we don't expect GDB to see file 1, line 18, as this is a
+# non-stmt line in a different file at the same address as the
+# previous is-stmt line.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# The .c files use __attribute__.
+if [get_compiler_info] {
+    return -1
+}
+if !$gcc_compiled {
+    return 0
+}
+
+standard_testfile dw2-inline-header-lbls.c dw2-inline-header.S \
+    dw2-inline-header.c dw2-inline-header.h
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global srcdir subdir srcfile srcfile3 srcfile4
+    declare_labels lines_label callee_subprog_label
+
+    get_func_info main
+
+    cu {} {
+	compile_unit {
+	    {producer "gcc" }
+	    {language @DW_LANG_C}
+	    {name ${srcfile3}}
+	    {low_pc 0 addr}
+	    {stmt_list ${lines_label} DW_FORM_sec_offset}
+	} {
+	    callee_subprog_label: subprogram {
+		{external 1 flag}
+		{name callee}
+		{inline 3 data1}
+	    }
+	    subprogram {
+		{external 1 flag}
+		{name main}
+		{low_pc $main_start addr}
+		{high_pc "$main_start + $main_len" addr}
+	    } {
+		inlined_subroutine {
+		    {abstract_origin %$callee_subprog_label}
+		    {low_pc line_label_1 addr}
+		    {high_pc line_label_7 addr}
+		    {call_file 1 data1}
+		    {call_line 18 data1}
+		}
+	    }
+	}
+    }
+
+    lines {version 2 default_is_stmt 1} lines_label {
+	include_dir "${srcdir}/${subdir}"
+	file_name "$srcfile3" 1
+	file_name "$srcfile4" 1
+
+	program {
+	    {DW_LNE_set_address line_label_1}
+	    {DW_LNS_advance_line 15}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_2}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_set_file 2}
+	    {DW_LNE_set_address line_label_3}
+	    {DW_LNS_advance_line 4}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_4}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNS_advance_line -4}
+	    {DW_LNS_set_file 1}
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_5}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_6}
+	    {DW_LNS_advance_line 1}
+	    {DW_LNS_negate_stmt}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address line_label_7}
+	    {DW_LNE_end_sequence}
+	}
+    }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile $asm_file] {nodebug optimize=-O1}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Delete all breakpoints so that the output of "info breakpoints"
+# below will only contain a single breakpoint.
+delete_breakpoints
+
+# Place a breakpoint within the function in the header file.
+gdb_breakpoint "${srcfile4}:22"
+
+# Check that the breakpoint was placed where we expected.  It should
+# appear at the requested line.  When the bug in GDB was present the
+# breakpoint would be placed on one of the following lines instead.
+gdb_test "info breakpoints" \
+    ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*"
+
+gdb_continue_to_breakpoint "${srcfile4}:22" \
+    ".* ${srcfile4} : 22 .*"
+
+# Now single instruction step forward.  Eventually we should hit
+# ${srcfile3}:20, but before we do we should hit the non-statement
+# line ${srcfile3}:19.
+#
+# We don't know how many instructions we'll need to step, but 100
+# should be enough for everyone (surely), and this stops us looping
+# forever if something goes wrong.
+set found_line_19 0
+set found_line_20 0
+set keep_going 1
+for { set i 0 } { $i < 100 && $keep_going } { incr i } {
+    set keep_going 0
+    gdb_test_multiple "stepi" "stepi ${i}" {
+	-re "${srcfile3} : 19 .*${gdb_prompt} " {
+	    set found_line_19 1
+	    set keep_going 1
+	}
+
+	-re "${srcfile3} : 20 .*${gdb_prompt} " {
+	    set found_line_20 1
+	}
+
+	-re "${srcfile4} : 22 .*${gdb_prompt} " {
+	    # Not left line 22 yet.
+	    set keep_going 1
+	}
+    }
+}
+
+gdb_assert { $found_line_19 && $found_line_20 } \
+    "found line 19 and 20"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c
new file mode 100644
index 00000000000..a1b7b17cbeb
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c
@@ -0,0 +1,46 @@
+/* Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Used to insert labels with which we can build a fake line table.  */
+#define LL(N) asm ("line_label_" #N ": .globl line_label_" #N)
+
+volatile int var;
+volatile int bar;
+
+/* Generate some code to take up some space.  */
+#define FILLER do { \
+    var = 99;	    \
+} while (0)
+
+int
+main ()
+{					/* main prologue */
+  asm ("main_label: .globl main_label");
+  LL (1);	// F1, Ln 16
+  FILLER;
+  LL (2);	// F1, Ln 17
+  FILLER;
+  LL (3);	// F2, Ln 21
+  FILLER;
+  LL (4);	// F2, Ln 22 // F1, Ln 18, !S
+  FILLER;
+  LL (5);	// F1, Ln 19 !S
+  FILLER;
+  LL (6);	// F1, Ln 20
+  FILLER;
+  LL (7);
+  FILLER;
+  return 0;				/* main end */
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c
new file mode 100644
index 00000000000..a8331268a09
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c
@@ -0,0 +1,24 @@
+/* Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* dw2-inline-header.c : 16 */
+/* dw2-inline-header.c : 17 */
+/* dw2-inline-header.c : 18 */
+/* dw2-inline-header.c : 19 */
+/* dw2-inline-header.c : 20 */
+/* dw2-inline-header.c : 21 */
+/* dw2-inline-header.c : 22 */
+/* dw2-inline-header.c : 23 */
+/* dw2-inline-header.c : 24 */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h
new file mode 100644
index 00000000000..7233acbcd76
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h
@@ -0,0 +1,24 @@
+/* Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* dw2-inline-header.h : 16 */
+/* dw2-inline-header.h : 17 */
+/* dw2-inline-header.h : 18 */
+/* dw2-inline-header.h : 19 */
+/* dw2-inline-header.h : 20 */
+/* dw2-inline-header.h : 21 */
+/* dw2-inline-header.h : 22 */
+/* dw2-inline-header.h : 23 */
+/* dw2-inline-header.h : 24 */
Bernd Edlinger April 14, 2020, 11:37 a.m. | #10
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 */

>
Bernd Edlinger April 14, 2020, 11:41 a.m. | #11
On 4/14/20 1:37 PM, Bernd Edlinger wrote:
> 

> 

> 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.


Sorry for typo, I blame my keyborad for it :)
I meant: subroutine 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 */

>>
Andrew Burgess April 14, 2020, 1:08 p.m. | #12
* Bernd Edlinger <bernd.edlinger@hotmail.de> [2020-04-14 13:37:56 +0200]:

> 

> 

> 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.


I think you're referring here to the invalid range information
produced by GCC, but maybe I'm wrong and you mean something else?

If you are talking about the invalid ranges, as produced in
gdb.cp/step-and-next-inline.exp, then no, I haven't tried to fix this
as I don't think we can.  Unless we can show that GCC is always wrong,
and always wrong in the same say then I don't see how we can know that
GCC has cut a range short.  That's why I raised GCC bug:

  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

with the hope that we'd get some clarity from the GCC maintainers.

I did hack GDB to "fix" the ranges, but this was done using fixed
addresses, basically, "if (range_end == 0x......) range_end =
0x......", which obviously isn't a real fix, but did show me that iff
GCC got the range information correct, then the test would basically
pass just fine.

Let me know if you were actually referencing something else.

Thanks
Andrew








> 

> 

> 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 */

> >
Andrew Burgess April 16, 2020, 5:18 p.m. | #13
Tested this patch on another machine threw up another issue with the
tests.  I was compiling the test file at -O0 to extract label
locations, and -O1 when creating the final build.  On my older machine
this (apparently) wasn't a problem, but with a newer GCC this causes a
test failure.

The only change in this version is in the
dw2-inline-header-{1,2,3}.exp files.

Thanks,
Andrew

---

commit 05c134477fa87759d018d59dc579382582dc6005
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..0ba481ad4b7
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp
@@ -0,0 +1,159 @@
+# 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 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_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] $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.*"
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..b8ce88ce32e
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp
@@ -0,0 +1,182 @@
+# 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 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_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] $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 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..a2a2dfd07bd
--- /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 |
+# |------|------|------|------|
+# | 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 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_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] $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 */
Tom Tromey April 22, 2020, 9:13 p.m. | #14
>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:


I read through the various threads on this topic, though I think maybe
not very well.

IIUC, the issue at hand is that there are two proposed patches to fix
various issues in this area.


Andrew's patch takes us roughly to the status quo from before is-stmt
landed.  This patch takes the view that GCC is currently buggy, so one
test is partly disabled; and there's a new bug so we can fix GDB once
GCC is fixed.

Bernd's patch takes the view that GCC won't be fixed and tries to work
around the problem; it drops at least one "FILE:LINE" case that
currently works.


Is that a fair summary?  There were many messages and details, so I'm
not sure I either understood it all or that it can be summarized like
this.

If that's fair, then my inclination is to move forward with Andrew's
patch for the time being, with the primary justification being
conservatism.  Bernd's patch can always land if/when we have some
clarification from GCC about whether the bugs there will be fixed.

Let me know what you think.

Tom
Bernd Edlinger April 25, 2020, 7:06 a.m. | #15
CC Alexandre Oliva, who maintains this part of GCC.


On 4/22/20 11:13 PM, Tom Tromey wrote:
>>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

> 

> I read through the various threads on this topic, though I think maybe

> not very well.

> 

> IIUC, the issue at hand is that there are two proposed patches to fix

> various issues in this area.

> 

> 

> Andrew's patch takes us roughly to the status quo from before is-stmt

> landed.  This patch takes the view that GCC is currently buggy, so one

> test is partly disabled; and there's a new bug so we can fix GDB once

> GCC is fixed.

> 

> Bernd's patch takes the view that GCC won't be fixed and tries to work

> around the problem; it drops at least one "FILE:LINE" case that

> currently works.

> 

> 

> Is that a fair summary?  There were many messages and details, so I'm

> not sure I either understood it all or that it can be summarized like

> this.

> 


Yes, I agree with this summary.

> If that's fair, then my inclination is to move forward with Andrew's

> patch for the time being, with the primary justification being

> conservatism.  Bernd's patch can always land if/when we have some

> clarification from GCC about whether the bugs there will be fixed.

> 

> Let me know what you think.

> 


I think if we take Andrew's patch the only possible outcome
will be that gcc will disable that statement frontiers debug
option by default, because they do not understand what we
want from them.  (I am one of them, but I came here to understand
you better)


Bernd.

> Tom

>
Andrew Burgess April 27, 2020, 10:34 a.m. | #16
* Bernd Edlinger <bernd.edlinger@hotmail.de> [2020-04-25 09:06:35 +0200]:

> CC Alexandre Oliva, who maintains this part of GCC.

> 

> 

> On 4/22/20 11:13 PM, Tom Tromey wrote:

> >>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

> > 

> > I read through the various threads on this topic, though I think maybe

> > not very well.

> > 

> > IIUC, the issue at hand is that there are two proposed patches to fix

> > various issues in this area.

> > 

> > 

> > Andrew's patch takes us roughly to the status quo from before is-stmt

> > landed.  This patch takes the view that GCC is currently buggy, so one

> > test is partly disabled; and there's a new bug so we can fix GDB once

> > GCC is fixed.

> > 

> > Bernd's patch takes the view that GCC won't be fixed and tries to work

> > around the problem; it drops at least one "FILE:LINE" case that

> > currently works.

> > 

> > 

> > Is that a fair summary?  There were many messages and details, so I'm

> > not sure I either understood it all or that it can be summarized like

> > this.

> > 

> 

> Yes, I agree with this summary.

> 

> > If that's fair, then my inclination is to move forward with Andrew's

> > patch for the time being, with the primary justification being

> > conservatism.  Bernd's patch can always land if/when we have some

> > clarification from GCC about whether the bugs there will be fixed.

> > 

> > Let me know what you think.

> > 

> 

> I think if we take Andrew's patch the only possible outcome

> will be that gcc will disable that statement frontiers debug

> option by default, because they do not understand what we

> want from them.  (I am one of them, but I came here to understand

> you better)


I tried to describe the two current issues I see with GCC in this bug
report[1] but after a stupid mistake by me of using an older version
of binutils the conversation got side-tracked into a discussion about
view numbers and GDB.

It is my position that neither of the bugs described in [1] require
view number changes, nor additional DWARF features, they could be
fixed entirely withing GCC (in theory at least).

I'm not entirely sure which bit of debug statement frontiers is
responsible for.

After reading one of your other email[2], in which you said this bug
was present from GCC-7 I went and ran some tests, as I thought
gdb.cp/step-and-next-inline.exp doesn't run on GCC-7 as GCC that old
doesn't support -gstatement-frontiers.  I was right, that flag doesn't
exist on GCC-7, and your were correct that some of the range bugs (at
least) do still exist on GCC-7.

After reading[2] I'd also be interest to understand what flaw in DWARF
you feel makes a difference in this case.  Given some of your feedback
in [1] I think that you might be talking about improvements (the
addition of?) to the view number support, but while I agree with you
that this might (would?) allow for improved debug experience, I don't
think it would be needed in order for GCC to do better in this case.

I think it is great Bernd, that you are reaching out from the GCC
community to engage with GDB, this is certainly the best way to ensure
that we can work together as communities to give the best possible
debug experience, and I'm sorry you feel that I have not been clear
enough about the issues I'm seeing here.

I do still think that merging my patch is the correct way to move
forward, however, I don't think the future has to be as bleak as you
describe above.  I am happy to continue discussing this issue for as
long as you are in order to try and find a solution that makes
everyone happy.  That said, here's what I think would need to happen
so that _I_ (personally) was happy to accept your patch:

  1. We need to agree what we're working around.  In [2] you describe
  this issue as a flaw in DWARF, while in [1] I describe this as an
  issue in GCC.  I think we need to first need to agree on what the
  spec says, what GCC can (currently) do in an ideal world, and what
  GCC can be expected to do (currently) in the real world.

  2. We should change GDB assuming that any bugs in GCC or DWARF will
  one day be fixed, and that when that happens we would, ideally, not
  have to apply the work around.  So fixes should be guarded with a
  check of either the producer or the DWARF version.

  3. Currently (to me) it appears that we are crafting a work around
  based on one test case (gdb.cp/step-and-next-inline.exp).  My
  concern here is that when we talk about changing the line table, or
  range handling, these are pretty core aspects of GDB.

  As a GCC developer you probably have more insight, but it doesn't
  feel clear to me yet, do we know that GCC always misbehaves in the
  same say across all, or most, compiled code?

  I don't know how we address this without merging your patch,
  releasing GDB and seeing how it works in the wild.  However, if we
  did decide to "just try it", I would still prefer we staged things
  as:
    (a) Merge my patch, targeted regression fix, then
    (b) Your patch, new functionality GCC/DWARF ranges work around.
  In this way, if we end up backing out some or all of (b) we still
  have (a) in place that fixes the regression.  I'm more than happy
  for a rebase of (b) in include full removal of (a).

Thanks for your continued input.

Andrew

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
[2] https://sourceware.org/pipermail/gdb-patches/2020-April/167933.html
Tom Tromey May 14, 2020, 8:18 p.m. | #17
>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:


Resurrecting this again ... we have some internal tests that have been
failing, and I want to land at least one of these patches to resolve
this.

Andrew> After reading[2] I'd also be interest to understand what flaw in
Andrew> DWARF you feel makes a difference in this case.

I also don't understand this.

Andrew> I think it is great Bernd, that you are reaching out from the GCC
Andrew> community to engage with GDB, this is certainly the best way to ensure
Andrew> that we can work together as communities to give the best possible
Andrew> debug experience, and I'm sorry you feel that I have not been clear
Andrew> enough about the issues I'm seeing here.

+1

Andrew>   I don't know how we address this without merging your patch,
Andrew>   releasing GDB and seeing how it works in the wild.  However, if we
Andrew>   did decide to "just try it", I would still prefer we staged things
Andrew>   as:
Andrew>     (a) Merge my patch, targeted regression fix, then
Andrew>     (b) Your patch, new functionality GCC/DWARF ranges work around.
Andrew>   In this way, if we end up backing out some or all of (b) we still
Andrew>   have (a) in place that fixes the regression.  I'm more than happy
Andrew>   for a rebase of (b) in include full removal of (a).

I think landing your patch is safe to do while we discuss part (b).
How about we move forward with that part?  Then if we come to agreement
on where the bug lies we can decide about that.

Tom
Andrew Burgess May 14, 2020, 10:39 p.m. | #18
* Tom Tromey <tom@tromey.com> [2020-05-14 14:18:44 -0600]:

> >>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

> 

> Resurrecting this again ... we have some internal tests that have been

> failing, and I want to land at least one of these patches to resolve

> this.

> 

> Andrew> After reading[2] I'd also be interest to understand what flaw in

> Andrew> DWARF you feel makes a difference in this case.

> 

> I also don't understand this.

> 

> Andrew> I think it is great Bernd, that you are reaching out from the GCC

> Andrew> community to engage with GDB, this is certainly the best way to ensure

> Andrew> that we can work together as communities to give the best possible

> Andrew> debug experience, and I'm sorry you feel that I have not been clear

> Andrew> enough about the issues I'm seeing here.

> 

> +1

> 

> Andrew>   I don't know how we address this without merging your patch,

> Andrew>   releasing GDB and seeing how it works in the wild.  However, if we

> Andrew>   did decide to "just try it", I would still prefer we staged things

> Andrew>   as:

> Andrew>     (a) Merge my patch, targeted regression fix, then

> Andrew>     (b) Your patch, new functionality GCC/DWARF ranges work around.

> Andrew>   In this way, if we end up backing out some or all of (b) we still

> Andrew>   have (a) in place that fixes the regression.  I'm more than happy

> Andrew>   for a rebase of (b) in include full removal of (a).

> 

> I think landing your patch is safe to do while we discuss part (b).

> How about we move forward with that part?  Then if we come to agreement

> on where the bug lies we can decide about that.


I agree. I already rebased this and retested it.  Unless someone
shouts out between now and tomorrow I plan to merge my patch.

Bernd (or anyone else) - I'm more than happy that if a better patch is
put forward it can revert some or all of my patch, as needed.  Like
Tom, I'd like to see the regressions squashed.

Thanks,
Andrew
Bernd Edlinger May 15, 2020, 3:35 a.m. | #19
Hi Andrew, and Tom

I'll try to help, if I can.
I must admit I was busy with other things, so I have
not much new info, but I can add my view.

First I want to make you aware, of my last e-mails
on this issue, I wonder if you got them.

I added  Alexandre Oliva who maintains the debug info
in GCC to CC then, and unfortunately although I was
hoping that he gives his view on this matter, I think
I have not received any response from him so far.

https://sourceware.org/pipermail/gdb-patches/2020-April/167933.html
https://sourceware.org/pipermail/gdb-patches/2020-April/167932.html

I must note that it is impossible to find out the
e-mail addresses which were in CC on the mailing list
archives since the unfortunate move to the new
maling list archive format.  But I added oliva@gnu.org
in CC, probably you should do that as well, since
I think we cannot get anything changed in the gcc
debug output unless we can convince him about it.

Andrew, as far as I remember the range info of the
inlined subroutines were not correct, in your patch.

GCC tells us where the code originating from the
inlined code starts and ends.  The byte addresses.
These must be the same addresses where the line numbers
switch from the calling procedure to the inlined procedure
but the range info in your dwarf code is artificially
and it is having start and end addresses where they
should be.

Can you please fix the range infos in your patch
and re-post it, before we decide how to proceed?

I will probably not have time to do much today,
since this is my son's birthday, and I will probably
bake a birthday cake instead :-)

But I would say that I see a way how I can adjust my
patch to fix the issues which were raised by your test
case (I added the test case from your patch to mine,
and most of it seems to be fine with my latest patch,
one remaining issue is a bit nasty but fixable).
I'll attach the patch file where I am at here, so
you can see what I have now.
It fails only one test case in dw2-inline-header-3.exp
but I would like how it compares to your patch
when Tom would like to try it out on the
internal test cases, he mentioned.

And, yes, of course my approach is that the debug info
is not optimal at all as it is emitted by gcc, but 
gdb can probably work around it until it is fixed
which should happen when a new updated dwarf extension
is invented which tells us the view number where
the inlined subroutine ends.  The line table program
has view numbers, but not the range info of the
subroutine.  That is the deficiency in the dwarf
format I think causes the trouble, apart from the
fact that dwarf is already too complicate to understand.

I must also say, that since if I remember correctly
Andrew's patch makes

gdb.cp/step-and-next-inline.exp

fail, I consider my attempt to make gdb work around
the debug info of inlined subroutines a failure.

While my patch did make

gdb.cp/step-and-next-inline.exp

succeed completely, also the case where the inline
function is not in a header file.

I must also say, and that is not because I have
emotions about it, but just because I consider it
the only possible option when we consider gcc's
debug output format completely broken, then
I will probably just send a one-line patch to
gcc-patches, which reverts the default of
-gstatement-frontiers, that would be safe for
backporting to all active branches.

And it would prevent the !is_stmt line infos
completely, the debug format will then
probably work as before gcc-8 implemented
that for the first time.

So I attached my latest patch version, together
with the Test case from Andrews patch.




On 5/15/20 12:39 AM, Andrew Burgess wrote:
> * Tom Tromey <tom@tromey.com> [2020-05-14 14:18:44 -0600]:

> 

>>>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

>>

>> Resurrecting this again ... we have some internal tests that have been

>> failing, and I want to land at least one of these patches to resolve

>> this.

>>

>> Andrew> After reading[2] I'd also be interest to understand what flaw in

>> Andrew> DWARF you feel makes a difference in this case.

>>

>> I also don't understand this.

>>


When you only know where an inline function ends at the byte address.
You can habe line table entries at the same address from the inline
funcion and from the calling function.  It is impossible to distinguish
between those, however there is a view number which would be different,
and as Alexandre explains it, these can be consider an extension to the
byte addresses, so if a range info would add a view number we would
know which line infos are from the subroutine and which are not, even
if the byte addresses are identical.

>> Andrew> I think it is great Bernd, that you are reaching out from the GCC

>> Andrew> community to engage with GDB, this is certainly the best way to ensure

>> Andrew> that we can work together as communities to give the best possible

>> Andrew> debug experience, and I'm sorry you feel that I have not been clear

>> Andrew> enough about the issues I'm seeing here.

>>

>> +1

>>


I still think this is possible, I think we need to understand each other
better.  Of course stress from release cycles might this even harder.
Are we (gdb maintainers) already under stress to reach the next release version?

>> Andrew>   I don't know how we address this without merging your patch,

>> Andrew>   releasing GDB and seeing how it works in the wild.  However, if we

>> Andrew>   did decide to "just try it", I would still prefer we staged things

>> Andrew>   as:

>> Andrew>     (a) Merge my patch, targeted regression fix, then

>> Andrew>     (b) Your patch, new functionality GCC/DWARF ranges work around.

>> Andrew>   In this way, if we end up backing out some or all of (b) we still

>> Andrew>   have (a) in place that fixes the regression.  I'm more than happy

>> Andrew>   for a rebase of (b) in include full removal of (a).

>>

>> I think landing your patch is safe to do while we discuss part (b).

>> How about we move forward with that part?  Then if we come to agreement

>> on where the bug lies we can decide about that.

> 

> I agree. I already rebased this and retested it.  Unless someone

> shouts out between now and tomorrow I plan to merge my patch.

> 

> Bernd (or anyone else) - I'm more than happy that if a better patch is

> put forward it can revert some or all of my patch, as needed.  Like

> Tom, I'd like to see the regressions squashed.

> 


No, I am not able to do this once we decide that gcc's debug info
is impossible to implement, I will send a patch to the gcc-patches
which restores the gcc-7 debug info.  My patch was based on the
assumption that there is a way to work around the issues, but if
that turns out to be a failure, I will not go back and revert
your patch again, since it seems to revert my work on that issue
completely (see how this patch breaks the step-and-next-inline.exp
test case).  And once again, I feel not at all emotional, just that
I want the issue fixed, and next time I will try a completely
different approach which is gcc was wrong, and therefore we will
revert Alexandre Oliva's patch, since it is the least effort and
Alexandre already signaled he also had considered that already.

Alexandre Oliva wrote on 11/19/19:
https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534845.html
> Perhaps we should change our defaults, if the situation with GDB does

> not change :-(



Andrew:
Have you attached your *latest* patch?
Have you done the changes I requested?

Thanks
Bernd.
From 1ae05f16f284d2367fcb233070b8664913a3b086 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 9 Feb 2020 21:13:17 +0100
Subject: [PATCH 1/2] Fix range end handling of inlined subroutines

Since the is_stmt is now handled, it becomes
possible to locate dubious is_stmt line entries
at the end of an inlined function, even if the
called inline function is in the same subfile.

When there is a sequence of line entries at the
same address where an inline range ends, and the
last item has is_stmt = 0, we force all previous
items to have is_stmt = 0 as well.

If the last line at that address has is_stmt = 1,
there is no need to change anything, since a step
over will always stop at that last line from the
same address, which is fine, since it is outside
the subroutine.

With this change we lose the ability to set
breakpoints on some lines using file:line syntax,
but the data is not completely lost, as the
line table is still holding those lines, just
with the is_stmt flag reset.

This is necessary as breakpoints on these lines
are problematic, as the call stack is often
wrong.  From the block info they appear to be
located in the caller, but they are actually meant
to be part of the subroutine, therefore usually one
frame is missing from the callstack when the
execution stops there.

This is about the best we can do at the moment,
unless location view information are added to the
block ranges debug info structure, and location
views are implemented in gdb in general.

This restores the previous behavior of
record_line that deletes lines at the end of
a function.

gdb:
2020-04-05  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* buildsym.c (buildsym_compunit::record_line): Delete
	previous lines at the same PC as the end sequence marker,
	but don't do that for a fake end sequence marker.
	(buildsym_compunit::record_inline_range_end,
	patch_inline_end_pos): New helper functions.
	(buildsym_compunit::end_symtab_with_blockvector): Patch line table.
	(buildsym_compunit::~buildsym_compunit): Cleanup m_inline_end_vector.
	* buildsym.h (buildsym_compunit::record_inline_range_end): Declare.
	(buildsym_compunit::m_inline_end_vector,
	buildsym_compunit::m_inline_end_vector_length,
	buildsym_compunit::m_inline_end_vector_nitems): New data items.
	* dwarf2/read.c (dwarf2_rnglists_process,
	dwarf2_ranges_process): Don't ignore empty ranges here.
	(dwarf2_ranges_read): Ignore empty ranges here.
	(dwarf2_record_block_ranges): Pass end of range PC to
	record_inline_range_end for inline functions.
	(dwarf_finish_line): Add new parameter end_sequence.
	(lnp_state_machine::record_line): Pass end_sequence to
	dwarf_finish_line.

gdb/testsuite:
2020-04-05  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* gdb.cp/step-and-next-inline.exp: Adjust test.
---
 gdb/buildsym.c                                | 115 +++++++++++++++++++++++---
 gdb/buildsym.h                                |  11 +++
 gdb/dwarf2/read.c                             |  30 ++++---
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |  17 ----
 4 files changed, 131 insertions(+), 42 deletions(-)

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index b9bcc33..ae90175 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -113,6 +113,8 @@ struct pending_block
       next1 = next->next;
       xfree ((void *) next);
     }
+
+  xfree (m_inline_end_vector);
 }
 
 struct macro_table *
@@ -691,19 +693,16 @@ struct blockvector *
 		      * sizeof (struct linetable_entry))));
     }
 
-  /* Normally, we treat lines as unsorted.  But the end of sequence
-     marker is special.  We sort line markers at the same PC by line
-     number, so end of sequence markers (which have line == 0) appear
-     first.  This is right if the marker ends the previous function,
-     and there is no padding before the next function.  But it is
-     wrong if the previous line was empty and we are now marking a
-     switch to a different subfile.  We must leave the end of sequence
-     marker at the end of this group of lines, not sort the empty line
-     to after the marker.  The easiest way to accomplish this is to
-     delete any empty lines from our table, if they are followed by
-     end of sequence markers.  All we lose is the ability to set
-     breakpoints at some lines which contain no instructions
-     anyway.  */
+  /* The end of sequence marker is special.  We need to delete any
+     previous lines at the same PC, otherwise these lines may cause
+     problems since they might be at the same address as the following
+     function.  For instance suppose a function calls abort there is no
+     reason to emit a ret after that point (no joke).
+     So the label may be at the same address where the following
+     function begins.  There is also a fake end of sequence marker (-1)
+     that we emit internally when switching between different CUs
+     In this case, duplicate line table entries shall not be deleted.
+     But the line table entry looks the same in both cases.  */
   if (line == 0)
     {
       while (subfile->line_vector->nitems > 0)
@@ -714,6 +713,8 @@ struct blockvector *
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == -1)
+    line = 0;
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
@@ -722,6 +723,90 @@ struct blockvector *
 }
 
 
+/* Record a PC where a inlined subroutine ends.  */
+
+void
+buildsym_compunit::record_inline_range_end (CORE_ADDR end)
+{
+  /* The performance of this function is very important,
+     it shall be O(n*log(n)) therefore we do not use std::vector
+     here since some compilers, e.g. visual studio, do not
+     guarantee that for vector::push_back.  */
+  if (m_inline_end_vector == nullptr)
+    {
+      m_inline_end_vector_length = INITIAL_LINE_VECTOR_LENGTH;
+      m_inline_end_vector = (CORE_ADDR *)
+	xmalloc (sizeof (CORE_ADDR) * m_inline_end_vector_length);
+      m_inline_end_vector_nitems = 0;
+    }
+  else if (m_inline_end_vector_nitems == m_inline_end_vector_length)
+    {
+      m_inline_end_vector_length *= 2;
+      m_inline_end_vector = (CORE_ADDR *)
+	xrealloc ((char *) m_inline_end_vector,
+		  sizeof (CORE_ADDR) * m_inline_end_vector_length);
+    }
+
+  m_inline_end_vector[m_inline_end_vector_nitems++] = end;
+}
+
+
+/* Patch the is_stmt bits at the given inline end address.
+   The line table has to be already sorted.  */
+
+static void
+patch_inline_end_pos (struct linetable *table, CORE_ADDR end)
+{
+  int a = 2, b = table->nitems - 1;
+  struct linetable_entry *items = table->item;
+
+  /* We need at least two items with pc = end in the table.
+     The lowest usable items are at pos 0 and 1, the highest
+     usable items are at pos b - 2 and b - 1.  */
+  if (a > b || end < items[1].pc || end > items[b - 2].pc)
+    return;
+
+  /* Look for the first item with pc > end in the range [a,b].
+     The previous element has pc = end or there is no match.
+     We set a = 2, since we need at least two consecutive elements
+     with pc = end to do anything useful.
+     We set b = nitems - 1, since we are not interested in the last
+     element which should be an end of sequence marker with line = 0
+     and is_stmt = 1.  */
+  while (a < b)
+    {
+      int c = (a + b) / 2;
+
+      if (end < items[c].pc)
+	b = c;
+      else
+	a = c + 1;
+    }
+
+  a--;
+  if (items[a].pc != end || items[a].is_stmt)
+    return;
+
+  /* When there is a sequence of line entries at the same address
+     where an inline range ends, and the last item has is_stmt = 0,
+     we force all previous items to have is_stmt = 0 as well.
+     Setting breakpoints at those addresses is currently not
+     supported, since it is unclear if the previous addresses are
+     part of the subroutine or the calling program.  */
+  do
+    {
+      /* We stop at the first line entry with a different address,
+	 or when we see an end of sequence marker.  */
+      a--;
+      if (items[a].pc != end || items[a].line == 0)
+	break;
+
+      items[a].is_stmt = 0;
+    }
+  while (a > 0);
+}
+
+
 /* Subroutine of end_symtab to simplify it.  Look for a subfile that
    matches the main source file's basename.  If there is only one, and
    if the main source file doesn't have any symbol or line number
@@ -955,6 +1040,10 @@ struct compunit_symtab *
 			      subfile->line_vector->item
 			      + subfile->line_vector->nitems,
 			      lte_is_less_than);
+
+	   for (int i = 0; i < m_inline_end_vector_nitems; i++)
+	     patch_inline_end_pos (subfile->line_vector,
+				   m_inline_end_vector[i]);
 	}
 
       /* Allocate a symbol table if necessary.  */
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index c768a4c..2845789 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -190,6 +190,8 @@ struct buildsym_compunit
   void record_line (struct subfile *subfile, int line, CORE_ADDR pc,
 		    bool is_stmt);
 
+  void record_inline_range_end (CORE_ADDR end);
+
   struct compunit_symtab *get_compunit_symtab ()
   {
     return m_compunit_symtab;
@@ -397,6 +399,15 @@ struct buildsym_compunit
 
   /* Pending symbols that are local to the lexical context.  */
   struct pending *m_local_symbols = nullptr;
+
+  /* Pending inline end range addresses.  */
+  CORE_ADDR * m_inline_end_vector = nullptr;
+
+  /* Number of allocated inline end range addresses.  */
+  int m_inline_end_vector_length = 0;
+
+  /* Number of pending inline end range addresses.  */
+  int m_inline_end_vector_nitems = 0;
 };
 
 
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ab21ab0..3c54a83 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -13703,10 +13703,6 @@ class process_die_scope
 	  return false;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       range_beginning += *base;
       range_end += *base;
 
@@ -13814,10 +13810,6 @@ class process_die_scope
 	  return 0;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       range_beginning += *base;
       range_end += *base;
 
@@ -13857,6 +13849,10 @@ class process_die_scope
   retval = dwarf2_ranges_process (offset, cu,
     [&] (CORE_ADDR range_beginning, CORE_ADDR range_end)
     {
+      /* Empty range entries have no effect.  */
+      if (range_beginning == range_end)
+	return;
+
       if (ranges_pst != NULL)
 	{
 	  CORE_ADDR lowpc;
@@ -14094,6 +14090,7 @@ class process_die_scope
   struct gdbarch *gdbarch = objfile->arch ();
   struct attribute *attr;
   struct attribute *attr_high;
+  bool inlined_subroutine = (die->tag == DW_TAG_inlined_subroutine);
 
   attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
   if (attr_high)
@@ -14109,7 +14106,10 @@ class process_die_scope
 
 	  low = gdbarch_adjust_dwarf2_addr (gdbarch, low + baseaddr);
 	  high = gdbarch_adjust_dwarf2_addr (gdbarch, high + baseaddr);
-	  cu->get_builder ()->record_block_range (block, low, high - 1);
+	  if (inlined_subroutine)
+	    cu->get_builder ()->record_inline_range_end (high);
+	  if (low < high)
+	    cu->get_builder ()->record_block_range (block, low, high - 1);
         }
     }
 
@@ -14134,6 +14134,10 @@ class process_die_scope
 	  end += baseaddr;
 	  start = gdbarch_adjust_dwarf2_addr (gdbarch, start);
 	  end = gdbarch_adjust_dwarf2_addr (gdbarch, end);
+	  if (inlined_subroutine)
+	    cu->get_builder ()->record_inline_range_end (end);
+	  if (start == end)
+	    return;
 	  cu->get_builder ()->record_block_range (block, start, end - 1);
 	  blockvec.emplace_back (start, end);
 	});
@@ -20031,7 +20035,7 @@ class lnp_state_machine
 
 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;
@@ -20044,7 +20048,8 @@ class lnp_state_machine
 			  paddress (gdbarch, address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu);
+  dwarf_record_line_1 (gdbarch, subfile, end_sequence ? 0 : -1, address,
+		       true, cu);
 }
 
 void
@@ -20077,7 +20082,8 @@ class lnp_state_machine
 	      || 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/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 3733fa7..e3a5793 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -52,37 +52,20 @@ proc do_test { use_header } {
     gdb_test "step" ".*" "step into get_alias_set"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 1"
-    # It's possible that this first failure (when not using a header
-    # file) is GCC's fault, though the remaining failures would best
-    # be fixed by adding location views support (though it could be
-    # that some easier heuristic could be figured out).  Still, it is
-    # not certain that the first failure wouldn't also be fixed by
-    # having location view support, so for now it is tagged as such.
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" ".*TREE_TYPE.*" "next step 1"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2"
     gdb_test "next" ".*TREE_TYPE.*" "next step 2"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3"
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" ".*TREE_TYPE.*" "next step 3"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 4"
-    if {!$use_header} { setup_kfail "*-*-*" symtab/25507 }
     gdb_test "next" "return 0.*" "next step 4"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 5"
 
-    if {!$use_header} {
-	# With the debug from GCC 10.x (and earlier) GDB is currently
-	# unable to successfully complete the following tests when we
-	# are not using a header file.
-	kfail symtab/25507 "stepping tests"
-	return
-    }
-
     clean_restart ${executable}
 
     if ![runto_main] {
Andrew Burgess May 15, 2020, 2:46 p.m. | #20
* Bernd Edlinger <bernd.edlinger@hotmail.de> [2020-05-15 05:35:43 +0200]:

<snip>

> 

> Andrew, as far as I remember the range info of the

> inlined subroutines were not correct, in your patch.


Thanks for pointing this out, I eventually figured out the problem
you'd seen and fixed this.

> Can you please fix the range infos in your patch

> and re-post it, before we decide how to proceed?


Rebased and latest version of the patch is attached.  As the bug fixes
are minor I don't think we should spend much longer discussing this.

> But I would say that I see a way how I can adjust my

> patch to fix the issues which were raised by your test

> case (I added the test case from your patch to mine,

> and most of it seems to be fine with my latest patch,

> one remaining issue is a bit nasty but fixable).

> I'll attach the patch file where I am at here, so

> you can see what I have now.

> It fails only one test case in dw2-inline-header-3.exp

> but I would like how it compares to your patch

> when Tom would like to try it out on the

> internal test cases, he mentioned.

> 

> And, yes, of course my approach is that the debug info

> is not optimal at all as it is emitted by gcc, but 

> gdb can probably work around it until it is fixed

> which should happen when a new updated dwarf extension

> is invented which tells us the view number where

> the inlined subroutine ends.  The line table program

> has view numbers, but not the range info of the

> subroutine.  That is the deficiency in the dwarf

> format I think causes the trouble, apart from the

> fact that dwarf is already too complicate to understand.


I think this is one of our sticking points.  I agree 100% with you
that adding view support to the range information would allow GCC to
be more expressive.

But I feel that, just because DWARF lacks a certain feature, this
doesn't mean we can't build a valid debug picture with the features we
do have.  Sure, me may have to compromise, but we can still create
something that is internally consistent.  GCC isn't doing this right
now.

Maybe it is the opinion of the GCC devs that they'll not fix GCC until
DWARF gains the extra features they'd like.  That's something you'd
have to take up on the GCC list.

Adding support to work around compiler bugs is absolutely fine, so
long as we understand exactly what issues we're working around, and
that the issue (hopefully) will get fixed eventually, so any work
around should be (I think) applied conservatively, only when we are
sure the work around is appropriate (maybe based on producer strings,
for example).

<snip>

> 

> On 5/15/20 12:39 AM, Andrew Burgess wrote:

> > * Tom Tromey <tom@tromey.com> [2020-05-14 14:18:44 -0600]:

> > 

> >>>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

> >>

> >> Resurrecting this again ... we have some internal tests that have been

> >> failing, and I want to land at least one of these patches to resolve

> >> this.

> >>

> >> Andrew> After reading[2] I'd also be interest to understand what flaw in

> >> Andrew> DWARF you feel makes a difference in this case.

> >>

> >> I also don't understand this.

> >>

> 

> When you only know where an inline function ends at the byte address.

> You can habe line table entries at the same address from the inline

> funcion and from the calling function.  It is impossible to distinguish

> between those, however there is a view number which would be different,

> and as Alexandre explains it, these can be consider an extension to the

> byte addresses, so if a range info would add a view number we would

> know which line infos are from the subroutine and which are not, even

> if the byte addresses are identical.


Please correct me if I'm wrong, but as for view support in ranges,
there's not even a GCC only extension for this yet (I did look, but
could easily have missed something).

I think we'd probably want to see this feature as at least a GCC
extension, then we could add support in GDB.

>

> >> Andrew>   I don't know how we address this without merging your patch,

> >> Andrew>   releasing GDB and seeing how it works in the wild.  However, if we

> >> Andrew>   did decide to "just try it", I would still prefer we staged things

> >> Andrew>   as:

> >> Andrew>     (a) Merge my patch, targeted regression fix, then

> >> Andrew>     (b) Your patch, new functionality GCC/DWARF ranges work around.

> >> Andrew>   In this way, if we end up backing out some or all of (b) we still

> >> Andrew>   have (a) in place that fixes the regression.  I'm more than happy

> >> Andrew>   for a rebase of (b) in include full removal of (a).

> >>

> >> I think landing your patch is safe to do while we discuss part (b).

> >> How about we move forward with that part?  Then if we come to agreement

> >> on where the bug lies we can decide about that.

> > 

> > I agree. I already rebased this and retested it.  Unless someone

> > shouts out between now and tomorrow I plan to merge my patch.

> > 

> > Bernd (or anyone else) - I'm more than happy that if a better patch is

> > put forward it can revert some or all of my patch, as needed.  Like

> > Tom, I'd like to see the regressions squashed.

> > 

> 

> No, I am not able to do this once we decide that gcc's debug info

> is impossible to implement, I will send a patch to the gcc-patches

> which restores the gcc-7 debug info.


I am certainly not suggesting, and having re-read many mails in this
thread, I don't think anyone else is suggesting, that it is impossible
to craft a work around for GCC's broken debug information.

I think that all we're suggesting is that your work around patch isn't
ready just yet, so instead of rushing that in to fix the is-stmt
regression, lets just merge my conservative regression fix patch, then
we can take our time and get your work around GCC patch correct.

This would be an easy discussion if it wasn't for
gdb.cp/step-and-next-inline.exp, which my regression fix patch
breaks.

That test is what motivated your original patch last year, so I
completely understand why my breaking it leaves you feeling
frustrated.

My position here is that this test is really an example of the GCC
broken debug issue and really should never have been merged with the
is-stmt patch, as such I would like to see it disabled until your
patch lands later.

>                                       My patch was based on the

> assumption that there is a way to work around the issues, but if

> that turns out to be a failure, I will not go back and revert

> your patch again, since it seems to revert my work on that issue

> completely


No you've misunderstood, when your patch succeeds you will (maybe)
revert this patch as part of your successful patch.

If your patch were to never land (and I'm sure we _can_ get it over
the line) then no, the patch I propose here wouldn't be reverted, but
that's exactly the point of pushing this patch first.

This patch is a low risk regression fix.

You patch is (slightly) higher risk, new functionality.

All Tom and I are suggesting is lets just merge them in that order,
rather than rushing into the high risk fix.

>             (see how this patch breaks the step-and-next-inline.exp

> test case).  And once again, I feel not at all emotional, just that

> I want the issue fixed, and next time I will try a completely

> different approach which is gcc was wrong, and therefore we will

> revert Alexandre Oliva's patch, since it is the least effort and

> Alexandre already signaled he also had considered that already.

> 

> Alexandre Oliva wrote on 11/19/19:

> https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534845.html

> > Perhaps we should change our defaults, if the situation with GDB does

> > not change :-(


There is some view information emitted by GCC now, but for
gdb.cp/step-and-next-inline.exp I don't think any of the view
information would help even if we did consume it.  The problem with
that test is entirely GCC emitting broken DWARF.

I interpret the last two paragraphs above as saying, it's easier to
disable a broken feature in GCC than to merge a partially complete
work around into GDB.  And that's as it should be.

If you can point to some non-broken DWARF that GDB doesn't currently
parse correctly, that would help gdb.cp/step-and-next-inline.exp pass,
then I would certainly be prepared to invest some time trying to help
improve GDB in that area.

Bernd, you asked for some time to follow up on this thread, but this
issue has dragged on for long enough now I think.  It is my intention
to merge the patch below on Monday unless I hear a compelling argument
against it.

After that it should be trivial for your to rebase your patch and
revert those parts of my patch you no longer need.  Repost the update
and we can discuss how to get it merged.

Thanks,
Andrew

----

From c5d89ffa3032c401cc79c241097006a12b306d02 Mon Sep 17 00:00:00 2001
From: Andrew Burgess <andrew.burgess@embecosm.com>

Date: Fri, 3 Apr 2020 20:32:38 +0100
Subject: [PATCH] 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.
---
 gdb/ChangeLog                                 |  10 +
 gdb/dwarf2/read.c                             |  47 ++++-
 gdb/testsuite/ChangeLog                       |  11 +
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |   7 +
 .../gdb.dwarf2/dw2-inline-header-1.exp        | 186 +++++++++++++++++
 .../gdb.dwarf2/dw2-inline-header-2.exp        | 189 +++++++++++++++++
 .../gdb.dwarf2/dw2-inline-header-3.exp        | 193 ++++++++++++++++++
 .../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, 734 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 ab21ab0d13a..fea980d0a33 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -19880,6 +19880,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;
 
@@ -20073,14 +20082,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;
 
@@ -20099,6 +20128,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,
@@ -20118,6 +20156,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..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 */
-- 
2.25.4
Bernd Edlinger May 16, 2020, 8:12 a.m. | #21
Thanks Andrew,

I tried you updated test case, and it does still have only one
failure:

FAIL: gdb.dwarf2/dw2-inline-header-3.exp: continue to breakpoint: dw2-inline-header.h:22

		=== gdb Summary ===

# of expected passes		2
# of unexpected failures	1

That is not a given thing as my patch depends completely on the inline end positions.

Also just for later reference Tom, you said there are internal tests failing, currently,
which are fixed by Andrew's patch, but did you ever try my latest patch ?
I sent it yesterday?

This information would be really helpful as it would at least be a proof of concept
for this attempt to fix the debug info.



On 5/15/20 4:46 PM, Andrew Burgess wrote:
> * Bernd Edlinger <bernd.edlinger@hotmail.de> [2020-05-15 05:35:43 +0200]:

> 

> <snip>

> 

>>

>> Andrew, as far as I remember the range info of the

>> inlined subroutines were not correct, in your patch.

> 

> Thanks for pointing this out, I eventually figured out the problem

> you'd seen and fixed this.

> 

>> Can you please fix the range infos in your patch

>> and re-post it, before we decide how to proceed?

> 

> Rebased and latest version of the patch is attached.  As the bug fixes

> are minor I don't think we should spend much longer discussing this.

> 

>> But I would say that I see a way how I can adjust my

>> patch to fix the issues which were raised by your test

>> case (I added the test case from your patch to mine,

>> and most of it seems to be fine with my latest patch,

>> one remaining issue is a bit nasty but fixable).

>> I'll attach the patch file where I am at here, so

>> you can see what I have now.

>> It fails only one test case in dw2-inline-header-3.exp

>> but I would like how it compares to your patch

>> when Tom would like to try it out on the

>> internal test cases, he mentioned.

>>

>> And, yes, of course my approach is that the debug info

>> is not optimal at all as it is emitted by gcc, but 

>> gdb can probably work around it until it is fixed

>> which should happen when a new updated dwarf extension

>> is invented which tells us the view number where

>> the inlined subroutine ends.  The line table program

>> has view numbers, but not the range info of the

>> subroutine.  That is the deficiency in the dwarf

>> format I think causes the trouble, apart from the

>> fact that dwarf is already too complicate to understand.

> 

> I think this is one of our sticking points.  I agree 100% with you

> that adding view support to the range information would allow GCC to

> be more expressive.

> 

> But I feel that, just because DWARF lacks a certain feature, this

> doesn't mean we can't build a valid debug picture with the features we

> do have.  Sure, me may have to compromise, but we can still create

> something that is internally consistent.  GCC isn't doing this right

> now.

> 

> Maybe it is the opinion of the GCC devs that they'll not fix GCC until

> DWARF gains the extra features they'd like.  That's something you'd

> have to take up on the GCC list.

> 

> Adding support to work around compiler bugs is absolutely fine, so

> long as we understand exactly what issues we're working around, and

> that the issue (hopefully) will get fixed eventually, so any work

> around should be (I think) applied conservatively, only when we are

> sure the work around is appropriate (maybe based on producer strings,

> for example).

> 

> <snip>

> 

>>

>> On 5/15/20 12:39 AM, Andrew Burgess wrote:

>>> * Tom Tromey <tom@tromey.com> [2020-05-14 14:18:44 -0600]:

>>>

>>>>>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

>>>>

>>>> Resurrecting this again ... we have some internal tests that have been

>>>> failing, and I want to land at least one of these patches to resolve

>>>> this.

>>>>

>>>> Andrew> After reading[2] I'd also be interest to understand what flaw in

>>>> Andrew> DWARF you feel makes a difference in this case.

>>>>

>>>> I also don't understand this.

>>>>

>>

>> When you only know where an inline function ends at the byte address.

>> You can habe line table entries at the same address from the inline

>> funcion and from the calling function.  It is impossible to distinguish

>> between those, however there is a view number which would be different,

>> and as Alexandre explains it, these can be consider an extension to the

>> byte addresses, so if a range info would add a view number we would

>> know which line infos are from the subroutine and which are not, even

>> if the byte addresses are identical.

> 

> Please correct me if I'm wrong, but as for view support in ranges,

> there's not even a GCC only extension for this yet (I did look, but

> could easily have missed something).

> 

> I think we'd probably want to see this feature as at least a GCC

> extension, then we could add support in GDB.

> 

>>

>>>> Andrew>   I don't know how we address this without merging your patch,

>>>> Andrew>   releasing GDB and seeing how it works in the wild.  However, if we

>>>> Andrew>   did decide to "just try it", I would still prefer we staged things

>>>> Andrew>   as:

>>>> Andrew>     (a) Merge my patch, targeted regression fix, then

>>>> Andrew>     (b) Your patch, new functionality GCC/DWARF ranges work around.

>>>> Andrew>   In this way, if we end up backing out some or all of (b) we still

>>>> Andrew>   have (a) in place that fixes the regression.  I'm more than happy

>>>> Andrew>   for a rebase of (b) in include full removal of (a).

>>>>

>>>> I think landing your patch is safe to do while we discuss part (b).

>>>> How about we move forward with that part?  Then if we come to agreement

>>>> on where the bug lies we can decide about that.

>>>

>>> I agree. I already rebased this and retested it.  Unless someone

>>> shouts out between now and tomorrow I plan to merge my patch.

>>>

>>> Bernd (or anyone else) - I'm more than happy that if a better patch is

>>> put forward it can revert some or all of my patch, as needed.  Like

>>> Tom, I'd like to see the regressions squashed.

>>>

>>

>> No, I am not able to do this once we decide that gcc's debug info

>> is impossible to implement, I will send a patch to the gcc-patches

>> which restores the gcc-7 debug info.

> 

> I am certainly not suggesting, and having re-read many mails in this

> thread, I don't think anyone else is suggesting, that it is impossible

> to craft a work around for GCC's broken debug information.

> 

> I think that all we're suggesting is that your work around patch isn't

> ready just yet, so instead of rushing that in to fix the is-stmt

> regression, lets just merge my conservative regression fix patch, then

> we can take our time and get your work around GCC patch correct.

> 

> This would be an easy discussion if it wasn't for

> gdb.cp/step-and-next-inline.exp, which my regression fix patch

> breaks.

> 

> That test is what motivated your original patch last year, so I

> completely understand why my breaking it leaves you feeling

> frustrated.

> 

> My position here is that this test is really an example of the GCC

> broken debug issue and really should never have been merged with the

> is-stmt patch, as such I would like to see it disabled until your

> patch lands later.

> 

>>                                       My patch was based on the

>> assumption that there is a way to work around the issues, but if

>> that turns out to be a failure, I will not go back and revert

>> your patch again, since it seems to revert my work on that issue

>> completely

> 

> No you've misunderstood, when your patch succeeds you will (maybe)

> revert this patch as part of your successful patch.

> 

> If your patch were to never land (and I'm sure we _can_ get it over

> the line) then no, the patch I propose here wouldn't be reverted, but

> that's exactly the point of pushing this patch first.

> 

> This patch is a low risk regression fix.

> 

> You patch is (slightly) higher risk, new functionality.

> 

> All Tom and I are suggesting is lets just merge them in that order,

> rather than rushing into the high risk fix.

> 

>>             (see how this patch breaks the step-and-next-inline.exp

>> test case).  And once again, I feel not at all emotional, just that

>> I want the issue fixed, and next time I will try a completely

>> different approach which is gcc was wrong, and therefore we will

>> revert Alexandre Oliva's patch, since it is the least effort and

>> Alexandre already signaled he also had considered that already.

>>

>> Alexandre Oliva wrote on 11/19/19:

>> https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534845.html

>>> Perhaps we should change our defaults, if the situation with GDB does

>>> not change :-(

> 

> There is some view information emitted by GCC now, but for

> gdb.cp/step-and-next-inline.exp I don't think any of the view

> information would help even if we did consume it.  The problem with

> that test is entirely GCC emitting broken DWARF.

> 

> I interpret the last two paragraphs above as saying, it's easier to

> disable a broken feature in GCC than to merge a partially complete

> work around into GDB.  And that's as it should be.

> 

> If you can point to some non-broken DWARF that GDB doesn't currently

> parse correctly, that would help gdb.cp/step-and-next-inline.exp pass,

> then I would certainly be prepared to invest some time trying to help

> improve GDB in that area.

> 

> Bernd, you asked for some time to follow up on this thread, but this

> issue has dragged on for long enough now I think.  It is my intention

> to merge the patch below on Monday unless I hear a compelling argument

> against it.

> 

> After that it should be trivial for your to rebase your patch and

> revert those parts of my patch you no longer need.  Repost the update

> and we can discuss how to get it merged.

> 

> Thanks,

> Andrew

> 

> ----

> 

> From c5d89ffa3032c401cc79c241097006a12b306d02 Mon Sep 17 00:00:00 2001

> From: Andrew Burgess <andrew.burgess@embecosm.com>

> Date: Fri, 3 Apr 2020 20:32:38 +0100

> Subject: [PATCH] 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.

> ---

>  gdb/ChangeLog                                 |  10 +

>  gdb/dwarf2/read.c                             |  47 ++++-

>  gdb/testsuite/ChangeLog                       |  11 +

>  gdb/testsuite/gdb.cp/step-and-next-inline.exp |   7 +

>  .../gdb.dwarf2/dw2-inline-header-1.exp        | 186 +++++++++++++++++

>  .../gdb.dwarf2/dw2-inline-header-2.exp        | 189 +++++++++++++++++

>  .../gdb.dwarf2/dw2-inline-header-3.exp        | 193 ++++++++++++++++++

>  .../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, 734 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 ab21ab0d13a..fea980d0a33 100644

> --- a/gdb/dwarf2/read.c

> +++ b/gdb/dwarf2/read.c

> @@ -19880,6 +19880,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;

>  

> @@ -20073,14 +20082,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;

>  

> @@ -20099,6 +20128,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,

> @@ -20118,6 +20156,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..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 */

>
Bernd Edlinger May 17, 2020, 5:26 p.m. | #22
Hi Tom, Andrew,

> On 5/15/20 12:39 AM, Andrew Burgess wrote:

>> * Tom Tromey <tom@tromey.com> [2020-05-14 14:18:44 -0600]:

>>

>>>>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

>>>

>>> Resurrecting this again ... we have some internal tests that have been

>>> failing, and I want to land at least one of these patches to resolve

>>> this.

>>>

>>> Andrew> After reading[2] I'd also be interest to understand what flaw in

>>> Andrew> DWARF you feel makes a difference in this case.

>>>

>>> I also don't understand this.

>>>

> 

> When you only know where an inline function ends at the byte address.

> You can habe line table entries at the same address from the inline

> funcion and from the calling function.  It is impossible to distinguish

> between those, however there is a view number which would be different,

> and as Alexandre explains it, these can be consider an extension to the

> byte addresses, so if a range info would add a view number we would

> know which line infos are from the subroutine and which are not, even

> if the byte addresses are identical.

> 

>>> Andrew> I think it is great Bernd, that you are reaching out from the GCC

>>> Andrew> community to engage with GDB, this is certainly the best way to ensure

>>> Andrew> that we can work together as communities to give the best possible

>>> Andrew> debug experience, and I'm sorry you feel that I have not been clear

>>> Andrew> enough about the issues I'm seeing here.

>>>

>>> +1

>>>


I am always happy to help.

Andrew, and/or Tom, could you please test my patch, obviously one new test
case is still failing, however I would not rule out the possibility, that
we can work together to even fix that, I must say that our cooperation made
things possible, that I would not have expected, like fixing the inline functions
that are not in a header file.

How does this patch work in practice, I would be happy to know what I have
to fix even when Andrews patch lands tomorrow, probably due to a release
schedule?  Attached are again the patch from myself, and test cases from
Andrew's patch.

By the way when is the next gdb release planned?

And let me say this, honestly, I am happy to take the blame for any GCC BUG :-),
that certainly still exists, and ideally those will be fixed in a way that
gdb can figure out that it is fixed, ideally by some kind of dwarf-version
info in the debug info.

What is a given thing that this broken debug info is already there for years,
and historic gcc version will continue to exist for quite a while.  So my goal
is to work around it, communicate with each other, look for solutions, but not
make the users unhappy unless absolutely necessary.



Thanks
Bernd.
From 7cfd74cfc6e14034779e6cc048c68877b7a08f88 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Sat, 16 May 2020 18:59:10 +0100
Subject: [PATCH 1/2] Fix gdb.multi/multi-re-run.exp with native-gdbserver

The new exec-file-mismatch feature reveals that when running
gdb.multi/multi-re-run.exp against --target_board=native-gdbserver,
we've been starting gdbserver with the wrong program:

 (gdb) spawn /home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/testsuite/../../gdbserver/gdbserver --once localhost:2347 /home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/te
 stsuite/outputs/gdb.multi/multi-re-run/multi-re-run-2
 Process /home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.multi/multi-re-run/multi-re-run-2 created; pid = 6280
 Listening on port 2347
 target remote localhost:2347
 Remote debugging using localhost:2347
 warning: Mismatch between current exec-file /home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.multi/multi-re-run/multi-re-run-1
 and automatically determined exec-file /home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.multi/multi-re-run/multi-re-run-2
 exec-file-mismatch handling is currently "ask"
 Load new symbol table from "/home/pedro/brno/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.multi/multi-re-run/multi-re-run-2"? (y or n) Quit
 (gdb) FAIL: gdb.multi/multi-re-run.exp: re_run_inf=1: iter=1: running to all_started in runto

The problem is that gdb_reload uses the last loaded file as binary to
spawn, but we load the program for inferior 2 and then switch to
inferior 1 and run it, so the last loaded file is the program for
inferior 2.

Fix this by tweaking last_loaded_file.

gdb/testsuite/ChangeLog:
2020-05-16  Pedro Alves  <palves@redhat.com>

	* gdb.multi/multi-re-run.exp (test_re_run): Switch
	LAST_LOADED_FILE accordingly.
---
 gdb/testsuite/ChangeLog                  | 5 +++++
 gdb/testsuite/gdb.multi/multi-re-run.exp | 7 +++++++
 2 files changed, 12 insertions(+)

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c57ddf5..0be2fd3 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-05-16  Pedro Alves  <palves@redhat.com>
+
+	* gdb.multi/multi-re-run.exp (test_re_run): Switch
+	LAST_LOADED_FILE accordingly.
+
 2020-05-15  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
 	* gdb.base/alias.exp: Verify 'help aliases' shows user defined aliases.
diff --git a/gdb/testsuite/gdb.multi/multi-re-run.exp b/gdb/testsuite/gdb.multi/multi-re-run.exp
index 93cd709..a243293 100644
--- a/gdb/testsuite/gdb.multi/multi-re-run.exp
+++ b/gdb/testsuite/gdb.multi/multi-re-run.exp
@@ -51,6 +51,7 @@ proc test_re_run {re_run_inf} {
     global binfile1 binfile2
     global inferior_exited_re
     global gdb_prompt
+    global last_loaded_file
 
     clean_restart ${binfile1}
 
@@ -65,12 +66,17 @@ proc test_re_run {re_run_inf} {
 
     if {$re_run_inf == 1} {
 	set steady_inf 2
+	set steady_binfile $binfile2
+	set re_run_binfile $binfile1
     } else {
 	set steady_inf 1
+	set steady_binfile $binfile1
+	set re_run_binfile $binfile2
     }
 
     gdb_test "inferior $steady_inf" "Switching to inferior $steady_inf.*" \
 	"switch to steady inferior"
+    set last_loaded_file $steady_binfile
 
     # Run the steady inferior to a breakpoint, and let it stay stopped
     # there.
@@ -81,6 +87,7 @@ proc test_re_run {re_run_inf} {
 
     gdb_test "inferior $re_run_inf" "Switching to inferior $re_run_inf.*" \
 	"switch to re-run inferior"
+    set last_loaded_file $re_run_binfile
 
     # Now run the RE_RUN_INF inferior a couple times.  GDB used to
     # have a bug that caused the second run to fail to load
Andrew Burgess May 20, 2020, 6:26 p.m. | #23
Bernd,

Below is a first draft of a currently WIP patch that is an alternative
to what I have previously proposed.

This patch is based on parts of your patch, specifically, those bits
related to having two different end-of-sequence type markers 0 or -1.

I have fixed the issue that prevented my new dw2-inline-header-3.exp
test from passing.

This does not include any of the inline range handling changes you
were proposing, but as this is a sub-set of your proposal, then I'm
hoping you might feel .... less bad .... about this patch, adding the
rest of your work should be much more building on top of this, rather
than backing this out and starting again.

The one contentious area where I have had to stick with my original
patch is in the treatment of gdb.cp/step-and-next-inline.exp, this
test still regresses with this patch, so I have still basically
disabled this test.  As we've discussed (at great length) I believe
the regressions here are due to GCC bugs, which your patch when its
completed will aim to address, so hopefully that will not be too much
to accept for now.

Like I said, this is still WIP, its just I'll likely not get to work
on this until Friday or the weekend now, so I wanted to share this
early so you could give me your thoughts.

Look forward to your feedback,

Thanks,
Andrew

----

From 009671f35e232d80f61fd7d86251a84be2d965db Mon Sep 17 00:00:00 2001
From: Andrew Burgess <andrew.burgess@embecosm.com>

Date: Wed, 20 May 2020 19:16:05 +0100
Subject: [PATCH] WIP: gdb: Don't delete empty lines when changing symtabs

Based on Bernd's patch found here:

  https://sourceware.org/pipermail/gdb-patches/2020-May/168591.html

TODO:

 - More testing,
 - Changelogs
 - Split out addition of linetable_entry::end_of_sequence
---
 gdb/buildsym.c                                |  24 ++-
 gdb/dwarf2/read.c                             |   8 +-
 gdb/symtab.c                                  |   4 +-
 gdb/symtab.h                                  |  16 +-
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |   7 +
 .../gdb.dwarf2/dw2-inline-header-1.exp        | 186 +++++++++++++++++
 .../gdb.dwarf2/dw2-inline-header-2.exp        | 189 +++++++++++++++++
 .../gdb.dwarf2/dw2-inline-header-3.exp        | 193 ++++++++++++++++++
 .../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 +++
 11 files changed, 714 insertions(+), 7 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/buildsym.c b/gdb/buildsym.c
index b9bcc33080a..2ff2a5455d0 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -662,7 +662,24 @@ buildsym_compunit::pop_subfile ()
 }
 
 /* Add a linetable entry for line number LINE and address PC to the
-   line vector for SUBFILE.  */
+   line vector for SUBFILE.
+
+   LINE is usually an integer greater than 0 representing the line number
+   within the file, however two special values also exist.  Pass 0 to
+   indicate an end of sequence marker found within the actual line table,
+   or -1 to indicate an artificial end of sequence generated during
+   parsing of the line table to indicate a switch between subfiles.
+
+   The difference between these values is how GDB treats apparently empty
+   lines at the end marker, with the end marker value 0 this function
+   deletes any empty lines at the same address as the end marker, while
+   when switching subfiles any empty lines are preserved.  The reason is
+   that a 0 style end of sequence most likely means the end of a function,
+   so trying to place a breakpoint on any empty lines at this address will
+   result in a breakpoint being placed within the next function.  A -1
+   style end of sequence marker will appear within a function when code
+   has been inlined, in this case placing a breakpoint at the address of
+   an end of sequence should be fine.  */
 
 void
 buildsym_compunit::record_line (struct subfile *subfile, int line,
@@ -704,7 +721,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 == linetable_entry::end_of_sequence)
     {
       while (subfile->line_vector->nitems > 0)
 	{
@@ -714,8 +731,11 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == linetable_entry::change_of_symtab)
+    line = linetable_entry::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/dwarf2/read.c b/gdb/dwarf2/read.c
index ab21ab0d13a..cbea38f9b1a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -20031,7 +20031,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;
@@ -20044,7 +20044,8 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
 			  paddress (gdbarch, address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu);
+  dwarf_record_line_1 (gdbarch, subfile, end_sequence ? 0 : -1, address,
+		       true, cu);
 }
 
 void
@@ -20077,7 +20078,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 2043d084140..070a3311a16 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3270,7 +3270,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 764c567a90b..ebb0c818bc8 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1304,7 +1304,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.  */
@@ -1312,6 +1315,17 @@ struct linetable_entry
 
   /* The address for this entry.  */
   CORE_ADDR pc;
+
+  /* Constant value that can be placed into the LINE field to indicate the
+     end of a sequence of line table entries.  */
+  static const int end_of_sequence = 0;
+
+  /* Constant that can be passed to buildsym_compunit::record_line when
+     creating the line table.  This indicates an artificial end of sequence
+     and is transformed into END_OF_SEQUENCE before being stored into the
+     line table, consequently CHANGE_OF_SYMTAB will never actually appear
+     in the LINE field.  */
+  static const int change_of_symtab = -1;
 };
 
 /* The order of entries in the linetable is significant.  They should
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 */
-- 
2.25.4
Andrew Burgess May 27, 2020, 1:10 p.m. | #24
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 ()
 }
 
 /* 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 */

Patch

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