diff mbox

Rewrite mixed source/assembler disassembly

Message ID m3h9oz1k4m.fsf@seba.sebabeach.org
State New
Headers show

Commit Message

Doug Evans July 20, 2015, 5:19 a.m. UTC
Hi.

This is a patch I've wanted to write for a very long time.
The current mixed source/assembler disassembly is not very usable.
In the presence of multiple source files (inlined functions, etc.)
it doesn't print usable output.
In the presence of optimized code, trying to be source centric
just doesn't work IMO. And with no optimization the before/after
should be identical.

One change I've made here is that I'm printing the source file
in the output.  This is critical when displaying inlined functions
from another source file.  If there's only one source file it's
more a matter of taste. To keep things simple, this patch displays
the source file name even if there's only one file.

The other change I've made is to remove the blank line between
assembly and the next source line. I'm ambivalent, what do you think?

E.g.,

(gdb) disas /m main
Dump of assembler code for function main:
hello.c: <<<--- this is new
5       {
   0x08048330 <+0>:    push   %ebp
   0x08048331 <+1>:    mov    %esp,%ebp
   0x08048333 <+3>:    sub    $0x8,%esp
   0x08048336 <+6>:    and    $0xfffffff0,%esp
   0x08048339 <+9>:    sub    $0x10,%esp
6         printf ("Hello.\n");
=> 0x0804833c <+12>:   movl   $0x8048440,(%esp)
   0x08048343 <+19>:   call   0x8048284 <puts@@plt>
7         return 0;
   0x08048348 <+24>:   mov    $0x0,%eax
8       }
   0x0804834d <+29>:   leave
   0x0804834e <+30>:   ret

I still need to test this with an MI frontend.

2015-07-19  Doug Evans  <xdje42@gmail.com>

	* NEWS: Document change is mixed source/assembly output.
	* disasm.c: #include "source.h".
	(dis_line_entry) <symtab>: New member.
	(dis_line_entry) <start_pc, end_pc>: Delete members.
	(hash_dis_line_entry, eq_dis_line_entry): New functions.
	(allocate_dis_line_table): New functions.
	(maybe_add_dis_line_entry, line_has_code_p): New functions.
	(compare_lines): Delete.
	(dump_insns): New arg end_pc.  All callers updated.
	(do_mixed_source_and_assembly): Rewrite.  Delete arg nlines, le.
	Rename arg symtab to main_symtab.  All callers updated.

	doc/
	* gdb.texinfo (Machine Code): Update docs for mixed source/assembly
	disassembly.

	testsuite/
	* gdb.mi/basics.c (main): Add comment.
	* gdb.mi/mi-cli.exp: Update.
	* gdb.mi/mi-disassemble.exp: Update.

Comments

