This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v3] Fix alignment of disassemble /r


When disassembling in raw mode (/r) in a variable-length insn architecture (i.e. x86),
the output can be messed since no alignment takes place.

The first version of this was sent on this mail thread
https://sourceware.org/ml/gdb-patches/2014-04/msg00226.html and this patch is
the same placed previously here https://sourceware.org/bugzilla/show_bug.cgi?id=19768

This patch performs the two passes: the first is at get_insn_set_longest_opcode
at line 136 in the patch, and the second is the while loop that follows like was
agreed here https://sourceware.org/ml/gdb-patches/2014-04/msg00427.html

In this version have been added the capability to compute longest opcode for
btrace.

If this is ok for commit I have a company-wide copyright access, and a coworker
of mine has write access.

gdb/ChangeLog
2016-04-07  Leonardo Boquillon  <leonardo.boquillon@tallertechnologies.com>

	* disasm.c (gdb_pretty_print_insn): Refactored to use longest opcode.
	(dump_insns): Add calls to calculate longest opcode, then pass it to the
	print function.
	(dis_get_longest_opcode): New function.
	* disasm.h (gdb_pretty_print_insn): Refactored to use longest opcode.
	* record-btrace.c (btrace_get_longest_opcode): New function.
	(btrace_insn_history): Add calls to calculate longest opcode,
	then pass it to the print function.

gdb/testsuite/ChangeLog
2016-04-07  Leonardo Boquillon  <leonardo.boquillon@tallertechnologies.com>

	* disas_raw.exp: New file.
	* main.S: New file.

---
 gdb/disasm.c                           | 32 +++++++++++++++++++++++++---
 gdb/disasm.h                           |  2 +-
 gdb/record-btrace.c                    | 28 +++++++++++++++++++++++-
 gdb/testsuite/gdb.disasm/disas_raw.exp | 39 ++++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.disasm/main.S        | 10 +++++++++
 5 files changed, 106 insertions(+), 5 deletions(-)
 create mode 100644 gdb/testsuite/gdb.disasm/disas_raw.exp
 create mode 100644 gdb/testsuite/gdb.disasm/main.S

diff --git a/gdb/disasm.c b/gdb/disasm.c
index 1cf0901..5027317 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -169,19 +169,39 @@ compare_lines (const void *mle1p, const void *mle2p)
   return val;
 }
 
+static unsigned int
+dis_get_longest_opcode(struct gdbarch *gdbarch, CORE_ADDR addr, CORE_ADDR high,
+		       int how_many)
+{
+  unsigned int longest_opcode = 0;
+  unsigned int insn_checked = 0;
+
+  while (addr < high && (how_many < 0 || insn_checked++ < how_many))
+    {
+      const unsigned int current_length = gdb_insn_length(gdbarch, addr);
+      longest_opcode =
+	(current_length > longest_opcode) ? current_length : longest_opcode;
+      addr += current_length;
+    }
+
+  return longest_opcode;
+}
+
 /* See disasm.h.  */
 
 int
 gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 		       struct disassemble_info * di,
 		       const struct disasm_insn *insn, int flags,
-		       struct ui_file *stb)
+		       struct ui_file *stb, unsigned int longest_opcode)
 {
   /* parts of the symbolic representation of the address */
   int unmapped;
   int offset;
   int line;
   int size;
+  unsigned int i;
+  unsigned int max_print_space;
   struct cleanup *ui_out_chain;
   char *filename = NULL;
   char *name = NULL;
@@ -267,7 +287,10 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 	}
 
       ui_out_field_stream (uiout, "opcodes", opcode_stream);
-      ui_out_text (uiout, "\t");
+      gdb_assert(longest_opcode >= size);
+      max_print_space = 3u * (1u + longest_opcode - size);
+      for (i = 0; i < max_print_space; i++)
+	ui_out_text(uiout, " ");
 
       do_cleanups (cleanups);
     }
