[v2,1/4] Introduce a new line table flag is_weak

Message ID AM8PR10MB470867D8E393F97F01FCB4CCE4209@AM8PR10MB4708.EURPRD10.PROD.OUTLOOK.COM
State Superseded
Headers show
Series
  • [v2,1/4] Introduce a new line table flag is_weak
Related show

Commit Message

Bernd Edlinger May 30, 2021, 1:58 p.m.
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.

Additionally this adds a "fake" end sequence to the
record_line function, that is line number -1.
That will be used in the next patch.

Finally this adds a handling for empty ranges to
record_block_range.  Currently this function is
not called with empty ranges, but that will be used
in the next patch.

There should be no functional changes after this commit.

gdb:
2021-01-01  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Update the comment about the
	end of sequence marker.  Mark previous lines at the same PC
	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.
	* 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.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

gdb/testsuite:
2021-01-01  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
	* gdb.dwarf2/dw2-out-of-range-end-of-seq.exp: Likewise.


Thanks,
Bernd.

Patch

From c5cd0f3b4ff374196ea7d218f693e072e03f588d 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 v2 1/4] Introduce a new line table flag is_weak

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.

Additionally this adds a "fake" end sequence to the
record_line function, that is line number -1.
That will be used in the next patch.

Finally this adds a handling for empty ranges to
record_block_range.  Currently this function is
not called with empty ranges, but that will be used
in the next patch.

There should be no functional changes after this commit.

gdb:
2021-01-01  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* buildsym.c (buildsym_compunit::record_block_range): Store inline
	range end PC values.  Make empty inline ranges one byte long.
	(buildsym_compunit::record_line): Update the comment about the
	end of sequence marker.  Mark previous lines at the same PC
	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.
	* 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.h (linetable_entry::is_weak,
	symtab_and_line::is_weak): New data items.
	* xcoffread.c (arrange_linetable): Initialize is_weak.

gdb/testsuite:
2021-01-01  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* gdb.dwarf2/dw2-ranges-base.exp: Adjust test, handle WEAK.
	* gdb.dwarf2/dw2-out-of-range-end-of-seq.exp: Likewise.
---
 gdb/buildsym.c                                     | 103 ++++++++++++++++++---
 gdb/buildsym.h                                     |   3 +
 gdb/jit.c                                          |   1 +
 gdb/symmisc.c                                      |  10 +-
 gdb/symtab.h                                       |   4 +
 .../gdb.dwarf2/dw2-out-of-range-end-of-seq.exp     |   4 +-
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp       |   6 +-
 gdb/xcoffread.c                                    |   1 +
 8 files changed, 111 insertions(+), 21 deletions(-)

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 0f7449f..7c0153c 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -425,6 +425,16 @@  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;
+	  m_pending_addrmap_interesting = true;
+	}
+    }
+
   if (m_pending_addrmap == nullptr)
     m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
 
@@ -692,19 +702,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)
     {
       struct linetable_entry *last = nullptr;
@@ -720,14 +727,80 @@  struct blockvector *
       if (last == nullptr || last->line == 0)
 	return;
     }
+  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;
 }
 
 
+/* 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);
+}
+
+
 /* 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
@@ -965,6 +1038,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 b35c26d..bacf308 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;
 };
 
 
diff --git a/gdb/jit.c b/gdb/jit.c
index 1de785b..0edc36b 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -439,6 +439,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 e38ceb6..7905a6f 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -271,6 +271,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");
 	}
     }
@@ -987,11 +989,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)
@@ -1007,7 +1010,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.h b/gdb/symtab.h
index efdbada..891505e 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1321,6 +1321,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 end.  */
+  unsigned is_weak : 1;
 
   /* The address for this entry.  */
   CORE_ADDR pc;
@@ -1906,6 +1908,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 end.  */
+  bool is_weak = false;
 
   /* The probe associated with this symtab_and_line.  */
   probe *prob = NULL;
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp b/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
index 42cfd0b..be5c29d 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
@@ -86,10 +86,10 @@  if ![runto_main] {
 
 set test "END with address 1 eliminated"
 gdb_test_multiple "maint info line-table $srcfile$" $test {
-    -re -wrap "END *0x0*1 *Y \r\n.*" {
+    -re -wrap "END *0x0*1 *Y *\r\n.*" {
 	fail $gdb_test_name
     }
-    -re -wrap "END *$hex *Y " {
+    -re -wrap "END *$hex *Y *" {
 	pass $gdb_test_name
     }
 }
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index 4a9634e..39a1ce7 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 a854d4d..1409971 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -449,6 +449,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