Doug Evans July 20, 2015, 5:38 a.m. UTC | #1
On Sun, Jul 19, 2015 at 10:19 PM, Doug Evans <xdje42@gmail.com> wrote:
> Hi.
>
> This is a patch I've wanted to write for a very long time.
> The current mixed source/assembler disassembly is not very usable.
> In the presence of multiple source files (inlined functions, etc.)
> it doesn't print usable output.
> In the presence of optimized code, trying to be source centric
> just doesn't work IMO. And with no optimization the before/after
> should be identical.
>
> One change I've made here is that I'm printing the source file
> in the output.  This is critical when displaying inlined functions
> from another source file.  If there's only one source file it's
> more a matter of taste. To keep things simple, this patch displays
> the source file name even if there's only one file.
>
> The other change I've made is to remove the blank line between
> assembly and the next source line. I'm ambivalent, what do you think?
>
> E.g.,
>
> (gdb) disas /m main
> Dump of assembler code for function main:
> hello.c: <<<--- this is new
> 5       {
>    0x08048330 <+0>:    push   %ebp
>    0x08048331 <+1>:    mov    %esp,%ebp
>    0x08048333 <+3>:    sub    $0x8,%esp
>    0x08048336 <+6>:    and    $0xfffffff0,%esp
>    0x08048339 <+9>:    sub    $0x10,%esp
> 6         printf ("Hello.\n");
> => 0x0804833c <+12>:   movl   $0x8048440,(%esp)
>    0x08048343 <+19>:   call   0x8048284 <puts@@plt>
> 7         return 0;
>    0x08048348 <+24>:   mov    $0x0,%eax
> 8       }
>    0x0804834d <+29>:   leave
>    0x0804834e <+30>:   ret
>
> I still need to test this with an MI frontend.
>
> 2015-07-19  Doug Evans  <xdje42@gmail.com>
>
>         * NEWS: Document change is mixed source/assembly output.
>         * disasm.c: #include "source.h".
>         (dis_line_entry) <symtab>: New member.
>         (dis_line_entry) <start_pc, end_pc>: Delete members.
>         (hash_dis_line_entry, eq_dis_line_entry): New functions.
>         (allocate_dis_line_table): New functions.
>         (maybe_add_dis_line_entry, line_has_code_p): New functions.
>         (compare_lines): Delete.
>         (dump_insns): New arg end_pc.  All callers updated.
>         (do_mixed_source_and_assembly): Rewrite.  Delete arg nlines, le.
>         Rename arg symtab to main_symtab.  All callers updated.
>
>         doc/
>         * gdb.texinfo (Machine Code): Update docs for mixed source/assembly
>         disassembly.
>
>         testsuite/
>         * gdb.mi/basics.c (main): Add comment.
>         * gdb.mi/mi-cli.exp: Update.
>         * gdb.mi/mi-disassemble.exp: Update.

Hmmm, looks like I need to do a bit of testing with TUI too.

TUI doesn't have a mixed source+assembly in one window AFAICT.
That would be cool, but that's a separate project.
For now I'm just going to make sure things work at least
as well as before (I'm seeing some problems I need to investigate).
Joel Brobecker July 21, 2015, 5:20 p.m. UTC | #2
> This is a patch I've wanted to write for a very long time.
> The current mixed source/assembler disassembly is not very usable.
> In the presence of multiple source files (inlined functions, etc.)
> it doesn't print usable output.
> In the presence of optimized code, trying to be source centric
> just doesn't work IMO. And with no optimization the before/after
> should be identical.

FWIW, I agree this is a more useful output.

> The other change I've made is to remove the blank line between
> assembly and the next source line. I'm ambivalent, what do you think?

Not sure either say, so going with your call on that one...

Thanks for doing this!
diff mbox

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 7ce9758..3222375 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -5,6 +5,10 @@ 
 
 * Support for tracepoints on aarch64-linux was added in GDBserver.
 
+* Mixed source disassembly output has been changed.
+  Disassembled instructions are now printed in program order,
+  and source for all relevant files are now printed.
+
 *** Changes in GDB 7.10
 
 * Support for process record-replay and reverse debugging on aarch64*-linux*
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 483df01..1a6ae28 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -24,6 +24,7 @@ 
 #include "disasm.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
+#include "source.h"
 
 /* Disassemble functions.
    FIXME: We should get rid of all the duplicate code in gdb that does
@@ -36,11 +37,75 @@ 
 
 struct dis_line_entry
 {
+  struct symtab *symtab;
   int line;
-  CORE_ADDR start_pc;
-  CORE_ADDR end_pc;
 };
 
+/* Hash function for dis_line_entry.  */
+
+static hashval_t
+hash_dis_line_entry (const void *item)
+{
+  const struct dis_line_entry *dle = item;
+
+  return htab_hash_pointer (dle->symtab) + dle->line;
+}
+
+/* Equal function for dis_line_entry.  */
+
+static int
+eq_dis_line_entry (const void *item_lhs, const void *item_rhs)
+{
+  const struct dis_line_entry *lhs = item_lhs;
+  const struct dis_line_entry *rhs = item_rhs;
+
+  return (lhs->symtab == rhs->symtab
+	  && lhs->line == rhs->line);
+}
+
+/* Create the table to manage lines for mixed source/disassembly.  */
+
+static htab_t
+allocate_dis_line_table (void)
+{
+  return htab_create_alloc (41,
+			    hash_dis_line_entry, eq_dis_line_entry,
+			    xfree, xcalloc, xfree);
+}
+
+/* Add DLE to TABLE.
+   Returns 1 if added, 0 if already present.  */
+
+static void
+maybe_add_dis_line_entry (htab_t table, struct symtab *symtab, int line)
+{
+  void **slot;
+  struct dis_line_entry dle, *dlep;
+
+  dle.symtab = symtab;
+  dle.line = line;
+  slot = htab_find_slot (table, &dle, INSERT);
+  if (*slot == NULL)
+    {
+      dlep = XNEW (struct dis_line_entry);
+      dlep->symtab = symtab;
+      dlep->line = line;
+      *slot = dlep;
+    }
+}
+
+/* Return non-zero if SYMTAB, LINE are in TABLE.  */
+
+static int
+line_has_code_p (htab_t table, struct symtab *symtab, int line)
+{
+  struct dis_line_entry dle;
+
+  dle.symtab = symtab;
+  dle.line = line;
+  return htab_find (table, &dle) != NULL;
+}
+
 /* Like target_read_memory, but slightly different parameters.  */
 static int
 dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
@@ -67,36 +132,11 @@  dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
 }
 
 static int
