public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix range end handling of inlined subroutines - restart
@ 2020-11-06 16:12 Bernd Edlinger
  2020-11-10 17:47 ` [PATCH v2 ] " Bernd Edlinger
  0 siblings, 1 reply; 6+ messages in thread
From: Bernd Edlinger @ 2020-11-06 16:12 UTC (permalink / raw)
  To: gdb-patches, Andrew Burgess

[-- Attachment #1: Type: text/plain, Size: 984 bytes --]

Hi,

I finally found some time to start this patch new, addressing the known
issues with the previous attempt, and making it even better than before.

This time the approach is that no line infos shall be discarded.  Instead
they are marked as weak, but they continue to work completely normal.

We no longer depend on the inline function to be in a header file for
instance, and the inline-frames always show the correct call frames
at the weak lines.

When we enter an (invalid) empty subroutine range, we are able to stop there,
and see the call stack in the subroutine.

Also when we have an is_stmt line at the end of a non-empty subroutine
range, we see the call stack including the subroutine, and can step
normally.

The test case gdb.cp/step-and-next-inline.exp is fully functional again,
while Andrew's test cases gdb.dwarf2/dw2-inline-header-*.exp continue
to function normally, so this nicely co-exists now.


Checked on x86_64-pc-linux-gnu.
OK for trunk?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-range-end-handling-of-inlined-subroutines.patch --]
[-- Type: text/x-patch; name="0001-Fix-range-end-handling-of-inlined-subroutines.patch", Size: 25288 bytes --]

From 866acd3ed1a77ca54351c0ee9be2426bea91455e Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 3 Nov 2020 18:41:43 +0100
Subject: [PATCH] Fix range end handling of inlined subroutines

This introduces a new line table flag is_weak.
The line entries at the end of a subroutine range,
use this to indicate that they may possibly
be part of the previous subroutine.

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_weak = 1.

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.

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

	* block.c (blockvector_for_pc_sect): For weak line table values,
	use the inline frame at PC - 1.
	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Delete previous lines
	at the same PC as the end sequence marker,
	but only mark them as weak for a fake end sequence marker.
	(buildsym_compunit::patch_inline_end_pos): New helper functions.
	(buildsym_compunit::end_symtab_with_blockvector): Patch line table.
	* buildsym.h (buildsym_compunit::m_inline_end_vector): New data item.
	* dwarf2/read.c (dwarf2_rnglists_process,
	dwarf2_ranges_process): Don't ignore empty ranges here.
	(dwarf2_ranges_read): Ignore empty ranges here.
	(dwarf_finish_line): Add new parameter end_sequence.
	(lnp_state_machine::m_last_address,
	lnp_state_machine::m_stmt_at_address): Remove data items.
	(lnp_state_machine::record_line): Do not filter line entries here,
	except for line == 0.  Pass end_sequence to dwarf_finish_line.
	* infrun.c (process_event_stop_test): Don't stop in !is_stmt lines
	when stepping into inlines.
	* jit.c (jit_symtab_line_mapping_add_impl): Initialize is_weak.
	* symmisc.c (dump_symtab_1,
	maintenance_print_one_line_table): Handle is_weak.
	* symtab.c (find_pc_sect_line): Handle is_weak.
	* symtab.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

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

	* gdb.cp/step-and-next-inline.exp: Remove KFAILs, enhance test.
	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
---
 gdb/block.c                                   |  12 +++-
 gdb/buildsym.c                                | 100 ++++++++++++++++++++++----
 gdb/buildsym.h                                |   3 +
 gdb/dwarf2/read.c                             |  72 ++++---------------
 gdb/infrun.c                                  |   2 +
 gdb/jit.c                                     |   1 +
 gdb/symmisc.c                                 |  10 ++-
 gdb/symtab.c                                  |  16 ++---
 gdb/symtab.h                                  |   4 ++
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |  69 ++++++++++--------
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |   6 +-
 gdb/xcoffread.c                               |   1 +
 12 files changed, 181 insertions(+), 115 deletions(-)

diff --git a/gdb/block.c b/gdb/block.c
index fc6bfb9..58e896c 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -205,7 +205,17 @@ struct symbol *
     return NULL;
 
   if (pblock)
-    *pblock = b;
+    {
+      struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+      if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+	{
+	  const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+	  if (contained_in (b2, b))
+	    b = b2;
+	}
+      *pblock = b;
+    }
+
   return bl;
 }
 
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 9525962..427cbb5 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -425,6 +425,13 @@ struct block *
       || end_inclusive + 1 != BLOCK_END (block))
     m_pending_addrmap_interesting = true;
 
+  if (block_inlined_p (block))
+    {
+      m_inline_end_vector.push_back (end_inclusive + 1);
+      if (end_inclusive + 1 == start)
+	end_inclusive = start;
+    }
+
   if (m_pending_addrmap == nullptr)
     m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
 
@@ -692,19 +699,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.
+     We simply set the is_weak marker in this case.  */
   if (line == 0)
     {
       while (subfile->line_vector->nitems > 0)
@@ -715,14 +719,80 @@ struct blockvector *
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == -1)
+    {
+      line = 0;
+      e = subfile->line_vector->item + subfile->line_vector->nitems;
+      while (e > subfile->line_vector->item)
+	{
+	  e--;
+	  if (e->pc != pc)
+	    break;
+	  e->is_weak = 1;
+	}
+    }
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
   e->is_stmt = is_stmt ? 1 : 0;
+  e->is_weak = 0;
   e->pc = pc;
 }
 
 \f
+/* 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_weak = 1 as well.  */
+  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_weak = 1;
+    }
+  while (a > 0);
+}
+
+\f
 /* 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
@@ -960,6 +1030,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.size (); 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..4fbe45b 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -397,6 +397,9 @@ struct buildsym_compunit
 
   /* Pending symbols that are local to the lexical context.  */
   struct pending *m_local_symbols = nullptr;
+
+  /* Pending inline end range addresses.  */
+  std::vector<CORE_ADDR> m_inline_end_vector;
 };
 
 \f
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 7d258f3..1733278 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -14344,10 +14344,6 @@ class process_die_scope
 	  return false;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       /* Only DW_RLE_offset_pair needs the base address added.  */
       if (rlet == DW_RLE_offset_pair)
 	{
@@ -14466,10 +14462,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;
 
@@ -14509,6 +14501,10 @@ class process_die_scope
   retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (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;
@@ -20618,15 +20614,6 @@ 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;
 
@@ -20778,7 +20765,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;
@@ -20791,7 +20778,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
@@ -20818,37 +20806,17 @@ class lnp_state_machine
   else if (m_op_index == 0 || end_sequence)
     {
       fe->included_p = 1;
-      if (m_record_lines_p)
-	{
-	  /* 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)
-	      || (!end_sequence && m_line == 0));
-
-	  if ((file_changed && !ignore_this_line) || end_sequence)
+      if (m_record_lines_p && (end_sequence || m_line != 0))
+	{
+	  if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+	      || 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 && !ignore_this_line)
+	  if (!end_sequence)
 	    {
 	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -20867,15 +20835,6 @@ class lnp_state_machine
 	    }
 	}
     }
-
-  /* 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,
@@ -20895,9 +20854,6 @@ class lnp_state_machine
   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/infrun.c b/gdb/infrun.c
index 990f40a..cd15703 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7043,6 +7043,8 @@ struct wait_one_event
       infrun_debug_printf ("stepping through inlined function");
 
       if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+	  || ecs->event_thread->suspend.stop_pc != stop_pc_sal.pc
+	  || !stop_pc_sal.is_stmt
 	  || inline_frame_is_marked_for_skip (false, ecs->event_thread))
 	keep_going (ecs);
       else
diff --git a/gdb/jit.c b/gdb/jit.c
index fd24d53..804b79c 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -517,6 +517,7 @@ struct gdb_object
       stab->linetable->item[i].pc = (CORE_ADDR) map[i].pc;
       stab->linetable->item[i].line = map[i].line;
       stab->linetable->item[i].is_stmt = 1;
+      stab->linetable->item[i].is_weak = 0;
     }
 }
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index acdbac6..06b544d 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -319,6 +319,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	  fputs_filtered (paddress (gdbarch, l->item[i].pc), outfile);
 	  if (l->item[i].is_stmt)
 	    fprintf_filtered (outfile, "\t(stmt)");
+	  if (l->item[i].is_weak)
+	    fprintf_filtered (outfile, "\t(weak)");
 	  fprintf_filtered (outfile, "\n");
 	}
     }
@@ -1039,11 +1041,12 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
       /* Leave space for 6 digits of index and line number.  After that the
 	 tables will just not format as well.  */
       struct ui_out *uiout = current_uiout;
-      ui_out_emit_table table_emitter (uiout, 4, -1, "line-table");
+      ui_out_emit_table table_emitter (uiout, 5, -1, "line-table");
       uiout->table_header (6, ui_left, "index", _("INDEX"));
       uiout->table_header (6, ui_left, "line", _("LINE"));
       uiout->table_header (18, ui_left, "address", _("ADDRESS"));
-      uiout->table_header (1, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (4, ui_left, "stmt", _("STMT"));
+      uiout->table_header (4, ui_left, "weak", _("WEAK"));
       uiout->table_body ();
 
       for (int i = 0; i < linetable->nitems; ++i)
@@ -1059,7 +1062,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	    uiout->field_string ("line", _("END"));
 	  uiout->field_core_addr ("address", objfile->arch (),
 				  item->pc);
-	  uiout->field_string ("is-stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("weak", item->is_weak ? "Y" : "");
 	  uiout->text ("\n");
 	}
     }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5cc875f..c985658 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3268,7 +3268,11 @@ struct symtab_and_line
 	 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_weak
+						   && prev->is_stmt)))))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
@@ -3309,18 +3313,14 @@ struct symtab_and_line
 	 We used to return alt->line - 1 here, but that could be
 	 anywhere; if we don't have line number info for this PC,
 	 don't make some up.  */
-      val.pc = pc;
-    }
-  else if (best->line == 0)
-    {
-      /* If our best fit is in a range of PC's for which no line
-	 number info is available (line number is zero) then we didn't
-	 find any valid line information.  */
+      if (notcurrent)
+	pc++;
       val.pc = pc;
     }
   else
     {
       val.is_stmt = best->is_stmt;
+      val.is_weak = best->is_weak;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dd67f86..650b8fa 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1311,6 +1311,8 @@ struct linetable_entry
 
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   unsigned is_stmt : 1;
+  /* True if this PC is at a subroutine range and.  */
+  unsigned is_weak : 1;
 
   /* The address for this entry.  */
   CORE_ADDR pc;
@@ -1896,6 +1898,8 @@ struct symtab_and_line
   /* If the line number information is valid, then this indicates if this
      line table entry had the is-stmt flag set or not.  */
   bool is_stmt = false;
+  /* True if this PC is at a subroutine range and.  */
+  bool is_weak = false;
 
   /* The probe associated with this symtab_and_line.  */
   probe *prob = NULL;
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index a95e211..bf1ee37 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] {
@@ -107,22 +83,57 @@ proc do_test { use_header } {
     gdb_test "step" ".*if \\(t->x != i\\).*" "step 2"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 1 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 3"
+    gdb_test "step" ".*return x.*" "step 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 1 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 4"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 4"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 5"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 2 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 5"
+    gdb_test "step" ".*return x.*" "step 6"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 2 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 7"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 6"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 8"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 3 pass 2"
-    gdb_test "step" "return 0.*" "step 7"
+    gdb_test "step" ".*return x.*" "step 9"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 3 pass 2"
+    gdb_test "step" "return 0.*" "step 10"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 4 pass 2"
+
+    clean_restart ${executable}
+
+    if ![runto_main] {
+	fail "can't run to main pass 3"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 3"
+    gdb_test "skip tree_check" ".*" "skip tree_check pass 3"
+    gdb_test "step" ".*" "step into get_alias_set pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "skip step 1"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "skip step 2"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 2 pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "skip step 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 3 pass 3"
+    gdb_test "step" "return 0.*" "skip step 4"
+    gdb_test "bt" \
+	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
+	"not in inline 4 pass 3"
     }
 }
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index 3f03fa6..89e4e67 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
@@ -148,7 +148,7 @@ set prev -1
 set seq_count 0
 gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
     "count END markers in line table" {
-	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)?(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 1" \
 		    "prev of normal entry at $seq_count is end marker"
@@ -157,7 +157,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	    incr seq_count
 	    exp_continue
 	}
-	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)?\(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 0" \
 		    "prev of end marker at $seq_count is normal entry"
@@ -173,7 +173,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	-re ".*linetable: \\(\\(struct linetable \\*\\) 0x0\\):\r\nNo line table.\r\n" {
 	    exp_continue
 	}
-	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT *\r\n" {
+	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+STMT\[ \t\]+WEAK *\r\n" {
 	    exp_continue
 	}
     }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c05060..db422cd 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -446,6 +446,7 @@ struct find_targ_sec_arg
 	    }
 	  fentry[function_count].line = ii;
 	  fentry[function_count].is_stmt = 1;
+	  fentry[function_count].is_weak = 0;
 	  fentry[function_count].pc = oldLineTb->item[ii].pc;
 	  ++function_count;
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 ] Fix range end handling of inlined subroutines - restart
  2020-11-06 16:12 [PATCH] Fix range end handling of inlined subroutines - restart Bernd Edlinger
@ 2020-11-10 17:47 ` Bernd Edlinger
  2020-11-19 17:25   ` [PATCH v3] " Bernd Edlinger
  0 siblings, 1 reply; 6+ messages in thread
From: Bernd Edlinger @ 2020-11-10 17:47 UTC (permalink / raw)
  To: gdb-patches, Andrew Burgess

[-- Attachment #1: Type: text/plain, Size: 1585 bytes --]


On 11/6/20 5:12 PM, Bernd Edlinger wrote:
> Hi,
> 
> I finally found some time to start this patch new, addressing the known
> issues with the previous attempt, and making it even better than before.
> 
> This time the approach is that no line infos shall be discarded.  Instead
> they are marked as weak, but they continue to work completely normal.
> 
> We no longer depend on the inline function to be in a header file for
> instance, and the inline-frames always show the correct call frames
> at the weak lines.
> 
> When we enter an (invalid) empty subroutine range, we are able to stop there,
> and see the call stack in the subroutine.
> 
> Also when we have an is_stmt line at the end of a non-empty subroutine
> range, we see the call stack including the subroutine, and can step
> normally.
> 
> The test case gdb.cp/step-and-next-inline.exp is fully functional again,
> while Andrew's test cases gdb.dwarf2/dw2-inline-header-*.exp continue
> to function normally, so this nicely co-exists now.
> 
> 
> Checked on x86_64-pc-linux-gnu.
> OK for trunk?
> 

I have now re-based this patch and improved a scenario when stepping
through an inline function that consists of multiple sub-ranges
did not work right, whenever the stepping was crossing a sub-range
beginning, gdb was again stepping back to the call site, and forth
again to the next line of the subroutine, as if a new subroutine was
entered.  I've added a test case which forces a branch a different subrange
of the "tree_check" function which does not pass with the previous version
of this patch.


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-range-end-handling-of-inlined-subroutines.patch --]
[-- Type: text/x-patch; name="0001-Fix-range-end-handling-of-inlined-subroutines.patch", Size: 28806 bytes --]

From b6f8a82444e24a38e3b5bbd95cc235a12335760e Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 3 Nov 2020 18:41:43 +0100
Subject: [PATCH] Fix range end handling of inlined subroutines

This introduces a new line table flag is_weak.
The line entries at the end of a subroutine range,
use this to indicate that they may possibly
be part of the previous subroutine.

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_weak = 1.

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.

gdb:
2020-11-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* block.c (blockvector_for_pc_sect): For weak line table values,
	use the inline frame at PC - 1 if it is deeper.
	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Delete previous lines
	at the same PC as the end sequence marker,
	but only mark them as weak for a fake end sequence marker.
	(buildsym_compunit::patch_inline_end_pos): New helper function.
	(buildsym_compunit::end_symtab_with_blockvector): Patch line table.
	* buildsym.h (buildsym_compunit::m_inline_end_vector): New data item.
	* dwarf2/read.c (dwarf2_rnglists_process,
	dwarf2_ranges_process): Don't ignore empty ranges here.
	(dwarf2_ranges_read): Ignore empty ranges here.
	(dwarf_finish_line): Add new parameter end_sequence.
	(lnp_state_machine::m_last_file, lnp_state_machine::m_last_address,
	lnp_state_machine::m_stmt_at_address): Remove data items.
	(lnp_state_machine::record_line): Do not filter line entries here,
	except for line == 0.  Pass end_sequence to dwarf_finish_line.
	* infrun.c (process_event_stop_test): Don't stop in !is_stmt lines
	when stepping into inlines.  Don't stop at the call site again, when
	stepping within inlined subroutines with multiple ranges.
	Don't refresh the step info the when executing !is_stmt lines of
	of a different inlined subroutine.
	* jit.c (jit_symtab_line_mapping_add_impl): Initialize is_weak.
	* symmisc.c (dump_symtab_1,
	maintenance_print_one_line_table): Handle is_weak.
	* symtab.c (find_pc_sect_line): Handle is_weak.
	* symtab.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

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

	* gdb.cp/step-and-next-inline.exp: Remove KFAILs, enhance test.
	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
---
 gdb/block.c                                   |  12 +++-
 gdb/buildsym.c                                | 100 ++++++++++++++++++++++----
 gdb/buildsym.h                                |   3 +
 gdb/dwarf2/read.c                             |  75 ++++---------------
 gdb/infrun.c                                  |  33 ++++++++-
 gdb/jit.c                                     |   1 +
 gdb/symmisc.c                                 |  10 ++-
 gdb/symtab.c                                  |  14 ++--
 gdb/symtab.h                                  |   4 ++
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |  93 +++++++++++++++---------
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |   6 +-
 gdb/xcoffread.c                               |   1 +
 12 files changed, 227 insertions(+), 125 deletions(-)

diff --git a/gdb/block.c b/gdb/block.c
index fc6bfb9..58e896c 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -205,7 +205,17 @@ struct symbol *
     return NULL;
 
   if (pblock)
-    *pblock = b;
+    {
+      struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+      if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+	{
+	  const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+	  if (contained_in (b2, b))
+	    b = b2;
+	}
+      *pblock = b;
+    }
+
   return bl;
 }
 
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 9525962..427cbb5 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -425,6 +425,13 @@ struct block *
       || end_inclusive + 1 != BLOCK_END (block))
     m_pending_addrmap_interesting = true;
 
+  if (block_inlined_p (block))
+    {
+      m_inline_end_vector.push_back (end_inclusive + 1);
+      if (end_inclusive + 1 == start)
+	end_inclusive = start;
+    }
+
   if (m_pending_addrmap == nullptr)
     m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
 
@@ -692,19 +699,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.
+     We simply set the is_weak marker in this case.  */
   if (line == 0)
     {
       while (subfile->line_vector->nitems > 0)
@@ -715,14 +719,80 @@ struct blockvector *
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == -1)
+    {
+      line = 0;
+      e = subfile->line_vector->item + subfile->line_vector->nitems;
+      while (e > subfile->line_vector->item)
+	{
+	  e--;
+	  if (e->pc != pc)
+	    break;
+	  e->is_weak = 1;
+	}
+    }
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
   e->is_stmt = is_stmt ? 1 : 0;
+  e->is_weak = 0;
   e->pc = pc;
 }
 
 \f
+/* 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_weak = 1 as well.  */
+  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_weak = 1;
+    }
+  while (a > 0);
+}
+
+\f
 /* 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
@@ -960,6 +1030,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.size (); 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..4fbe45b 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -397,6 +397,9 @@ struct buildsym_compunit
 
   /* Pending symbols that are local to the lexical context.  */
   struct pending *m_local_symbols = nullptr;
+
+  /* Pending inline end range addresses.  */
+  std::vector<CORE_ADDR> m_inline_end_vector;
 };
 
 \f
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index dbf0a3e..2fcd622 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -14354,10 +14354,6 @@ class process_die_scope
 	  return false;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       /* Only DW_RLE_offset_pair needs the base address added.  */
       if (rlet == DW_RLE_offset_pair)
 	{
@@ -14476,10 +14472,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;
 
@@ -14519,6 +14511,10 @@ class process_die_scope
   retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (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;
@@ -20947,21 +20943,9 @@ class lnp_state_machine
 
   /* Additional bits of state we need to track.  */
 
-  /* The last file that we called dwarf2_start_subfile for.
-     This is only used for TLLs.  */
-  unsigned int m_last_file = 0;
   /* 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;
 
@@ -21113,7 +21097,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;
@@ -21126,7 +21110,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
@@ -21153,37 +21138,17 @@ class lnp_state_machine
   else if (m_op_index == 0 || end_sequence)
     {
       fe->included_p = 1;
-      if (m_record_lines_p)
-	{
-	  /* 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)
-	      || (!end_sequence && m_line == 0));
-
-	  if ((file_changed && !ignore_this_line) || end_sequence)
+      if (m_record_lines_p && (end_sequence || m_line != 0))
+	{
+	  if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+	      || 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 || m_is_stmt);
 	    }
 
-	  if (!end_sequence && !ignore_this_line)
+	  if (!end_sequence)
 	    {
 	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -21202,15 +21167,6 @@ class lnp_state_machine
 	    }
 	}
     }
-
-  /* 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,
@@ -21230,9 +21186,6 @@ class lnp_state_machine
   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/infrun.c b/gdb/infrun.c
index 990f40a..0a263f1 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6982,6 +6982,31 @@ struct wait_one_event
       return;
     }
 
+  /* Handle the case when subroutines have multiple ranges.
+     When we step from one part to the next part of the same subroutine,
+     all subroutine levels are skipped again which begin here.
+     Compensate for this by removing all skipped subroutines,
+     which were already executing from the user's perspective.  */
+
+  if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+		   ecs->event_thread->control.step_stack_frame_id)
+      && inline_skipped_frames (ecs->event_thread)
+      && ecs->event_thread->control.step_frame_id.artificial_depth > 0
+      && ecs->event_thread->control.step_frame_id.code_addr_p)
+    {
+      const struct block *prev, *curr;
+      int depth = 0;
+      prev = block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
+      curr = block_for_pc (ecs->event_thread->suspend.stop_pc);
+      while (curr && block_inlined_p (curr) && !contained_in (prev, curr))
+	{
+	  depth ++;
+	  curr = BLOCK_SUPERBLOCK (curr);
+	}
+      while (inline_skipped_frames (ecs->event_thread) > depth)
+	step_into_inline_frame (ecs->event_thread);
+    }
+
   /* Look for "calls" to inlined functions, part one.  If the inline
      frame machinery detected some skipped call sites, we have entered
      a new inline function.  */
@@ -7043,6 +7068,8 @@ struct wait_one_event
       infrun_debug_printf ("stepping through inlined function");
 
       if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+	  || ecs->event_thread->suspend.stop_pc != stop_pc_sal.pc
+	  || !stop_pc_sal.is_stmt
 	  || inline_frame_is_marked_for_skip (false, ecs->event_thread))
 	keep_going (ecs);
       else
@@ -7065,8 +7092,8 @@ struct wait_one_event
 	  end_stepping_range (ecs);
 	  return;
 	}
-      else if (frame_id_eq (get_frame_id (get_current_frame ()),
-			    ecs->event_thread->control.step_frame_id))
+      else if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+			    ecs->event_thread->control.step_stack_frame_id))
 	{
 	  /* We are at the start of a different line, however, this line is
 	     not marked as a statement, and we have not changed frame.  We
@@ -7096,7 +7123,7 @@ struct wait_one_event
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
   if (refresh_step_info)
-    set_step_info (ecs->event_thread, frame, stop_pc_sal);
+    set_step_info (ecs->event_thread, get_current_frame (), stop_pc_sal);
 
   infrun_debug_printf ("keep going");
   keep_going (ecs);
diff --git a/gdb/jit.c b/gdb/jit.c
index fd24d53..804b79c 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -517,6 +517,7 @@ struct gdb_object
       stab->linetable->item[i].pc = (CORE_ADDR) map[i].pc;
       stab->linetable->item[i].line = map[i].line;
       stab->linetable->item[i].is_stmt = 1;
+      stab->linetable->item[i].is_weak = 0;
     }
 }
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index acdbac6..06b544d 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -319,6 +319,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	  fputs_filtered (paddress (gdbarch, l->item[i].pc), outfile);
 	  if (l->item[i].is_stmt)
 	    fprintf_filtered (outfile, "\t(stmt)");
+	  if (l->item[i].is_weak)
+	    fprintf_filtered (outfile, "\t(weak)");
 	  fprintf_filtered (outfile, "\n");
 	}
     }
@@ -1039,11 +1041,12 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
       /* Leave space for 6 digits of index and line number.  After that the
 	 tables will just not format as well.  */
       struct ui_out *uiout = current_uiout;
-      ui_out_emit_table table_emitter (uiout, 4, -1, "line-table");
+      ui_out_emit_table table_emitter (uiout, 5, -1, "line-table");
       uiout->table_header (6, ui_left, "index", _("INDEX"));
       uiout->table_header (6, ui_left, "line", _("LINE"));
       uiout->table_header (18, ui_left, "address", _("ADDRESS"));
-      uiout->table_header (1, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (4, ui_left, "stmt", _("STMT"));
+      uiout->table_header (4, ui_left, "weak", _("WEAK"));
       uiout->table_body ();
 
       for (int i = 0; i < linetable->nitems; ++i)
@@ -1059,7 +1062,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	    uiout->field_string ("line", _("END"));
 	  uiout->field_core_addr ("address", objfile->arch (),
 				  item->pc);
-	  uiout->field_string ("is-stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("weak", item->is_weak ? "Y" : "");
 	  uiout->text ("\n");
 	}
     }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5cc875f..3a027c4 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3268,7 +3268,9 @@ struct symtab_and_line
 	 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)))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
@@ -3309,18 +3311,14 @@ struct symtab_and_line
 	 We used to return alt->line - 1 here, but that could be
 	 anywhere; if we don't have line number info for this PC,
 	 don't make some up.  */
-      val.pc = pc;
-    }
-  else if (best->line == 0)
-    {
-      /* If our best fit is in a range of PC's for which no line
-	 number info is available (line number is zero) then we didn't
-	 find any valid line information.  */
+      if (notcurrent)
+	pc++;
       val.pc = pc;
     }
   else
     {
       val.is_stmt = best->is_stmt;
+      val.is_weak = best->is_weak;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dd67f86..650b8fa 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1311,6 +1311,8 @@ struct linetable_entry
 
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   unsigned is_stmt : 1;
+  /* True if this PC is at a subroutine range and.  */
+  unsigned is_weak : 1;
 
   /* The address for this entry.  */
   CORE_ADDR pc;
@@ -1896,6 +1898,8 @@ struct symtab_and_line
   /* If the line number information is valid, then this indicates if this
      line table entry had the is-stmt flag set or not.  */
   bool is_stmt = false;
+  /* True if this PC is at a subroutine range and.  */
+  bool is_weak = false;
 
   /* The probe associated with this symtab_and_line.  */
   probe *prob = NULL;
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 43a7101..4181fc6 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -29,13 +29,6 @@ if {[test_compiler_info gcc*] && ![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}
     if { [supports_statement_frontiers] } {
 	lappend options -gstatement-frontiers
@@ -67,41 +60,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 {[test_compiler_info gcc*] && !$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 {[test_compiler_info gcc*] && !$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] {
@@ -119,22 +91,77 @@ proc do_test { use_header } {
     gdb_test "step" ".*if \\(t->x != i\\).*" "step 2"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 1 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 3"
+    gdb_test "step" ".*return x.*" "step 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 1 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 4"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 4"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 5"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 2 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 5"
+    gdb_test "step" ".*return x.*" "step 6"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 2 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 7"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 6"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 8"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 3 pass 2"
-    gdb_test "step" "return 0.*" "step 7"
+    gdb_test "step" ".*return x.*" "step 9"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 3 pass 2"
+    gdb_test "step" "return 0.*" "step 10"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 4 pass 2"
+
+    clean_restart ${executable}
+
+    if ![runto_main] {
+	fail "can't run to main pass 3"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 3"
+    gdb_test "step" ".*" "step into get_alias_set pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 3"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 2 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"in inline 1 pass 3"
+    gdb_test "p t->x = 2" ".* = 2.*" "change value pass 3"
+    gdb_test "step" ".*abort.*" "step 4, pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"abort from inline 1 pass 3"
+
+    if ![runto_main] {
+	fail "can't run to main pass 4"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 4"
+    gdb_test "skip tree_check" ".*" "skip tree_check pass 4"
+    gdb_test "step" ".*" "step into get_alias_set pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 2 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 2 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 3 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 3 pass 4"
+    gdb_test "step" "return 0.*" "step 4 pass 4"
+    gdb_test "bt" \
+	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
+	"not in inline 4 pass 4"
     }
 }
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index 3164a90..a1132e3 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
@@ -148,7 +148,7 @@ set prev -1
 set seq_count 0
 gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
     "count END markers in line table" {
-	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)?(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 1" \
 		    "prev of normal entry at $seq_count is end marker"
@@ -157,7 +157,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	    incr seq_count
 	    exp_continue
 	}
-	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)?\(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 0" \
 		    "prev of end marker at $seq_count is normal entry"
@@ -173,7 +173,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	-re ".*linetable: \\(\\(struct linetable \\*\\) 0x0\\):\r\nNo line table.\r\n" {
 	    exp_continue
 	}
-	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT *\r\n" {
+	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+STMT\[ \t\]+WEAK *\r\n" {
 	    exp_continue
 	}
     }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c05060..db422cd 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -446,6 +446,7 @@ struct find_targ_sec_arg
 	    }
 	  fentry[function_count].line = ii;
 	  fentry[function_count].is_stmt = 1;
+	  fentry[function_count].is_weak = 0;
 	  fentry[function_count].pc = oldLineTb->item[ii].pc;
 	  ++function_count;
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3] Fix range end handling of inlined subroutines - restart
  2020-11-10 17:47 ` [PATCH v2 ] " Bernd Edlinger
