[PATCH] gdb: Don't hard code 0 as end marker in GDB's line table

Andrew Burgess andrew.burgess@embecosm.com
Mon Jul 20 12:55:05 GMT 2020


Currently GDB hard-codes the use of 0 as the end of sequence marker in
its line tables.  After this commit GDB now uses a named
constant (linetable_entry::end_marker) as the end of sequence marker.
The value of this constant is -1, not 0.  This change was made in
order to aid fixing bug PR gdb/26243.

Bug PR gdb/26243 is about allowing line number 0 to be used to
indicate a program address that has no corresponding source line (this
use is specified in the DWARF standard).  Currently GDB can't use line
number 0 as this line number is hard coded as the end of sequence
marker, but, after this commit line number 0 no longer has any special
meaning.

This commit does not fix PR gdb/26243, but it is step towards allowing
that issue to be fixed.

gdb/ChangeLog:

	PR gdb/26243
	* buildsym.c (buildsym_compunit::record_line): Add an assert for
	the incoming line number.  Update comments to not mention 0
	specifically.  Update to check for linetable_entry::end_marker
	rather than 0.
	* disasm.c (do_mixed_source_and_assembly_deprecated): Check for
	linetable_entry::end_marker not 0.
	(do_mixed_source_and_assembly): Likewise.
	* dwarf2/read.c (dwarf_finish_line): Pass
	linetable_entry::end_marker not 0.
	* mdebugread.c (add_line): Set is_stmt field.
	* python/py-linetable.c (ltpy_get_all_source_lines): Check for
	linetable_entry::end_marker not 0, update comments.
	(ltpy_iternext): Likewise.
	* record-btrace.c (btrace_find_line_range): Likewise.
	* symmisc.c (maintenance_print_one_line_table): Likewise.
	* symtab.c (find_pc_sect_line): Likewise.
	(find_line_symtab): Likewise.
	(skip_prologue_using_sal): Likewise.
	* symtab.h (linetable_entry::end_marker): New const static member
	variable.  Add a static assert for this field.
	* xcoffread.c (arrange_linetable): Check for
	linetable_entry::end_marker not 0.