-compare_lines (const void *mle1p, const void *mle2p)
-{
-  struct dis_line_entry *mle1, *mle2;
-  int val;
-
-  mle1 = (struct dis_line_entry *) mle1p;
-  mle2 = (struct dis_line_entry *) mle2p;
-
-  /* End of sequence markers have a line number of 0 but don't want to
-     be sorted to the head of the list, instead sort by PC.  */
-  if (mle1->line == 0 || mle2->line == 0)
-    {
-      val = mle1->start_pc - mle2->start_pc;
-      if (val == 0)
-        val = mle1->line - mle2->line;
-    }
-  else
-    {
-      val = mle1->line - mle2->line;
-      if (val == 0)
-        val = mle1->start_pc - mle2->start_pc;
-    }
-  return val;
-}
-
-static int
 dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 	    struct disassemble_info * di,
 	    CORE_ADDR low, CORE_ADDR high,
-	    int how_many, int flags, struct ui_file *stb)
+	    int how_many, int flags, struct ui_file *stb,
+	    CORE_ADDR *end_pc)
 {
   int num_displayed = 0;
   CORE_ADDR pc;
@@ -182,6 +222,9 @@  dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
       do_cleanups (ui_out_chain);
       ui_out_text (uiout, "\n");
     }
+
+  if (end_pc != NULL)
+    *end_pc = pc;
   return num_displayed;
 }
 
@@ -192,10 +235,9 @@  dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 
 static void
 do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
-			      struct disassemble_info *di, int nlines,
-			      struct linetable_entry *le,
+			      struct disassemble_info *di,
+			      struct symtab *main_symtab,
 			      CORE_ADDR low, CORE_ADDR high,