@ 2020-11-19 17:25   ` Bernd Edlinger
  2020-11-29 14:43     ` [PATCH v4] " Bernd Edlinger
  0 siblings, 1 reply; 6+ messages in thread
From: Bernd Edlinger @ 2020-11-19 17:25 UTC (permalink / raw)
  To: gdb-patches, Andrew Burgess

[-- Attachment #1: Type: text/plain, Size: 2585 bytes --]

On 11/10/20 6:47 PM, Bernd Edlinger wrote:
> 
> On 11/6/20 5:12 PM, Bernd Edlinger wrote:
>> Hi,
>>
>> I finally found some time to start this patch new, addressing the known
>> issues with the previous attempt, and making it even better than before.
>>
>> This time the approach is that no line infos shall be discarded.  Instead
>> they are marked as weak, but they continue to work completely normal.
>>
>> We no longer depend on the inline function to be in a header file for
>> instance, and the inline-frames always show the correct call frames
>> at the weak lines.
>>
>> When we enter an (invalid) empty subroutine range, we are able to stop there,
>> and see the call stack in the subroutine.
>>
>> Also when we have an is_stmt line at the end of a non-empty subroutine
>> range, we see the call stack including the subroutine, and can step
>> normally.
>>
>> The test case gdb.cp/step-and-next-inline.exp is fully functional again,
>> while Andrew's test cases gdb.dwarf2/dw2-inline-header-*.exp continue
>> to function normally, so this nicely co-exists now.
>>
>>
>> Checked on x86_64-pc-linux-gnu.
>> OK for trunk?
>>
> 
> I have now re-based this patch and improved a scenario when stepping
> through an inline function that consists of multiple sub-ranges
> did not work right, whenever the stepping was crossing a sub-range
> beginning, gdb was again stepping back to the call site, and forth
> again to the next line of the subroutine, as if a new subroutine was
> entered.  I've added a test case which forces a branch a different subrange
> of the "tree_check" function which does not pass with the previous version
> of this patch.
> 
> 

This adds just one small fix to the previous version, that is here:

--- a/gdb/block.c
+++ b/gdb/block.c
@@ -210,7 +210,10 @@ struct symbol *
       if (sal.line != 0 && sal.pc == pc && sal.is_weak)
        {
          const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
-         if (contained_in (b2, b))
+         const struct block *b0 = b;
+         while (BLOCK_SUPERBLOCK (b0) && !BLOCK_FUNCTION (b0))
+           b0 = BLOCK_SUPERBLOCK (b0);
+         if (contained_in (b2, b0))
            b = b2;
        }
       *pblock = b;


It happens occasionally, that an inline block is followed by a lexical
block, but the call stack is in fact always from the inline function.
So ignore any lexical block and use any inline frame ending here,
if it is deeper.

Unfortunatley I was not able to extract a small test case for this.

Attached is the latest version of my patch.

Is it OK for trunk?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-range-end-handling-of-inlined-subroutines.patch --]
[-- Type: text/x-patch; name="0001-Fix-range-end-handling-of-inlined-subroutines.patch", Size: 28933 bytes --]