@@ -291,15 +314,18 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 {
   struct disasm_insn insn;
   int num_displayed = 0;
+  unsigned int longest_opcode;
 
   memset (&insn, 0, sizeof (insn));
   insn.addr = low;
 
+  longest_opcode = dis_get_longest_opcode(gdbarch, low, high, how_many);
   while (insn.addr < high && (how_many < 0 || num_displayed < how_many))
     {
       int size;
 
-      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
+      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb,
+				    longest_opcode);
       if (size <= 0)
 	break;
 
diff --git a/gdb/disasm.h b/gdb/disasm.h
index a2b72b9..06f2f5e 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -53,7 +53,7 @@ struct disasm_insn
 extern int gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 				  struct disassemble_info * di,
 				  const struct disasm_insn *insn, int flags,
-				  struct ui_file *stb);
+				  struct ui_file *stb, unsigned int longest_opcode);
 
 /* Return a filled in disassemble_info object for use by gdb.  */
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 77b5180..84d9d57 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -660,6 +660,29 @@ btrace_print_lines (struct btrace_line_range lines, struct ui_out *uiout,
     }
 }
 
+static unsigned int
+btrace_get_longest_opcode(struct gdbarch *gdbarch,
+			  const struct btrace_insn_iterator *begin,
+			  const struct btrace_insn_iterator *end)
+{
+  unsigned int longest_opcode = 0;
+  struct btrace_insn_iterator it;
+
+  for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
+    {
+      const struct btrace_insn *insn = btrace_insn_get (&it);
+
+      if (insn != NULL)
+	{
+	  const unsigned int current_length =
+	    gdb_insn_length(gdbarch, insn->pc);
+	  longest_opcode =
+	    (current_length > longest_opcode) ? current_length : longest_opcode;
+	}
+    }
+
+  return longest_opcode;
+}
 /* Disassemble a section of the recorded instruction trace.  */
 
 static void
@@ -674,6 +697,7 @@ btrace_insn_history (struct ui_out *uiout,
   struct gdbarch *gdbarch;
   struct btrace_insn_iterator it;
   struct btrace_line_range last_lines;
+  unsigned int longest_opcode;
 
   DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
 	 btrace_insn_number (end));
@@ -692,6 +716,7 @@ btrace_insn_history (struct ui_out *uiout,
      instructions corresponding to that line.  */
   ui_item_chain = NULL;
 
+  longest_opcode = btrace_get_longest_opcode(gdbarch, begin, end);
   for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
     {
       const struct btrace_insn *insn;
@@ -745,7 +770,8 @@ btrace_insn_history (struct ui_out *uiout,
 	  if ((insn->flags & BTRACE_INSN_FLAG_SPECULATIVE) != 0)
 	    dinsn.is_speculative = 1;
 
-	  gdb_pretty_print_insn (gdbarch, uiout, &di, &dinsn, flags, stb);
+	  gdb_pretty_print_insn (gdbarch, uiout, &di, &dinsn, flags, stb,
+				 longest_opcode);
 	}
     }
 
diff --git a/gdb/testsuite/gdb.disasm/disas_raw.exp b/gdb/testsuite/gdb.disasm/disas_raw.exp
new file mode 100644
index 0000000..a233bad
--- /dev/null
+++ b/gdb/testsuite/gdb.disasm/disas_raw.exp
@@ -0,0 +1,39 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2016 Free Software Foundation, Inc.
+#
+# Contributed by Taller Technologies <leonardo.boquillon@tallertechnologies.com>
+#
+# 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/>.
+
+# Test alignment of raw disassemble dump (Bugzilla #19768).
+
+if { ![istarget "x86_64-*-*"] } { return -1 }
+
+set asm_file "main.S"
+
+standard_testfile ${asm_file}
+
+if [prepare_for_testing ${testfile}.exp ${testfile} ${asm_file} {}] {
+    return -1
+}
+
+set asm_line ".*55                        push   %rbp"
+append asm_line ".*48 89 e5                  mov    %rsp,%rbp"
+append asm_line ".*b8 00 00 00 00            mov    \\\$0x0,%eax"
+append asm_line ".*5d                        pop    %rbp"
+append asm_line ".*c3                        retq   "
+append asm_line ".*0f 1f 84 00 00 00 00 00   nopl   0x0\\(%rax,%rax,1\\).*"
+
+gdb_test "disass /r main" ${asm_line} "disass /r main"
\ No newline at end of file
diff --git a/gdb/testsuite/gdb.disasm/main.S b/gdb/testsuite/gdb.disasm/main.S
new file mode 100644
index 0000000..0178938
--- /dev/null
+++ b/gdb/testsuite/gdb.disasm/main.S
@@ -0,0 +1,10 @@
+	.file	"main.c"
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	pushq	%rbp
+	movq	%rsp, %rbp
+	movl	$0, %eax
+	popq	%rbp
+	ret
-- 
1.9.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]