-			      struct symtab *symtab,
 			      int how_many, int flags, struct ui_file *stb)
 {
   int newlines = 0;
@@ -206,143 +248,169 @@  do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
   int next_line = 0;
   int num_displayed = 0;
   enum print_source_lines_flags psl_flags = 0;
+  struct cleanup *cleanups;
   struct cleanup *ui_out_chain;
-  struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
-  struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
-
-  if (flags & DISASSEMBLY_FILENAME)
-    psl_flags |= PRINT_SOURCE_LINES_FILENAME;
-
-  mle = (struct dis_line_entry *) alloca (nlines
-					  * sizeof (struct dis_line_entry));
+  struct cleanup *ui_out_tuple_chain;
+  struct cleanup *ui_out_list_chain;
+  CORE_ADDR pc;
+  struct symtab *last_symtab;
+  int last_line;
+  htab_t dis_line_table;
 
-  /* Copy linetable entries for this function into our data
-     structure, creating end_pc's and setting out_of_order as
-     appropriate.  */
+  gdb_assert (main_symtab != NULL && SYMTAB_LINETABLE (main_symtab) != NULL);
 
-  /* First, skip all the preceding functions.  */
+  /* First pass is to collect the list of all source files and lines.
+     We do this so that we can only print lines containing code once.
+     We try to print the source text leading up to the next instruction,
+     but if that text is for code that will be disassembled later, then
+     we'll want to defer printing it until later where it's used.  */
 
-  for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
+  dis_line_table = allocate_dis_line_table ();
+  cleanups = make_cleanup_htab_delete (dis_line_table);
 
-  /* Now, copy all entries before the end of this function.  */
+  pc = low;
 
-  for (; i < nlines - 1 && le[i].pc < high; i++)
+  while (pc < high)
     {
-      if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
-	continue;		/* Ignore duplicates.  */
-
-      /* Skip any end-of-function markers.  */
-      if (le[i].line == 0)
-	continue;
-
-      mle[newlines].line = le[i].line;
-      if (le[i].line > le[i + 1].line)
-	out_of_order = 1;
-      mle[newlines].start_pc = le[i].pc;
-      mle[newlines].end_pc = le[i + 1].pc;
-      newlines++;
-    }
+      struct symtab_and_line sal;
+      int length;
 
-  /* If we're on the last line, and it's part of the function,
-     then we need to get the end pc in a special way.  */
+      sal = find_pc_line (pc, 0);
+      length = gdb_insn_length (gdbarch, pc);
+      pc += length;
 
-  if (i == nlines - 1 && le[i].pc < high)
-    {
-      mle[newlines].line = le[i].line;
-      mle[newlines].start_pc = le[i].pc;
-      sal = find_pc_line (le[i].pc, 0);
-      mle[newlines].end_pc = sal.end;
-      newlines++;
+      if (sal.symtab != NULL)
+	maybe_add_dis_line_entry (dis_line_table, sal.symtab, sal.line);
     }
 
-  /* Now, sort mle by line #s (and, then by addresses within
-     lines).  */
-
-  if (out_of_order)
-    qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
+  /* Second pass prints the disassembly.  */
 
-  /* Now, for each line entry, emit the specified lines (unless
-     they have been emitted before), followed by the assembly code
-     for that line.  */
+  if (flags & DISASSEMBLY_FILENAME)
+    psl_flags |= PRINT_SOURCE_LINES_FILENAME;
 
+  ui_out_text (uiout, symtab_to_filename_for_display (main_symtab));
+  ui_out_text (uiout, ":\n");
   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
 
-  for (i = 0; i < newlines; i++)
+  ui_out_tuple_chain = make_cleanup (null_cleanup, NULL);
+  ui_out_list_chain = make_cleanup (null_cleanup, NULL);
+
+  last_symtab = main_symtab;
+  last_line = 0;
+  pc = low;
+
+  while (pc < high)
     {
-      /* Print out everything from next_line to the current line.  */
-      if (mle[i].line >= next_line)
+      struct linetable_entry *le = NULL;
+      struct symtab_and_line sal;
+      CORE_ADDR end_pc;
+      int start_preceding_line_to_display = 0;
+      int end_preceding_line_to_display = 0;
+      int new_line = 0;
+
+      sal = find_pc_line (pc, 0);
+
+      if (sal.symtab != last_symtab)
 	{
-	  if (next_line != 0)
+	  /* New source file.  */
+	  do_cleanups (ui_out_chain);
+	  ui_out_text (uiout, symtab_to_filename_for_display (sal.symtab));
+	  ui_out_text (uiout, ":\n");
+	  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout,
+							     "asm_insns");
+	  new_line = 1;
+	}
+      else
+	{
+	  /* Same source file as last time.  */
+	  if (sal.symtab != NULL)
 	    {
-	      /* Just one line to print.  */
-	      if (next_line == mle[i].line)
+	      if (sal.line > last_line + 1 && last_line != 0)
 		{
-		  ui_out_tuple_chain
-		    = make_cleanup_ui_out_tuple_begin_end (uiout,
-							   "src_and_asm_line");
-		  print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
+		  int l;
+
+		  /* Several preceding source lines.  Print the trailing ones
+		     not associated with code that we'll print later.  */
+		  for (l = sal.line - 1; l > last_line; --l)
+		    {
+		      if (line_has_code_p (dis_line_table, sal.symtab, l))
+			break;
+		    }
+		  if (l < sal.line - 1)
+		    {
+		      start_preceding_line_to_display = l + 1;
+		      end_preceding_line_to_display = sal.line;
+		    }
 		}
+	      if (sal.line != last_line)
+		new_line = 1;
 	      else
 		{
-		  /* Several source lines w/o asm instructions associated.  */
-		  for (; next_line < mle[i].line; next_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 (symtab, next_line, next_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);
-		    }
-		  /* Print the last line and leave list open for
-		     asm instructions to be added.  */
-		  ui_out_tuple_chain
+		  /* Same source line as last time.  This can happen, depending
+		     on the debug info.  */
+		}
+	    }
+	}
+
+      if (new_line)
+	{
+	  if (sal.symtab == last_symtab)
+	    {
+	      do_cleanups (ui_out_list_chain);
+	      do_cleanups (ui_out_tuple_chain);
+	    }
+	  if (start_preceding_line_to_display > 0)
+	    {
+	      /* Several source lines w/o asm instructions associated.  */
+	      int l;
+	      struct cleanup *ui_out_list_chain_line;
+	      struct cleanup *ui_out_tuple_chain_line;
+
+	      gdb_assert (sal.symtab != NULL);
+	      for (l = start_preceding_line_to_display;
+		   l < end_preceding_line_to_display;
+		   ++l)
+		{
+		  ui_out_tuple_chain_line
 		    = make_cleanup_ui_out_tuple_begin_end (uiout,
 							   "src_and_asm_line");
-		  print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
+		  print_source_lines (sal.symtab, l, l + 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);
 		}
 	    }
+	  ui_out_tuple_chain
+	    = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
+	  if (sal.symtab != NULL)
+	    print_source_lines (sal.symtab, sal.line, sal.line + 1, psl_flags);
 	  else
-	    {
-	      ui_out_tuple_chain
-		= make_cleanup_ui_out_tuple_begin_end (uiout,
-						       "src_and_asm_line");
-	      print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags);
-	    }
-
-	  next_line = mle[i].line + 1;
+	    ui_out_text (uiout, _("--- no source info for this pc ---\n"));
 	  ui_out_list_chain
 	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
 	}
 