From 84261b86bdc772aa34123d8fa9cd10efa8f2bb8f Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 3 Nov 2020 18:41:43 +0100
Subject: [PATCH] Fix range end handling of inlined subroutines

This introduces a new line table flag is_weak.
The line entries at the end of a subroutine range,
use this to indicate that they may possibly
be part of the previous subroutine.

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_weak = 1.

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.

gdb:
2020-11-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* block.c (blockvector_for_pc_sect): For weak line table values,
	use the inline frame at PC - 1 if it is deeper.
	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Delete previous lines
	at the same PC as the end sequence marker,
	but only mark them as weak for a fake end sequence marker.
	(buildsym_compunit::patch_inline_end_pos): New helper function.
	(buildsym_compunit::end_symtab_with_blockvector): Patch line table.
	* buildsym.h (buildsym_compunit::m_inline_end_vector): New data item.
	* dwarf2/read.c (dwarf2_rnglists_process,
	dwarf2_ranges_process): Don't ignore empty ranges here.
	(dwarf2_ranges_read): Ignore empty ranges here.
	(dwarf_finish_line): Add new parameter end_sequence.
	(lnp_state_machine::m_last_file, lnp_state_machine::m_last_address,
	lnp_state_machine::m_stmt_at_address): Remove data items.
	(lnp_state_machine::record_line): Do not filter line entries here,
	except for line == 0.  Pass end_sequence to dwarf_finish_line.
	* infrun.c (process_event_stop_test): Don't stop in !is_stmt lines
	when stepping into inlines.  Don't stop at the call site again, when
	stepping within inlined subroutines with multiple ranges.
	Don't refresh the step info the when executing !is_stmt lines of
	of a different inlined subroutine.
	* jit.c (jit_symtab_line_mapping_add_impl): Initialize is_weak.
	* symmisc.c (dump_symtab_1,
	maintenance_print_one_line_table): Handle is_weak.
	* symtab.c (find_pc_sect_line): Handle is_weak.
	* symtab.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

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

	* gdb.cp/step-and-next-inline.exp: Remove KFAILs, enhance test.
	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
