[rfc] btrace: change record instruction-history /m

Markus Metzger markus.t.metzger@intel.com
Fri Aug 14 11:37:00 GMT 2015


The /m modifier interleaves source lines with the disassembly of recorded
instructions.  This calls disasm.c's do_mixed_source_and_assembly once for
each recorded instruction to be printed.

The latter really does a source print with intermixed disassembly.  To that
purpose, it may reorder instructions to better match the source.  This is
nice for disassembling an entire function, but it doesn't work for printing
a single instruction.

Change record instruction-history /m to use its own simple source interleaving
algorithm.  The most important part is that instructions are printed in
the order in which they were executed.  Before each instruction, we print
a range of source lines that are attributed to the instruction's PC.  If the
source line range has already been printed (or skipped) for the previous
instruction, we skip it.

The algorithm would fill in the missing lines if a PC is attributed to more
than one source line.  I have not seen this.  There always seems to be at
most one source line per PC.

I don't think that there is an MI consumer of "record instruction-history"
and I have no idea if and how this might affect MI.

Alternatively, we could extend Doug Evan's new algorithm
https://sourceware.org/ml/gdb-patches/2015-08/msg00335.html to take a vector
of PCs.

2015-08-14  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (struct btrace_line_range): New.
	(btrace_mk_line_range, btrace_line_range_add)
	(btrace_line_range_is_empty, btrace_line_range_contains_range)
	(btrace_find_line_range, btrace_print_lines): New.
	(btrace_insn_history): Add source interleaving algorithm.
---
 gdb/record-btrace.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 152 insertions(+), 2 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 2f43171..df03e50 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -530,6 +530,137 @@ ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
   ui_out_field_fmt (uiout, fld, "%u", val);
 }
 
+/* A range of source lines.  */
+
+struct btrace_line_range
+{
+  /* The symtab this line is from.  */
+  struct symtab *symtab;
+
+  /* The first line (inclusive).  */
+  int begin;
+
+  /* The last line (exclusive).  */
+  int end;
+};
+
+/* Construct a line range.  */
+
+static struct btrace_line_range
+btrace_mk_line_range (struct symtab *symtab, int begin, int end)
+{
+  struct btrace_line_range range;
+
+  range.symtab = symtab;
+  range.begin = begin;
+  range.end = end;
+
+  return range;
+}
+
+/* Add a line to a line range.  */
+
+static struct btrace_line_range
+btrace_line_range_add (struct btrace_line_range range, int line)
+{
+  if (range.end <= range.begin)
+    {
+      /* This is the first entry.  */
+      range.begin = line;
+      range.end = line + 1;
+    }
+  else if (line < range.begin)
+    range.begin = line;
+  else if (range.end < line)
+    range.end = line;
+
+  return range;
+}
+
+/* Return non-zero if RANGE is empty, zero otherwise.  */
+
+static int
+btrace_line_range_is_empty (struct btrace_line_range range)
+{
+  return (range.end <= range.begin);
+}
+
+/* Return non-zero if LHS contains RHS, zero otherwise.  */
+
+static int
+btrace_line_range_contains_range (struct btrace_line_range lhs,
+				  struct btrace_line_range rhs)
+{
+  return ((lhs.symtab == rhs.symtab)
+	  && (lhs.begin <= rhs.begin)
+	  && (rhs.end <= lhs.end));
+}
+
+/* Find the lange range associated with PC.  */
+
+static struct btrace_line_range
+btrace_find_line_range (CORE_ADDR pc)
+{
+  struct btrace_line_range range;
+  struct linetable_entry *lines;
+  struct linetable *ltable;
+  struct symtab *symtab;
+  int nlines, i;
+
+  symtab = find_pc_line_symtab (pc);
+  if (symtab == NULL)
+    return btrace_mk_line_range (NULL, 0, 0);
+
+  ltable = SYMTAB_LINETABLE (symtab);
+  if (ltable == NULL)
+    return btrace_mk_line_range (symtab, 0, 0);
+
+  nlines = ltable->nitems;
+  lines = ltable->item;
+  if (nlines <= 0)
+    return btrace_mk_line_range (symtab, 0, 0);
+
+  range = btrace_mk_line_range (symtab, 0, 0);
+  for (i = 0; i < nlines - 1; i++)
+    {
+      if ((lines[i].pc == pc) && (lines[i].line != 0))
+	range = btrace_line_range_add (range, lines[i].line);
+    }
+
+  return range;
+}
+
+/* Print source lines in LINES.  */
+
+static void
+btrace_print_lines (struct btrace_line_range lines, struct ui_out *uiout,
+		    int flags)
+{
+  enum print_source_lines_flags psl_flags;
+  int line;
+
+  psl_flags = 0;
+  if (flags & DISASSEMBLY_FILENAME)
+    psl_flags |= PRINT_SOURCE_LINES_FILENAME;
+
+  for (line = lines.begin; line < lines.end; ++line)
+    {
+      struct cleanup *ui_out_list_chain_line;
+      struct cleanup *ui_out_tuple_chain_line;
+
+      ui_out_tuple_chain_line
+	= make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
+
+      print_source_lines (lines.symtab, line, line + 1, psl_flags);
+
+      ui_out_list_chain_line
+	= make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
+
+      do_cleanups (ui_out_list_chain_line);
+      do_cleanups (ui_out_tuple_chain_line);
+    }
+}
+
 /* Disassemble a section of the recorded instruction trace.  */
 
 static void
@@ -540,11 +671,17 @@ btrace_insn_history (struct ui_out *uiout,
 {
   struct gdbarch *gdbarch;
   struct btrace_insn_iterator it;
+  struct btrace_line_range last_lines;
+  int disas_flags;
 
   DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
 	 btrace_insn_number (end));
 
   gdbarch = target_gdbarch ();
+  disas_flags = ((flags
+		  & ~(DISASSEMBLY_SOURCE | DISASSEMBLY_FILENAME))
+		 | DISASSEMBLY_OMIT_PC);
+  last_lines = btrace_mk_line_range (NULL, 0, 0);
 
   for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
     {
@@ -569,6 +706,19 @@ btrace_insn_history (struct ui_out *uiout,
 	{
 	  char prefix[4];
 
+	  if ((flags & DISASSEMBLY_SOURCE) != 0)
+	    {
+	      struct btrace_line_range lines;
+
+	      lines = btrace_find_line_range (insn->pc);
+	      if (!btrace_line_range_is_empty (lines)
+		  && !btrace_line_range_contains_range (last_lines, lines))
+		{
+		  btrace_print_lines (lines, uiout, flags);
+		  last_lines = lines;
+		}
+	    }
+
 	  /* We may add a speculation prefix later.  We use the same space
 	     that is used for the pc prefix.  */
 	  if ((flags & DISASSEMBLY_OMIT_PC) == 0)
@@ -594,8 +744,8 @@ btrace_insn_history (struct ui_out *uiout,
 
 	  /* Disassembly with '/m' flag may not produce the expected result.
 	     See PR gdb/11833.  */
-	  gdb_disassembly (gdbarch, uiout, NULL, flags | DISASSEMBLY_OMIT_PC,
-			   1, insn->pc, insn->pc + 1);
+	  gdb_disassembly (gdbarch, uiout, NULL, disas_flags, 1, insn->pc,
+			   insn->pc + 1);
 	}
     }
 }
-- 
1.8.3.1



More information about the Gdb-patches mailing list