-      num_displayed += dump_insns (gdbarch, uiout, di,
-				   mle[i].start_pc, mle[i].end_pc,
-				   how_many, flags, stb);
+      if (sal.end != 0)
+	end_pc = min (sal.end, high);
+      else
+	end_pc = pc + 1;
+      num_displayed += dump_insns (gdbarch, uiout, di, pc, end_pc,
+				   how_many, flags, stb, &end_pc);
+      pc = end_pc;
 
-      /* When we've reached the end of the mle array, or we've seen the last
-         assembly range for this source line, close out the list/tuple.  */
-      if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
-	{
-	  do_cleanups (ui_out_list_chain);
-	  do_cleanups (ui_out_tuple_chain);
-	  ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
-	  ui_out_list_chain = make_cleanup (null_cleanup, 0);
-	  ui_out_text (uiout, "\n");
-	}
       if (how_many >= 0 && num_displayed >= how_many)
 	break;
+
+      last_symtab = sal.symtab;
+      last_line = sal.line;
     }
+
   do_cleanups (ui_out_chain);
+  do_cleanups (cleanups);
 }
 
-
 static void
 do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
 		  struct disassemble_info * di,
@@ -355,7 +423,7 @@  do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
 
   num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many,
-                              flags, stb);
+                              flags, stb, NULL);
 
   do_cleanups (ui_out_chain);
 }