---
 gdb/block.c                                   |  15 +++-
 gdb/buildsym.c                                | 100 ++++++++++++++++++++++----
 gdb/buildsym.h                                |   3 +
 gdb/dwarf2/read.c                             |  75 ++++---------------
 gdb/infrun.c                                  |  33 ++++++++-
 gdb/jit.c                                     |   1 +
 gdb/symmisc.c                                 |  10 ++-
 gdb/symtab.c                                  |  14 ++--
 gdb/symtab.h                                  |   4 ++
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |  93 +++++++++++++++---------
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |   6 +-
 gdb/xcoffread.c                               |   1 +
 12 files changed, 230 insertions(+), 125 deletions(-)

diff --git a/gdb/block.c b/gdb/block.c
index fc6bfb9..6f6044b 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -205,7 +205,20 @@ struct symbol *
     return NULL;
 
   if (pblock)
-    *pblock = b;
+    {
+      struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+      if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+	{
+	  const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+	  const struct block *b0 = b;
+	  while (BLOCK_SUPERBLOCK (b0) && !BLOCK_FUNCTION (b0))
+	    b0 = BLOCK_SUPERBLOCK (b0);
+	  if (contained_in (b2, b0))
+	    b = b2;
+	}
+      *pblock = b;
+    }
+
   return bl;
 }
 
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 9525962..427cbb5 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -425,6 +425,13 @@ struct block *
       || end_inclusive + 1 != BLOCK_END (block))
     m_pending_addrmap_interesting = true;
 
+  if (block_inlined_p (block))
+    {
+      m_inline_end_vector.push_back (end_inclusive + 1);
+      if (end_inclusive + 1 == start)
+	end_inclusive = start;
+    }
+
   if (m_pending_addrmap == nullptr)
     m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
 
@@ -692,19 +699,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.
+     We simply set the is_weak marker in this case.  */
   if (line == 0)
     {
       while (subfile->line_vector->nitems > 0)
@@ -715,14 +719,80 @@ struct blockvector *
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == -1)
+    {
+      line = 0;
+      e = subfile->line_vector->item + subfile->line_vector->nitems;
+      while (e > subfile->line_vector->item)
+	{
+	  e--;
+	  if (e->pc != pc)
+	    break;
+	  e->is_weak = 1;
+	}
+    }
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
   e->is_stmt = is_stmt ? 1 : 0;
+  e->is_weak = 0;
   e->pc = pc;
 }
 
 \f
+/* 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_weak = 1 as well.  */
+  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_weak = 1;
+    }
+  while (a > 0);
+}
+
+\f
 /* 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
@@ -960,6 +1030,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.size (); 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..4fbe45b 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -397,6 +397,9 @@ struct buildsym_compunit
 
   /* Pending symbols that are local to the lexical context.  */
   struct pending *m_local_symbols = nullptr;