---
 gdb/ChangeLog             | 26 ++++++++++++++++++++++++++
 gdb/buildsym.c            | 36 ++++++++++++++++++++----------------
 gdb/disasm.c              |  9 +++++----
 gdb/dwarf2/read.c         |  3 ++-
 gdb/mdebugread.c          |  1 +
 gdb/python/py-linetable.c | 13 +++++++------
 gdb/record-btrace.c       |  3 ++-
 gdb/symmisc.c             |  2 +-
 gdb/symtab.c              | 22 +++++++++++++---------
 gdb/symtab.h              | 12 ++++++++++++
 gdb/xcoffread.c           | 11 +++++++----
 11 files changed, 96 insertions(+), 42 deletions(-)

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index bd0ca491401..e6d4dc117c1 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -671,6 +671,10 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
 {
   struct linetable_entry *e;
 
+  /* Is this an asset?  Or is this processing user input and so should we
+     be handling, or throwing an error for invalid data?  */
+  gdb_assert (line == linetable_entry::end_marker || line >= 0);
+
   /* Make sure line vector exists and is big enough.  */
   if (!subfile->line_vector)
     {
@@ -692,20 +696,19 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
 		      * 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.  */
-  if (line == 0)
+  /* 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 ==
+     linetable_entry::end_marker) 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.  */
+  if (line == linetable_entry::end_marker)
     {
       while (subfile->line_vector->nitems > 0)
 	{
@@ -944,8 +947,9 @@ buildsym_compunit::end_symtab_with_blockvector (struct block *static_block,
 		  const linetable_entry &ln2) -> bool
 	      {
 		if (ln1.pc == ln2.pc
-		    && ((ln1.line == 0) != (ln2.line == 0)))
-		  return ln1.line == 0;
+		    && ((ln1.line == linetable_entry::end_marker)
+			!= (ln2.line == linetable_entry::end_marker)))
+		  return ln1.line == linetable_entry::end_marker;
 
 		return (ln1.pc < ln2.pc);
 	      };
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 143ba2f59b9..4b7cc88fbfb 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -383,7 +383,7 @@ do_mixed_source_and_assembly_deprecated
 	continue;
 
       /* Skip any end-of-function markers.  */
-      if (le[i].line == 0)
+      if (le[i].line == linetable_entry::end_marker)
 	continue;
 
       mle[newlines].line = le[i].line;
@@ -571,7 +571,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
   gdb::optional<ui_out_emit_list> list_emitter;
 
   last_symtab = NULL;
-  last_line = 0;
+  last_line = linetable_entry::end_marker;
   pc = low;
 
   while (pc < high)
@@ -591,7 +591,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
 
 	  /* If this is the first line of output, check for any preceding
 	     lines.  */
-	  if (last_line == 0
+	  if (last_line == linetable_entry::end_marker
 	      && first_le != NULL
 	      && first_le->line < sal.line)
 	    {
@@ -604,7 +604,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
 	  /* Same source file as last time.  */
 	  if (sal.symtab != NULL)
 	    {
-	      if (sal.line > last_line + 1 && last_line != 0)
+	      if (last_line != linetable_entry::end_marker
+		  && sal.line > last_line + 1)
 		{
 		  int l;
 
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 39ed455def5..bdbecf640ff 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -20390,7 +20390,8 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
 			  paddress (gdbarch, address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu);
+  dwarf_record_line_1 (gdbarch, subfile, linetable_entry::end_marker,
+		       address, true, cu);
 }
 
 void
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index d38372041d7..01029fbd971 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -4516,6 +4516,7 @@ add_line (struct linetable *lt, int lineno, CORE_ADDR adr, int last)
     return lineno;
 
   lt->item[lt->nitems].line = lineno;
+  lt->item[lt->nitems].is_stmt = 1;
   lt->item[lt->nitems++].pc = adr << 2;
   return lineno;
 }
diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
index 858313bb22d..22a44fe5f36 100644
--- a/gdb/python/py-linetable.c
+++ b/gdb/python/py-linetable.c
@@ -238,10 +238,11 @@ ltpy_get_all_source_lines (PyObject *self, PyObject *args)
     {
       item = &(SYMTAB_LINETABLE (symtab)->item[index]);
 
-      /* 0 is used to signify end of line table information.  Do not
-	 include in the source set. */
-      if (item->line > 0)
+      /* The special value linetable_entry::end_marker is used to signify
+	 end of line table information.  Do not include in the source set.  */
+      if (item->line != linetable_entry::end_marker)
 	{
+	  gdb_assert (item->line >= 0);
 	  gdbpy_ref<> line = gdb_py_object_from_longest (item->line);
 
 	  if (line == NULL)
@@ -407,9 +408,9 @@ ltpy_iternext (PyObject *self)
 
   item = &(SYMTAB_LINETABLE (symtab)->item[iter_obj->current_index]);
 
-  /* Skip over internal entries such as 0.  0 signifies the end of
-     line table data and is not useful to the API user.  */
-  while (item->line < 1)
+  /* Skip over internal entries such as the end of sequence marker,
+     linetable_entry::end_marker as this is not useful to the API user.  */
+  while (item->line == linetable_entry::end_marker)
     {
       iter_obj->current_index++;
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 718de62f280..36ae671fa90 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -732,7 +732,8 @@ btrace_find_line_range (CORE_ADDR pc)
 	 possibly adding more line numbers to the range.  At the time this
 	 change was made I was unsure how to test this so chose to go with
 	 maintaining the existing experience.  */
-      if ((lines[i].pc == pc) && (lines[i].line != 0)
+      if ((lines[i].pc == pc)
+	  && (lines[i].line != linetable_entry::end_marker)
 	  && (lines[i].is_stmt == 1))
 	range = btrace_line_range_add (range, lines[i].line);
     }
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index fc56cfa9381..9b05ca2f4da 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -1036,7 +1036,7 @@ maintenance_print_one_line_table (struct symtab *symtab, void *data)
 	  item = &linetable->item [i];
 	  ui_out_emit_tuple tuple_emitter (uiout, nullptr);
 	  uiout->field_signed ("index", i);
-	  if (item->line > 0)
+	  if (item->line != linetable_entry::end_marker)
 	    uiout->field_signed ("line", item->line);
 	  else
 	    uiout->field_string ("line", _("END"));
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f96ad9554d9..02a08481008 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3248,7 +3248,8 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
          save prev if it represents the end of a function (i.e. line number
          0) instead of a real line.  */
 
-      if (prev && prev->line && (!best || prev->pc > best->pc))
+      if (prev && prev->line != linetable_entry::end_marker
+	  && (!best || prev->pc > best->pc))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
@@ -3264,7 +3265,8 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 	    {
 	      struct linetable_entry *tmp = best;
 	      while (tmp > first && (tmp - 1)->pc == tmp->pc
-		     && (tmp - 1)->line != 0 && !tmp->is_stmt)
+		     && (tmp - 1)->line != linetable_entry::end_marker
+		     && !tmp->is_stmt)
 		--tmp;
 	      if (tmp->is_stmt)
 		best = tmp;
@@ -3291,7 +3293,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 	 don't make some up.  */
       val.pc = pc;
     }
-  else if (best->line == 0)
+  else if (best->line == linetable_entry::end_marker)
     {
       /* 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
@@ -3378,14 +3380,14 @@ find_line_symtab (struct symtab *sym_tab, int line,
          the GLOBAL_BLOCK of a symtab has a begin and end address).  */
 
       /* BEST is the smallest linenumber > LINE so far seen,
-         or 0 if none has been seen so far.
+         or the end marker if none has been seen so far.
          BEST_INDEX and BEST_LINETABLE identify the item for it.  */
       int best;
 
       if (best_index >= 0)
 	best = best_linetable->item[best_index].line;
       else
-	best = 0;
+	best = linetable_entry::end_marker;
 
       for (objfile *objfile : current_program_space->objfiles ())
 	{
@@ -3419,7 +3421,8 @@ find_line_symtab (struct symtab *sym_tab, int line,
 			  best_symtab = s;
 			  goto done;
 			}
-		      if (best == 0 || l->item[ind].line < best)
+		      if (best == linetable_entry::end_marker
+			  || l->item[ind].line < best)
 			{
 			  best = l->item[ind].line;
 			  best_index = ind;
@@ -3718,7 +3721,8 @@ skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab)
       /* Don't use line numbers of zero, they mark special entries in
 	 the table.  See the commentary on symtab.h before the
 	 definition of struct linetable.  */
-      if (item->line > 0 && func_start <= item->pc && item->pc < func_end)
+      if (item->line != linetable_entry::end_marker
+	  && func_start <= item->pc && item->pc < func_end)
 	return item->pc;
     }
 
@@ -3946,11 +3950,11 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
 	  /* Skip any earlier lines, and any end-of-sequence marker
 	     from a previous function.  */
 	  while (linetable->item[idx].pc != prologue_sal.pc
-		 || linetable->item[idx].line == 0)
+		 || linetable->item[idx].line == linetable_entry::end_marker)
 	    idx++;
 
 	  if (idx+1 < linetable->nitems
-	      && linetable->item[idx+1].line != 0
+	      && linetable->item[idx+1].line != linetable_entry::end_marker
 	      && linetable->item[idx+1].pc == start_pc)
 	    return start_pc;
 	}
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 0b186554ea1..83d60d8d64b 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1306,6 +1306,11 @@ struct rust_vtable_symbol : public symbol
 
 struct linetable_entry
 {
+  /* Special value placed into the LINE field to indicate an end of
+     sequence in the line table.  */
+
+  static const int end_marker = -1;
+
   /* The line number for this entry.  */
   int line;
 
@@ -1316,6 +1321,13 @@ struct linetable_entry
   CORE_ADDR pc;
 };
 
+/* Normally line numbers in a program are positive integers greater than
+   zero.  The line number 0 is reserved in DWARF to indicate instructions
+   that don't have associated source code.  The end marker then must be
+   less than zero.  */
+
+gdb_static_assert (linetable_entry::end_marker < 0);
+
 /* The order of entries in the linetable is significant.  They should
    be sorted by increasing values of the pc field.  If there is more than
    one entry for a given pc, then I'm not sure what should happen (and
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index a792c0fea2e..4c99c2da3ef 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -435,7 +435,7 @@ arrange_linetable (struct linetable *oldLineTb)
       if (oldLineTb->item[ii].is_stmt == 0)
 	continue;
 
-      if (oldLineTb->item[ii].line == 0)
+      if (oldLineTb->item[ii].line == linetable_entry::end_marker)
 	{			/* Function entry found.  */
 	  if (function_count >= fentry_size)
 	    {			/* Make sure you have room.  */
@@ -477,9 +477,11 @@ arrange_linetable (struct linetable *oldLineTb)
      a function begin.  */
 
   newline = 0;
-  if (oldLineTb->item[0].line != 0)
+  if (oldLineTb->item[0].line != linetable_entry::end_marker)
     for (newline = 0;
-    newline < oldLineTb->nitems && oldLineTb->item[newline].line; ++newline)
+	 newline < oldLineTb->nitems
+	   && oldLineTb->item[newline].line != linetable_entry::end_marker;
+	 ++newline)
       newLineTb->item[newline] = oldLineTb->item[newline];
 
   /* Now copy function lines one by one.  */
@@ -498,7 +500,8 @@ arrange_linetable (struct linetable *oldLineTb)
 	}
 
       for (jj = fentry[ii].line + 1;
-	   jj < oldLineTb->nitems && oldLineTb->item[jj].line != 0;
+	   jj < oldLineTb->nitems
+	     && oldLineTb->item[jj].line != linetable_entry::end_marker;
 	   ++jj, ++newline)
 	newLineTb->item[newline] = oldLineTb->item[jj];
     }
-- 
2.25.4



More information about the Gdb-patches mailing list