@@ -411,26 +479,21 @@  gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
   struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
   struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
   struct symtab *symtab;
-  struct linetable_entry *le = NULL;
   int nlines = -1;
 
   /* Assume symtab is valid for whole PC range.  */
   symtab = find_pc_line_symtab (low);
 
   if (symtab != NULL && SYMTAB_LINETABLE (symtab) != NULL)
-    {
-      /* Convert the linetable to a bunch of my_line_entry's.  */
-      le = SYMTAB_LINETABLE (symtab)->item;
-      nlines = SYMTAB_LINETABLE (symtab)->nitems;
-    }
+    nlines = SYMTAB_LINETABLE (symtab)->nitems;
 
   if (!(flags & DISASSEMBLY_SOURCE) || nlines <= 0
       || symtab == NULL || SYMTAB_LINETABLE (symtab) == NULL)
     do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
 
   else if (flags & DISASSEMBLY_SOURCE)
-    do_mixed_source_and_assembly (gdbarch, uiout, &di, nlines, le, low,
-				  high, symtab, how_many, flags, stb);
+    do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
+				  how_many, flags, stb);
 
   do_cleanups (cleanups);
   gdb_flush (gdb_stdout);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9e2ecd1..8e6efb9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8082,20 +8082,19 @@  program is stopped just after function prologue:
 @smallexample
 (@value{GDBP}) disas /m main
 Dump of assembler code for function main:
+hello.c:
 5       @{
    0x08048330 <+0>:    push   %ebp
    0x08048331 <+1>:    mov    %esp,%ebp
    0x08048333 <+3>:    sub    $0x8,%esp
    0x08048336 <+6>:    and    $0xfffffff0,%esp
    0x08048339 <+9>:    sub    $0x10,%esp
-
 6         printf ("Hello.\n");
 => 0x0804833c <+12>:   movl   $0x8048440,(%esp)
    0x08048343 <+19>:   call   0x8048284 <puts@@plt>
-
 7         return 0;
-8       @}
    0x08048348 <+24>:   mov    $0x0,%eax
+8       @}
    0x0804834d <+29>:   leave
    0x0804834e <+30>:   ret
 