+
+  /* Pending inline end range addresses.  */
+  std::vector<CORE_ADDR> m_inline_end_vector;
 };
 
 \f
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 3c5982629..2234eea 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -14316,10 +14316,6 @@ class process_die_scope
 	  return false;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       /* Only DW_RLE_offset_pair needs the base address added.  */
       if (rlet == DW_RLE_offset_pair)
 	{
@@ -14438,10 +14434,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;
 
@@ -14481,6 +14473,10 @@ class process_die_scope
   retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (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;
@@ -21119,21 +21115,9 @@ class lnp_state_machine
 
   /* Additional bits of state we need to track.  */
 
-  /* The last file that we called dwarf2_start_subfile for.
-     This is only used for TLLs.  */
-  unsigned int m_last_file = 0;
   /* 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;
 
@@ -21285,7 +21269,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;
@@ -21298,7 +21282,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
@@ -21325,37 +21310,17 @@ class lnp_state_machine
   else if (m_op_index == 0 || end_sequence)
     {
       fe->included_p = 1;
-      if (m_record_lines_p)
-	{
-	  /* 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)
-	      || (!end_sequence && m_line == 0));
-
-	  if ((file_changed && !ignore_this_line) || end_sequence)
+      if (m_record_lines_p && (end_sequence || m_line != 0))
+	{
+	  if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+	      || 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 || m_is_stmt);
 	    }
 
-	  if (!end_sequence && !ignore_this_line)
+	  if (!end_sequence)
 	    {
 	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -21374,15 +21339,6 @@ class lnp_state_machine
 	    }
 	}
     }
-
-  /* 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,
@@ -21402,9 +21358,6 @@ class lnp_state_machine
   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/infrun.c b/gdb/infrun.c
index 2e5e837..5c19657 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6982,6 +6982,31 @@ struct wait_one_event
       return;
     }
 
+  /* Handle the case when subroutines have multiple ranges.
+     When we step from one part to the next part of the same subroutine,
+     all subroutine levels are skipped again which begin here.
+     Compensate for this by removing all skipped subroutines,
+     which were already executing from the user's perspective.  */
+
+  if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+		   ecs->event_thread->control.step_stack_frame_id)
+      && inline_skipped_frames (ecs->event_thread)
+      && ecs->event_thread->control.step_frame_id.artificial_depth > 0
+      && ecs->event_thread->control.step_frame_id.code_addr_p)
+    {
+      const struct block *prev, *curr;
+      int depth = 0;
+      prev = block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
+      curr = block_for_pc (ecs->event_thread->suspend.stop_pc);
+      while (curr && block_inlined_p (curr) && !contained_in (prev, curr))
+	{
+	  depth ++;
+	  curr = BLOCK_SUPERBLOCK (curr);
+	}
+      while (inline_skipped_frames (ecs->event_thread) > depth)
+	step_into_inline_frame (ecs->event_thread);
+    }
+
   /* Look for "calls" to inlined functions, part one.  If the inline
      frame machinery detected some skipped call sites, we have entered
      a new inline function.  */
@@ -7043,6 +7068,8 @@ struct wait_one_event
       infrun_debug_printf ("stepping through inlined function");
 
       if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+	  || ecs->event_thread->suspend.stop_pc != stop_pc_sal.pc
+	  || !stop_pc_sal.is_stmt
 	  || inline_frame_is_marked_for_skip (false, ecs->event_thread))
 	keep_going (ecs);
       else
@@ -7065,8 +7092,8 @@ struct wait_one_event
 	  end_stepping_range (ecs);
 	  return;
 	}
-      else if (frame_id_eq (get_frame_id (get_current_frame ()),
-			    ecs->event_thread->control.step_frame_id))
+      else if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+			    ecs->event_thread->control.step_stack_frame_id))
 	{
 	  /* We are at the start of a different line, however, this line is
 	     not marked as a statement, and we have not changed frame.  We
@@ -7096,7 +7123,7 @@ struct wait_one_event
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
   if (refresh_step_info)
-    set_step_info (ecs->event_thread, frame, stop_pc_sal);
+    set_step_info (ecs->event_thread, get_current_frame (), stop_pc_sal);
 
   infrun_debug_printf ("keep going");
   keep_going (ecs);
diff --git a/gdb/jit.c b/gdb/jit.c
index fd24d53..804b79c 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -517,6 +517,7 @@ struct gdb_object
       stab->linetable->item[i].pc = (CORE_ADDR) map[i].pc;
       stab->linetable->item[i].line = map[i].line;
       stab->linetable->item[i].is_stmt = 1;
+      stab->linetable->item[i].is_weak = 0;
     }
 }
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index acdbac6..06b544d 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -319,6 +319,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	  fputs_filtered (paddress (gdbarch, l->item[i].pc), outfile);
 	  if (l->item[i].is_stmt)
 	    fprintf_filtered (outfile, "\t(stmt)");
+	  if (l->item[i].is_weak)
+	    fprintf_filtered (outfile, "\t(weak)");
 	  fprintf_filtered (outfile, "\n");
 	}
     }
@@ -1039,11 +1041,12 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
       /* Leave space for 6 digits of index and line number.  After that the
 	 tables will just not format as well.  */
       struct ui_out *uiout = current_uiout;
-      ui_out_emit_table table_emitter (uiout, 4, -1, "line-table");
+      ui_out_emit_table table_emitter (uiout, 5, -1, "line-table");
       uiout->table_header (6, ui_left, "index", _("INDEX"));
       uiout->table_header (6, ui_left, "line", _("LINE"));
       uiout->table_header (18, ui_left, "address", _("ADDRESS"));
-      uiout->table_header (1, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (4, ui_left, "stmt", _("STMT"));
+      uiout->table_header (4, ui_left, "weak", _("WEAK"));
       uiout->table_body ();
 
       for (int i = 0; i < linetable->nitems; ++i)
@@ -1059,7 +1062,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	    uiout->field_string ("line", _("END"));
 	  uiout->field_core_addr ("address", objfile->arch (),
 				  item->pc);
-	  uiout->field_string ("is-stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("weak", item->is_weak ? "Y" : "");
 	  uiout->text ("\n");
 	}
     }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index dccc3d1..3195196 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3291,7 +3291,9 @@ struct symtab_and_line
 	 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)))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
@@ -3332,18 +3334,14 @@ struct symtab_and_line
 	 We used to return alt->line - 1 here, but that could be
 	 anywhere; if we don't have line number info for this PC,
 	 don't make some up.  */
-      val.pc = pc;
-    }
-  else if (best->line == 0)
-    {
-      /* If our best fit is in a range of PC's for which no line
-	 number info is available (line number is zero) then we didn't
-	 find any valid line information.  */
+      if (notcurrent)
+	pc++;
       val.pc = pc;
     }
   else
     {
       val.is_stmt = best->is_stmt;
+      val.is_weak = best->is_weak;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dd67f86..650b8fa 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1311,6 +1311,8 @@ struct linetable_entry
 
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   unsigned is_stmt : 1;
+  /* True if this PC is at a subroutine range and.  */
+  unsigned is_weak : 1;
 
   /* The address for this entry.  */
   CORE_ADDR pc;
@@ -1896,6 +1898,8 @@ struct symtab_and_line
   /* If the line number information is valid, then this indicates if this
      line table entry had the is-stmt flag set or not.  */
   bool is_stmt = false;
+  /* True if this PC is at a subroutine range and.  */
+  bool is_weak = false;
 
   /* The probe associated with this symtab_and_line.  */
   probe *prob = NULL;
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 43a7101..4181fc6 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -29,13 +29,6 @@ if {[test_compiler_info gcc*] && ![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}
     if { [supports_statement_frontiers] } {
 	lappend options -gstatement-frontiers
@@ -67,41 +60,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 {[test_compiler_info gcc*] && !$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 {[test_compiler_info gcc*] && !$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] {
@@ -119,22 +91,77 @@ proc do_test { use_header } {
     gdb_test "step" ".*if \\(t->x != i\\).*" "step 2"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 1 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 3"
+    gdb_test "step" ".*return x.*" "step 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 1 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 4"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 4"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 5"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 2 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 5"
+    gdb_test "step" ".*return x.*" "step 6"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 2 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 7"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 6"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 8"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 3 pass 2"
-    gdb_test "step" "return 0.*" "step 7"
+    gdb_test "step" ".*return x.*" "step 9"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 3 pass 2"
+    gdb_test "step" "return 0.*" "step 10"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 4 pass 2"
+
+    clean_restart ${executable}
+
+    if ![runto_main] {
+	fail "can't run to main pass 3"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 3"
+    gdb_test "step" ".*" "step into get_alias_set pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 3"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 2 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"in inline 1 pass 3"
+    gdb_test "p t->x = 2" ".* = 2.*" "change value pass 3"
+    gdb_test "step" ".*abort.*" "step 4, pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"abort from inline 1 pass 3"
+
+    if ![runto_main] {
+	fail "can't run to main pass 4"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 4"
+    gdb_test "skip tree_check" ".*" "skip tree_check pass 4"
+    gdb_test "step" ".*" "step into get_alias_set pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 2 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 2 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 3 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 3 pass 4"
+    gdb_test "step" "return 0.*" "step 4 pass 4"
+    gdb_test "bt" \
+	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
+	"not in inline 4 pass 4"
     }
 }
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index 3164a90..a1132e3 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
@@ -148,7 +148,7 @@ set prev -1
 set seq_count 0
 gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
     "count END markers in line table" {
-	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)?(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 1" \
 		    "prev of normal entry at $seq_count is end marker"
@@ -157,7 +157,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	    incr seq_count
 	    exp_continue
 	}
-	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)?\(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 0" \
 		    "prev of end marker at $seq_count is normal entry"
@@ -173,7 +173,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	-re ".*linetable: \\(\\(struct linetable \\*\\) 0x0\\):\r\nNo line table.\r\n" {
 	    exp_continue
 	}
-	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT *\r\n" {
+	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+STMT\[ \t\]+WEAK *\r\n" {
 	    exp_continue
 	}
     }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c05060..db422cd 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -446,6 +446,7 @@ struct find_targ_sec_arg
 	    }
 	  fentry[function_count].line = ii;
 	  fentry[function_count].is_stmt = 1;
+	  fentry[function_count].is_weak = 0;
 	  fentry[function_count].pc = oldLineTb->item[ii].pc;
 	  ++function_count;
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4] Fix range end handling of inlined subroutines - restart
  2020-11-19 17:25   ` [PATCH v3] " Bernd Edlinger
@ 2020-11-29 14:43     ` Bernd Edlinger
  2020-12-08 13:27       ` Hannes Domani
  0 siblings, 1 reply; 6+ messages in thread
From: Bernd Edlinger @ 2020-11-29 14:43 UTC (permalink / raw)
  To: gdb-patches, Andrew Burgess

[-- Attachment #1: Type: text/plain, Size: 1082 bytes --]

Hi,

this is a new improved version of my patch.

It addresses two issues that came up when playing and debugging
the rather big and complex gcc application.

First I found cases where a completely empty inlined subroutine
was encountered, the step command can step into the inline,
but the call stack does not reflect that.  Fixed that by
making an exception in dwarf2_get_pc_bounds for empty inlined
routines.

Then if a function is called immediatly after the inline,
the call stack shows the last line of the inline, but we
have a better line, a !is-stmt one following the inline
function.  Fixed that by making find_pc_sect_line prefer a
!is_stmt line over a weak one if an in-between PC is requested.

There is a new test case for those two issues.

Finally I found that a "b inline-function" does not
always find the entry_pc, and instead the breakpoint is
at the first non-zero block range of the inline block.

Fixed that by moving the block that starts at entry_pc
to the first position.


Tested successfully on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.
 

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-range-end-handling-of-inlined-subroutines.patch --]
[-- Type: text/x-patch; name="0001-Fix-range-end-handling-of-inlined-subroutines.patch", Size: 35817 bytes --]

From e50910012f77b0908cd71b179ed796914adc03ad Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 3 Nov 2020 18:41:43 +0100
Subject: [PATCH] Fix range end handling of inlined subroutines

This introduces a new line table flag is_weak.
The line entries at the end of a subroutine range,
use this to indicate that they may possibly
be part of the previous subroutine.

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_weak = 1.

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.

gdb:
2020-11-29  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* block.c (blockvector_for_pc_sect): For weak line table values,
	use the inline frame at PC - 1 if it is deeper.
	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Delete previous lines
	at the same PC as the end sequence marker,
	but only mark them as weak for a fake end sequence marker.
	(buildsym_compunit::patch_inline_end_pos): New helper function.
	(buildsym_compunit::end_symtab_with_blockvector): Patch line table.
	* buildsym.h (buildsym_compunit::m_inline_end_vector): New data item.
	* dwarf2/read.c (dwarf2_rnglists_process,
	dwarf2_ranges_process): Don't ignore empty ranges here.
	(dwarf2_ranges_read): Ignore empty ranges here.
	(dwarf2_get_pc_bounds): Allow empty inlined subroutines.
	(partial_die_info::read): Likewise.
	(dwarf2_record_block_ranges): Move range beginning at DW_AT_entry_pc
	to the first block range.
	(dwarf_finish_line): Add new parameter end_sequence.
	(lnp_state_machine::m_last_file, lnp_state_machine::m_last_address,
	lnp_state_machine::m_stmt_at_address): Remove data items.
	(lnp_state_machine::record_line): Do not filter line entries here,
	except for line == 0.  Pass end_sequence to dwarf_finish_line.
	* infrun.c (process_event_stop_test): Don't stop in !is_stmt lines
	when stepping into inlines.  Don't stop at the call site again, when
	stepping within inlined subroutines with multiple ranges.
	Don't refresh the step info the when executing !is_stmt lines of
	of a different inlined subroutine.
	* jit.c (jit_symtab_line_mapping_add_impl): Initialize is_weak.
	* symmisc.c (dump_symtab_1,
	maintenance_print_one_line_table): Handle is_weak.
	* symtab.c (find_pc_sect_line): Handle is_weak.
	* symtab.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

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

	* gdb.cp/empty-inline.exp: New test.
	* gdb.cp/empty-inline.c: New test.
	* gdb.cp/step-and-next-inline.exp: Remove KFAILs, enhance test.
	* gdb.cp/step-and-next-inline.cc: Work around failure with
	gcc-9.3.0 from ubuntu 20.04.
	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
---
 gdb/block.c                                   |  15 +++-
 gdb/buildsym.c                                | 100 ++++++++++++++++++++++----
 gdb/buildsym.h                                |   3 +
 gdb/dwarf2/read.c                             |  98 +++++++++----------------
 gdb/infrun.c                                  |  33 ++++++++-
 gdb/jit.c                                     |   1 +
 gdb/symmisc.c                                 |  10 ++-
 gdb/symtab.c                                  |  18 ++---
 gdb/symtab.h                                  |   4 ++
 gdb/testsuite/gdb.base/empty-inline.c         |  42 +++++++++++
 gdb/testsuite/gdb.base/empty-inline.exp       |  48 +++++++++++++
 gdb/testsuite/gdb.cp/step-and-next-inline.cc  |   6 ++
 gdb/testsuite/gdb.cp/step-and-next-inline.exp |  95 +++++++++++++++---------
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |   6 +-
 gdb/xcoffread.c                               |   1 +
 15 files changed, 349 insertions(+), 131 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/empty-inline.c
 create mode 100644 gdb/testsuite/gdb.base/empty-inline.exp

diff --git a/gdb/block.c b/gdb/block.c
index fc6bfb9..6f6044b 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -205,7 +205,20 @@ struct symbol *
     return NULL;
 
   if (pblock)
-    *pblock = b;
+    {
+      struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+      if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+	{
+	  const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+	  const struct block *b0 = b;
+	  while (BLOCK_SUPERBLOCK (b0) && !BLOCK_FUNCTION (b0))
+	    b0 = BLOCK_SUPERBLOCK (b0);
+	  if (contained_in (b2, b0))
+	    b = b2;
+	}
+      *pblock = b;
+    }
+
   return bl;
 }
 
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 9525962..427cbb5 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -425,6 +425,13 @@ struct block *
       || end_inclusive + 1 != BLOCK_END (block))
     m_pending_addrmap_interesting = true;
 
+  if (block_inlined_p (block))
+    {
+      m_inline_end_vector.push_back (end_inclusive + 1);
+      if (end_inclusive + 1 == start)
+	end_inclusive = start;
+    }
+
   if (m_pending_addrmap == nullptr)
     m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
 
@@ -692,19 +699,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.
+     We simply set the is_weak marker in this case.  */
   if (line == 0)
     {
       while (subfile->line_vector->nitems > 0)
@@ -715,14 +719,80 @@ struct blockvector *
 	  subfile->line_vector->nitems--;
 	}
     }
+  else if (line == -1)
+    {
+      line = 0;
+      e = subfile->line_vector->item + subfile->line_vector->nitems;
+      while (e > subfile->line_vector->item)
+	{
+	  e--;
+	  if (e->pc != pc)
+	    break;
+	  e->is_weak = 1;
+	}
+    }
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
   e->is_stmt = is_stmt ? 1 : 0;
+  e->is_weak = 0;
   e->pc = pc;
 }
 
 \f
+/* 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_weak = 1 as well.  */
+  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_weak = 1;
+    }
+  while (a > 0);
+}
+
+\f
 /* 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
@@ -960,6 +1030,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.size (); 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..4fbe45b 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -397,6 +397,9 @@ struct buildsym_compunit
 
   /* Pending symbols that are local to the lexical context.  */
   struct pending *m_local_symbols = nullptr;
+
+  /* Pending inline end range addresses.  */
+  std::vector<CORE_ADDR> m_inline_end_vector;
 };
 
 \f
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 28244e5..b9b75ab 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -14316,10 +14316,6 @@ class process_die_scope
 	  return false;
 	}
 
-      /* Empty range entries have no effect.  */
-      if (range_beginning == range_end)
-	continue;
-
       /* Only DW_RLE_offset_pair needs the base address added.  */
       if (rlet == DW_RLE_offset_pair)
 	{
@@ -14438,10 +14434,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;
 
@@ -14481,6 +14473,10 @@ class process_die_scope
   retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (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;
@@ -14595,8 +14591,8 @@ class process_die_scope
 	return PC_BOUNDS_NOT_PRESENT;
     }
 
-  /* partial_die_info::read has also the strict LOW < HIGH requirement.  */
-  if (high <= low)
+  /* partial_die_info::read has also the same low < high requirement.  */
+  if (low > high || (low == high && die->tag != DW_TAG_inlined_subroutine))
     return PC_BOUNDS_INVALID;
 
   /* When using the GNU linker, .gnu.linkonce. sections are used to
@@ -14762,6 +14758,18 @@ class process_die_scope
       unsigned long offset = (attr->as_unsigned ()
 			      + (need_ranges_base ? cu->ranges_base : 0));
 
+      CORE_ADDR entry_pc = (CORE_ADDR) -1;
+      if (die->tag == DW_TAG_inlined_subroutine)
+	{
+	  attr = dwarf2_attr (die, DW_AT_entry_pc, cu);
+	  if (attr != nullptr)
+	    {
+	      entry_pc = attr->as_address ();
+	      entry_pc += baseaddr;
+	      entry_pc = gdbarch_adjust_dwarf2_addr (gdbarch, entry_pc);
+	    }
+	}
+
       std::vector<blockrange> blockvec;
       dwarf2_ranges_process (offset, cu, die->tag,
 	[&] (CORE_ADDR start, CORE_ADDR end)
@@ -14772,6 +14780,8 @@ class process_die_scope
 	  end = gdbarch_adjust_dwarf2_addr (gdbarch, end);
 	  cu->get_builder ()->record_block_range (block, start, end - 1);
 	  blockvec.emplace_back (start, end);
+	  if (entry_pc == start && blockvec.size () > 1)
+	    std::swap (blockvec[0], blockvec[blockvec.size () - 1]);
 	});
 
       BLOCK_RANGES(block) = make_blockranges (objfile, blockvec);
@@ -19710,8 +19720,9 @@ struct type *
 		     sect_offset_str (sect_off),
 		     objfile_name (objfile));
 	}
-      /* dwarf2_get_pc_bounds has also the strict low < high requirement.  */
-      else if (lowpc >= highpc)
+      /* dwarf2_get_pc_bounds has also the same low < high requirement.  */
+      else if (lowpc > highpc
+	       || (lowpc == highpc && tag != DW_TAG_inlined_subroutine))
 	{
 	  struct objfile *objfile = per_objfile->objfile;
 	  struct gdbarch *gdbarch = objfile->arch ();
@@ -21119,21 +21130,9 @@ class lnp_state_machine
 
   /* Additional bits of state we need to track.  */
 
-  /* The last file that we called dwarf2_start_subfile for.
-     This is only used for TLLs.  */
-  unsigned int m_last_file = 0;
   /* 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;
 
@@ -21285,7 +21284,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;
@@ -21298,7 +21297,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
@@ -21325,37 +21325,17 @@ class lnp_state_machine
   else if (m_op_index == 0 || end_sequence)
     {
       fe->included_p = 1;
-      if (m_record_lines_p)
-	{
-	  /* 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)
-	      || (!end_sequence && m_line == 0));
-
-	  if ((file_changed && !ignore_this_line) || end_sequence)
+      if (m_record_lines_p && (end_sequence || m_line != 0))
+	{
+	  if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+	      || 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 || m_is_stmt);
 	    }
 
-	  if (!end_sequence && !ignore_this_line)
+	  if (!end_sequence)
 	    {
 	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -21374,15 +21354,6 @@ class lnp_state_machine
 	    }
 	}
     }
-
-  /* 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,
@@ -21402,9 +21373,6 @@ class lnp_state_machine
   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/infrun.c b/gdb/infrun.c
index 2e5e837..5c19657 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6982,6 +6982,31 @@ struct wait_one_event
       return;
     }
 
+  /* Handle the case when subroutines have multiple ranges.
+     When we step from one part to the next part of the same subroutine,
+     all subroutine levels are skipped again which begin here.
+     Compensate for this by removing all skipped subroutines,
+     which were already executing from the user's perspective.  */
+
+  if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+		   ecs->event_thread->control.step_stack_frame_id)
+      && inline_skipped_frames (ecs->event_thread)
+      && ecs->event_thread->control.step_frame_id.artificial_depth > 0
+      && ecs->event_thread->control.step_frame_id.code_addr_p)
+    {
+      const struct block *prev, *curr;
+      int depth = 0;
+      prev = block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
+      curr = block_for_pc (ecs->event_thread->suspend.stop_pc);
+      while (curr && block_inlined_p (curr) && !contained_in (prev, curr))
+	{
+	  depth ++;
+	  curr = BLOCK_SUPERBLOCK (curr);
+	}
+      while (inline_skipped_frames (ecs->event_thread) > depth)
+	step_into_inline_frame (ecs->event_thread);
+    }
+
   /* Look for "calls" to inlined functions, part one.  If the inline
      frame machinery detected some skipped call sites, we have entered
      a new inline function.  */
@@ -7043,6 +7068,8 @@ struct wait_one_event
       infrun_debug_printf ("stepping through inlined function");
 
       if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+	  || ecs->event_thread->suspend.stop_pc != stop_pc_sal.pc
+	  || !stop_pc_sal.is_stmt
 	  || inline_frame_is_marked_for_skip (false, ecs->event_thread))
 	keep_going (ecs);
       else
@@ -7065,8 +7092,8 @@ struct wait_one_event
 	  end_stepping_range (ecs);
 	  return;
 	}
-      else if (frame_id_eq (get_frame_id (get_current_frame ()),
-			    ecs->event_thread->control.step_frame_id))
+      else if (frame_id_eq (get_stack_frame_id (get_current_frame ()),
+			    ecs->event_thread->control.step_stack_frame_id))
 	{
 	  /* We are at the start of a different line, however, this line is
 	     not marked as a statement, and we have not changed frame.  We
@@ -7096,7 +7123,7 @@ struct wait_one_event
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
   if (refresh_step_info)
-    set_step_info (ecs->event_thread, frame, stop_pc_sal);
+    set_step_info (ecs->event_thread, get_current_frame (), stop_pc_sal);
 
   infrun_debug_printf ("keep going");
   keep_going (ecs);
diff --git a/gdb/jit.c b/gdb/jit.c
index fd24d53..804b79c 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -517,6 +517,7 @@ struct gdb_object
       stab->linetable->item[i].pc = (CORE_ADDR) map[i].pc;
       stab->linetable->item[i].line = map[i].line;
       stab->linetable->item[i].is_stmt = 1;
+      stab->linetable->item[i].is_weak = 0;
     }
 }
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index acdbac6..06b544d 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -319,6 +319,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	  fputs_filtered (paddress (gdbarch, l->item[i].pc), outfile);
 	  if (l->item[i].is_stmt)
 	    fprintf_filtered (outfile, "\t(stmt)");
+	  if (l->item[i].is_weak)
+	    fprintf_filtered (outfile, "\t(weak)");
 	  fprintf_filtered (outfile, "\n");
 	}
     }
@@ -1039,11 +1041,12 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
       /* Leave space for 6 digits of index and line number.  After that the
 	 tables will just not format as well.  */
       struct ui_out *uiout = current_uiout;
-      ui_out_emit_table table_emitter (uiout, 4, -1, "line-table");
+      ui_out_emit_table table_emitter (uiout, 5, -1, "line-table");
       uiout->table_header (6, ui_left, "index", _("INDEX"));
       uiout->table_header (6, ui_left, "line", _("LINE"));
       uiout->table_header (18, ui_left, "address", _("ADDRESS"));
-      uiout->table_header (1, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (4, ui_left, "stmt", _("STMT"));
+      uiout->table_header (4, ui_left, "weak", _("WEAK"));
       uiout->table_body ();
 
       for (int i = 0; i < linetable->nitems; ++i)
@@ -1059,7 +1062,8 @@ static void print_symbol (struct gdbarch *gdbarch, struct symbol *symbol,
 	    uiout->field_string ("line", _("END"));
 	  uiout->field_core_addr ("address", objfile->arch (),
 				  item->pc);
-	  uiout->field_string ("is-stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("weak", item->is_weak ? "Y" : "");
 	  uiout->text ("\n");
 	}
     }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index dccc3d1..09e6361 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3291,7 +3291,11 @@ struct symtab_and_line
 	 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->pc == pc
+					       ? !best->is_stmt
+					       : best->is_weak))))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
@@ -3309,7 +3313,7 @@ struct symtab_and_line
 	      while (tmp > first && (tmp - 1)->pc == tmp->pc
 		     && (tmp - 1)->line != 0 && !tmp->is_stmt)
 		--tmp;
-	      if (tmp->is_stmt)
+	      if (tmp->is_stmt && (tmp->pc == pc || !tmp->is_weak))
 		best = tmp;
 	    }
 
@@ -3332,18 +3336,14 @@ struct symtab_and_line
 	 We used to return alt->line - 1 here, but that could be
 	 anywhere; if we don't have line number info for this PC,
 	 don't make some up.  */
-      val.pc = pc;
-    }
-  else if (best->line == 0)
-    {
-      /* If our best fit is in a range of PC's for which no line
-	 number info is available (line number is zero) then we didn't
-	 find any valid line information.  */
+      if (notcurrent)
+	pc++;
       val.pc = pc;
     }
   else
     {
       val.is_stmt = best->is_stmt;
+      val.is_weak = best->is_weak;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dd67f86..650b8fa 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1311,6 +1311,8 @@ struct linetable_entry
 
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   unsigned is_stmt : 1;
+  /* True if this PC is at a subroutine range and.  */
+  unsigned is_weak : 1;
 
   /* The address for this entry.  */
   CORE_ADDR pc;
@@ -1896,6 +1898,8 @@ struct symtab_and_line
   /* If the line number information is valid, then this indicates if this
      line table entry had the is-stmt flag set or not.  */
   bool is_stmt = false;
+  /* True if this PC is at a subroutine range and.  */
+  bool is_weak = false;
 
   /* The probe associated with this symtab_and_line.  */
   probe *prob = NULL;
diff --git a/gdb/testsuite/gdb.base/empty-inline.c b/gdb/testsuite/gdb.base/empty-inline.c
new file mode 100644
index 0000000..9203af1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/empty-inline.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+static int test0 (void)
+{
+  asm ("");
+  return 1; /* line 21 */
+}
+
+int __attribute__((noinline, noclone))
+#ifdef __CET__
+  __attribute__((nocf_check))
+#endif
+test1 (int x)
+{
+  asm ("");
+  return x+1; /* line 31 */
+}
+
+int
+#ifdef __CET__
+  __attribute__((nocf_check))
+#endif
+main()
+{
+  test1 (test0 ()); /* line 40*/
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/empty-inline.exp b/gdb/testsuite/gdb.base/empty-inline.exp
new file mode 100644
index 0000000..6348ca2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/empty-inline.exp
@@ -0,0 +1,48 @@
+# 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/>.
+
+standard_testfile .c
+
+if [get_compiler_info] {
+    return -1
+}
+
+if {[test_compiler_info gcc*] && ![supports_statement_frontiers] } {
+    return -1
+}
+
+global srcfile testfile
+
+set options {debug nowarnings optimize=-O2}
+if { [supports_statement_frontiers] } {
+    lappend options additional_flags=-gstatement-frontiers
+}
+
+if { [prepare_for_testing "failed to prepare" $binfile \
+      $srcfile $options] } {
+    return -1
+}
+
+if ![runto_main] {
+    fail "can't run to main"
+    return -1
+}
+
+gdb_test "frame 0" "\\s*\\#0\\s+main.*empty-inline.c:40.*" "in main"
+gdb_test "step" ".*test0.*empty-inline.c:21.*" "step into test0"
+gdb_test "frame 1" "\\s*\\#1\\s+main.*empty-inline.c:40.*" "frame1"
+gdb_test "step" ".*test1.*empty-inline.c:31.*" "step into test1"
+gdb_test "frame 1" "\\s*\\#1.*in main.*empty-inline.c:40.*" "frame2"
+gdb_test "step" ".*main.*empty-inline.c:41.*" "step back to main"
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.cc b/gdb/testsuite/gdb.cp/step-and-next-inline.cc
index d923cc5..698dcd7 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.cc
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.cc
@@ -46,6 +46,9 @@ tree_check (tree *t, int i)
 #endif	/* USE_NEXT_INLINE_H */
 
 int __attribute__((noinline, noclone))
+#ifdef __CET__
+  __attribute__((nocf_check))
+#endif
 get_alias_set (tree *t)
 {
   if (t != NULL
@@ -59,6 +62,9 @@ get_alias_set (tree *t)
 tree xx;
 
 int
+#ifdef __CET__
+  __attribute__((nocf_check))
+#endif
 main()
 {
   get_alias_set (&xx);
diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
index 43a7101..3dff7f0 100644
--- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp
+++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp
@@ -29,16 +29,9 @@ if {[test_compiler_info gcc*] && ![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}
     if { [supports_statement_frontiers] } {
-	lappend options -gstatement-frontiers
+	lappend options additional_flags=-gstatement-frontiers
     }
     if { $use_header } {
 	lappend options additional_flags=-DUSE_NEXT_INLINE_H
@@ -67,41 +60,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 {[test_compiler_info gcc*] && !$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 {[test_compiler_info gcc*] && !$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] {
@@ -119,22 +91,77 @@ proc do_test { use_header } {
     gdb_test "step" ".*if \\(t->x != i\\).*" "step 2"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 1 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 3"
+    gdb_test "step" ".*return x.*" "step 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 1 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 4"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 2 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 4"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 5"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 2 pass 2"
-    gdb_test "step" ".*TREE_TYPE.*" "step 5"
+    gdb_test "step" ".*return x.*" "step 6"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 2 pass 2"
+    gdb_test "step" ".*TREE_TYPE.*" "step 7"
     gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
 	"not in inline 3 pass 2"
-    gdb_test "step" ".*if \\(t->x != i\\).*" "step 6"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 8"
     gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
 	"in inline 3 pass 2"
-    gdb_test "step" "return 0.*" "step 7"
+    gdb_test "step" ".*return x.*" "step 9"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"return from inline 3 pass 2"
+    gdb_test "step" "return 0.*" "step 10"
     gdb_test "bt" \
 	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
 	"not in inline 4 pass 2"
+
+    clean_restart ${executable}
+
+    if ![runto_main] {
+	fail "can't run to main pass 3"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 3"
+    gdb_test "step" ".*" "step into get_alias_set pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 3"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 3"
+    gdb_test "step" ".*if \\(t->x != i\\).*" "step 2 pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"in inline 1 pass 3"
+    gdb_test "p t->x = 2" ".* = 2.*" "change value pass 3"
+    gdb_test "step" ".*abort.*" "step 4, pass 3"
+    gdb_test "bt" "\\s*\\#0\\s+\[^\r\]*tree_check\[^\r\]*${hdrfile}:.*" \
+	"abort from inline 1 pass 3"
+
+    if ![runto_main] {
+	fail "can't run to main pass 4"
+	return
+    }
+
+    gdb_test "bt" "\\s*\\#0\\s+main.*" "in main pass 4"
+    gdb_test "skip tree_check" ".*" "skip tree_check pass 4"
+    gdb_test "step" ".*" "step into get_alias_set pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"in get_alias_set pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 1 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 1 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 2 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 2 pass 4"
+    gdb_test "step" ".*TREE_TYPE.*" "step 3 pass 4"
+    gdb_test "bt" "\\s*\\#0\\s+get_alias_set\[^\r\]*${srcfile}:.*" \
+	"not in inline 3 pass 4"
+    gdb_test "step" "return 0.*" "step 4 pass 4"
+    gdb_test "bt" \
+	"\\s*\\#0\\s+(main|get_alias_set)\[^\r\]*${srcfile}:.*" \
+	"not in inline 4 pass 4"
     }
 }
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index 3164a90..a1132e3 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
@@ -148,7 +148,7 @@ set prev -1
 set seq_count 0
 gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
     "count END markers in line table" {
-	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+$decimal\[ \t\]+$hex\(\[ \t\]+Y\)?(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 1" \
 		    "prev of normal entry at $seq_count is end marker"
@@ -157,7 +157,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	    incr seq_count
 	    exp_continue
 	}
-	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)? *\r\n" {
+	-re "^$decimal\[ \t\]+END\[ \t\]+$hex\(\[ \t\]+Y\)?\(\[ \t\]+Y\)? *\r\n" {
 	    if { $prev != -1 } {
 		gdb_assert "$prev == 0" \
 		    "prev of end marker at $seq_count is normal entry"
@@ -173,7 +173,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	-re ".*linetable: \\(\\(struct linetable \\*\\) 0x0\\):\r\nNo line table.\r\n" {
 	    exp_continue
 	}
-	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT *\r\n" {
+	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+STMT\[ \t\]+WEAK *\r\n" {
 	    exp_continue
 	}
     }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c05060..db422cd 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -446,6 +446,7 @@ struct find_targ_sec_arg
 	    }
 	  fentry[function_count].line = ii;
 	  fentry[function_count].is_stmt = 1;
+	  fentry[function_count].is_weak = 0;
 	  fentry[function_count].pc = oldLineTb->item[ii].pc;
 	  ++function_count;
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4] Fix range end handling of inlined subroutines - restart
  2020-11-29 14:43     ` [PATCH v4] " Bernd Edlinger
@ 2020-12-08 13:27       ` Hannes Domani
  2020-12-09 18:19         ` Bernd Edlinger
  0 siblings, 1 reply; 6+ messages in thread
From: Hannes Domani @ 2020-12-08 13:27 UTC (permalink / raw)
  To: gdb-patches, Andrew Burgess, Bernd Edlinger

 Am Sonntag, 29. November 2020, 15:43:27 MEZ hat Bernd Edlinger <bernd.edlinger@hotmail.de> Folgendes geschrieben:

> Tested successfully on x86_64-pc-linux-gnu.
> Is it OK for trunk?

I can't approve it, but it's working great for me so far.


I just noticed some small style/spelling issues:

> @@ -960,6 +1030,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.size (); i++)
> +         patch_inline_end_pos (subfile->line_vector,
> +                   m_inline_end_vector[i]);
>      }
>  
>        /* Allocate a symbol table if necessary.  */