diff --git a/gdb/testsuite/gdb.mi/basics.c b/gdb/testsuite/gdb.mi/basics.c
index a7ce3e6..f5db825 100644
--- a/gdb/testsuite/gdb.mi/basics.c
+++ b/gdb/testsuite/gdb.mi/basics.c
@@ -59,7 +59,7 @@  void do_nothing (void)
 
 int main ()
 {
-  callee1 (2, "A string argument.", 3.5);
+  callee1 (2, "A string argument.", 3.5); /* callee1-1 */
   callee1 (2, "A string argument.", 3.5);
 
   do_nothing (); /* Hello, World! */
diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp
index 08c8f02..286d920 100644
--- a/gdb/testsuite/gdb.mi/mi-cli.exp
+++ b/gdb/testsuite/gdb.mi/mi-cli.exp
@@ -93,7 +93,7 @@  mi_gdb_test "-interpreter-exec console \"set listsize 1\"" \
 
 # {.*\~"32[ \t(\\t)]*callee1.*\\n".*\^done }
 mi_gdb_test "-interpreter-exec console \"list\"" \
-  ".*\~\"$line_main_body\[\\\\t \]*callee1.*;\\\\n\".*\\^done" \
+    ".*\~\"$line_main_body\[\\\\t \]*callee1.*; /\\* callee1-1 \\*/\\\\n\".*\\^done" \
   "-interpreter-exec console \"list\""
 
 mi_execute_to "exec-continue" "breakpoint-hit" "callee4" "" ".*basics.c" $line_callee4_body \
diff --git a/gdb/testsuite/gdb.mi/mi-disassemble.exp b/gdb/testsuite/gdb.mi/mi-disassemble.exp
index 4f5a352..7c9c8fd 100644
--- a/gdb/testsuite/gdb.mi/mi-disassemble.exp
+++ b/gdb/testsuite/gdb.mi/mi-disassemble.exp
@@ -116,6 +116,7 @@  proc test_disassembly_mixed {} {
     global decimal
     global fullname_syntax
 
+    set line_mixed_range        [gdb_get_line_number "callee1-1"]
     set line_callee2_head       [gdb_get_line_number "callee2 ("]
     set line_callee2_open_brace [expr $line_callee2_head + 1]
 
@@ -128,12 +129,14 @@  proc test_disassembly_mixed {} {
 	    "002\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$line_callee2_open_brace\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"callee2\",offset=\"0\",inst=\".*\"\}.*\\\]\}.*,src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[.*\{address=\"$hex\",func-name=\"callee2\",offset=\"$decimal\",inst=\".*\"\}\\\]\}\\\]" \
              "data-disassemble file, line assembly mixed"
 
-    #
-    # In mixed mode, the lowest level of granularity is the source line.
-    # So we are going to get the disassembly for the source line at
-    # which we are now, even if we have specified that the range is only 2 insns.
-    #
-    mi_gdb_test "003-data-disassemble -s \$pc -e \"\$pc+4\" -- 1" \
+    global expect_out
+    mi_gdb_test "-interpreter-exec console \"info line $line_mixed_range\"" \
+	".* starts at address ($hex) .* ends at ($hex).*\\^done" \
+	"info line mixed-range"
+    set mixed_start $expect_out(3,string)
+    set mixed_end $expect_out(4,string)
+
+    mi_gdb_test "003-data-disassemble -s $mixed_start -e $mixed_end -- 1" \
 	    "003\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",inst=\".*\"\}.*\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",inst=\".*\"\}\\\]\}\\\]" \
              "data-disassemble range assembly mixed"
 }
@@ -144,6 +147,7 @@  proc test_disassembly_mixed_with_opcodes {} {
     global decimal
     global fullname_syntax
 
+    set line_mixed_range        [gdb_get_line_number "callee1-1"]
     set line_callee2_head       [gdb_get_line_number "callee2 ("]
     set line_callee2_open_brace [expr $line_callee2_head + 1]
 
@@ -156,12 +160,14 @@  proc test_disassembly_mixed_with_opcodes {} {
            "002\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$line_callee2_open_brace\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"callee2\",offset=\"0\",opcodes=\".*\",inst=\".*\"\}.*\\\]\}.*,src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[.*\{address=\"$hex\",func-name=\"callee2\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}\\\]\}\\\]" \
              "data-disassemble file, line assembly mixed with opcodes"
 
-    #
-    # In mixed mode, the lowest level of granularity is the source line.
-    # So we are going to get the disassembly for the source line at
-    # which we are now, even if we have specified that the range is only 2 insns.
-    #
-    mi_gdb_test "003-data-disassemble -s \$pc -e \"\$pc+4\" -- 3" \
+    global expect_out
+    mi_gdb_test "-interpreter-exec console \"info line $line_mixed_range\"" \
+	".* starts at address ($hex) .* ends at ($hex).*\\^done" \
+	"info line mixed-range with opcodes"
+    set mixed_start $expect_out(3,string)
+    set mixed_end $expect_out(4,string)
+
+    mi_gdb_test "003-data-disassemble -s $mixed_start -e $mixed_end -- 3" \
            "003\\^done,asm_insns=\\\[src_and_asm_line=\{line=\"$decimal\",file=\".*basics.c\",fullname=\"${fullname_syntax}basics.c\",line_asm_insn=\\\[\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}.*\{address=\"$hex\",func-name=\"main\",offset=\"$decimal\",opcodes=\".*\",inst=\".*\"\}\\\]\}\\\]" \
              "data-disassemble range assembly mixed with opcodes"
 }