Here is 1 space too much of indention.


> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -1311,6 +1311,8 @@ struct linetable_entry
>  
>    /* True if this PC is a good location to place a breakpoint for LINE.  */
>    unsigned is_stmt : 1;
> +  /* True if this PC is at a subroutine range and.  */
> +  unsigned is_weak : 1;
>  
>    /* The address for this entry.  */
>    CORE_ADDR pc;
> @@ -1896,6 +1898,8 @@ struct symtab_and_line
>    /* If the line number information is valid, then this indicates if this
>       line table entry had the is-stmt flag set or not.  */
>    bool is_stmt = false;
> +  /* True if this PC is at a subroutine range and.  */
> +  bool is_weak = false;
>  
>    /* The probe associated with this symtab_and_line.  */
>    probe *prob = NULL;

Both times it's "range and", but it should be "range end".


Hannes

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4] Fix range end handling of inlined subroutines - restart
  2020-12-08 13:27       ` Hannes Domani
@ 2020-12-09 18:19         ` Bernd Edlinger
  0 siblings, 0 replies; 6+ messages in thread
From: Bernd Edlinger @ 2020-12-09 18:19 UTC (permalink / raw)
  To: Hannes Domani, gdb-patches, Andrew Burgess

On 12/8/20 2:27 PM, Hannes Domani wrote:
>  Am Sonntag, 29. November 2020, 15:43:27 MEZ hat Bernd Edlinger <bernd.edlinger@hotmail.de> Folgendes geschrieben:
> 
>> Tested successfully on x86_64-pc-linux-gnu.
>> Is it OK for trunk?
> 
> I can't approve it, but it's working great for me so far.
> 
> 
> I just noticed some small style/spelling issues:
> 
>> @@ -960,6 +1030,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.size (); i++)
>> +         patch_inline_end_pos (subfile->line_vector,
>> +                   m_inline_end_vector[i]);
>>      }
>>  
>>         /* Allocate a symbol table if necessary.  */
> 
> Here is 1 space too much of indention.
> 
> 
>> --- a/gdb/symtab.h
>> +++ b/gdb/symtab.h
>> @@ -1311,6 +1311,8 @@ struct linetable_entry
>>  
>>     /* True if this PC is a good location to place a breakpoint for LINE.  */
>>     unsigned is_stmt : 1;
>> +  /* True if this PC is at a subroutine range and.  */
>> +  unsigned is_weak : 1;
>>  
>>     /* The address for this entry.  */
>>     CORE_ADDR pc;
>> @@ -1896,6 +1898,8 @@ struct symtab_and_line
>>     /* If the line number information is valid, then this indicates if this
>>        line table entry had the is-stmt flag set or not.  */
>>     bool is_stmt = false;
>> +  /* True if this PC is at a subroutine range and.  */
>> +  bool is_weak = false;
>>  
>>     /* The probe associated with this symtab_and_line.  */
>>     probe *prob = NULL;
> 
> Both times it's "range and", but it should be "range end".
> 

Thanks for your kind feedback.
I have fixed the formatting locally.


Bernd.

> 
> Hannes
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-12-09 18:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-06 16:12 [PATCH] Fix range end handling of inlined subroutines - restart Bernd Edlinger
2020-11-10 17:47 ` [PATCH v2 ] " Bernd Edlinger
2020-11-19 17:25   ` [PATCH v3] " Bernd Edlinger
2020-11-29 14:43     ` [PATCH v4] " Bernd Edlinger
2020-12-08 13:27       ` Hannes Domani
2020-12-09 18:19         ` Bernd Edlinger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).