public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 7/8] Disassembly unit test: memory error
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
  2017-01-10 12:26 ` [PATCH 4/8] Return -1 on memory error in print_insn_msp430 Yao Qi
  2017-01-10 12:26 ` [PATCH 6/8] Return -1 on memory error in print_insn_m68k Yao Qi
@ 2017-01-10 12:26 ` Yao Qi
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

This patch adds a unit test about memory error occurs on reading
memory, and check MEMORY_ERROR exception is always thrown.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* disasm.c (gdb_disassembler_print_one_insn_test):
	(gdb_disassembler_memory_error_test): New function.
	(_initialize_disasm): Register
	gdb_disassembler_memory_error_test.
---
 gdb/disasm.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index 6e403da..e908199 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -424,6 +424,53 @@ gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
   SELF_CHECK (di.print_insn (0) == len);
 }
 
+/* Test disassembly on memory error.  */
+
+static void
+gdb_disassembler_memory_error_test (struct gdbarch *gdbarch)
+{
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+    gdb_disassembler_test (struct gdbarch *gdbarch)
+      : gdb_disassembler (gdbarch, ui_file_new (),
+			  gdb_disassembler_test::read_memory)
+    {
+    }
+
+    ~gdb_disassembler_test ()
+    {
+      ui_file_delete ((struct ui_file *) m_di.stream);
+    }
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len,
+			    struct disassemble_info *info)
+    {
+      /* Always get an error.  */
+      return -1;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch);
+  bool see_memory_error = false;
+
+  TRY
+    {
+      di.print_insn (0);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == MEMORY_ERROR)
+	see_memory_error = true;
+    }
+  END_CATCH
+
+  /* Expect MEMORY_ERROR.   */
+  SELF_CHECK (see_memory_error);
+
+}
+
 } // namespace selftests
 #endif /* GDB_SELF_TEST */
 
@@ -1083,5 +1130,6 @@ _initialize_disasm (void)
 {
 #if GDB_SELF_TEST
   register_self_test (selftests::gdb_disassembler_print_one_insn_test);
+  register_self_test (selftests::gdb_disassembler_memory_error_test);
 #endif
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
  2017-01-10 12:26 ` [PATCH 4/8] Return -1 on memory error in print_insn_msp430 Yao Qi
@ 2017-01-10 12:26 ` Yao Qi
  2017-01-11 22:15   ` Alan Modra
  2017-01-10 12:26 ` [PATCH 7/8] Disassembly unit test: memory error Yao Qi
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

m68k-dis.c:print_insn_m68k doesn't return -1 on memory error, but GDB
expects it returning -1 on memory error.

opcodes:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
	if FETCH_DATA returns 0.
	(m68k_scan_mask): Likewise.
	(print_insn_m68k): Update code to handle -1 return value.
---
 opcodes/m68k-dis.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c
index 3159a47..c531e2d 100644
--- a/opcodes/m68k-dis.c
+++ b/opcodes/m68k-dis.c
@@ -1331,7 +1331,8 @@ print_insn_arg (const char *d,
 }
 
 /* Try to match the current instruction to best and if so, return the
-   number of bytes consumed from the instruction stream, else zero.  */
+   number of bytes consumed from the instruction stream, else zero.
+   Return -1 on memory error.  */
 
 static int
 match_insn_m68k (bfd_vma memaddr,
@@ -1415,12 +1416,14 @@ match_insn_m68k (bfd_vma memaddr,
 	 this because we know exactly what the second word is, and we
 	 aren't going to print anything based on it.  */
       p = buffer + 6;
-      FETCH_DATA (info, p);
+      if (!FETCH_DATA (info, p))
+	return -1;
       buffer[2] = buffer[4];
       buffer[3] = buffer[5];
     }
 
-  FETCH_DATA (info, p);
+  if (!FETCH_DATA (info, p))
+    return -1;
 
   save_p = p;
   info->print_address_func = dummy_print_address;
@@ -1439,7 +1442,7 @@ match_insn_m68k (bfd_vma memaddr,
 	{
 	  info->fprintf_func = save_printer;
 	  info->print_address_func = save_print_address;
-	  return 0;
+	  return eaten == PRINT_INSN_ARG_MEMORY_ERROR ? -1 : 0;
 	}
       else
 	{
@@ -1481,7 +1484,8 @@ match_insn_m68k (bfd_vma memaddr,
 /* Try to interpret the instruction at address MEMADDR as one that
    can execute on a processor with the features given by ARCH_MASK.
    If successful, print the instruction to INFO->STREAM and return
-   its length in bytes.  Return 0 otherwise.  */
+   its length in bytes.  Return 0 otherwise.  Return -1 on memory
+   error.  */
 
 static int
 m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
@@ -1523,7 +1527,8 @@ m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
 	*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
     }
 
-  FETCH_DATA (info, buffer + 2);
+  if (!FETCH_DATA (info, buffer + 2))
+    return -1;
   major_opcode = (buffer[0] >> 4) & 15;
 
   for (i = 0; i < numopcodes[major_opcode]; i++)
@@ -1628,7 +1633,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
       /* First try printing an m680x0 instruction.  Try printing a Coldfire
 	 one if that fails.  */
       val = m68k_scan_mask (memaddr, info, m68k_mask);
-      if (val == 0)
+      if (val <= 0)
 	val = m68k_scan_mask (memaddr, info, mcf_mask);
     }
   else
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (2 preceding siblings ...)
  2017-01-10 12:26 ` [PATCH 7/8] Disassembly unit test: memory error Yao Qi
@ 2017-01-10 12:26 ` Yao Qi
  2017-01-11 21:15   ` Simon Marchi
                     ` (3 more replies)
  2017-01-10 12:26 ` [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg Yao Qi
                   ` (4 subsequent siblings)
  8 siblings, 4 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

This patch adds one unit test, which disassemble one instruction for
every gdbarch if available.  The test needs one valid instruction of
each gdbarch, and most of them are got from breakpoint instruction.
For the rest gdbarch whose breakpoint instruction isn't a valid
instruction, I copy one instruction from the gas/testsuite/gas/
directory.

I get the valid instruction of most gdbarch except ia64, mep, mips,
tic6x, and xtensa.  People familiar with these arch should be easy
to extend the test.

In order to achieve "do the unit test for every gdbarch", I extend
selftest.[c,h], so that we can register a function pointer, which
has one argument gdbarch.  selftest.c will iterate over all gdbarches
to call the registered function pointer.

gdb:

2017-01-06  Yao Qi  <yao.qi@linaro.org>

	* disasm.c [GDB_SELF_TEST]: Include selftest.h.
	(selftests::gdb_disassembler_print_one_insn_test): New function.
	(_initialize_disasm): New function.
	* selftest.c: Include "arch-utils.h".
	(gdbarch_tests): New vector.
	(register_self_test): New function.
	(run_self_tests): Iterate each gdbarch and call functions in
	gdbarch_tests.
	* selftest.h (self_test_function_with_gdbarch): New typedef.
	(register_self_test): Declare.
---
 gdb/disasm.c   | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/selftest.c |  55 +++++++++++++++++++++
 gdb/selftest.h |   3 ++
 3 files changed, 206 insertions(+)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index 6a3f3aa..6e403da 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -27,6 +27,10 @@
 #include "source.h"
 #include <algorithm>
 
+#if GDB_SELF_TEST
+#include "selftest.h"
+#endif /* GDB_SELF_TEST */
+
 /* Disassemble functions.
    FIXME: We should get rid of all the duplicate code in gdb that does
    the same thing: disassemble_command() and the gdbtk variation.  */
@@ -290,6 +294,139 @@ gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
   return size;
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Test disassembly one instruction.  */
+
+static void
+gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
+{
+  int len = -1;
+  const gdb_byte *insn = NULL;
+
+  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
+    {
+    case bfd_arch_bfin:
+      /* M3.L = 0xe117 */
+      insn = (const gdb_byte[]) {0x17, 0xe1, 0xff, 0xff};
+      len = 4;
+      break;
+    case bfd_arch_arm:
+      /* mov     r0, #0 */
+      insn = (const gdb_byte[]) {0x0, 0x0, 0xa0, 0xe3};
+      len = 4;
+      break;
+    case bfd_arch_ia64:
+    case bfd_arch_mep:
+    case bfd_arch_mips:
+    case bfd_arch_tic6x:
+    case bfd_arch_xtensa:
+      return;
+    case bfd_arch_s390:
+      /* nopr %r7 */
+      insn = (const gdb_byte[]) {0x07, 0x07};
+      len = 2;
+      break;
+    case bfd_arch_xstormy16:
+      /* nop */
+      insn = (const gdb_byte[]) {0x0, 0x0};
+      len = 2;
+      break;
+    case bfd_arch_arc:
+      {
+	/* PR 21003 */
+	if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
+	  return;
+      }
+    case bfd_arch_nios2:
+    case bfd_arch_score:
+      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &len);
+      break;
+    case bfd_arch_sh:
+      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 2, &len);
+      break;
+    default:
+      {
+	/* Test disassemble breakpoint instruction.  */
+	CORE_ADDR pc = 0;
+	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
+
+	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind,
+						&len);
+
+	break;
+      }
+    }
+  SELF_CHECK (len > 0);
+
+  /* Test gdb_disassembler for a given gdbarch by reading data from a
+     pre-allocated buffer.  If you want to see the disassembled
+     instruction printed to gdb_stdout, define macro
+     DISASSEMBLER_TEST_VERBOSE.  */
+
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+
+#ifndef DISASSEMBLER_TEST_VERBOSE
+    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
+				    const gdb_byte *insn)
+      : gdb_disassembler (gdbarch, ui_file_new (),
+			  gdb_disassembler_test::read_memory),
+	m_insn (insn)
+    {
+    }
+
+    ~gdb_disassembler_test ()
+    {
+      ui_file_delete ((struct ui_file *) m_di.stream);
+    }
+#else
+    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
+				    const gdb_byte *insn)
+      : gdb_disassembler (gdbarch, gdb_stdout,
+			  gdb_disassembler_test::read_memory),
+	m_insn (insn)
+    {
+    }
+
+    int
+    print_insn (CORE_ADDR memaddr)
+    {
+      fprintf_unfiltered (stream (), "%s ",
+			  gdbarch_bfd_arch_info (arch ())->arch_name);
+
+      int len = gdb_disassembler::print_insn (memaddr);
+
+      fprintf_unfiltered (stream (), "\n");
+      return len;
+    }
+#endif /* DISASSEMBLER_TEST_VERBOSE */
+
+  private:
+    const gdb_byte *m_insn;
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len, struct disassemble_info *info)
+    {
+      gdb_disassembler_test *self
+	= static_cast<gdb_disassembler_test *>(info->application_data);
+
+      memcpy (myaddr, self->m_insn, len);
+      return 0;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch, insn);
+
+  SELF_CHECK (di.print_insn (0) == len);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 static int
 dump_insns (struct ui_out *uiout, gdb_disassembler *di,
 	    CORE_ADDR low, CORE_ADDR high,
@@ -937,3 +1074,14 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
 
   return gdbarch_print_insn (gdbarch, addr, &di);
 }
+
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_disasm;
+
+void
+_initialize_disasm (void)
+{
+#if GDB_SELF_TEST
+  register_self_test (selftests::gdb_disassembler_print_one_insn_test);
+#endif
+}
diff --git a/gdb/selftest.c b/gdb/selftest.c
index adc7dda..8835473 100644
--- a/gdb/selftest.c
+++ b/gdb/selftest.c
@@ -18,11 +18,13 @@
 
 #include "defs.h"
 #include "selftest.h"
+#include "arch-utils.h"
 #include <vector>
 
 /* All the tests that have been registered.  */
 
 static std::vector<self_test_function *> tests;
+static std::vector<self_test_function_with_gdbarch *> gdbarch_tests;
 
 /* See selftest.h.  */
 
@@ -32,6 +34,12 @@ register_self_test (self_test_function *function)
   tests.push_back (function);
 }
 
+void
+register_self_test (self_test_function_with_gdbarch *function)
+{
+  gdbarch_tests.push_back (function);
+}
+
 /* See selftest.h.  */
 
 void
@@ -55,6 +63,53 @@ run_self_tests (void)
       END_CATCH
     }
 
+  for (const auto &f : gdbarch_tests)
+    {
+      const char **arches = gdbarch_printable_names ();
+      int i;
+
+      for (i = 0; arches[i] != NULL; i++)
+	{
+	  if (strcmp ("fr300", arches[i]) == 0)
+	    {
+	      /* PR 20946 */
+	      continue;
+	    }
+	  else if (strcmp ("powerpc:EC603e", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc64", arches[i]) == 0
+		   || strcmp ("powerpc:titan", arches[i]) == 0
+		   || strcmp ("powerpc:vle", arches[i]) == 0
+		   || strcmp ("powerpc:e5500", arches[i]) == 0
+		   || strcmp ("powerpc:e6500", arches[i]) == 0)
+	    {
+	      /* PR 19797 */
+	      continue;
+	    }
+
+	  QUIT;
+
+	  TRY
+	    {
+	      struct gdbarch_info info;
+
+	      gdbarch_info_init (&info);
+	      info.bfd_arch_info = bfd_scan_arch (arches[i]);
+
+	      struct gdbarch *gdbarch = gdbarch_find_by_info (info);
+	      SELF_CHECK (gdbarch != NULL);
+	      f (gdbarch);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      ++failed;
+	      exception_fprintf (gdb_stderr, ex,
+				 _("Self test failed: arch %s: "), arches[i]);
+	    }
+	  END_CATCH
+	}
+    }
+
   printf_filtered (_("Ran %lu unit tests, %d failed\n"),
 		   (long) tests.size (), failed);
 }
diff --git a/gdb/selftest.h b/gdb/selftest.h
index 94684ff..4446780 100644
--- a/gdb/selftest.h
+++ b/gdb/selftest.h
@@ -24,9 +24,12 @@
 
 typedef void self_test_function (void);
 
+typedef void self_test_function_with_gdbarch (struct gdbarch *);
+
 /* Register a new self-test.  */
 
 extern void register_self_test (self_test_function *function);
+extern void register_self_test (self_test_function_with_gdbarch *function);
 
 /* Run all the self tests.  This print a message describing the number
    of test and the number of failures.  */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 4/8] Return -1 on memory error in print_insn_msp430
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
@ 2017-01-10 12:26 ` Yao Qi
  2017-01-11 21:54   ` Alan Modra
  2017-01-10 12:26 ` [PATCH 6/8] Return -1 on memory error in print_insn_m68k Yao Qi
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

Disassemblers in opcodes return -1 on memory error, but msp430 doesn't
follow this convention.  If I change GDB not to throw exception in
disassemble_info.memory_error_func and rely on the return value of
disassembler, I'll get the following output.

(gdb) disassemble 0x0,+8
Dump of assembler code from 0x0 to 0x8:
   0x00000000:  .word   0xffff; ????
   0x00000002:  .word   0xffff; ????
   0x00000004:  .word   0xffff; ????
   0x00000006:  .word   0xffff; ????
End of assembler dump.

This patch teaches print_insn_msp430 and its callees to return -1
on memory error.

opcodes:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* msp430-dis.c (msp430_singleoperand): Return -1 if
	msp430dis_opcode_signed returns false.
	(msp430_doubleoperand): Likewise.
	(msp430_branchinstr): Return -1 if
	msp430dis_opcode_unsigned returns false.
	(msp430x_calla_instr): Likewise.
	(print_insn_msp430): Likewise.
---
 opcodes/msp430-dis.c | 85 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 14 deletions(-)

diff --git a/opcodes/msp430-dis.c b/opcodes/msp430-dis.c
index 9c62193..bb82643 100644
--- a/opcodes/msp430-dis.c
+++ b/opcodes/msp430-dis.c
@@ -270,6 +270,8 @@ msp430_singleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -285,6 +287,8 @@ msp430_singleoperand (disassemble_info *info,
 		      sprintf (op, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    {
@@ -300,6 +304,8 @@ msp430_singleoperand (disassemble_info *info,
 		    }
 		  sprintf (op, "%d(r%d)", dst, regd);
 		}
+	      else
+		return -1;
 	    }
 	}
       break;
@@ -346,6 +352,8 @@ msp430_singleoperand (disassemble_info *info,
 			sprintf (comm, "#0x%05x", dst);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
@@ -370,6 +378,8 @@ msp430_singleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -384,6 +394,8 @@ msp430_singleoperand (disassemble_info *info,
 		      sprintf (op, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 3)
 	    {
@@ -407,6 +419,8 @@ msp430_singleoperand (disassemble_info *info,
 		  if (dst > 9 || dst < 0)
 		    sprintf (comm, "%05x", dst);
 		}
+	      else
+		return -1;
 	    }
 	}
       break;
@@ -511,6 +525,8 @@ msp430_doubleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -526,6 +542,8 @@ msp430_doubleoperand (disassemble_info *info,
 		      if (src != dst)
 			return 0;
 		    }
+		  else
+		    return -1;
 		  cmd_len += 4;
 		  *cycles = 6;
 		  sprintf (op1, "&0x%04x", PS (dst));
@@ -535,6 +553,8 @@ msp430_doubleoperand (disassemble_info *info,
 		      sprintf (op1, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    {
@@ -613,6 +633,8 @@ msp430_doubleoperand (disassemble_info *info,
 		    sprintf (comm1, "0x%05x", dst & 0xfffff);
 		}
 	    }
+	  else
+	    return -1;
 	}
       else
 	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
@@ -640,6 +662,8 @@ msp430_doubleoperand (disassemble_info *info,
 			   (long) ((addr + 2 + dst) & 0xfffff));
 		}
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 2)
 	{
@@ -658,6 +682,8 @@ msp430_doubleoperand (disassemble_info *info,
 		  * comm1 = 0;
 		}
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 3)
 	{
@@ -728,6 +754,8 @@ msp430_doubleoperand (disassemble_info *info,
 			   (long)((addr + cmd_len + dst) & 0xfffff));
 		}
 	    }
+	  else
+	    return -1;
 	  cmd_len += 2;
 	}
       else if (regd == 2)
@@ -821,6 +849,8 @@ msp430_branchinstr (disassemble_info *info,
 	      cmd_len += 2;
 	      sprintf (op1, "#0x%04x", PS (udst));
 	    }
+	  else
+	    return -1;
 	}
       else
 	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
@@ -849,6 +879,8 @@ msp430_branchinstr (disassemble_info *info,
 	      cmd_len += 2;
 	      sprintf (op1, "&0x%04x", PS (udst));
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 3)
 	{
@@ -923,6 +955,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  sprintf (op1, "&%d", (ureg << 16) + udst);
 	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
 	}
+      else
+	return -1;
       break;
 
     case 9: /* CALLA pcrel-sym */
@@ -944,6 +978,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  sprintf (op1, "#%d", (ureg << 16) + udst);
 	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
 	}
+      else
+	return -1;
       break;
 
     default:
@@ -969,10 +1005,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
   unsigned short bits;
 
   if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
-    {
-      prin (stream, ".word	0xffff;	????");
-      return 2;
-    }
+    return -1;
 
   if (((int) addr & 0xffff) > 0xffdf)
     {
@@ -989,11 +1022,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
       extension_word = insn;
       addr += 2;
       if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
-	{
-	  prin (stream, ".word	0x%04x, 0xffff;	????",
-		extension_word);
-	  return 4;
-	}
+	return -1;
    }
 
   for (opcode = msp430_opcodes; opcode->name; opcode++)
@@ -1011,9 +1040,13 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 	      && (insn & 0x000f) == 0
 	      && (insn & 0x0080) == 0)
 	    {
-	      cmd_len +=
+	      int ret =
 		msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
 				    &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (cmd_len)
 		break;
 	    }
@@ -1022,10 +1055,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 	    {
 	      int n;
 	      int reg;
+	      int ret;
 
 	    case 4:
-	      cmd_len += msp430x_calla_instr (info, addr, insn,
-					      op1, comm1, & cycles);
+	      ret = msp430x_calla_instr (info, addr, insn,
+					 op1, comm1, & cycles);
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      break;
 
 	    case 5: /* PUSHM/POPM */
@@ -1080,6 +1117,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (n > 9 || n < 0)
 			sprintf (comm1, "0x%05x", n);
 		    }
+		  else
+		    return -1;
 		  cmd_len = 4;
 		}
 	      sprintf (op2, "r%d", reg);
@@ -1120,6 +1159,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (strcmp (opcode->name, "bra") != 0)
 			sprintf (op2, "r%d", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 3: /* MOVA x(Rsrc), Rdst */
@@ -1152,6 +1193,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (reg > 9 || reg < 0)
 			sprintf (comm2, "0x%05x", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 7: /* MOVA Rsrc, x(Rdst) */
@@ -1169,6 +1212,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 			    sprintf (comm2, "0x%05x", n);
 			}
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 8: /* MOVA #imm20, Rdst */
@@ -1185,6 +1230,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (strcmp (opcode->name, "bra") != 0)
 			sprintf (op2, "r%d", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 12: /* MOVA Rsrc, Rdst */
@@ -1206,15 +1253,21 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 
 	  switch (opcode->insn_opnumb)
 	    {
+	      int ret;
+
 	    case 0:
 	      cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
 	      break;
 	    case 2:
-	      cmd_len +=
+	      ret =
 		msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
 				      comm1, comm2,
 				      extension_word,
 				      &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (insn & BYTE_OPERATION)
 		{
 		  if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
@@ -1235,10 +1288,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 
 	      break;
 	    case 1:
-	      cmd_len +=
+	      ret =
 		msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
 				      extension_word,
 				      &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (extension_word
 		  && (strcmp (opcode->name, "swpb") == 0
 		      || strcmp (opcode->name, "sxt") == 0))
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (3 preceding siblings ...)
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
@ 2017-01-10 12:26 ` Yao Qi
  2017-01-11 22:14   ` Alan Modra
  2017-01-10 12:27 ` [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn Yao Qi
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

When I inspect the return values of disassmblers, I happen to see
various -1/-2/-3 magic numbers are used in m68k-dis.c.  This patch
is to replace them with enum.

-1 and -2 is "clearly documented" in print_ins_arg's comments, but
-3 isn't.  In fact, -3 is returned when FETCH_DATA returns false,
which means memory error (because fetch_data return 0 on memory
error).  So I name enum PRINT_INSN_ARG_MEMORY_ERROR for -3.

This patch is a refactor patch, doesn't affect any functionality.

opcodes:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* m68k-dis.c (enum print_insn_arg_error): New.
	(NEXTBYTE): Replace -3 with
	PRINT_INSN_ARG_MEMORY_ERROR.
	(NEXTULONG): Likewise.
	(NEXTSINGLE): Likewise.
	(NEXTDOUBLE): Likewise.
	(NEXTDOUBLE): Likewise.
	(NEXTPACKED): Likewise.
	(FETCH_DATA): Update comments.
	(print_insn_arg): Update comments. Replace magic numbers with
	enum.
	(match_insn_m68k): Likewise.
---
 opcodes/m68k-dis.c | 95 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 55 insertions(+), 40 deletions(-)

diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c
index de88f23..3159a47 100644
--- a/opcodes/m68k-dis.c
+++ b/opcodes/m68k-dis.c
@@ -57,13 +57,27 @@ static char *const reg_half_names[] =
 #define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128)
 #endif
 
+/* Error code of print_insn_arg's return value.  */
+
+enum print_insn_arg_error
+  {
+    /* An invalid operand is found.  */
+    PRINT_INSN_ARG_INVALID_OPERAND = -1,
+
+    /* An opcode table error.  */
+    PRINT_INSN_ARG_INVALID_OP_TABLE = -2,
+
+    /* A memory error.  */
+    PRINT_INSN_ARG_MEMORY_ERROR = -3,
+  };
+
 /* Get a 1 byte signed integer.  */
 #define NEXTBYTE(p, val)			\
   do						\
     {						\
       p += 2;					\
       if (!FETCH_DATA (info, p))		\
-	return -3;				\
+	return PRINT_INSN_ARG_MEMORY_ERROR;	\
       val = COERCE_SIGNED_CHAR (p[-1]);		\
     }						\
   while (0)
@@ -100,7 +114,7 @@ static char *const reg_half_names[] =
     {									\
       p += 4;								\
       if (!FETCH_DATA (info, p))					\
-	return -3;							\
+	return PRINT_INSN_ARG_MEMORY_ERROR;				\
       val = (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]); \
     }									\
   while (0)
@@ -111,7 +125,7 @@ static char *const reg_half_names[] =
     {								\
       p += 4;							\
       if (!FETCH_DATA (info, p))				\
-	return -3;						\
+	return PRINT_INSN_ARG_MEMORY_ERROR;			\
       floatformat_to_double (& floatformat_ieee_single_big,	\
 			     (char *) p - 4, & val);		\
     }								\
@@ -123,7 +137,7 @@ static char *const reg_half_names[] =
     {								\
       p += 8;							\
       if (!FETCH_DATA (info, p))				\
-	return -3;						\
+	return PRINT_INSN_ARG_MEMORY_ERROR;			\
       floatformat_to_double (& floatformat_ieee_double_big,	\
 			     (char *) p - 8, & val);		\
     }								\
@@ -135,7 +149,7 @@ static char *const reg_half_names[] =
     {							\
       p += 12;						\
       if (!FETCH_DATA (info, p))			\
-	return -3;					\
+	return PRINT_INSN_ARG_MEMORY_ERROR;		\
       floatformat_to_double (& floatformat_m68881_ext,	\
 			     (char *) p - 12, & val);	\
     }							\
@@ -150,7 +164,7 @@ static char *const reg_half_names[] =
     {						\
       p += 12;					\
       if (!FETCH_DATA (info, p))		\
-	return -3;				\
+	return PRINT_INSN_ARG_MEMORY_ERROR;	\
       val = 0.0;				\
     }						\
   while (0)
@@ -168,7 +182,8 @@ struct private
 };
 
 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
-   to ADDR (exclusive) are valid.  Returns 1 for success, 0 on error.  */
+   to ADDR (exclusive) are valid.  Returns 1 for success, 0 on memory
+   error.  */
 #define FETCH_DATA(info, addr) \
   ((addr) <= ((struct private *) (info->private_data))->max_fetched \
    ? 1 : fetch_data ((info), (addr)))
@@ -622,9 +637,8 @@ print_indexed (int basereg,
   while (0)
 
 /* Returns number of bytes "eaten" by the operand, or
-   return -1 if an invalid operand was found, or -2 if
-   an opcode tabe error was found or -3 to simply abort.
-   ADDR is the pc for this arg to be relative to.  */
+   return enum print_insn_arg_error.  ADDR is the pc for this arg to be
+   relative to.  */
 
 static int
 print_insn_arg (const char *d,
@@ -864,7 +878,7 @@ print_insn_arg (const char *d,
 	  (*info->fprintf_func) (info->stream, "{#%d}", val);
 	}
       else
-	return -1;
+	return PRINT_INSN_ARG_INVALID_OPERAND;
       break;
 
     case '#':
@@ -881,11 +895,11 @@ print_insn_arg (const char *d,
       else if (place == 'b')
 	NEXTBYTE (p1, val);
       else if (place == 'w' || place == 'W')
-	NEXTWORD (p1, val, -3);
+	NEXTWORD (p1, val, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'l')
-	NEXTLONG (p1, val, -3);
+	NEXTLONG (p1, val, PRINT_INSN_ARG_MEMORY_ERROR);
       else
-	return -2;
+	return PRINT_INSN_ARG_INVALID_OP_TABLE;
 
       (*info->fprintf_func) (info->stream, "#%d", val);
       break;
@@ -896,26 +910,26 @@ print_insn_arg (const char *d,
       else if (place == 'B')
 	disp = COERCE_SIGNED_CHAR (buffer[1]);
       else if (place == 'w' || place == 'W')
-	NEXTWORD (p, disp, -3);
+	NEXTWORD (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'l' || place == 'L' || place == 'C')
-	NEXTLONG (p, disp, -3);
+	NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'g')
 	{
 	  NEXTBYTE (buffer, disp);
 	  if (disp == 0)
-	    NEXTWORD (p, disp, -3);
+	    NEXTWORD (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
 	  else if (disp == -1)
-	    NEXTLONG (p, disp, -3);
+	    NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
 	}
       else if (place == 'c')
 	{
 	  if (buffer[1] & 0x40)		/* If bit six is one, long offset.  */
-	    NEXTLONG (p, disp, -3);
+	    NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
 	  else
-	    NEXTWORD (p, disp, -3);
+	    NEXTWORD (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
 	}
       else
-	return -2;
+	return PRINT_INSN_ARG_INVALID_OP_TABLE;
 
       (*info->print_address_func) (addr + disp, info);
       break;
@@ -924,7 +938,7 @@ print_insn_arg (const char *d,
       {
 	int val1;
 
-	NEXTWORD (p, val, -3);
+	NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 	FETCH_ARG (3, val1);
 	(*info->fprintf_func) (info->stream, "%s@(%d)", reg_names[val1 + 8], val);
 	break;
@@ -952,14 +966,14 @@ print_insn_arg (const char *d,
       else if (val == 3)
 	(*info->fprintf_func) (info->stream, ">>");
       else
-	return -1;
+	return PRINT_INSN_ARG_INVALID_OPERAND;
       break;
 
     case 'I':
       /* Get coprocessor ID... */
       val = fetch_arg (buffer, 'd', 3, info);
       if (val < 0)
-	return -3;
+	return PRINT_INSN_ARG_MEMORY_ERROR;
       if (val != 1)				/* Unusual coprocessor ID?  */
 	(*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
       break;
@@ -992,19 +1006,19 @@ print_insn_arg (const char *d,
 	{
 	  val = fetch_arg (buffer, 'x', 6, info);
 	  if (val < 0)
-	    return -3;
+	    return PRINT_INSN_ARG_MEMORY_ERROR;
 	  val = ((val & 7) << 3) + ((val >> 3) & 7);
 	}
       else
 	{
 	  val = fetch_arg (buffer, 's', 6, info);
 	  if (val < 0)
-	    return -3;
+	    return PRINT_INSN_ARG_MEMORY_ERROR;
 	}
 
       /* If the <ea> is invalid for *d, then reject this match.  */
       if (!m68k_valid_ea (*d, val))
-	return -1;
+	return PRINT_INSN_ARG_INVALID_OPERAND;
 
       /* Get register number assuming address register.  */
       regno = (val & 7) + 8;
@@ -1032,21 +1046,21 @@ print_insn_arg (const char *d,
 	  break;
 
 	case 5:
-	  NEXTWORD (p, val, -3);
+	  NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 	  (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
 	  break;
 
 	case 6:
 	  p = print_indexed (regno, p, addr, info);
 	  if (p == NULL)
-	    return -3;
+	    return PRINT_INSN_ARG_MEMORY_ERROR;
 	  break;
 
 	case 7:
 	  switch (val & 7)
 	    {
 	    case 0:
-	      NEXTWORD (p, val, -3);
+	      NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 	      (*info->print_address_func) (val, info);
 	      break;
 
@@ -1056,7 +1070,7 @@ print_insn_arg (const char *d,
 	      break;
 
 	    case 2:
-	      NEXTWORD (p, val, -3);
+	      NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 	      (*info->fprintf_func) (info->stream, "%%pc@(");
 	      (*info->print_address_func) (addr + val, info);
 	      (*info->fprintf_func) (info->stream, ")");
@@ -1065,7 +1079,7 @@ print_insn_arg (const char *d,
 	    case 3:
 	      p = print_indexed (-1, p, addr, info);
 	      if (p == NULL)
-		return -3;
+		return PRINT_INSN_ARG_MEMORY_ERROR;
 	      break;
 
 	    case 4:
@@ -1078,12 +1092,12 @@ print_insn_arg (const char *d,
 		  break;
 
 		case 'w':
-		  NEXTWORD (p, val, -3);
+		  NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 		  flt_p = 0;
 		  break;
 
 		case 'l':
-		  NEXTLONG (p, val, -3);
+		  NEXTLONG (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
 		  flt_p = 0;
 		  break;
 
@@ -1104,7 +1118,7 @@ print_insn_arg (const char *d,
 		  break;
 
 		default:
-		  return -1;
+		  return PRINT_INSN_ARG_INVALID_OPERAND;
 	      }
 	      if (flt_p)	/* Print a float? */
 		(*info->fprintf_func) (info->stream, "#0e%g", flval);
@@ -1113,7 +1127,7 @@ print_insn_arg (const char *d,
 	      break;
 
 	    default:
-	      return -1;
+	      return PRINT_INSN_ARG_INVALID_OPERAND;
 	    }
 	}
 
@@ -1134,7 +1148,7 @@ print_insn_arg (const char *d,
 	  {
 	    char doneany;
 	    p1 = buffer + 2;
-	    NEXTWORD (p1, val, -3);
+	    NEXTWORD (p1, val, PRINT_INSN_ARG_MEMORY_ERROR);
 	    /* Move the pointer ahead if this point is farther ahead
 	       than the last.  */
 	    p = p1 > p ? p1 : p;
@@ -1215,7 +1229,7 @@ print_insn_arg (const char *d,
 	    (*info->fprintf_func) (info->stream, "%s", fpcr_names[val]);
 	  }
 	else
-	  return -2;
+	  return PRINT_INSN_ARG_INVALID_OP_TABLE;
       break;
 
     case 'X':
@@ -1310,7 +1324,7 @@ print_insn_arg (const char *d,
       break;
 
     default:
-      return -2;
+      return PRINT_INSN_ARG_INVALID_OP_TABLE;
     }
 
   return p - p0;
@@ -1420,7 +1434,8 @@ match_insn_m68k (bfd_vma memaddr,
 
       if (eaten >= 0)
 	p += eaten;
-      else if (eaten == -1 || eaten == -3)
+      else if (eaten == PRINT_INSN_ARG_INVALID_OPERAND
+	       || eaten == PRINT_INSN_ARG_MEMORY_ERROR)
 	{
 	  info->fprintf_func = save_printer;
 	  info->print_address_func = save_print_address;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 0/8] Handle memory error on disassemble
@ 2017-01-10 12:26 Yao Qi
  2017-01-10 12:26 ` [PATCH 4/8] Return -1 on memory error in print_insn_msp430 Yao Qi
                   ` (8 more replies)
  0 siblings, 9 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:26 UTC (permalink / raw)
  To: binutils, gdb-patches

Hi,
Nowadays, we can set function pointer
disassemble_info.memory_error_func to throw error or exception when
disassembler gets an error, and the caller can/may catch the exception.
Both gdb and objdump use this interface for many years.  After GDB is
switched to C++, this stops working due to the "foreign frame" from
opcodes.  That is to say, a C++ program calls a C function
(print_insn_XXX from opcodes) and this function calls a C++ code which
throws exception.  DW2 C++ exception unwinder can unwind across the C
function frame, unless the C code is compiled with -fexceptions.  As
a result, GDB aborts on memory error during disassembly on some hosts.
See PR 20939 and patch #8 for more details.

This patch series fix this problem by stopping throwing exception
in disassemble_info.memory_error_func from gdb, but record the failed
memory address.  Exception is thrown when it is returned from opcodes
function and return value is -1.  Fortunately, most of disassemblers
in opcodes follow this convention except msp430 and m68k.  Patch 4,
5 and 6 fix these disassmblers in opcodes.  (Note that during the work
in opcodes, I find include/dis-asm.h exposes print_ins_$ARCH for each
arch, which is not necessary, because they can be got via
disassemble.c:disassembler by objdump and gdb.  This will be done
in a follow-up series.)

Patch 1 is a refactor patch, to rewrite GDB disassemble in C++, so that
1) we can record the failed memory address during disassebly, 2) easier
to do unit tests.  Patch 8 does the change in GDB to stop throwing
exception in disassemble_info.memory_error_func.  In order to make sure
such change doesn't cause any regression, patch 3 and 7 are the unit
test to GDB disassembler on normal case and error case.

Note that PR 20939 needs to be fixed on GDB 7.12 branch, which still
can be built as a C program, so I probably need to rewrite the patch
using C for 7.12 branch.

Tested binutils with all targets enabled on x86_64-linux.  Tested
gdb for {x86_64, aarch64}-linux and arm-linux (on aarch64-linux).

*** BLURB HERE ***

Yao Qi (8):
  Refactor disassembly code
  Call print_insn_mep in mep_gdb_print_insn
  Disassembly unit test: disassemble one instruction
  Return -1 on memory error in print_insn_msp430
  Remove magic numbers in m68k-dis.c:print_insn_arg
  Return -1 on  memory error in print_insn_m68k
  Disassembly unit test: memory error
  Don't throw exception in dis_asm_memory_error

 gdb/arm-tdep.c                                  |   5 +-
 gdb/disasm.c                                    | 365 +++++++++++++++++++-----
 gdb/disasm.h                                    |  56 +++-
 gdb/guile/scm-disasm.c                          |  77 ++---
 gdb/mep-tdep.c                                  |   8 +-
 gdb/mips-tdep.c                                 |   5 +-
 gdb/record-btrace.c                             |   5 +-
 gdb/selftest.c                                  |  55 ++++
 gdb/selftest.h                                  |   3 +
 gdb/spu-tdep.c                                  |  20 +-
 gdb/testsuite/gdb.base/all-architectures.exp.in |   3 +
 opcodes/m68k-dis.c                              | 114 +++++---
 opcodes/msp430-dis.c                            |  85 +++++-
 13 files changed, 580 insertions(+), 221 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 8/8] Don't throw exception in dis_asm_memory_error
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (6 preceding siblings ...)
  2017-01-10 12:27 ` [PATCH 1/8] Refactor disassembly code Yao Qi
@ 2017-01-10 12:27 ` Yao Qi
  2017-01-12 16:40   ` Pedro Alves
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:27 UTC (permalink / raw)
  To: binutils, gdb-patches

Hi,
GDB calls some APIs from opcodes to do disassembly and provide some
call backs.  This model makes troubles on C++ exception unwinding,
because GDB is a C++ program, and opcodes is still compiled as C.
As we can see, frame #10 and #12 are C++, while #frame 11 is C,

 #10 0x0000000000544228 in memory_error (err=TARGET_XFER_E_IO, memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:237
 #11 0x00000000006b0a54 in print_insn_aarch64 (pc=0, info=0xffffffffeeb0) at ../../binutils-gdb/opcodes/aarch64-dis.c:3185
 #12 0x0000000000553590 in gdb_pretty_print_insn (gdbarch=gdbarch@entry=0xbbceb0, uiout=uiout@entry=0xbc73d0, di=di@entry=0xffffffffeeb0,
    insn=0xffffffffed40, insn@entry=0xffffffffed90, flags=flags@entry=0,

C++ exception unwinder can't go across frame #11 unless it has
unwind table.  However, C program on many architectures doesn't
have it in default.  As a result, GDB aborts, which is described
in PR 20939.

This is not the first time we see this kind of problem.  We've
had a commit 89525768cd086a0798a504c81fdf7ebcd4c904e1
"Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH".
We can fix the disassembly bug in a similar way, this is the option one.

Since opcodes is built with gdb, we fix this problem in a different
way as we did for the same issue with readline.  Instead of throwing
exception in dis_asm_memory_error, we record the failed memory
address, and throw exception when GDB returns from opcodes disassemblers.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	PR gdb/20939
	* disasm.c (gdb_disassembler::dis_asm_memory_error): Don't
	call memory_error, save memaddr instead.
	(gdb_disassembler::print_insn): If gdbarch_print_insn returns
	negative, cal memory_error.
	* disasm.h (gdb_disassembler) <m_err_memaddr>: New field.

gdb/testsuite:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* gdb.base/all-architectures.exp.in (do_arch_tests): Test
	disassemble on address 0.
---
 gdb/disasm.c                                    | 12 ++++++++++--
 gdb/disasm.h                                    |  1 +
 gdb/testsuite/gdb.base/all-architectures.exp.in |  3 +++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index e908199..aa00510 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -139,7 +139,10 @@ void
 gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
 					struct disassemble_info *info)
 {
-  memory_error (TARGET_XFER_E_IO, memaddr);
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  self->m_err_memaddr = memaddr;
 }
 
 /* Like print_address with slightly different parameters.  */
@@ -955,7 +958,8 @@ fprintf_disasm (void *stream, const char *format, ...)
 gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
 				    struct ui_file *file,
 				    di_read_memory_ftype func)
-  : m_gdbarch (gdbarch)
+  : m_gdbarch (gdbarch),
+    m_err_memaddr (0)
 {
   init_disassemble_info (&m_di, file, fprintf_disasm);
   m_di.flavour = bfd_target_unknown_flavour;
@@ -981,8 +985,12 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
 int
 gdb_disassembler::print_insn (CORE_ADDR memaddr)
 {
+  m_err_memaddr = 0;
+
   int length = gdbarch_print_insn (arch (), memaddr, &m_di);
 
+  if (length < 0)
+    memory_error (TARGET_XFER_E_IO, m_err_memaddr);
   return length;
 }
 
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 5592cdb..9e89828 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -65,6 +65,7 @@ protected:
 
 private:
   struct gdbarch *m_gdbarch;
+  CORE_ADDR m_err_memaddr;
 
   static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
 				  unsigned int len,
diff --git a/gdb/testsuite/gdb.base/all-architectures.exp.in b/gdb/testsuite/gdb.base/all-architectures.exp.in
index c7615ac..50a615c 100644
--- a/gdb/testsuite/gdb.base/all-architectures.exp.in
+++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
@@ -152,6 +152,9 @@ proc print_floats {} {
 
 proc do_arch_tests {} {
     print_floats
+
+    gdb_test_internal "disassemble 0x0,+4" \
+	"Cannot access memory at address 0x0"
 }
 
 # Given we can't change arch, osabi, endianness, etc. atomically, we
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 1/8] Refactor disassembly code
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (5 preceding siblings ...)
  2017-01-10 12:27 ` [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn Yao Qi
@ 2017-01-10 12:27 ` Yao Qi
  2017-01-11 20:43   ` Simon Marchi
  2017-01-10 12:27 ` [PATCH 8/8] Don't throw exception in dis_asm_memory_error Yao Qi
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:27 UTC (permalink / raw)
  To: binutils, gdb-patches

This patch addes class gdb_disassembler, and refactor
code to use it.  The gdb_disassembler object is saved
in disassember_info.application_data.  However,
disassember_info.application_data is already used by
gdb for arm, mips spu, and scm-disasm.  In arm and mips,
.application_data is gdbarch, but we can still get gdbarch
from gdb_disassember.

The use of application_data in spu is a little bit
complicated.  It creates its own disassemble_info, and
save spu_dis_asm_data in .application_data.  This will
overwrite the pointer to gdb_disassembler, so we need
to find another place to save spu_dis_asm_data.  I
extend disassemble_info, and put "id" there.

gdb:

2017-01-10  Pedro Alves  <palves@redhat.com>
	    Yao Qi  <yao.qi@linaro.org>

	* arm-tdep.c: Include "disasm.h".
	(gdb_print_insn_arm): Update code to get gdbarch.
	* disasm.c (dis_asm_read_memory): Change it to
	gdb_disassembler::dis_asm_read_memory.
	(dis_asm_memory_error): Likewise.
	(dis_asm_print_address): Likewise.
	(gdb_pretty_print_insn): Change it to
	gdb_disassembler::pretty_print_insn.
	(dump_insns): Add one argument gdb_disassemlber.  All
	callers updated.
	(do_mixed_source_and_assembly_deprecated): Likewise.
	(do_mixed_source_and_assembly): Likewise.
	(do_assembly_only): Likewise.
	(gdb_disassembler::gdb_disassembler): New.
	(gdb_disassembler::print_insn): New.
	* disasm.h (class gdb_disassembler): New.
	(gdb_pretty_print_insn): Remove declaration.
	(gdb_disassemble_info): Likewise.
	* guile/scm-disasm.c (class gdbscm_disassembler): New.
	(gdbscm_disasm_read_memory_worker): Update.
	(gdbscm_disasm_read_memory): Update.
	(gdbscm_disasm_memory_error): Remove.
	(gdbscm_disasm_print_address): Remove.
	(gdbscm_disassembler::gdbscm_disassembler): New.
	(gdbscm_print_insn_from_port): Update.
	* mips-tdep.c: Include disasm.h.
	(gdb_print_insn_mips): Update code to get gdbarch.
	* record-btrace.c (btrace_insn_history): Update.
	* spu-tdep.c: Include disasm.h.
	(struct spu_dis_asm_data): Remove.
	(struct spu_dis_asm_info): New.
	(spu_dis_asm_print_address): Use spu_dis_asm_info to get
	SPU id.
	(gdb_print_insn_spu): Cast disassemble_info to
	spu_dis_asm_info.
---
 gdb/arm-tdep.c         |   5 +-
 gdb/disasm.c           | 159 ++++++++++++++++++++++++++++---------------------
 gdb/disasm.h           |  55 +++++++++++++----
 gdb/guile/scm-disasm.c |  77 +++++++-----------------
 gdb/mips-tdep.c        |   5 +-
 gdb/record-btrace.c    |   5 +-
 gdb/spu-tdep.c         |  20 +++----
 7 files changed, 172 insertions(+), 154 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 2bdfa57..0ae311f 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -27,6 +27,7 @@
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "dis-asm.h"		/* For register styles.  */
+#include "disasm.h"
 #include "regcache.h"
 #include "reggroups.h"
 #include "doublest.h"
@@ -7739,7 +7740,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
 static int
 gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   if (arm_pc_is_thumb (gdbarch, memaddr))
     {
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 84a03e9..6a3f3aa 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -120,28 +120,34 @@ line_has_code_p (htab_t table, struct symtab *symtab, int line)
 }
 
 /* Like target_read_memory, but slightly different parameters.  */
-static int
-dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
-		     struct disassemble_info *info)
+
+int
+gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				       unsigned int len,
+				       struct disassemble_info *info)
 {
   return target_read_code (memaddr, myaddr, len);
 }
 
 /* Like memory_error with slightly different parameters.  */
-static void
-dis_asm_memory_error (int err, bfd_vma memaddr,
-		      struct disassemble_info *info)
+
+void
+gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
+					struct disassemble_info *info)
 {
   memory_error (TARGET_XFER_E_IO, memaddr);
 }
 
 /* Like print_address with slightly different parameters.  */
-static void
-dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+
+void
+gdb_disassembler::dis_asm_print_address (bfd_vma addr,
+					 struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
 
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
+  print_address (self->arch (), addr, self->stream ());
 }
 
 static int
@@ -173,10 +179,9 @@ compare_lines (const void *mle1p, const void *mle2p)
 /* 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)
+gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
+				     const struct disasm_insn *insn,
+				     int flags)
 {
   /* parts of the symbolic representation of the address */
   int unmapped;
@@ -187,6 +192,8 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
   char *filename = NULL;
   char *name = NULL;
   CORE_ADDR pc;
+  struct ui_file *stb = stream ();
+  struct gdbarch *gdbarch = arch ();
 
   ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
   pc = insn->addr;
@@ -254,14 +261,14 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       struct cleanup *cleanups =
 	make_cleanup_ui_file_delete (opcode_stream);
 
-      size = gdbarch_print_insn (gdbarch, pc, di);
+      size = print_insn (pc);
       end_pc = pc + size;
 
       for (;pc < end_pc; ++pc)
 	{
-	  err = (*di->read_memory_func) (pc, &data, 1, di);
+	  err = m_di.read_memory_func (pc, &data, 1, &m_di);
 	  if (err != 0)
-	    (*di->memory_error_func) (err, pc, di);
+	    m_di.memory_error_func (err, pc, &m_di);
 	  fprintf_filtered (opcode_stream, "%s%02x",
 			    spacer, (unsigned) data);
 	  spacer = " ";
@@ -273,7 +280,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       do_cleanups (cleanups);
     }
   else
-    size = gdbarch_print_insn (gdbarch, pc, di);
+    size = print_insn (pc);
 
   uiout->field_stream ("inst", stb);
   ui_file_rewind (stb);
@@ -284,10 +291,9 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static int
-dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
-	    struct disassemble_info * di,
+dump_insns (struct ui_out *uiout, gdb_disassembler *di,
 	    CORE_ADDR low, CORE_ADDR high,
-	    int how_many, int flags, struct ui_file *stb,
+	    int how_many, int flags,
 	    CORE_ADDR *end_pc)
 {
   struct disasm_insn insn;
@@ -300,7 +306,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
     {
       int size;
 
-      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
+      size = di->pretty_print_insn (uiout, &insn, flags);
       if (size <= 0)
 	break;
 
@@ -326,10 +332,10 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 
 static void
 do_mixed_source_and_assembly_deprecated
-  (struct gdbarch *gdbarch, struct ui_out *uiout,
-   struct disassemble_info *di, struct symtab *symtab,
+  (struct ui_out *uiout,
+   gdb_disassembler *di, struct symtab *symtab,
    CORE_ADDR low, CORE_ADDR high,
-   int how_many, int flags, struct ui_file *stb)
+   int how_many, int flags)
 {
   int newlines = 0;
   int nlines;
@@ -462,9 +468,9 @@ do_mixed_source_and_assembly_deprecated
 	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
 	}
 
-      num_displayed += dump_insns (gdbarch, uiout, di,
+      num_displayed += dump_insns (uiout, di,
 				   mle[i].start_pc, mle[i].end_pc,
-				   how_many, flags, stb, NULL);
+				   how_many, flags, NULL);
 
       /* 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.  */
@@ -488,11 +494,12 @@ do_mixed_source_and_assembly_deprecated
    immediately following.  */
 
 static void
-do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
-			      struct disassemble_info *di,
+do_mixed_source_and_assembly (struct gdbarch *gdbarch,
+			      struct ui_out *uiout,
+			      gdb_disassembler *di,
 			      struct symtab *main_symtab,
 			      CORE_ADDR low, CORE_ADDR high,
-			      int how_many, int flags, struct ui_file *stb)
+			      int how_many, int flags)
 {
   const struct linetable_entry *le, *first_le;
   int i, nlines;
@@ -716,8 +723,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 	end_pc = std::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);
+      num_displayed += dump_insns (uiout, di, pc, end_pc,
+				   how_many, flags, &end_pc);
       pc = end_pc;
 
       if (how_many >= 0 && num_displayed >= how_many)
@@ -732,16 +739,16 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static void
-do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
-		  struct disassemble_info * di,
+do_assembly_only (struct ui_out *uiout,
+		  gdb_disassembler *di,
 		  CORE_ADDR low, CORE_ADDR high,
-		  int how_many, int flags, struct ui_file *stb)
+		  int how_many, int flags)
 {
   struct cleanup *ui_out_chain;
 
   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
 
-  dump_insns (gdbarch, uiout, di, low, high, how_many, flags, stb, NULL);
+  dump_insns (uiout, di, low, high, how_many, flags, NULL);
 
   do_cleanups (ui_out_chain);
 }
@@ -761,15 +768,15 @@ fprintf_disasm (void *stream, const char *format, ...)
   return 0;
 }
 
-struct disassemble_info
-gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
+gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
+				    struct ui_file *file,
+				    di_read_memory_ftype func)
+  : m_gdbarch (gdbarch)
 {
-  struct disassemble_info di;
-
-  init_disassemble_info (&di, file, fprintf_disasm);
-  di.flavour = bfd_target_unknown_flavour;
-  di.memory_error_func = dis_asm_memory_error;
-  di.print_address_func = dis_asm_print_address;
+  init_disassemble_info (&m_di, file, fprintf_disasm);
+  m_di.flavour = bfd_target_unknown_flavour;
+  m_di.memory_error_func = dis_asm_memory_error;
+  m_di.print_address_func = dis_asm_print_address;
   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
      disassembler had a local optomization here.  By default it would
      access the executable file, instead of the target memory (there
@@ -778,14 +785,37 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
      didn't work as they relied on the access going to the target.
      Further, it has been supperseeded by trust-read-only-sections
      (although that should be superseeded by target_trust..._p()).  */
-  di.read_memory_func = dis_asm_read_memory;
-  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
-  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
-  di.endian = gdbarch_byte_order (gdbarch);
-  di.endian_code = gdbarch_byte_order_for_code (gdbarch);
-  di.application_data = gdbarch;
-  disassemble_init_for_target (&di);
-  return di;
+  m_di.read_memory_func = func;
+  m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  m_di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  m_di.endian = gdbarch_byte_order (gdbarch);
+  m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
+  m_di.application_data = this;
+  disassemble_init_for_target (&m_di);
+}
+
+int
+gdb_disassembler::print_insn (CORE_ADDR memaddr)
+{
+  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+
+  return length;
+}
+
+int
+gdb_disassembler::print_insn (CORE_ADDR memaddr,
+			      int *branch_delay_insns)
+{
+  int length = print_insn (memaddr);
+
+  if (branch_delay_insns != NULL)
+    {
+      if (m_di.insn_info_valid)
+	*branch_delay_insns = m_di.branch_delay_insns;
+      else
+	*branch_delay_insns = 0;
+    }
+  return length;
 }
 
 void
@@ -795,7 +825,7 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 {
   struct ui_file *stb = mem_fileopen ();
   struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
-  struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   struct symtab *symtab;
   int nlines = -1;
 
@@ -807,15 +837,15 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 
   if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
       || nlines <= 0)
-    do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
+    do_assembly_only (uiout, &di, low, high, how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE)
     do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
-				  how_many, flags, stb);
+				  how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
-    do_mixed_source_and_assembly_deprecated (gdbarch, uiout, &di, symtab,
-					     low, high, how_many, flags, stb);
+    do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+					     low, high, how_many, flags);
 
   do_cleanups (cleanups);
   gdb_flush (gdb_stdout);
@@ -829,19 +859,10 @@ int
 gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
 		struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
 
-  di = gdb_disassemble_info (gdbarch, stream);
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
-  return length;
+  gdb_disassembler di (gdbarch, stream);
+
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 static void
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 4c6fd54..5592cdb 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -33,6 +33,48 @@ struct gdbarch;
 struct ui_out;
 struct ui_file;
 
+class gdb_disassembler
+{
+  using di_read_memory_ftype = decltype (disassemble_info::read_memory_func);
+
+public:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
+    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
+  {}
+
+  int print_insn (CORE_ADDR memaddr);
+  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns);
+
+  /* Prints the instruction INSN into UIOUT and returns the length of
+     the printed instruction in bytes.  */
+  int pretty_print_insn (struct ui_out *uiout,
+			 const struct disasm_insn *insn, int flags);
+
+  /* Return the gdbarch of gdb_disassembler.  */
+  struct gdbarch *arch ()
+  { return m_gdbarch; }
+
+protected:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
+		    di_read_memory_ftype func);
+
+  struct ui_file *stream ()
+  { return (struct ui_file *) m_di.stream; }
+
+  struct disassemble_info m_di;
+
+private:
+  struct gdbarch *m_gdbarch;
+
+  static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				  unsigned int len,
+				  struct disassemble_info *info);
+  static void dis_asm_memory_error (int err, bfd_vma memaddr,
+				    struct disassemble_info *info);
+  static void dis_asm_print_address (bfd_vma addr,
+				     struct disassemble_info *info);
+};
+
 /* An instruction to be disassembled.  */
 
 struct disasm_insn
@@ -47,19 +89,6 @@ struct disasm_insn
   unsigned int is_speculative:1;
 };
 
-/* Prints the instruction INSN into UIOUT and returns the length of the
-   printed instruction in bytes.  */
-
-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);
-
-/* Return a filled in disassemble_info object for use by gdb.  */
-
-extern struct disassemble_info gdb_disassemble_info (struct gdbarch *gdbarch,
-						     struct ui_file *file);
-
 extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 			     char *file_string, int flags, int how_many,
 			     CORE_ADDR low, CORE_ADDR high);
diff --git a/gdb/guile/scm-disasm.c b/gdb/guile/scm-disasm.c
index d06c481..25cae5a 100644
--- a/gdb/guile/scm-disasm.c
+++ b/gdb/guile/scm-disasm.c
@@ -37,11 +37,13 @@ static SCM address_symbol;
 static SCM asm_symbol;
 static SCM length_symbol;
 
-/* Struct used to pass "application data" in disassemble_info.  */
-
-struct gdbscm_disasm_data
+class gdbscm_disassembler : public gdb_disassembler
 {
-  struct gdbarch *gdbarch;
+public:
+  gdbscm_disassembler (struct gdbarch *gdbarch,
+		       struct ui_file *stream,
+		       SCM port, ULONGEST offset);
+
   SCM port;
   /* The offset of the address of the first instruction in PORT.  */
   ULONGEST offset;
@@ -55,7 +57,7 @@ struct gdbscm_disasm_read_data
   bfd_vma memaddr;
   bfd_byte *myaddr;
   unsigned int length;
-  struct disassemble_info *dinfo;
+  gdbscm_disassembler *dinfo;
 };
 \f
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -81,13 +83,11 @@ gdbscm_disasm_read_memory_worker (void *datap)
 {
   struct gdbscm_disasm_read_data *data
     = (struct gdbscm_disasm_read_data *) datap;
-  struct disassemble_info *dinfo = data->dinfo;
-  struct gdbscm_disasm_data *disasm_data
-    = (struct gdbscm_disasm_data *) dinfo->application_data;
-  SCM seekto, newpos, port = disasm_data->port;
+  gdbscm_disassembler *dinfo = data->dinfo;
+  SCM seekto, newpos, port = dinfo->port;
   size_t bytes_read;
 
-  seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->offset);
+  seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
   newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
   if (!scm_is_eq (seekto, newpos))
     return "seek error";
@@ -108,13 +108,15 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
 			   unsigned int length,
 			   struct disassemble_info *dinfo)
 {
+  gdbscm_disassembler *self
+    = static_cast<gdbscm_disassembler *> (dinfo->application_data);
   struct gdbscm_disasm_read_data data;
   const char *status;
 
   data.memaddr = memaddr;
   data.myaddr = myaddr;
   data.length = length;
-  data.dinfo = dinfo;
+  data.dinfo = self;
 
   status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
 
@@ -123,30 +125,12 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
   return status != NULL ? -1 : 0;
 }
 
-/* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
-   Technically speaking, we don't need our own memory_error_func,
-   but to not provide one would leave a subtle dependency in the code.
-   This function exists to keep a clear boundary.  */
-
-static void
-gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
-			    struct disassemble_info *info)
-{
-  memory_error (TARGET_XFER_E_IO, memaddr);
-}
-
-/* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
-   Since we need to use our own application_data value, we need to supply
-   this routine as well.  */
-
-static void
-gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
+gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
+					  struct ui_file *stream,
+					  SCM port_, ULONGEST offset_)
+  : gdb_disassembler (gdbarch, stream, gdbscm_disasm_read_memory),
+    port (port_), offset (offset_)
 {
-  struct gdbscm_disasm_data *data
-    = (struct gdbscm_disasm_data *) info->application_data;
-  struct gdbarch *gdbarch = data->gdbarch;
-
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
 }
 
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -164,30 +148,9 @@ gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
 			     SCM port, ULONGEST offset, CORE_ADDR memaddr,
 			     struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
-  struct gdbscm_disasm_data data;
-
-  di = gdb_disassemble_info (gdbarch, stream);
-  data.gdbarch = gdbarch;
-  data.port = port;
-  data.offset = offset;
-  di.application_data = &data;
-  di.read_memory_func = gdbscm_disasm_read_memory;
-  di.memory_error_func = gdbscm_disasm_memory_error;
-  di.print_address_func = gdbscm_disasm_print_address;
-
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
+  gdbscm_disassembler di (gdbarch, stream, port, offset);
 
-  return length;
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 /* (arch-disassemble <gdb:arch> address
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 637b34e..41cb9d8 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -44,6 +44,7 @@
 #include "symcat.h"
 #include "sim-regno.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
 #include "trad-frame.h"
@@ -6982,7 +6983,9 @@ reinit_frame_cache_sfunc (char *args, int from_tty,
 static int
 gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   /* FIXME: cagney/2003-06-26: Is this even necessary?  The
      disassembler needs to be able to locally determine the ISA, and
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 6cba1d2..8896241 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -698,7 +698,6 @@ btrace_insn_history (struct ui_out *uiout,
 {
   struct ui_file *stb;
   struct cleanup *cleanups, *ui_item_chain;
-  struct disassemble_info di;
   struct gdbarch *gdbarch;
   struct btrace_insn_iterator it;
   struct btrace_line_range last_lines;
@@ -711,7 +710,7 @@ btrace_insn_history (struct ui_out *uiout,
   gdbarch = target_gdbarch ();
   stb = mem_fileopen ();
   cleanups = make_cleanup_ui_file_delete (stb);
-  di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   last_lines = btrace_mk_line_range (NULL, 0, 0);
 
   make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
@@ -773,7 +772,7 @@ 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);
+	  di.pretty_print_insn (uiout, &dinsn, flags);
 	}
     }
 
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 8756256..70d7f6f 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -33,6 +33,7 @@
 #include "value.h"
 #include "inferior.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "objfiles.h"
 #include "language.h"
 #include "regcache.h"
@@ -1693,18 +1694,19 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 
 /* Disassembler.  */
 
-struct spu_dis_asm_data
+struct spu_dis_asm_info : disassemble_info
 {
-  struct gdbarch *gdbarch;
   int id;
 };
 
 static void
 spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
 {
-  struct spu_dis_asm_data *data
-    = (struct spu_dis_asm_data *) info->application_data;
-  print_address (data->gdbarch, SPUADDR (data->id, addr),
+  struct spu_dis_asm_info *data = (struct spu_dis_asm_info *) info;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  print_address (di->arch (), SPUADDR (data->id, addr),
 		 (struct ui_file *) info->stream);
 }
 
@@ -1714,12 +1716,10 @@ gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
   /* The opcodes disassembler does 18-bit address arithmetic.  Make
      sure the SPU ID encoded in the high bits is added back when we
      call print_address.  */
-  struct disassemble_info spu_info = *info;
-  struct spu_dis_asm_data data;
-  data.gdbarch = (struct gdbarch *) info->application_data;
-  data.id = SPUADDR_SPU (memaddr);
+  struct spu_dis_asm_info spu_info;
 
-  spu_info.application_data = &data;
+  memcpy (&spu_info, info, sizeof (*info));
+  spu_info.id = SPUADDR_SPU (memaddr);
   spu_info.print_address_func = spu_dis_asm_print_address;
   return print_insn_spu (memaddr, &spu_info);
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (4 preceding siblings ...)
  2017-01-10 12:26 ` [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg Yao Qi
@ 2017-01-10 12:27 ` Yao Qi
  2017-01-11 20:50   ` Simon Marchi
  2017-01-10 12:27 ` [PATCH 1/8] Refactor disassembly code Yao Qi
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-10 12:27 UTC (permalink / raw)
  To: binutils, gdb-patches

opcodes/mep-dis.c:mep_print_insn has already had the code to
handle the case when info->section is NULL,

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
    }
  else /* sid or gdb */
    {
    }

so that we can still cal print_insn_mep even section can't be found.
On the other hand, user can disassemble an arbitrary address which
doesn't map to any section at all.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* mep-tdep.c (mep_gdb_print_insn): Set info->arch
	to bfd_arch_mep.  Don't return 0 if section is not
	found.  Call print_insn_mep.
---
 gdb/mep-tdep.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
index 68b0c4b..7d04983 100644
--- a/gdb/mep-tdep.c
+++ b/gdb/mep-tdep.c
@@ -1273,6 +1273,7 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
 {
   struct obj_section * s = find_pc_section (pc);
 
+  info->arch = bfd_arch_mep;
   if (s)
     {
       /* The libopcodes disassembly code uses the section to find the
@@ -1280,12 +1281,9 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
          the me_module index, and the me_module index to select the
          right instructions to print.  */
       info->section = s->the_bfd_section;
-      info->arch = bfd_arch_mep;
-	
-      return print_insn_mep (pc, info);
     }
-  
-  return 0;
+
+  return print_insn_mep (pc, info);
 }
 
 \f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/8] Refactor disassembly code
  2017-01-10 12:27 ` [PATCH 1/8] Refactor disassembly code Yao Qi
@ 2017-01-11 20:43   ` Simon Marchi
  2017-01-12 12:19     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Simon Marchi @ 2017-01-11 20:43 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On 2017-01-10 07:26, Yao Qi wrote:
> @@ -761,15 +768,15 @@ fprintf_disasm (void *stream, const char *format, 
> ...)
>    return 0;
>  }
> 
> -struct disassemble_info
> -gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
> +gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
> +				    struct ui_file *file,
> +				    di_read_memory_ftype func)

Perhaps name this parameter "read_memory_func"?

> diff --git a/gdb/disasm.h b/gdb/disasm.h
> index 4c6fd54..5592cdb 100644
> --- a/gdb/disasm.h
> +++ b/gdb/disasm.h
> @@ -33,6 +33,48 @@ struct gdbarch;
>  struct ui_out;
>  struct ui_file;
> 
> +class gdb_disassembler
> +{
> +  using di_read_memory_ftype = decltype 
> (disassemble_info::read_memory_func);
> +
> +public:
> +  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
> +    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
> +  {}
> +
> +  int print_insn (CORE_ADDR memaddr);
> +  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns);

Not very important, but since print_insn(CORE_ADDR) is trivial, you 
could merge those two methods and provide a default parameter value of 
NULL for branch_delay_insns.

> +
> +  /* Prints the instruction INSN into UIOUT and returns the length of
> +     the printed instruction in bytes.  */
> +  int pretty_print_insn (struct ui_out *uiout,
> +			 const struct disasm_insn *insn, int flags);

It could be a good time to modernize the flags parameter and make it an 
enum flag.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn
  2017-01-10 12:27 ` [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn Yao Qi
@ 2017-01-11 20:50   ` Simon Marchi
  2017-01-12 12:21     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Simon Marchi @ 2017-01-11 20:50 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On 2017-01-10 07:26, Yao Qi wrote:
> diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
> index 68b0c4b..7d04983 100644
> --- a/gdb/mep-tdep.c
> +++ b/gdb/mep-tdep.c
> @@ -1273,6 +1273,7 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info 
> * info)
>  {
>    struct obj_section * s = find_pc_section (pc);
> 
> +  info->arch = bfd_arch_mep;
>    if (s)
>      {
>        /* The libopcodes disassembly code uses the section to find the
> @@ -1280,12 +1281,9 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info 
> * info)
>           the me_module index, and the me_module index to select the
>           right instructions to print.  */
>        info->section = s->the_bfd_section;
> -      info->arch = bfd_arch_mep;
> -
> -      return print_insn_mep (pc, info);
>      }
> -
> -  return 0;
> +
> +  return print_insn_mep (pc, info);
>  }
> 
>  \f

Does the comment above mep_gdb_print_insn need to be changed?

/* The mep disassembler needs to know about the section in order to
    work correctly.  */

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
@ 2017-01-11 21:15   ` Simon Marchi
  2017-01-12 13:06   ` Pedro Alves
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 80+ messages in thread
From: Simon Marchi @ 2017-01-11 21:15 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On 2017-01-10 07:26, Yao Qi wrote:
> @@ -290,6 +294,139 @@ gdb_disassembler::pretty_print_insn (struct 
> ui_out *uiout,
>    return size;
>  }
> 
> +#if GDB_SELF_TEST
> +
> +namespace selftests {
> +
> +/* Test disassembly one instruction.  */

I'd say either

   /* Test disassembly of one instruction.  */

or

   /* Test disassembling one instruction.  */

> +
> +static void
> +gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
> +{
> +  int len = -1;
> +  const gdb_byte *insn = NULL;
> +
> +  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
> +    {
> +    case bfd_arch_bfin:
> +      /* M3.L = 0xe117 */
> +      insn = (const gdb_byte[]) {0x17, 0xe1, 0xff, 0xff};
> +      len = 4;
> +      break;
> +    case bfd_arch_arm:
> +      /* mov     r0, #0 */
> +      insn = (const gdb_byte[]) {0x0, 0x0, 0xa0, 0xe3};
> +      len = 4;
> +      break;
> +    case bfd_arch_ia64:
> +    case bfd_arch_mep:
> +    case bfd_arch_mips:
> +    case bfd_arch_tic6x:
> +    case bfd_arch_xtensa:
> +      return;
> +    case bfd_arch_s390:
> +      /* nopr %r7 */
> +      insn = (const gdb_byte[]) {0x07, 0x07};
> +      len = 2;
> +      break;
> +    case bfd_arch_xstormy16:
> +      /* nop */
> +      insn = (const gdb_byte[]) {0x0, 0x0};
> +      len = 2;
> +      break;
> +    case bfd_arch_arc:
> +      {
> +	/* PR 21003 */
> +	if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
> +	  return;
> +      }
> +    case bfd_arch_nios2:
> +    case bfd_arch_score:
> +      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &len);
> +      break;
> +    case bfd_arch_sh:
> +      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 2, &len);
> +      break;

Is there a reason why these two can't fall in the default case?  If so, 
maybe add a comment explaining why?

> +  private:
> +    const gdb_byte *m_insn;
> +
> +    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +			    unsigned int len, struct disassemble_info *info)
> +    {
> +      gdb_disassembler_test *self
> +	= static_cast<gdb_disassembler_test *>(info->application_data);
> +
> +      memcpy (myaddr, self->m_insn, len);

Would this break if the disassembler decided to do a memory read at 
memaddr != 0?  I suppose it doesn't happen in practice now since the 
test passes, but it might some day, like if we make a test that 
disassembles more than one instruction.

I'd suggest either putting some kind of assert here that memaddr == 0, 
or consider memaddr in the copy, ideally with some bounds checking.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/8] Return -1 on memory error in print_insn_msp430
  2017-01-10 12:26 ` [PATCH 4/8] Return -1 on memory error in print_insn_msp430 Yao Qi
@ 2017-01-11 21:54   ` Alan Modra
  2017-01-12  9:43     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Alan Modra @ 2017-01-11 21:54 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On Tue, Jan 10, 2017 at 12:26:14PM +0000, Yao Qi wrote:
> 	* msp430-dis.c (msp430_singleoperand): Return -1 if
> 	msp430dis_opcode_signed returns false.
> 	(msp430_doubleoperand): Likewise.
> 	(msp430_branchinstr): Return -1 if
> 	msp430dis_opcode_unsigned returns false.
> 	(msp430x_calla_instr): Likewise.
> 	(print_insn_msp430): Likewise.

You missed nine msp430dis_opcode_signed calls.  OK with those done too.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg
  2017-01-10 12:26 ` [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg Yao Qi
@ 2017-01-11 22:14   ` Alan Modra
  2017-01-13 12:23     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Alan Modra @ 2017-01-11 22:14 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On Tue, Jan 10, 2017 at 12:26:15PM +0000, Yao Qi wrote:
> 	* m68k-dis.c (enum print_insn_arg_error): New.
> 	(NEXTBYTE): Replace -3 with
> 	PRINT_INSN_ARG_MEMORY_ERROR.
> 	(NEXTULONG): Likewise.
> 	(NEXTSINGLE): Likewise.
> 	(NEXTDOUBLE): Likewise.
> 	(NEXTDOUBLE): Likewise.
> 	(NEXTPACKED): Likewise.
> 	(FETCH_DATA): Update comments.
> 	(print_insn_arg): Update comments. Replace magic numbers with
> 	enum.
> 	(match_insn_m68k): Likewise.

OK.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-10 12:26 ` [PATCH 6/8] Return -1 on memory error in print_insn_m68k Yao Qi
@ 2017-01-11 22:15   ` Alan Modra
  2017-01-12 11:50     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Alan Modra @ 2017-01-11 22:15 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On Tue, Jan 10, 2017 at 12:26:16PM +0000, Yao Qi wrote:
> 	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
> 	if FETCH_DATA returns 0.
> 	(m68k_scan_mask): Likewise.
> 	(print_insn_m68k): Update code to handle -1 return value.

This misses one FETCH_DATA call, in m68k_scan_mask.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/8] Return -1 on memory error in print_insn_msp430
  2017-01-11 21:54   ` Alan Modra
@ 2017-01-12  9:43     ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-12  9:43 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, gdb-patches

On 17-01-12 08:24:46, Alan Modra wrote:
> On Tue, Jan 10, 2017 at 12:26:14PM +0000, Yao Qi wrote:
> > 	* msp430-dis.c (msp430_singleoperand): Return -1 if
> > 	msp430dis_opcode_signed returns false.
> > 	(msp430_doubleoperand): Likewise.
> > 	(msp430_branchinstr): Return -1 if
> > 	msp430dis_opcode_unsigned returns false.
> > 	(msp430x_calla_instr): Likewise.
> > 	(print_insn_msp430): Likewise.
> 
> You missed nine msp430dis_opcode_signed calls.  OK with those done too.
> 

Looks cscope missed some "Functions calling this function: msp430dis_opcode_signed"
but "C symbol: msp430dis_opcode_signed" can capture all of them.  Fixed.

Patch below is what I pushed in.

-- 
Yao (齐尧)

From d95014a2ef6e9aee927c13960fa37e509d46eb32 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao.qi@linaro.org>
Date: Thu, 12 Jan 2017 09:40:41 +0000
Subject: [PATCH] Return -1 on memory error in print_insn_msp430

Disassemblers in opcodes return -1 on memory error, but msp430 doesn't
follow this convention.  If I change GDB not to throw exception in
disassemble_info.memory_error_func and rely on the return value of
disassembler, I'll get the following output.

(gdb) disassemble 0x0,+8
Dump of assembler code from 0x0 to 0x8:
   0x00000000:  .word   0xffff; ????
   0x00000002:  .word   0xffff; ????
   0x00000004:  .word   0xffff; ????
   0x00000006:  .word   0xffff; ????
End of assembler dump.

This patch teaches print_insn_msp430 and its callees to return -1
on memory error.

opcodes:

2017-01-12  Yao Qi  <yao.qi@linaro.org>

	* msp430-dis.c (msp430_singleoperand): Return -1 if
	msp430dis_opcode_signed returns false.
	(msp430_doubleoperand): Likewise.
	(msp430_branchinstr): Return -1 if
	msp430dis_opcode_unsigned returns false.
	(msp430x_calla_instr): Likewise.
	(print_insn_msp430): Likewise.

diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 8494c51..5d670f6 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,13 @@
+2017-01-12  Yao Qi  <yao.qi@linaro.org>
+
+	* msp430-dis.c (msp430_singleoperand): Return -1 if
+	msp430dis_opcode_signed returns false.
+	(msp430_doubleoperand): Likewise.
+	(msp430_branchinstr): Return -1 if
+	msp430dis_opcode_unsigned returns false.
+	(msp430x_calla_instr): Likewise.
+	(print_insn_msp430): Likewise.
+
 2017-01-05  Nick Clifton  <nickc@redhat.com>
 
 	PR 20946
diff --git a/opcodes/msp430-dis.c b/opcodes/msp430-dis.c
index 9c62193..58d31df 100644
--- a/opcodes/msp430-dis.c
+++ b/opcodes/msp430-dis.c
@@ -270,6 +270,8 @@ msp430_singleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -285,6 +287,8 @@ msp430_singleoperand (disassemble_info *info,
 		      sprintf (op, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    {
@@ -300,6 +304,8 @@ msp430_singleoperand (disassemble_info *info,
 		    }
 		  sprintf (op, "%d(r%d)", dst, regd);
 		}
+	      else
+		return -1;
 	    }
 	}
       break;
@@ -346,6 +352,8 @@ msp430_singleoperand (disassemble_info *info,
 			sprintf (comm, "#0x%05x", dst);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
@@ -370,6 +378,8 @@ msp430_singleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -384,6 +394,8 @@ msp430_singleoperand (disassemble_info *info,
 		      sprintf (op, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 3)
 	    {
@@ -407,6 +419,8 @@ msp430_singleoperand (disassemble_info *info,
 		  if (dst > 9 || dst < 0)
 		    sprintf (comm, "%05x", dst);
 		}
+	      else
+		return -1;
 	    }
 	}
       break;
@@ -511,6 +525,8 @@ msp430_doubleoperand (disassemble_info *info,
 			       (long)((addr + 2 + dst) & 0xfffff));
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else if (regd == 2)
 	    {
@@ -526,6 +542,8 @@ msp430_doubleoperand (disassemble_info *info,
 		      if (src != dst)
 			return 0;
 		    }
+		  else
+		    return -1;
 		  cmd_len += 4;
 		  *cycles = 6;
 		  sprintf (op1, "&0x%04x", PS (dst));
@@ -535,6 +553,8 @@ msp430_doubleoperand (disassemble_info *info,
 		      sprintf (op1, "&0x%05x", dst & 0xfffff);
 		    }
 		}
+	      else
+		return -1;
 	    }
 	  else
 	    {
@@ -553,6 +573,8 @@ msp430_doubleoperand (disassemble_info *info,
 		  if (dst > 9 || dst < -9)
 		    sprintf (comm1, "#0x%05x", dst);
 		}
+	      else
+		return -1;
 	    }
 	}
 
@@ -613,6 +635,8 @@ msp430_doubleoperand (disassemble_info *info,
 		    sprintf (comm1, "0x%05x", dst & 0xfffff);
 		}
 	    }
+	  else
+	    return -1;
 	}
       else
 	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
@@ -640,6 +664,8 @@ msp430_doubleoperand (disassemble_info *info,
 			   (long) ((addr + 2 + dst) & 0xfffff));
 		}
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 2)
 	{
@@ -658,6 +684,8 @@ msp430_doubleoperand (disassemble_info *info,
 		  * comm1 = 0;
 		}
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 3)
 	{
@@ -683,6 +711,8 @@ msp430_doubleoperand (disassemble_info *info,
 	      if (dst > 9 || dst < -9)
 		sprintf (comm1, "0x%05x", dst);
 	    }
+	  else
+	    return -1;
 	}
     }
 
@@ -728,6 +758,8 @@ msp430_doubleoperand (disassemble_info *info,
 			   (long)((addr + cmd_len + dst) & 0xfffff));
 		}
 	    }
+	  else
+	    return -1;
 	  cmd_len += 2;
 	}
       else if (regd == 2)
@@ -743,6 +775,8 @@ msp430_doubleoperand (disassemble_info *info,
 		  sprintf (op2, "&0x%05x", dst & 0xfffff);
 		}
 	    }
+	  else
+	    return -1;
 	}
       else
 	{
@@ -761,6 +795,8 @@ msp430_doubleoperand (disassemble_info *info,
 		}
 	      sprintf (op2, "%d(r%d)", dst, regd);
 	    }
+	  else
+	    return -1;
 	}
     }
 
@@ -821,6 +857,8 @@ msp430_branchinstr (disassemble_info *info,
 	      cmd_len += 2;
 	      sprintf (op1, "#0x%04x", PS (udst));
 	    }
+	  else
+	    return -1;
 	}
       else
 	* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
@@ -840,6 +878,8 @@ msp430_branchinstr (disassemble_info *info,
 	      sprintf (comm1, "PC rel. 0x%04x",
 		       PS ((short) addr + 2 + dst));
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 2)
 	{
@@ -849,6 +889,8 @@ msp430_branchinstr (disassemble_info *info,
 	      cmd_len += 2;
 	      sprintf (op1, "&0x%04x", PS (udst));
 	    }
+	  else
+	    return -1;
 	}
       else if (regs == 3)
 	{
@@ -864,6 +906,8 @@ msp430_branchinstr (disassemble_info *info,
 	      cmd_len += 2;
 	      sprintf (op1, "%d(r%d)", dst, regs);
 	    }
+	  else
+	    return -1;
 	}
     }
 
@@ -903,6 +947,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  else
 	    sprintf (comm1, "0x%05x", dst);
 	}
+      else
+	return -1;
       break;
 
     case 6: /* CALLA @Rdst */
@@ -923,6 +969,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  sprintf (op1, "&%d", (ureg << 16) + udst);
 	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
 	}
+      else
+	return -1;
       break;
 
     case 9: /* CALLA pcrel-sym */
@@ -934,6 +982,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  sprintf (comm1, "PC rel. 0x%05lx",
 		   (long) (addr + 2 + dst + (reg << 16)));
 	}
+      else
+	return -1;
       break;
 
     case 11: /* CALLA #imm20 */
@@ -944,6 +994,8 @@ msp430x_calla_instr (disassemble_info * info,
 	  sprintf (op1, "#%d", (ureg << 16) + udst);
 	  sprintf (comm1, "0x%05x", (ureg << 16) + udst);
 	}
+      else
+	return -1;
       break;
 
     default:
@@ -969,10 +1021,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
   unsigned short bits;
 
   if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
-    {
-      prin (stream, ".word	0xffff;	????");
-      return 2;
-    }
+    return -1;
 
   if (((int) addr & 0xffff) > 0xffdf)
     {
@@ -989,11 +1038,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
       extension_word = insn;
       addr += 2;
       if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
-	{
-	  prin (stream, ".word	0x%04x, 0xffff;	????",
-		extension_word);
-	  return 4;
-	}
+	return -1;
    }
 
   for (opcode = msp430_opcodes; opcode->name; opcode++)
@@ -1011,9 +1056,13 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 	      && (insn & 0x000f) == 0
 	      && (insn & 0x0080) == 0)
 	    {
-	      cmd_len +=
+	      int ret =
 		msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
 				    &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (cmd_len)
 		break;
 	    }
@@ -1022,10 +1071,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 	    {
 	      int n;
 	      int reg;
+	      int ret;
 
 	    case 4:
-	      cmd_len += msp430x_calla_instr (info, addr, insn,
-					      op1, comm1, & cycles);
+	      ret = msp430x_calla_instr (info, addr, insn,
+					 op1, comm1, & cycles);
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      break;
 
 	    case 5: /* PUSHM/POPM */
@@ -1080,6 +1133,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (n > 9 || n < 0)
 			sprintf (comm1, "0x%05x", n);
 		    }
+		  else
+		    return -1;
 		  cmd_len = 4;
 		}
 	      sprintf (op2, "r%d", reg);
@@ -1120,6 +1175,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (strcmp (opcode->name, "bra") != 0)
 			sprintf (op2, "r%d", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 3: /* MOVA x(Rsrc), Rdst */
@@ -1139,6 +1196,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 			    sprintf (comm1, "0x%05x", n);
 			}
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 6: /* MOVA Rsrc, &abs20 */
@@ -1152,6 +1211,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (reg > 9 || reg < 0)
 			sprintf (comm2, "0x%05x", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 7: /* MOVA Rsrc, x(Rdst) */
@@ -1169,6 +1230,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 			    sprintf (comm2, "0x%05x", n);
 			}
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 8: /* MOVA #imm20, Rdst */
@@ -1185,6 +1248,8 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 		      if (strcmp (opcode->name, "bra") != 0)
 			sprintf (op2, "r%d", reg);
 		    }
+		  else
+		    return -1;
 		  break;
 
 		case 12: /* MOVA Rsrc, Rdst */
@@ -1206,15 +1271,21 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 
 	  switch (opcode->insn_opnumb)
 	    {
+	      int ret;
+
 	    case 0:
 	      cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
 	      break;
 	    case 2:
-	      cmd_len +=
+	      ret =
 		msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
 				      comm1, comm2,
 				      extension_word,
 				      &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (insn & BYTE_OPERATION)
 		{
 		  if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
@@ -1235,10 +1306,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 
 	      break;
 	    case 1:
-	      cmd_len +=
+	      ret =
 		msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
 				      extension_word,
 				      &cycles);
+
+	      if (ret == -1)
+		return -1;
+	      cmd_len += ret;
 	      if (extension_word
 		  && (strcmp (opcode->name, "swpb") == 0
 		      || strcmp (opcode->name, "sxt") == 0))

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-11 22:15   ` Alan Modra
@ 2017-01-12 11:50     ` Yao Qi
  2017-01-12 14:38       ` Alan Modra
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-12 11:50 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, gdb-patches

On 17-01-12 08:45:14, Alan Modra wrote:
> On Tue, Jan 10, 2017 at 12:26:16PM +0000, Yao Qi wrote:
> > 	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
> > 	if FETCH_DATA returns 0.
> > 	(m68k_scan_mask): Likewise.
> > 	(print_insn_m68k): Update code to handle -1 return value.
> 
> This misses one FETCH_DATA call, in m68k_scan_mask.
> 

I can't remember the reason I didn't change it.  Sorry.

What about the patch below?  Regression tested on x86_64-linux
with all targets enabled.

-- 
Yao (齐尧)

From 926e74e41c2f0248d18821c2ac83adbd6c13d544 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao.qi@linaro.org>
Date: Thu, 8 Dec 2016 17:16:39 +0000
Subject: [PATCH] Return -1 on  memory error in print_insn_m68k

m68k-dis.c:print_insn_m68k doesn't return -1 on memory error, but GDB
expects it returning -1 on memory error.

FETCH_DATA is used in m68k_scan_mask to fetch the next two bytes and
match instruction in the buffer if opcode is four-byte long.  That
makes difficult to check the return value of FETCH_DATA, so this
patch moves FETCH_DATA before matching instruction, so FETCH_DATA
is called if we know the opcode is four-byte long by
((0xffff & match) != 0).

opcodes:

2017-01-12  Yao Qi  <yao.qi@linaro.org>

	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
	if FETCH_DATA returns 0.
	(m68k_scan_mask): Likewise.  Call FETCH_DATA before matching
	instructions.
	(print_insn_m68k): Update code to handle -1 return value.

diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c
index a14db9a..2871ad8 100644
--- a/opcodes/m68k-dis.c
+++ b/opcodes/m68k-dis.c
@@ -1331,7 +1331,8 @@ print_insn_arg (const char *d,
 }
 
 /* Try to match the current instruction to best and if so, return the
-   number of bytes consumed from the instruction stream, else zero.  */
+   number of bytes consumed from the instruction stream, else zero.
+   Return -1 on memory error.  */
 
 static int
 match_insn_m68k (bfd_vma memaddr,
@@ -1415,12 +1416,14 @@ match_insn_m68k (bfd_vma memaddr,
 	 this because we know exactly what the second word is, and we
 	 aren't going to print anything based on it.  */
       p = buffer + 6;
-      FETCH_DATA (info, p);
+      if (!FETCH_DATA (info, p))
+	return -1;
       buffer[2] = buffer[4];
       buffer[3] = buffer[5];
     }
 
-  FETCH_DATA (info, p);
+  if (!FETCH_DATA (info, p))
+    return -1;
 
   save_p = p;
   info->print_address_func = dummy_print_address;
@@ -1439,7 +1442,7 @@ match_insn_m68k (bfd_vma memaddr,
 	{
 	  info->fprintf_func = save_printer;
 	  info->print_address_func = save_print_address;
-	  return 0;
+	  return eaten == PRINT_INSN_ARG_MEMORY_ERROR ? -1 : 0;
 	}
       else
 	{
@@ -1481,7 +1484,8 @@ match_insn_m68k (bfd_vma memaddr,
 /* Try to interpret the instruction at address MEMADDR as one that
    can execute on a processor with the features given by ARCH_MASK.
    If successful, print the instruction to INFO->STREAM and return
-   its length in bytes.  Return 0 otherwise.  */
+   its length in bytes.  Return 0 otherwise.  Return -1 on memory
+   error.  */
 
 static int
 m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
@@ -1523,7 +1527,8 @@ m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
 	*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
     }
 
-  FETCH_DATA (info, buffer + 2);
+  if (!FETCH_DATA (info, buffer + 2))
+    return -1;
   major_opcode = (buffer[0] >> 4) & 15;
 
   for (i = 0; i < numopcodes[major_opcode]; i++)
@@ -1536,14 +1541,19 @@ m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
       if (*args == '.')
 	args++;
 
+      /* Fetch the next two bytes if opcode is four-bytes long.  */
+      if ((0xffff & match) != 0)
+	{
+	  if (!FETCH_DATA (info, buffer + 4))
+	    return -1;
+	}
+
       if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
 	  && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
-	  /* Only fetch the next two bytes if we need to.  */
 	  && (((0xffff & match) == 0)
-	      ||
-	      (FETCH_DATA (info, buffer + 4)
-	       && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
-	       && ((0xff & buffer[3] & match) == (0xff & opcode)))
+	      /* Match the next two bytes if opcode is four-bytes long.  */
+	      || (((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+		  && ((0xff & buffer[3] & match) == (0xff & opcode)))
 	      )
 	  && (opc->arch & arch_mask) != 0)
 	{
@@ -1628,7 +1638,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
       /* First try printing an m680x0 instruction.  Try printing a Coldfire
 	 one if that fails.  */
       val = m68k_scan_mask (memaddr, info, m68k_mask);
-      if (val == 0)
+      if (val <= 0)
 	val = m68k_scan_mask (memaddr, info, mcf_mask);
     }
   else

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/8] Refactor disassembly code
  2017-01-11 20:43   ` Simon Marchi
@ 2017-01-12 12:19     ` Yao Qi
  2017-01-12 12:36       ` Pedro Alves
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-12 12:19 UTC (permalink / raw)
  To: Simon Marchi; +Cc: binutils, gdb-patches

On 17-01-11 15:42:58, Simon Marchi wrote:
> On 2017-01-10 07:26, Yao Qi wrote:
> >@@ -761,15 +768,15 @@ fprintf_disasm (void *stream, const char
> >*format, ...)
> >   return 0;
> > }
> >
> >-struct disassemble_info
> >-gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
> >+gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
> >+				    struct ui_file *file,
> >+				    di_read_memory_ftype func)
> 
> Perhaps name this parameter "read_memory_func"?
> 

OK.

> >diff --git a/gdb/disasm.h b/gdb/disasm.h
> >index 4c6fd54..5592cdb 100644
> >--- a/gdb/disasm.h
> >+++ b/gdb/disasm.h
> >@@ -33,6 +33,48 @@ struct gdbarch;
> > struct ui_out;
> > struct ui_file;
> >
> >+class gdb_disassembler
> >+{
> >+  using di_read_memory_ftype = decltype
> >(disassemble_info::read_memory_func);
> >+
> >+public:
> >+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
> >+    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
> >+  {}
> >+
> >+  int print_insn (CORE_ADDR memaddr);
> >+  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns);
> 
> Not very important, but since print_insn(CORE_ADDR) is trivial, you
> could merge those two methods and provide a default parameter value
> of NULL for branch_delay_insns.

OK.  Fixed them locally.

> 
> >+
> >+  /* Prints the instruction INSN into UIOUT and returns the length of
> >+     the printed instruction in bytes.  */
> >+  int pretty_print_insn (struct ui_out *uiout,
> >+			 const struct disasm_insn *insn, int flags);
> 
> It could be a good time to modernize the flags parameter and make it
> an enum flag.
> 

This can be done later.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn
  2017-01-11 20:50   ` Simon Marchi
@ 2017-01-12 12:21     ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-12 12:21 UTC (permalink / raw)
  To: Simon Marchi; +Cc: binutils, gdb-patches

On 17-01-11 15:50:32, Simon Marchi wrote:
> 
> Does the comment above mep_gdb_print_insn need to be changed?
>

Yes.
 
> /* The mep disassembler needs to know about the section in order to
>    work correctly.  */
> 

I removed it locally.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/8] Refactor disassembly code
  2017-01-12 12:19     ` Yao Qi
@ 2017-01-12 12:36       ` Pedro Alves
  2017-01-12 15:29         ` Simon Marchi
  0 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 12:36 UTC (permalink / raw)
  To: Yao Qi, Simon Marchi; +Cc: binutils, gdb-patches

On 01/12/2017 12:19 PM, Yao Qi wrote:

>>> diff --git a/gdb/disasm.h b/gdb/disasm.h
>>> index 4c6fd54..5592cdb 100644
>>> --- a/gdb/disasm.h
>>> +++ b/gdb/disasm.h
>>> @@ -33,6 +33,48 @@ struct gdbarch;
>>> struct ui_out;
>>> struct ui_file;
>>>
>>> +class gdb_disassembler
>>> +{
>>> +  using di_read_memory_ftype = decltype
>>> (disassemble_info::read_memory_func);
>>> +
>>> +public:
>>> +  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
>>> +    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
>>> +  {}
>>> +
>>> +  int print_insn (CORE_ADDR memaddr);
>>> +  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns);
>>
>> Not very important, but since print_insn(CORE_ADDR) is trivial, you
>> could merge those two methods and provide a default parameter value
>> of NULL for branch_delay_insns.
> 
> OK.  Fixed them locally.

I had written it that way originally because a default parameter forces
the compiler to pass down an extra parameter (adding to register pressure)
to all call sites, when only a few places actually need the extra
output parameter.  It's like a double-optional -- i.e., the
parameter can be NULL, so merging doesn't simplify that much,
given that the version with the single argument does not need to
check the parameter.  I.e., one function can be built on top of the
other.  I see it as a different case from when a parameter is optional
such that the passed in value always need to be taken in consideration
by the method implementation, like when passing a flags argument, with
the default being some flag value (or zero).

But this is not really performance critical code, so if you
want to change it, I don't mind.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
  2017-01-11 21:15   ` Simon Marchi
@ 2017-01-12 13:06   ` Pedro Alves
  2017-01-12 17:03     ` Yao Qi
  2017-01-12 14:35   ` Pedro Alves
  2017-01-12 15:15   ` Pedro Alves
  3 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 13:06 UTC (permalink / raw)
  To: Yao Qi, binutils, gdb-patches

I'd much prefer if the core of the unit testing framework doesn't learn
about different random subsystems.  Consider what we'd do if we
wanted to reuse selftest.c in gdbserver.  I think we will at some point.

How about we move all this gdbarch stuff elsewhere, like
gdb/arch-utils.c or a new gdb/arch-selftests.c?

You'd then have,

- call the new function typedef "arch_self_test_function"

- in arch-selftests.c:

static std::vector<arch_self_test_function *> gdbarch_tests;

void
register_arch_self_test (arch_self_test_function *function)
{
  gdbarch_tests.push_back (function);
}

namespace selftests {

arch_tests ()
{
  for (const auto &f : gdbarch_tests)
    {
      const char **arches = gdbarch_printable_names ();
      int i;
   [...]
}

} /* namespace selftests */

void
_initialize_arch_selftests (void)
{
#if GDB_SELF_TEST
  register_self_test (selftests::arch_tests);
#endif
}

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
  2017-01-11 21:15   ` Simon Marchi
  2017-01-12 13:06   ` Pedro Alves
@ 2017-01-12 14:35   ` Pedro Alves
  2017-01-12 15:15   ` Pedro Alves
  3 siblings, 0 replies; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 14:35 UTC (permalink / raw)
  To: Yao Qi, binutils, gdb-patches

On 01/10/2017 12:26 PM, Yao Qi wrote:
> +static void
> +gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
> +{
> +  int len = -1;
> +  const gdb_byte *insn = NULL;
> +
> +  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
> +    {
> +    case bfd_arch_bfin:
> +      /* M3.L = 0xe117 */
> +      insn = (const gdb_byte[]) {0x17, 0xe1, 0xff, 0xff};
> +      len = 4;
> +      break;

This is construct is problematic.

Unfortunately, compound literals aren't valid C++.  They're
valid in C, but not in C++.  G++ accepts them as an extension.

Maybe all C++ compilers we care about support them too, so that's
not the real problem I'm pointing at.

The problem is that compound literal above may have automatic
storage duration, and thus die at the end of the switch scope.

From http://en.cppreference.com/w/c/language/compound_literal

 "The unnamed object to which the compound literal evaluates has static
 storage duration if the compound literal occurs at file scope and automatic
 storage duration if the compound literal occurs at block scope (in which
 case the object's lifetime ends at the end of the enclosing block)."

I didn't check the C standard, but I assume that's correct.

At <https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html>,
we see:

"As an optimization, G++ sometimes gives array compound literals
 longer lifetimes: when the array either appears outside a function
 or has a const-qualified type. If foo and its initializer had elements
 of type char *const rather than char *, or if foo were a global
 variable, the array would have static storage duration. But it is probably
 safest just to avoid the use of array compound literals in C++ code. "

Given all the warnings, I'd think it best to avoid the construct.
We can just name the arrays:

static void
gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
{
  int len = -1;
  const gdb_byte *insn = NULL;

  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
    {
    case bfd_arch_bfin:
      /* M3.L = 0xe117 */
      static const gdb_byte bfin_insn[] = { 0x17, 0xe1, 0xff, 0xff };
      insn = bfin_insn;
      len = 4;
      break;
    case bfd_arch_bfin:
      /* mov     r0, #0 */
      static const gdb_byte arm_insn[] = { 0x0, 0x0, 0xa0, 0xe3 };
      insn = arm_insn;
      len = 4;


Or maybe make the compiler do the "sizeof" for us,
maybe eliminating copy/paste mistakes:

struct test_insn
 {
   template<size_t SIZE>
   explicit test_insn (const gdb_byte (&insn_)[Len])
    : insn (insn_), len_ (Len)
   {}
   gdb_byte *insn;
   int len;
 };

static void
gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
{
  test_insn insn = { NULL, -1 };

  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
    {
    case bfd_arch_bfin:
      /* M3.L = 0xe117 */
      static const gdb_byte bfin_insn[] = { 0x17, 0xe1, 0xff, 0xff };
      insn = test_insn (bfin_insn);
      break;
    case bfd_arch_bfin:
      /* mov     r0, #0 */
      static const gdb_byte arm_insn[] = { 0x0, 0x0, 0xa0, 0xe3 };
      insn = test_insn (arm_insn);
  [....]


Maybe split the insns out of the switch:

/* M3.L = 0xe117 */
static const gdb_byte bfin_test_insn[] = { 0x17, 0xe1, 0xff, 0xff };
/* mov     r0, #0 */
static const gdb_byte arm_test_insn[] = { 0x0, 0x0, 0xa0, 0xe3 };

static void
gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
{
  test_insn insn = { NULL, -1 };

  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
    {
    case bfd_arch_bfin:
      insn = test_insn (bfin_test_insn);
      break;
    case bfd_arch_bfin:
      insn = test_insn (arm_test_insn);
      break;
  [....]


Just some ideas.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-12 11:50     ` Yao Qi
@ 2017-01-12 14:38       ` Alan Modra
  2017-01-12 14:52         ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Alan Modra @ 2017-01-12 14:38 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On Thu, Jan 12, 2017 at 11:50:21AM +0000, Yao Qi wrote:
> On 17-01-12 08:45:14, Alan Modra wrote:
> > On Tue, Jan 10, 2017 at 12:26:16PM +0000, Yao Qi wrote:
> > > 	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
> > > 	if FETCH_DATA returns 0.
> > > 	(m68k_scan_mask): Likewise.
> > > 	(print_insn_m68k): Update code to handle -1 return value.
> > 
> > This misses one FETCH_DATA call, in m68k_scan_mask.
> > 
> 
> I can't remember the reason I didn't change it.  Sorry.

Actually there is a good reason not to change that call, I just didn't
look at the code well enough and thought you'd accidentally missed
it.  The previous patch is OK.  The newest one would fail if you had
a 2-byte insn at the end of a segment and happened to try a 4-byte
insn match first.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-12 14:38       ` Alan Modra
@ 2017-01-12 14:52         ` Yao Qi
  2017-01-13  1:54           ` Alan Modra
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-12 14:52 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, gdb-patches

On 17-01-13 01:08:14, Alan Modra wrote:
> On Thu, Jan 12, 2017 at 11:50:21AM +0000, Yao Qi wrote:
> > On 17-01-12 08:45:14, Alan Modra wrote:
> > > On Tue, Jan 10, 2017 at 12:26:16PM +0000, Yao Qi wrote:
> > > > 	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
> > > > 	if FETCH_DATA returns 0.
> > > > 	(m68k_scan_mask): Likewise.
> > > > 	(print_insn_m68k): Update code to handle -1 return value.
> > > 
> > > This misses one FETCH_DATA call, in m68k_scan_mask.
> > > 
> > 
> > I can't remember the reason I didn't change it.  Sorry.
> 
> Actually there is a good reason not to change that call, I just didn't
> look at the code well enough and thought you'd accidentally missed
> it.  The previous patch is OK.  The newest one would fail if you had
> a 2-byte insn at the end of a segment and happened to try a 4-byte
> insn match first.
>

Hi Alan,
This won't happen in the 2nd patch, because if the instruction is 2-byte,
it won't read and match the next 2 bytes.  There is a guard
((0xffff & match) != 0) for read.  Am I missing something?

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
                     ` (2 preceding siblings ...)
  2017-01-12 14:35   ` Pedro Alves
@ 2017-01-12 15:15   ` Pedro Alves
  2017-01-12 15:35     ` Yao Qi
  2017-01-12 16:06     ` Pedro Alves
  3 siblings, 2 replies; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 15:15 UTC (permalink / raw)
  To: Yao Qi, binutils, gdb-patches

On 01/10/2017 12:26 PM, Yao Qi wrote:
> +  class gdb_disassembler_test : public gdb_disassembler
> +  {
> +  public:
> +
> +#ifndef DISASSEMBLER_TEST_VERBOSE
> +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> +				    const gdb_byte *insn)
> +      : gdb_disassembler (gdbarch, ui_file_new (),
> +			  gdb_disassembler_test::read_memory),
> +	m_insn (insn)
> +    {
> +    }
> +
> +    ~gdb_disassembler_test ()
> +    {
> +      ui_file_delete ((struct ui_file *) m_di.stream);


Hmm, looks like you've made m_di be "protected" for
these uses.

But we have the public stream() method already,
so I think could be:

    ~gdb_disassembler_test ()
    {
      ui_file_delete (stream ());
    }

You could then make m_di private again.

But you shouldn't really need to create a new stream for
testing.  We have other places that want to print to a
a null stream.  We can factor out out the null_stream creation
from gdb_insn_length into a new function:

struct ui_file *
null_stream ()
{
  static struct ui_file *stream = NULL;

  if (stream == NULL)
    {
      stream = ui_file_new ();
      make_final_cleanup (do_ui_file_delete, stream);
    }
  return stream;
}

and then use it wherever necessary.

> +    }
> +#else
> +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> +				    const gdb_byte *insn)
> +      : gdb_disassembler (gdbarch, gdb_stdout,
> +			  gdb_disassembler_test::read_memory),
> +	m_insn (insn)
> +    {
> +    }
> +
> +    int
> +    print_insn (CORE_ADDR memaddr)
> +    {
> +      fprintf_unfiltered (stream (), "%s ",
> +			  gdbarch_bfd_arch_info (arch ())->arch_name);
> +
> +      int len = gdb_disassembler::print_insn (memaddr);
> +
> +      fprintf_unfiltered (stream (), "\n");
> +      return len;
> +    }
> +#endif /* DISASSEMBLER_TEST_VERBOSE */
> +

I think it'll be nicer if you make DISASSEMBLER_TEST_VERBOSE always
defined, either to 0 or 1, so we can use
"if (DISASSEMBLER_TEST_VERBOSE)" instead of #ifdef.
That ensures that both paths keep compiling.  The compiler
easily gets rid of the dead path when compiling with
optimizations enabled.

Putting it all together, you'd have something like:

    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
			            struct ui_file *stream,
				    const gdb_byte *insn)
      : gdb_disassembler (gdbarch, 
                          (DISASSEMBLER_TEST_VERBOSE
                           ? gdb_stdout : null_stream ()),
			  gdb_disassembler_test::read_memory),
	m_insn (insn)
    {}

    int
    print_insn (CORE_ADDR memaddr)
    {
      if (DISASSEMBLER_TEST_VERBOSE)
        {
          fprintf_unfiltered (stream (), "%s ",
	    		  gdbarch_bfd_arch_info (arch ())->arch_name);
        }

      int len = gdb_disassembler::print_insn (memaddr);

      if (DISASSEMBLER_TEST_VERBOSE)
        fprintf_unfiltered (stream (), "\n");
      return len;
    }

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/8] Refactor disassembly code
  2017-01-12 12:36       ` Pedro Alves
@ 2017-01-12 15:29         ` Simon Marchi
  0 siblings, 0 replies; 80+ messages in thread
From: Simon Marchi @ 2017-01-12 15:29 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Yao Qi, binutils, gdb-patches

On 2017-01-12 07:36, Pedro Alves wrote:
> I had written it that way originally because a default parameter forces
> the compiler to pass down an extra parameter (adding to register 
> pressure)
> to all call sites, when only a few places actually need the extra
> output parameter.  It's like a double-optional -- i.e., the
> parameter can be NULL, so merging doesn't simplify that much,
> given that the version with the single argument does not need to
> check the parameter.  I.e., one function can be built on top of the
> other.  I see it as a different case from when a parameter is optional
> such that the passed in value always need to be taken in consideration
> by the method implementation, like when passing a flags argument, with
> the default being some flag value (or zero).
> 
> But this is not really performance critical code, so if you
> want to change it, I don't mind.

Ok, I hadn't gone that far in my reflexion, I thought it was simply a 
convenience thing.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 15:15   ` Pedro Alves
@ 2017-01-12 15:35     ` Yao Qi
  2017-01-12 15:44       ` Pedro Alves
  2017-01-12 16:06     ` Pedro Alves
  1 sibling, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-12 15:35 UTC (permalink / raw)
  To: Pedro Alves; +Cc: binutils, gdb-patches

On 17-01-12 15:15:34, Pedro Alves wrote:
> On 01/10/2017 12:26 PM, Yao Qi wrote:
> > +  class gdb_disassembler_test : public gdb_disassembler
> > +  {
> > +  public:
> > +
> > +#ifndef DISASSEMBLER_TEST_VERBOSE
> > +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> > +				    const gdb_byte *insn)
> > +      : gdb_disassembler (gdbarch, ui_file_new (),
> > +			  gdb_disassembler_test::read_memory),
> > +	m_insn (insn)
> > +    {
> > +    }
> > +
> > +    ~gdb_disassembler_test ()
> > +    {
> > +      ui_file_delete ((struct ui_file *) m_di.stream);
> 
> 
> Hmm, looks like you've made m_di be "protected" for
> these uses.
> 
> But we have the public stream() method already,
> so I think could be:
> 
>     ~gdb_disassembler_test ()
>     {
>       ui_file_delete (stream ());
>     }
> 
> You could then make m_di private again.
> 
> But you shouldn't really need to create a new stream for
> testing.  We have other places that want to print to a
> a null stream.  We can factor out out the null_stream creation
> from gdb_insn_length into a new function:
> 
> struct ui_file *
> null_stream ()
> {
>   static struct ui_file *stream = NULL;
> 
>   if (stream == NULL)
>     {
>       stream = ui_file_new ();
>       make_final_cleanup (do_ui_file_delete, stream);
>     }
>   return stream;
> }
> 
> and then use it wherever necessary.
> 

I did write code that way, but I changed it because the destroy of
stream is done in cleanup.  I want the test case depends on other
part of GDB as less as possible.  I hope this test case can be run
even without cleanup stuff.  It is sort of RAII (stream is regarded
as resource).

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 15:35     ` Yao Qi
@ 2017-01-12 15:44       ` Pedro Alves
  0 siblings, 0 replies; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 15:44 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On 01/12/2017 03:34 PM, Yao Qi wrote:
> On 17-01-12 15:15:34, Pedro Alves wrote:
>> On 01/10/2017 12:26 PM, Yao Qi wrote:
>>> +  class gdb_disassembler_test : public gdb_disassembler
>>> +  {
>>> +  public:
>>> +
>>> +#ifndef DISASSEMBLER_TEST_VERBOSE
>>> +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
>>> +				    const gdb_byte *insn)
>>> +      : gdb_disassembler (gdbarch, ui_file_new (),
>>> +			  gdb_disassembler_test::read_memory),
>>> +	m_insn (insn)
>>> +    {
>>> +    }
>>> +
>>> +    ~gdb_disassembler_test ()
>>> +    {
>>> +      ui_file_delete ((struct ui_file *) m_di.stream);
>>
>>
>> Hmm, looks like you've made m_di be "protected" for
>> these uses.
>>
>> But we have the public stream() method already,
>> so I think could be:
>>
>>     ~gdb_disassembler_test ()
>>     {
>>       ui_file_delete (stream ());
>>     }
>>
>> You could then make m_di private again.
>>
>> But you shouldn't really need to create a new stream for
>> testing.  We have other places that want to print to a
>> a null stream.  We can factor out out the null_stream creation
>> from gdb_insn_length into a new function:
>>
>> struct ui_file *
>> null_stream ()
>> {
>>   static struct ui_file *stream = NULL;
>>
>>   if (stream == NULL)
>>     {
>>       stream = ui_file_new ();
>>       make_final_cleanup (do_ui_file_delete, stream);
>>     }
>>   return stream;
>> }
>>
>> and then use it wherever necessary.
>>
> 
> I did write code that way, but I changed it because the destroy of
> stream is done in cleanup.  I want the test case depends on other
> part of GDB as less as possible.  I hope this test case can be run
> even without cleanup stuff.  It is sort of RAII (stream is regarded
> as resource).

Note that's a _final_ cleanup.  I.e., it only runs when GDB exits.
There's no need for gdb_disassembler_test to destroy the stream
with that.

And in my palves/cxx-eliminate-cleanups branch, where I've
C++-fied the whole ui_file hierarchy, the cleanup completely
disappears.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 15:15   ` Pedro Alves
  2017-01-12 15:35     ` Yao Qi
@ 2017-01-12 16:06     ` Pedro Alves
  1 sibling, 0 replies; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 16:06 UTC (permalink / raw)
  To: Yao Qi, binutils, gdb-patches

On 01/12/2017 03:15 PM, Pedro Alves wrote:
> Putting it all together, you'd have something like:
> 
>     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> 			            struct ui_file *stream,

                                    ^^^^^^^^^^^^^^^^^^^^^^

This stream parameter here shouldn't exist, of course.  It's just
that my Thunderbird hasn't learned to flag coding problems yet.  :-)

> 				    const gdb_byte *insn)
>       : gdb_disassembler (gdbarch, 
>                           (DISASSEMBLER_TEST_VERBOSE
>                            ? gdb_stdout : null_stream ()),
> 			  gdb_disassembler_test::read_memory),
> 	m_insn (insn)
>     {}


-- 
Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 8/8] Don't throw exception in dis_asm_memory_error
  2017-01-10 12:27 ` [PATCH 8/8] Don't throw exception in dis_asm_memory_error Yao Qi
@ 2017-01-12 16:40   ` Pedro Alves
  2017-01-12 21:09     ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 16:40 UTC (permalink / raw)
  To: Yao Qi, binutils, gdb-patches

On 01/10/2017 12:26 PM, Yao Qi wrote:
> --- a/gdb/testsuite/gdb.base/all-architectures.exp.in
> +++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
> @@ -152,6 +152,9 @@ proc print_floats {} {
>  
>  proc do_arch_tests {} {
>      print_floats
> +
> +    gdb_test_internal "disassemble 0x0,+4" \
> +	"Cannot access memory at address 0x0"
>  }

This will fail if you're testing against a non-MMU target,
where you can read address 0.  Check is_address_zero_readable?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 13:06   ` Pedro Alves
@ 2017-01-12 17:03     ` Yao Qi
  2017-01-12 17:43       ` Pedro Alves
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-12 17:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: binutils, gdb-patches

On 17-01-12 13:06:26, Pedro Alves wrote:
> I'd much prefer if the core of the unit testing framework doesn't learn
> about different random subsystems.  Consider what we'd do if we
> wanted to reuse selftest.c in gdbserver.  I think we will at some point.

Can we consider using some general c++ unit test frameworks rather than
selftest.c?  I don't see any issues if we can merge the unit test
results into dejagnu test result gdb.sum.

It should be straightforward to convert some c++ unit test result
to the dejagnu style, and use dg-extract-results.sh to merge them
into a single gdb.sum.

David proposed using gtest in gcc unit test, and the major objection
/concern is we may have two different format of test results.
https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html but the
concern can be addressed as I stated above.

> 
> How about we move all this gdbarch stuff elsewhere, like
> gdb/arch-utils.c or a new gdb/arch-selftests.c?
> 

OK, I'd like to name it as gdb/selftests-arch.c, because
arch-selftests.c looks like "a unit test case of arch".  However,
I want this file serves as "a runner to run one test case for every
gdbarch".

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 17:03     ` Yao Qi
@ 2017-01-12 17:43       ` Pedro Alves
  2017-01-12 21:04         ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-12 17:43 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On 01/12/2017 05:03 PM, Yao Qi wrote:
> On 17-01-12 13:06:26, Pedro Alves wrote:
>> I'd much prefer if the core of the unit testing framework doesn't learn
>> about different random subsystems.  Consider what we'd do if we
>> wanted to reuse selftest.c in gdbserver.  I think we will at some point.
> 
> Can we consider using some general c++ unit test frameworks rather than
> selftest.c?  I don't see any issues if we can merge the unit test
> results into dejagnu test result gdb.sum.

We can consider anything, of course.  But I don't know whether
that's give us any significant advantage.  I never evaluated any myself.
Do we miss something important with the current framework?  
Would it be used as an as external dependency (required? optional?), or
would we import it into the codebase?  How would it
affect the way we write tests?  And the way we write the code that ends
up tested?  Would it force something on the codebase that would be
undesirable?  Etc., etc.

> It should be straightforward to convert some c++ unit test result
> to the dejagnu style, and use dg-extract-results.sh to merge them
> into a single gdb.sum.
> 
> David proposed using gtest in gcc unit test, and the major objection
> /concern is we may have two different format of test results.
> https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00765.html but the
> concern can be addressed as I stated above.
> 
>>
>> How about we move all this gdbarch stuff elsewhere, like
>> gdb/arch-utils.c or a new gdb/arch-selftests.c?
>>
> 
> OK, I'd like to name it as gdb/selftests-arch.c, because
> arch-selftests.c looks like "a unit test case of arch".  However,
> I want this file serves as "a runner to run one test case for every
> gdbarch".

Makes sense.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/8] Disassembly unit test: disassemble one instruction
  2017-01-12 17:43       ` Pedro Alves
@ 2017-01-12 21:04         ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-12 21:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Thu, Jan 12, 2017 at 5:43 PM, Pedro Alves <palves@redhat.com> wrote:
> On 01/12/2017 05:03 PM, Yao Qi wrote:
>> On 17-01-12 13:06:26, Pedro Alves wrote:
>>> I'd much prefer if the core of the unit testing framework doesn't learn
>>> about different random subsystems.  Consider what we'd do if we
>>> wanted to reuse selftest.c in gdbserver.  I think we will at some point.
>>
>> Can we consider using some general c++ unit test frameworks rather than
>> selftest.c?  I don't see any issues if we can merge the unit test
>> results into dejagnu test result gdb.sum.
>
> We can consider anything, of course.  But I don't know whether
> that's give us any significant advantage.  I never evaluated any myself.
> Do we miss something important with the current framework?

Nothing so far.  I need an assert or check that an exception should be
thrown in some statement in patch #7, like EXPECT_THROW in gtest.

All current unit/self tests are started by a command "maint selftests".
Probably, we can't unit test event loop or command handling.

> Would it be used as an as external dependency (required? optional?), or
> would we import it into the codebase?  How would it
> affect the way we write tests?  And the way we write the code that ends
> up tested?  Would it force something on the codebase that would be
> undesirable?  Etc., etc.
>

We only have one assertion SELF_CHECK, but we need more, like EXPECT_EQ,
EXPECT_TRUE, etc.  They can be easily added to selftest.h.  I don't
think of the answers of these questions either, but we should think of them
at this stage, because we don't have many unit test cases yet, it is
easy to change to any framework.  It is difficult to change when we have
thousands of unit tests on top of selftest.{c,h} framework.  so, if we
want to use
something as a framework, be careful :)

I'll try some c++ unit test frameworks in gdb, and see what I can get.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 8/8] Don't throw exception in dis_asm_memory_error
  2017-01-12 16:40   ` Pedro Alves
@ 2017-01-12 21:09     ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-12 21:09 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Thu, Jan 12, 2017 at 4:40 PM, Pedro Alves <palves@redhat.com> wrote:
> On 01/10/2017 12:26 PM, Yao Qi wrote:
>> --- a/gdb/testsuite/gdb.base/all-architectures.exp.in
>> +++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
>> @@ -152,6 +152,9 @@ proc print_floats {} {
>>
>>  proc do_arch_tests {} {
>>      print_floats
>> +
>> +    gdb_test_internal "disassemble 0x0,+4" \
>> +     "Cannot access memory at address 0x0"
>>  }
>
> This will fail if you're testing against a non-MMU target,
> where you can read address 0.  Check is_address_zero_readable?
>

There is no live inferior created in the test, so GDB can't access any
memory.  Probably I need a line of comment,

# GDB can't access any memory because there is no live inferior.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-12 14:52         ` Yao Qi
@ 2017-01-13  1:54           ` Alan Modra
  2017-01-13 12:29             ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Alan Modra @ 2017-01-13  1:54 UTC (permalink / raw)
  To: Yao Qi; +Cc: binutils, gdb-patches

On Thu, Jan 12, 2017 at 02:52:30PM +0000, Yao Qi wrote:
> On 17-01-13 01:08:14, Alan Modra wrote:
> > On Thu, Jan 12, 2017 at 11:50:21AM +0000, Yao Qi wrote:
> > > On 17-01-12 08:45:14, Alan Modra wrote:
> > > > On Tue, Jan 10, 2017 at 12:26:16PM +0000, Yao Qi wrote:
> > > > > 	* m68k-dis.c (match_insn_m68k): Extend comments.  Return -1
> > > > > 	if FETCH_DATA returns 0.
> > > > > 	(m68k_scan_mask): Likewise.
> > > > > 	(print_insn_m68k): Update code to handle -1 return value.
> > > > 
> > > > This misses one FETCH_DATA call, in m68k_scan_mask.
> > > > 
> > > 
> > > I can't remember the reason I didn't change it.  Sorry.
> > 
> > Actually there is a good reason not to change that call, I just didn't
> > look at the code well enough and thought you'd accidentally missed
> > it.  The previous patch is OK.  The newest one would fail if you had
> > a 2-byte insn at the end of a segment and happened to try a 4-byte
> > insn match first.
> >
> 
> Hi Alan,
> This won't happen in the 2nd patch, because if the instruction is 2-byte,
> it won't read and match the next 2 bytes.  There is a guard
> ((0xffff & match) != 0) for read.  Am I missing something?

The code is looping over an opcode table.  You might try to match a
4-byte instruction from the opcode table before matching the 2-byte
instruction you have.  If you exit the loop due to failing to read 4
bytes then you won't disassemble the instruction.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg
  2017-01-11 22:14   ` Alan Modra
@ 2017-01-13 12:23     ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-13 12:23 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, gdb-patches

On 17-01-12 08:44:06, Alan Modra wrote:
> On Tue, Jan 10, 2017 at 12:26:15PM +0000, Yao Qi wrote:
> > 	* m68k-dis.c (enum print_insn_arg_error): New.
> > 	(NEXTBYTE): Replace -3 with
> > 	PRINT_INSN_ARG_MEMORY_ERROR.
> > 	(NEXTULONG): Likewise.
> > 	(NEXTSINGLE): Likewise.
> > 	(NEXTDOUBLE): Likewise.
> > 	(NEXTDOUBLE): Likewise.
> > 	(NEXTPACKED): Likewise.
> > 	(FETCH_DATA): Update comments.
> > 	(print_insn_arg): Update comments. Replace magic numbers with
> > 	enum.
> > 	(match_insn_m68k): Likewise.
> 
> OK.
> 

Patch is pushed in.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/8] Return -1 on  memory error in print_insn_m68k
  2017-01-13  1:54           ` Alan Modra
@ 2017-01-13 12:29             ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-13 12:29 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, gdb-patches

On 17-01-13 12:24:12, Alan Modra wrote:
> > > Actually there is a good reason not to change that call, I just didn't
> > > look at the code well enough and thought you'd accidentally missed
> > > it.  The previous patch is OK.  The newest one would fail if you had
> > > a 2-byte insn at the end of a segment and happened to try a 4-byte
> > > insn match first.
> > >
> > 
> > Hi Alan,
> > This won't happen in the 2nd patch, because if the instruction is 2-byte,
> > it won't read and match the next 2 bytes.  There is a guard
> > ((0xffff & match) != 0) for read.  Am I missing something?
> 
> The code is looping over an opcode table.  You might try to match a
> 4-byte instruction from the opcode table before matching the 2-byte
> instruction you have.  If you exit the loop due to failing to read 4
> bytes then you won't disassemble the instruction.
> 

OK, the v1 is pushed in.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
                     ` (4 preceding siblings ...)
  2017-01-16 10:03   ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 14:33     ` Luis Machado
  2017-01-20  0:04     ` Pedro Alves
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
  6 siblings, 2 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

This patch adds one unit test, which disassemble one instruction for
every gdbarch if available.  The test needs one valid instruction of
each gdbarch, and most of them are got from breakpoint instruction.
For the rest gdbarch whose breakpoint instruction isn't a valid
instruction, I copy one instruction from the gas/testsuite/gas/
directory.

I get the valid instruction of most gdbarch except ia64, mep, mips,
tic6x, and xtensa.  People familiar with these arch should be easy
to extend the test.

In order to achieve "do the unit test for every gdbarch", I add
selftest-arch.[c,h], so that we can register a function pointer,
which has one argument gdbarch.  selftest.c will iterate over all
gdbarches to call the registered function pointer.

v2:
 - Add comments for getting breakpoint instructions for score and
   nios2,
 - Provide more contents in gdb_disassembler_test::read_memory if
   caller requests more than one instruction,
 - Stop using compound literal,
 - Use null_stream,
 - Split "selftest for each gdbarch" out of selftest.{c,h},

gdb:

2017-01-13  Yao Qi  <yao.qi@linaro.org>

	* Makefile.in (SFILES): Add disasm-selftests.c and
	selftest-arch.c.
	(COMMON_OBS): Add disasm-selftests.o and selftest-arch.o.
	* disasm-selftests.c: New file.
	* selftest-arch.c: New file.
	* selftest-arch.h: New file.
---
 gdb/Makefile.in        |   5 ++
 gdb/disasm-selftests.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/selftest-arch.c    | 103 ++++++++++++++++++++++++++++
 gdb/selftest-arch.h    |  26 ++++++++
 4 files changed, 312 insertions(+)
 create mode 100644 gdb/disasm-selftests.c
 create mode 100644 gdb/selftest-arch.c
 create mode 100644 gdb/selftest-arch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3ce7d69..e0fe442 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1039,6 +1039,7 @@ SFILES = \
 	dfp.c \
 	dictionary.c \
 	disasm.c \
+	disasm-selftests.c \
 	doublest.c \
 	dtrace-probe.c \
 	dummy-frame.c \
@@ -1140,6 +1141,7 @@ SFILES = \
 	rust-exp.y \
 	rust-lang.c \
 	selftest.c \
+	selftest-arch.c \
 	sentinel-frame.c \
 	ser-base.c \
 	ser-event.c \
@@ -1396,6 +1398,7 @@ HFILES_NO_SRCDIR = \
 	rs6000-tdep.h \
 	s390-linux-tdep.h \
 	score-tdep.h \
+	selftest-arch.h \
 	sentinel-frame.h \
 	ser-base.h \
 	ser-event.h \
@@ -1643,6 +1646,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	dfp.o \
 	dictionary.o \
 	disasm.o \
+	disasm-selftests.o \
 	doublest.o \
 	dummy-frame.o \
 	dwarf2-frame.o \
@@ -1744,6 +1748,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	run-time-clock.o \
 	rust-lang.o \
 	selftest.o \
+	selftest-arch.o \
 	sentinel-frame.o \
 	ser-event.o \
 	serial.o \
diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
new file mode 100644
index 0000000..46a0a21
--- /dev/null
+++ b/gdb/disasm-selftests.c
@@ -0,0 +1,178 @@
+/* Self tests for disassembler for GDB, the GNU debugger.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "disasm.h"
+
+#if GDB_SELF_TEST
+#include "selftest.h"
+#include "selftest-arch.h"
+
+namespace selftests {
+
+/* Test disassembly of one instruction.  */
+
+static void
+gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
+{
+  size_t len = 0;
+  const gdb_byte *insn = NULL;
+
+  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
+    {
+    case bfd_arch_bfin:
+      /* M3.L = 0xe117 */
+      static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
+
+      insn = bfin_insn;
+      len = sizeof (bfin_insn);
+      break;
+    case bfd_arch_arm:
+      /* mov     r0, #0 */
+      static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
+
+      insn = arm_insn;
+      len = sizeof (arm_insn);
+      break;
+    case bfd_arch_ia64:
+    case bfd_arch_mep:
+    case bfd_arch_mips:
+    case bfd_arch_tic6x:
+    case bfd_arch_xtensa:
+      return;
+    case bfd_arch_s390:
+      /* nopr %r7 */
+      static const gdb_byte s390_insn[] = {0x07, 0x07};
+
+      insn = s390_insn;
+      len = sizeof (s390_insn);
+      break;
+    case bfd_arch_xstormy16:
+      /* nop */
+      static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
+
+      insn = xstormy16_insn;
+      len = sizeof (xstormy16_insn);
+      break;
+    case bfd_arch_arc:
+      {
+	/* PR 21003 */
+	if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
+	  return;
+      }
+    case bfd_arch_nios2:
+    case bfd_arch_score:
+      /* nios2 and score need to know the current instruction to select
+	 breakpoint instruction.  Give the breakpoint instruction kind
+	 explicitly.  */
+      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, (int *) &len);
+      break;
+    default:
+      {
+	/* Test disassemble breakpoint instruction.  */
+	CORE_ADDR pc = 0;
+	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
+
+	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind,
+						(int *) &len);
+
+	break;
+      }
+    }
+  SELF_CHECK (len > 0);
+
+  /* Test gdb_disassembler for a given gdbarch by reading data from a
+     pre-allocated buffer.  If you want to see the disassembled
+     instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
+     to true.  */
+
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+
+    const bool DISASSEMBLER_TEST_VERBOSE = false;
+
+    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
+				    const gdb_byte *insn,
+				    size_t len)
+      : gdb_disassembler (gdbarch,
+			  (DISASSEMBLER_TEST_VERBOSE
+			   ? gdb_stdout : null_stream ()),
+			  gdb_disassembler_test::read_memory),
+	m_insn (insn), m_len (len)
+    {
+    }
+
+    int
+    print_insn (CORE_ADDR memaddr)
+    {
+      if (DISASSEMBLER_TEST_VERBOSE)
+	{
+	  fprintf_unfiltered (stream (), "%s ",
+			      gdbarch_bfd_arch_info (arch ())->arch_name);
+	}
+
+      int len = gdb_disassembler::print_insn (memaddr);
+
+      if (DISASSEMBLER_TEST_VERBOSE)
+	fprintf_unfiltered (stream (), "\n");
+
+      return len;
+    }
+
+  private:
+    /* A buffer contain one instruction.  */
+    const gdb_byte *m_insn;
+
+    /* Length of the buffer.  */
+    size_t m_len;
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len, struct disassemble_info *info)
+    {
+      gdb_disassembler_test *self
+	= static_cast<gdb_disassembler_test *>(info->application_data);
+
+      /* The disassembler in opcodes may read more data than one
+	 instruction.  */
+      for (unsigned int i = 0; i < len; i++)
+	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
+
+      return 0;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch, insn, len);
+
+  SELF_CHECK (di.print_insn (0) == len);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_disasm_test;
+
+void
+_initialize_disasm_test (void)
+{
+#if GDB_SELF_TEST
+  register_self_test (selftests::gdb_disassembler_print_one_insn_test);
+#endif
+}
diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
new file mode 100644
index 0000000..aa716be
--- /dev/null
+++ b/gdb/selftest-arch.c
@@ -0,0 +1,103 @@
+/* GDB self-test for each gdbarch.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+
+#if GDB_SELF_TEST
+#include "selftest.h"
+#include "selftest-arch.h"
+#include "arch-utils.h"
+
+static std::vector<self_test_function_with_gdbarch *> gdbarch_tests;
+
+void
+register_self_test (self_test_function_with_gdbarch *function)
+{
+  gdbarch_tests.push_back (function);
+}
+
+namespace selftests {
+
+static void
+tests_with_arch (void)
+{
+  int failed = 0;
+
+  for (const auto &f : gdbarch_tests)
+    {
+      const char **arches = gdbarch_printable_names ();
+      int i;
+
+      for (i = 0; arches[i] != NULL; i++)
+	{
+	  if (strcmp ("fr300", arches[i]) == 0)
+	    {
+	      /* PR 20946 */
+	      continue;
+	    }
+	  else if (strcmp ("powerpc:EC603e", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc64", arches[i]) == 0
+		   || strcmp ("powerpc:titan", arches[i]) == 0
+		   || strcmp ("powerpc:vle", arches[i]) == 0
+		   || strcmp ("powerpc:e5500", arches[i]) == 0
+		   || strcmp ("powerpc:e6500", arches[i]) == 0)
+	    {
+	      /* PR 19797 */
+	      continue;
+	    }
+
+	  QUIT;
+
+	  TRY
+	    {
+	      struct gdbarch_info info;
+
+	      gdbarch_info_init (&info);
+	      info.bfd_arch_info = bfd_scan_arch (arches[i]);
+
+	      struct gdbarch *gdbarch = gdbarch_find_by_info (info);
+	      SELF_CHECK (gdbarch != NULL);
+	      f (gdbarch);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      ++failed;
+	      exception_fprintf (gdb_stderr, ex,
+				 _("Self test failed: arch %s: "), arches[i]);
+	    }
+	  END_CATCH
+	}
+    }
+
+  SELF_CHECK (failed == 0);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_selftests_with_arch;
+
+void
+_initialize_selftests_with_arch (void)
+{
+#if GDB_SELF_TEST
+  register_self_test (selftests::tests_with_arch);
+#endif
+}
diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h
new file mode 100644
index 0000000..d63c2d2
--- /dev/null
+++ b/gdb/selftest-arch.h
@@ -0,0 +1,26 @@
+/* GDB self-test for each gdbarch.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef SELFTEST_ARCH_H
+#define SELFTEST_ARCH_H
+
+typedef void self_test_function_with_gdbarch (struct gdbarch *);
+
+extern void register_self_test (self_test_function_with_gdbarch *function);
+
+#endif /* SELFTEST_ARCH_H */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
                     ` (3 preceding siblings ...)
  2017-01-16 10:03   ` [PATCH 2/6] Refactor disassembly code Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 14:19     ` Luis Machado
  2017-01-16 10:03   ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
  6 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

opcodes/mep-dis.c:mep_print_insn has already had the code to
handle the case when info->section is NULL,

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
    }
  else /* sid or gdb */
    {
    }

so that we can still cal print_insn_mep even section can't be found.
On the other hand, user can disassemble an arbitrary address which
doesn't map to any section at all.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* mep-tdep.c (mep_gdb_print_insn): Set info->arch
	to bfd_arch_mep.  Don't return 0 if section is not
	found.  Call print_insn_mep.
---
 gdb/mep-tdep.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
index 68b0c4b..b1dcc86 100644
--- a/gdb/mep-tdep.c
+++ b/gdb/mep-tdep.c
@@ -1266,13 +1266,12 @@ mep_pseudo_register_write (struct gdbarch *gdbarch,
 \f
 /* Disassembly.  */
 
-/* The mep disassembler needs to know about the section in order to
-   work correctly.  */
 static int
 mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
 {
   struct obj_section * s = find_pc_section (pc);
 
+  info->arch = bfd_arch_mep;
   if (s)
     {
       /* The libopcodes disassembly code uses the section to find the
@@ -1280,12 +1279,9 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
          the me_module index, and the me_module index to select the
          right instructions to print.  */
       info->section = s->the_bfd_section;
-      info->arch = bfd_arch_mep;
-	
-      return print_insn_mep (pc, info);
     }
-  
-  return 0;
+
+  return print_insn_mep (pc, info);
 }
 
 \f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 2/6] Refactor disassembly code
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
                     ` (2 preceding siblings ...)
  2017-01-16 10:03   ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 14:14     ` Luis Machado
  2017-01-16 10:03   ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

This patch addes class gdb_disassembler, and refactor
code to use it.  The gdb_disassembler object is saved
in disassember_info.application_data.  However,
disassember_info.application_data is already used by
gdb for arm, mips spu, and scm-disasm.  In arm and mips,
.application_data is gdbarch, but we can still get gdbarch
from gdb_disassember.

The use of application_data in spu is a little bit
complicated.  It creates its own disassemble_info, and
save spu_dis_asm_data in .application_data.  This will
overwrite the pointer to gdb_disassembler, so we need
to find another place to save spu_dis_asm_data.  I
extend disassemble_info, and put "id" there.

v2:
 - Merge to print_insn functions into one, with default
   parameter value,

gdb:

2017-01-13  Pedro Alves  <palves@redhat.com>
	    Yao Qi  <yao.qi@linaro.org>

	* arm-tdep.c: Include "disasm.h".
	(gdb_print_insn_arm): Update code to get gdbarch.
	* disasm.c (dis_asm_read_memory): Change it to
	gdb_disassembler::dis_asm_read_memory.
	(dis_asm_memory_error): Likewise.
	(dis_asm_print_address): Likewise.
	(gdb_pretty_print_insn): Change it to
	gdb_disassembler::pretty_print_insn.
	(dump_insns): Add one argument gdb_disassemlber.  All
	callers updated.
	(do_mixed_source_and_assembly_deprecated): Likewise.
	(do_mixed_source_and_assembly): Likewise.
	(do_assembly_only): Likewise.
	(gdb_disassembler::gdb_disassembler): New.
	(gdb_disassembler::print_insn): New.
	* disasm.h (class gdb_disassembler): New.
	(gdb_pretty_print_insn): Remove declaration.
	(gdb_disassemble_info): Likewise.
	* guile/scm-disasm.c (class gdbscm_disassembler): New.
	(gdbscm_disasm_read_memory_worker): Update.
	(gdbscm_disasm_read_memory): Update.
	(gdbscm_disasm_memory_error): Remove.
	(gdbscm_disasm_print_address): Remove.
	(gdbscm_disassembler::gdbscm_disassembler): New.
	(gdbscm_print_insn_from_port): Update.
	* mips-tdep.c: Include disasm.h.
	(gdb_print_insn_mips): Update code to get gdbarch.
	* record-btrace.c (btrace_insn_history): Update.
	* spu-tdep.c: Include disasm.h.
	(struct spu_dis_asm_data): Remove.
	(struct spu_dis_asm_info): New.
	(spu_dis_asm_print_address): Use spu_dis_asm_info to get
	SPU id.
	(gdb_print_insn_spu): Cast disassemble_info to
	spu_dis_asm_info.
---
 gdb/arm-tdep.c         |   5 +-
 gdb/disasm.c           | 151 +++++++++++++++++++++++++++----------------------
 gdb/disasm.h           |  53 ++++++++++++-----
 gdb/guile/scm-disasm.c |  77 +++++++------------------
 gdb/mips-tdep.c        |   5 +-
 gdb/record-btrace.c    |   5 +-
 gdb/spu-tdep.c         |  20 +++----
 7 files changed, 162 insertions(+), 154 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 2bdfa57..0ae311f 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -27,6 +27,7 @@
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "dis-asm.h"		/* For register styles.  */
+#include "disasm.h"
 #include "regcache.h"
 #include "reggroups.h"
 #include "doublest.h"
@@ -7739,7 +7740,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
 static int
 gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   if (arm_pc_is_thumb (gdbarch, memaddr))
     {
diff --git a/gdb/disasm.c b/gdb/disasm.c
index ae3a2f1..f31d8d3 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -120,28 +120,34 @@ line_has_code_p (htab_t table, struct symtab *symtab, int line)
 }
 
 /* Like target_read_memory, but slightly different parameters.  */
-static int
-dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
-		     struct disassemble_info *info)
+
+int
+gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				       unsigned int len,
+				       struct disassemble_info *info)
 {
   return target_read_code (memaddr, myaddr, len);
 }
 
 /* Like memory_error with slightly different parameters.  */
-static void
-dis_asm_memory_error (int err, bfd_vma memaddr,
-		      struct disassemble_info *info)
+
+void
+gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
+					struct disassemble_info *info)
 {
   memory_error (TARGET_XFER_E_IO, memaddr);
 }
 
 /* Like print_address with slightly different parameters.  */
-static void
-dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+
+void
+gdb_disassembler::dis_asm_print_address (bfd_vma addr,
+					 struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
 
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
+  print_address (self->arch (), addr, self->stream ());
 }
 
 static int
@@ -173,10 +179,9 @@ compare_lines (const void *mle1p, const void *mle2p)
 /* 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)
+gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
+				     const struct disasm_insn *insn,
+				     int flags)
 {
   /* parts of the symbolic representation of the address */
   int unmapped;
@@ -187,6 +192,8 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
   char *filename = NULL;
   char *name = NULL;
   CORE_ADDR pc;
+  struct ui_file *stb = stream ();
+  struct gdbarch *gdbarch = arch ();
 
   ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
   pc = insn->addr;
@@ -254,14 +261,14 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       struct cleanup *cleanups =
 	make_cleanup_ui_file_delete (opcode_stream);
 
-      size = gdbarch_print_insn (gdbarch, pc, di);
+      size = print_insn (pc);
       end_pc = pc + size;
 
       for (;pc < end_pc; ++pc)
 	{
-	  err = (*di->read_memory_func) (pc, &data, 1, di);
+	  err = m_di.read_memory_func (pc, &data, 1, &m_di);
 	  if (err != 0)
-	    (*di->memory_error_func) (err, pc, di);
+	    m_di.memory_error_func (err, pc, &m_di);
 	  fprintf_filtered (opcode_stream, "%s%02x",
 			    spacer, (unsigned) data);
 	  spacer = " ";
@@ -273,7 +280,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       do_cleanups (cleanups);
     }
   else
-    size = gdbarch_print_insn (gdbarch, pc, di);
+    size = print_insn (pc);
 
   uiout->field_stream ("inst", stb);
   ui_file_rewind (stb);
@@ -284,10 +291,9 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static int
-dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
-	    struct disassemble_info * di,
+dump_insns (struct ui_out *uiout, gdb_disassembler *di,
 	    CORE_ADDR low, CORE_ADDR high,
-	    int how_many, int flags, struct ui_file *stb,
+	    int how_many, int flags,
 	    CORE_ADDR *end_pc)
 {
   struct disasm_insn insn;
@@ -300,7 +306,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
     {
       int size;
 
-      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
+      size = di->pretty_print_insn (uiout, &insn, flags);
       if (size <= 0)
 	break;
 
@@ -326,10 +332,10 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 
 static void
 do_mixed_source_and_assembly_deprecated
-  (struct gdbarch *gdbarch, struct ui_out *uiout,
-   struct disassemble_info *di, struct symtab *symtab,
+  (struct ui_out *uiout,
+   gdb_disassembler *di, struct symtab *symtab,
    CORE_ADDR low, CORE_ADDR high,
-   int how_many, int flags, struct ui_file *stb)
+   int how_many, int flags)
 {
   int newlines = 0;
   int nlines;
@@ -462,9 +468,9 @@ do_mixed_source_and_assembly_deprecated
 	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
 	}
 
-      num_displayed += dump_insns (gdbarch, uiout, di,
+      num_displayed += dump_insns (uiout, di,
 				   mle[i].start_pc, mle[i].end_pc,
-				   how_many, flags, stb, NULL);
+				   how_many, flags, NULL);
 
       /* 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.  */
@@ -488,11 +494,12 @@ do_mixed_source_and_assembly_deprecated
    immediately following.  */
 
 static void
-do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
-			      struct disassemble_info *di,
+do_mixed_source_and_assembly (struct gdbarch *gdbarch,
+			      struct ui_out *uiout,
+			      gdb_disassembler *di,
 			      struct symtab *main_symtab,
 			      CORE_ADDR low, CORE_ADDR high,
-			      int how_many, int flags, struct ui_file *stb)
+			      int how_many, int flags)
 {
   const struct linetable_entry *le, *first_le;
   int i, nlines;
@@ -711,8 +718,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 	end_pc = std::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);
+      num_displayed += dump_insns (uiout, di, pc, end_pc,
+				   how_many, flags, &end_pc);
       pc = end_pc;
 
       if (how_many >= 0 && num_displayed >= how_many)
@@ -726,16 +733,16 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static void
-do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
-		  struct disassemble_info * di,
+do_assembly_only (struct ui_out *uiout,
+		  gdb_disassembler *di,
 		  CORE_ADDR low, CORE_ADDR high,
-		  int how_many, int flags, struct ui_file *stb)
+		  int how_many, int flags)
 {
   struct cleanup *ui_out_chain;
 
   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
 
-  dump_insns (gdbarch, uiout, di, low, high, how_many, flags, stb, NULL);
+  dump_insns (uiout, di, low, high, how_many, flags, NULL);
 
   do_cleanups (ui_out_chain);
 }
@@ -755,15 +762,15 @@ fprintf_disasm (void *stream, const char *format, ...)
   return 0;
 }
 
-struct disassemble_info
-gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
+gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
+				    struct ui_file *file,
+				    di_read_memory_ftype read_memory_func)
+  : m_gdbarch (gdbarch)
 {
-  struct disassemble_info di;
-
-  init_disassemble_info (&di, file, fprintf_disasm);
-  di.flavour = bfd_target_unknown_flavour;
-  di.memory_error_func = dis_asm_memory_error;
-  di.print_address_func = dis_asm_print_address;
+  init_disassemble_info (&m_di, file, fprintf_disasm);
+  m_di.flavour = bfd_target_unknown_flavour;
+  m_di.memory_error_func = dis_asm_memory_error;
+  m_di.print_address_func = dis_asm_print_address;
   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
      disassembler had a local optomization here.  By default it would
      access the executable file, instead of the target memory (there
@@ -772,14 +779,29 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
      didn't work as they relied on the access going to the target.
      Further, it has been supperseeded by trust-read-only-sections
      (although that should be superseeded by target_trust..._p()).  */
-  di.read_memory_func = dis_asm_read_memory;
-  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
-  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
-  di.endian = gdbarch_byte_order (gdbarch);
-  di.endian_code = gdbarch_byte_order_for_code (gdbarch);
-  di.application_data = gdbarch;
-  disassemble_init_for_target (&di);
-  return di;
+  m_di.read_memory_func = read_memory_func;
+  m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  m_di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  m_di.endian = gdbarch_byte_order (gdbarch);
+  m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
+  m_di.application_data = this;
+  disassemble_init_for_target (&m_di);
+}
+
+int
+gdb_disassembler::print_insn (CORE_ADDR memaddr,
+			      int *branch_delay_insns)
+{
+  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+
+  if (branch_delay_insns != NULL)
+    {
+      if (m_di.insn_info_valid)
+	*branch_delay_insns = m_di.branch_delay_insns;
+      else
+	*branch_delay_insns = 0;
+    }
+  return length;
 }
 
 void
@@ -789,7 +811,7 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 {
   struct ui_file *stb = mem_fileopen ();
   struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
-  struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   struct symtab *symtab;
   int nlines = -1;
 
@@ -801,15 +823,15 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 
   if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
       || nlines <= 0)
-    do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
+    do_assembly_only (uiout, &di, low, high, how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE)
     do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
-				  how_many, flags, stb);
+				  how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
-    do_mixed_source_and_assembly_deprecated (gdbarch, uiout, &di, symtab,
-					     low, high, how_many, flags, stb);
+    do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+					     low, high, how_many, flags);
 
   do_cleanups (cleanups);
   gdb_flush (gdb_stdout);
@@ -823,19 +845,10 @@ int
 gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
 		struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
 
-  di = gdb_disassemble_info (gdbarch, stream);
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
-  return length;
+  gdb_disassembler di (gdbarch, stream);
+
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 /* Return the length in bytes of the instruction at address MEMADDR in
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 4c6fd54..5122fa3 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -33,6 +33,46 @@ struct gdbarch;
 struct ui_out;
 struct ui_file;
 
+class gdb_disassembler
+{
+  using di_read_memory_ftype = decltype (disassemble_info::read_memory_func);
+
+public:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
+    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
+  {}
+
+  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns = NULL);
+
+  /* Prints the instruction INSN into UIOUT and returns the length of
+     the printed instruction in bytes.  */
+  int pretty_print_insn (struct ui_out *uiout,
+			 const struct disasm_insn *insn, int flags);
+
+  /* Return the gdbarch of gdb_disassembler.  */
+  struct gdbarch *arch ()
+  { return m_gdbarch; }
+
+protected:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
+		    di_read_memory_ftype func);
+
+  struct ui_file *stream ()
+  { return (struct ui_file *) m_di.stream; }
+
+private:
+  struct gdbarch *m_gdbarch;
+  struct disassemble_info m_di;
+
+  static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				  unsigned int len,
+				  struct disassemble_info *info);
+  static void dis_asm_memory_error (int err, bfd_vma memaddr,
+				    struct disassemble_info *info);
+  static void dis_asm_print_address (bfd_vma addr,
+				     struct disassemble_info *info);
+};
+
 /* An instruction to be disassembled.  */
 
 struct disasm_insn
@@ -47,19 +87,6 @@ struct disasm_insn
   unsigned int is_speculative:1;
 };
 
-/* Prints the instruction INSN into UIOUT and returns the length of the
-   printed instruction in bytes.  */
-
-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);
-
-/* Return a filled in disassemble_info object for use by gdb.  */
-
-extern struct disassemble_info gdb_disassemble_info (struct gdbarch *gdbarch,
-						     struct ui_file *file);
-
 extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 			     char *file_string, int flags, int how_many,
 			     CORE_ADDR low, CORE_ADDR high);
diff --git a/gdb/guile/scm-disasm.c b/gdb/guile/scm-disasm.c
index d06c481..25cae5a 100644
--- a/gdb/guile/scm-disasm.c
+++ b/gdb/guile/scm-disasm.c
@@ -37,11 +37,13 @@ static SCM address_symbol;
 static SCM asm_symbol;
 static SCM length_symbol;
 
-/* Struct used to pass "application data" in disassemble_info.  */
-
-struct gdbscm_disasm_data
+class gdbscm_disassembler : public gdb_disassembler
 {
-  struct gdbarch *gdbarch;
+public:
+  gdbscm_disassembler (struct gdbarch *gdbarch,
+		       struct ui_file *stream,
+		       SCM port, ULONGEST offset);
+
   SCM port;
   /* The offset of the address of the first instruction in PORT.  */
   ULONGEST offset;
@@ -55,7 +57,7 @@ struct gdbscm_disasm_read_data
   bfd_vma memaddr;
   bfd_byte *myaddr;
   unsigned int length;
-  struct disassemble_info *dinfo;
+  gdbscm_disassembler *dinfo;
 };
 \f
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -81,13 +83,11 @@ gdbscm_disasm_read_memory_worker (void *datap)
 {
   struct gdbscm_disasm_read_data *data
     = (struct gdbscm_disasm_read_data *) datap;
-  struct disassemble_info *dinfo = data->dinfo;
-  struct gdbscm_disasm_data *disasm_data
-    = (struct gdbscm_disasm_data *) dinfo->application_data;
-  SCM seekto, newpos, port = disasm_data->port;
+  gdbscm_disassembler *dinfo = data->dinfo;
+  SCM seekto, newpos, port = dinfo->port;
   size_t bytes_read;
 
-  seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->offset);
+  seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
   newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
   if (!scm_is_eq (seekto, newpos))
     return "seek error";
@@ -108,13 +108,15 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
 			   unsigned int length,
 			   struct disassemble_info *dinfo)
 {
+  gdbscm_disassembler *self
+    = static_cast<gdbscm_disassembler *> (dinfo->application_data);
   struct gdbscm_disasm_read_data data;
   const char *status;
 
   data.memaddr = memaddr;
   data.myaddr = myaddr;
   data.length = length;
-  data.dinfo = dinfo;
+  data.dinfo = self;
 
   status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
 
@@ -123,30 +125,12 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
   return status != NULL ? -1 : 0;
 }
 
-/* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
-   Technically speaking, we don't need our own memory_error_func,
-   but to not provide one would leave a subtle dependency in the code.
-   This function exists to keep a clear boundary.  */
-
-static void
-gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
-			    struct disassemble_info *info)
-{
-  memory_error (TARGET_XFER_E_IO, memaddr);
-}
-
-/* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
-   Since we need to use our own application_data value, we need to supply
-   this routine as well.  */
-
-static void
-gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
+gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
+					  struct ui_file *stream,
+					  SCM port_, ULONGEST offset_)
+  : gdb_disassembler (gdbarch, stream, gdbscm_disasm_read_memory),
+    port (port_), offset (offset_)
 {
-  struct gdbscm_disasm_data *data
-    = (struct gdbscm_disasm_data *) info->application_data;
-  struct gdbarch *gdbarch = data->gdbarch;
-
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
 }
 
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -164,30 +148,9 @@ gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
 			     SCM port, ULONGEST offset, CORE_ADDR memaddr,
 			     struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
-  struct gdbscm_disasm_data data;
-
-  di = gdb_disassemble_info (gdbarch, stream);
-  data.gdbarch = gdbarch;
-  data.port = port;
-  data.offset = offset;
-  di.application_data = &data;
-  di.read_memory_func = gdbscm_disasm_read_memory;
-  di.memory_error_func = gdbscm_disasm_memory_error;
-  di.print_address_func = gdbscm_disasm_print_address;
-
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
+  gdbscm_disassembler di (gdbarch, stream, port, offset);
 
-  return length;
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 /* (arch-disassemble <gdb:arch> address
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 637b34e..41cb9d8 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -44,6 +44,7 @@
 #include "symcat.h"
 #include "sim-regno.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
 #include "trad-frame.h"
@@ -6982,7 +6983,9 @@ reinit_frame_cache_sfunc (char *args, int from_tty,
 static int
 gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   /* FIXME: cagney/2003-06-26: Is this even necessary?  The
      disassembler needs to be able to locally determine the ISA, and
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 6cba1d2..8896241 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -698,7 +698,6 @@ btrace_insn_history (struct ui_out *uiout,
 {
   struct ui_file *stb;
   struct cleanup *cleanups, *ui_item_chain;
-  struct disassemble_info di;
   struct gdbarch *gdbarch;
   struct btrace_insn_iterator it;
   struct btrace_line_range last_lines;
@@ -711,7 +710,7 @@ btrace_insn_history (struct ui_out *uiout,
   gdbarch = target_gdbarch ();
   stb = mem_fileopen ();
   cleanups = make_cleanup_ui_file_delete (stb);
-  di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   last_lines = btrace_mk_line_range (NULL, 0, 0);
 
   make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
@@ -773,7 +772,7 @@ 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);
+	  di.pretty_print_insn (uiout, &dinsn, flags);
 	}
     }
 
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 8756256..70d7f6f 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -33,6 +33,7 @@
 #include "value.h"
 #include "inferior.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "objfiles.h"
 #include "language.h"
 #include "regcache.h"
@@ -1693,18 +1694,19 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 
 /* Disassembler.  */
 
-struct spu_dis_asm_data
+struct spu_dis_asm_info : disassemble_info
 {
-  struct gdbarch *gdbarch;
   int id;
 };
 
 static void
 spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
 {
-  struct spu_dis_asm_data *data
-    = (struct spu_dis_asm_data *) info->application_data;
-  print_address (data->gdbarch, SPUADDR (data->id, addr),
+  struct spu_dis_asm_info *data = (struct spu_dis_asm_info *) info;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  print_address (di->arch (), SPUADDR (data->id, addr),
 		 (struct ui_file *) info->stream);
 }
 
@@ -1714,12 +1716,10 @@ gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
   /* The opcodes disassembler does 18-bit address arithmetic.  Make
      sure the SPU ID encoded in the high bits is added back when we
      call print_address.  */
-  struct disassemble_info spu_info = *info;
-  struct spu_dis_asm_data data;
-  data.gdbarch = (struct gdbarch *) info->application_data;
-  data.id = SPUADDR_SPU (memaddr);
+  struct spu_dis_asm_info spu_info;
 
-  spu_info.application_data = &data;
+  memcpy (&spu_info, info, sizeof (*info));
+  spu_info.id = SPUADDR_SPU (memaddr);
   spu_info.print_address_func = spu_dis_asm_print_address;
   return print_insn_spu (memaddr, &spu_info);
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 5/6] Disassembly unit test: memory error
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 14:38     ` Luis Machado
  2017-01-20  0:08     ` Pedro Alves
  2017-01-16 10:03   ` [PATCH 1/6] New function null_stream Yao Qi
                     ` (5 subsequent siblings)
  6 siblings, 2 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

This patch adds a unit test about memory error occurs on reading
memory, and check MEMORY_ERROR exception is always thrown.

v2:
 - use null_stream,

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* disasm-selftests.c (gdb_disassembler_memory_error_test): New function.
	(_initialize_disasm_test): Register
	gdb_disassembler_memory_error_test.
---
 gdb/disasm-selftests.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
index 46a0a21..ad2b4eb 100644
--- a/gdb/disasm-selftests.c
+++ b/gdb/disasm-selftests.c
@@ -163,6 +163,48 @@ gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
   SELF_CHECK (di.print_insn (0) == len);
 }
 
+/* Test disassembly on memory error.  */
+
+static void
+gdb_disassembler_memory_error_test (struct gdbarch *gdbarch)
+{
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+    gdb_disassembler_test (struct gdbarch *gdbarch)
+      : gdb_disassembler (gdbarch, null_stream (),
+			  gdb_disassembler_test::read_memory)
+    {
+    }
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len,
+			    struct disassemble_info *info)
+    {
+      /* Always get an error.  */
+      return -1;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch);
+  bool see_memory_error = false;
+
+  TRY
+    {
+      di.print_insn (0);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == MEMORY_ERROR)
+	see_memory_error = true;
+    }
+  END_CATCH
+
+  /* Expect MEMORY_ERROR.   */
+  SELF_CHECK (see_memory_error);
+
+}
+
 } // namespace selftests
 #endif /* GDB_SELF_TEST */
 
@@ -174,5 +216,6 @@ _initialize_disasm_test (void)
 {
 #if GDB_SELF_TEST
   register_self_test (selftests::gdb_disassembler_print_one_insn_test);
+  register_self_test (selftests::gdb_disassembler_memory_error_test);
 #endif
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 0/6 v2] Handle memory error on disassemble
  2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
                   ` (7 preceding siblings ...)
  2017-01-10 12:27 ` [PATCH 8/8] Don't throw exception in dis_asm_memory_error Yao Qi
@ 2017-01-16 10:03 ` Yao Qi
  2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
                     ` (6 more replies)
  8 siblings, 7 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

Hi,
Nowadays, we can set function pointer
disassemble_info.memory_error_func to throw error or exception when
disassembler gets an error, and the caller can/may catch the exception.
Both gdb and objdump use this interface for many years.  After GDB is
switched to C++, this stops working due to the "foreign frame" from
opcodes.  That is to say, a C++ program calls a C function
(print_insn_XXX from opcodes) and this function calls a C++ code which
throws exception.  DW2 C++ exception unwinder can unwind across the C
function frame, unless the C code is compiled with -fexceptions.  As
a result, GDB aborts on memory error during disassembly on some hosts.

This is the V2 of the patch series, and V1 can be found
https://sourceware.org/ml/gdb-patches/2017-01/msg00146.html
All opcodes patches are already committed, and V2 addressed
all the comments from the review.

Patch 1 and 2 are refactor patch.  Patch 4 and 5 add unit
tests to disassembly.  Patch 6 fixes PR 20939 by stopping
throwing exception in disassemble_info.memory_error_func
from gdb, but record the failed memory address.  Exception
is thrown when it is returned from opcodes function and
return value is -1.

Note that PR 20939 needs to be fixed on GDB 7.12 branch, which still
can be built as a C program, so I need to rewrite the patch using C
for 7.12 branch in next step.

Tested gdb for {x86_64, aarch64}-linux.

Yao Qi (6):
  New function null_stream
  Refactor disassembly code
  Call print_insn_mep in mep_gdb_print_insn
  Disassembly unit test: disassemble one instruction
  Disassembly unit test: memory error
  Don't throw exception in dis_asm_memory_error

 gdb/Makefile.in                                 |   5 +
 gdb/arm-tdep.c                                  |   5 +-
 gdb/disasm-selftests.c                          | 221 ++++++++++++++++++++++++
 gdb/disasm.c                                    | 177 ++++++++++---------
 gdb/disasm.h                                    |  54 ++++--
 gdb/guile/scm-disasm.c                          |  77 +++------
 gdb/mep-tdep.c                                  |  10 +-
 gdb/mips-tdep.c                                 |   5 +-
 gdb/record-btrace.c                             |   5 +-
 gdb/selftest-arch.c                             | 103 +++++++++++
 gdb/selftest-arch.h                             |  26 +++
 gdb/spu-tdep.c                                  |  20 +--
 gdb/testsuite/gdb.base/all-architectures.exp.in |   3 +
 gdb/utils.c                                     |  13 ++
 gdb/utils.h                                     |   4 +
 15 files changed, 551 insertions(+), 177 deletions(-)
 create mode 100644 gdb/disasm-selftests.c
 create mode 100644 gdb/selftest-arch.c
 create mode 100644 gdb/selftest-arch.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 6/6] Don't throw exception in dis_asm_memory_error
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
  2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
  2017-01-16 10:03   ` [PATCH 1/6] New function null_stream Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 14:42     ` Luis Machado
  2017-01-16 10:03   ` [PATCH 2/6] Refactor disassembly code Yao Qi
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

Hi,
GDB calls some APIs from opcodes to do disassembly and provide some
call backs.  This model makes troubles on C++ exception unwinding,
because GDB is a C++ program, and opcodes is still compiled as C.
As we can see, frame #10 and #12 are C++, while #frame 11 is C,

 #10 0x0000000000544228 in memory_error (err=TARGET_XFER_E_IO, memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:237
 #11 0x00000000006b0a54 in print_insn_aarch64 (pc=0, info=0xffffffffeeb0) at ../../binutils-gdb/opcodes/aarch64-dis.c:3185
 #12 0x0000000000553590 in gdb_pretty_print_insn (gdbarch=gdbarch@entry=0xbbceb0, uiout=uiout@entry=0xbc73d0, di=di@entry=0xffffffffeeb0,
    insn=0xffffffffed40, insn@entry=0xffffffffed90, flags=flags@entry=0,

C++ exception unwinder can't go across frame #11 unless it has
unwind table.  However, C program on many architectures doesn't
have it in default.  As a result, GDB aborts, which is described
in PR 20939.

This is not the first time we see this kind of problem.  We've
had a commit 89525768cd086a0798a504c81fdf7ebcd4c904e1
"Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH".
We can fix the disassembly bug in a similar way, this is the option one.

Since opcodes is built with gdb, we fix this problem in a different
way as we did for the same issue with readline.  Instead of throwing
exception in dis_asm_memory_error, we record the failed memory
address, and throw exception when GDB returns from opcodes disassemblers.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>
	    Pedro Alves  <palves@redhat.com>

	PR gdb/20939
	* disasm.c (gdb_disassembler::dis_asm_memory_error): Don't
	call memory_error, save memaddr instead.
	(gdb_disassembler::print_insn): If gdbarch_print_insn returns
	negative, cal memory_error.
	* disasm.h (gdb_disassembler) <m_err_memaddr>: New field.

gdb/testsuite:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* gdb.base/all-architectures.exp.in (do_arch_tests): Test
	disassemble on address 0.
---
 gdb/disasm.c                                    | 13 +++++++++++--
 gdb/disasm.h                                    |  1 +
 gdb/testsuite/gdb.base/all-architectures.exp.in |  3 +++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index f31d8d3..8c8c42e 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -135,7 +135,10 @@ void
 gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
 					struct disassemble_info *info)
 {
-  memory_error (TARGET_XFER_E_IO, memaddr);
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  self->m_err_memaddr = memaddr;
 }
 
 /* Like print_address with slightly different parameters.  */
@@ -765,7 +768,8 @@ fprintf_disasm (void *stream, const char *format, ...)
 gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
 				    struct ui_file *file,
 				    di_read_memory_ftype read_memory_func)
-  : m_gdbarch (gdbarch)
+  : m_gdbarch (gdbarch),
+    m_err_memaddr (0)
 {
   init_disassemble_info (&m_di, file, fprintf_disasm);
   m_di.flavour = bfd_target_unknown_flavour;
@@ -792,8 +796,13 @@ int
 gdb_disassembler::print_insn (CORE_ADDR memaddr,
 			      int *branch_delay_insns)
 {
+  m_err_memaddr = 0;
+
   int length = gdbarch_print_insn (arch (), memaddr, &m_di);
 
+  if (length < 0)
+    memory_error (TARGET_XFER_E_IO, m_err_memaddr);
+
   if (branch_delay_insns != NULL)
     {
       if (m_di.insn_info_valid)
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 5122fa3..8e0b9f9 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -63,6 +63,7 @@ protected:
 private:
   struct gdbarch *m_gdbarch;
   struct disassemble_info m_di;
+  CORE_ADDR m_err_memaddr;
 
   static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
 				  unsigned int len,
diff --git a/gdb/testsuite/gdb.base/all-architectures.exp.in b/gdb/testsuite/gdb.base/all-architectures.exp.in
index c7615ac..50a615c 100644
--- a/gdb/testsuite/gdb.base/all-architectures.exp.in
+++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
@@ -152,6 +152,9 @@ proc print_floats {} {
 
 proc do_arch_tests {} {
     print_floats
+
+    gdb_test_internal "disassemble 0x0,+4" \
+	"Cannot access memory at address 0x0"
 }
 
 # Given we can't change arch, osabi, endianness, etc. atomically, we
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 1/6] New function null_stream
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
  2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
@ 2017-01-16 10:03   ` Yao Qi
  2017-01-17 13:49     ` Luis Machado
  2017-01-16 10:03   ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-16 10:03 UTC (permalink / raw)
  To: gdb-patches

This patch adds a new function null_stream, which returns a null
stream.  The null stream can be used in multiple places.  It is
used in gdb_insn_length, and the following patches will use it too.

gdb:

2017-01-13  Yao Qi  <yao.qi@linaro.org>

	* disasm.c (do_ui_file_delete): Delete.
	(gdb_insn_length): Move code creating stream to ...
	* utils.c (null_stream): ... here.  New function.
	* utils.h (null_stream): Declare.
---
 gdb/disasm.c | 17 +----------------
 gdb/utils.c  | 13 +++++++++++++
 gdb/utils.h  |  4 ++++
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index f419501..ae3a2f1 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -838,28 +838,13 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
   return length;
 }
 
-static void
-do_ui_file_delete (void *arg)
-{
-  ui_file_delete ((struct ui_file *) arg);
-}
-
 /* Return the length in bytes of the instruction at address MEMADDR in
    debugged memory.  */
 
 int
 gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
-  static struct ui_file *null_stream = NULL;
-
-  /* Dummy file descriptor for the disassembler.  */
-  if (!null_stream)
-    {
-      null_stream = ui_file_new ();
-      make_final_cleanup (do_ui_file_delete, null_stream);
-    }
-
-  return gdb_print_insn (gdbarch, addr, null_stream, NULL);
+  return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
 }
 
 /* fprintf-function for gdb_buffered_insn_length.  This function is a
diff --git a/gdb/utils.c b/gdb/utils.c
index f142ffe..7bad193 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -199,6 +199,19 @@ make_cleanup_ui_file_delete (struct ui_file *arg)
   return make_cleanup (do_ui_file_delete, arg);
 }
 
+struct ui_file *
+null_stream (void)
+{
+  static struct ui_file *stream = NULL;
+
+  if (stream == NULL)
+    {
+      stream = ui_file_new ();
+      make_final_cleanup (do_ui_file_delete, stream);
+    }
+  return stream;
+}
+
 /* Helper function for make_cleanup_ui_out_redirect_pop.  */
 
 static void
diff --git a/gdb/utils.h b/gdb/utils.h
index c548a50..26e60af 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -189,6 +189,10 @@ extern struct ui_file *gdb_stdtarg;
 extern struct ui_file *gdb_stdtargerr;
 extern struct ui_file *gdb_stdtargin;
 
+/* Return a null stream.  */
+
+extern struct ui_file *null_stream (void);
+
 /* Set the screen dimensions to WIDTH and HEIGHT.  */
 
 extern void set_screen_width_and_height (int width, int height);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-16 10:03   ` [PATCH 1/6] New function null_stream Yao Qi
@ 2017-01-17 13:49     ` Luis Machado
  2017-01-18 14:45       ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-17 13:49 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> This patch adds a new function null_stream, which returns a null
> stream.  The null stream can be used in multiple places.  It is
> used in gdb_insn_length, and the following patches will use it too.
>
> gdb:
>
> 2017-01-13  Yao Qi  <yao.qi@linaro.org>
>
> 	* disasm.c (do_ui_file_delete): Delete.
> 	(gdb_insn_length): Move code creating stream to ...
> 	* utils.c (null_stream): ... here.  New function.
> 	* utils.h (null_stream): Declare.
> ---
>  gdb/disasm.c | 17 +----------------
>  gdb/utils.c  | 13 +++++++++++++
>  gdb/utils.h  |  4 ++++
>  3 files changed, 18 insertions(+), 16 deletions(-)
>
> diff --git a/gdb/disasm.c b/gdb/disasm.c
> index f419501..ae3a2f1 100644
> --- a/gdb/disasm.c
> +++ b/gdb/disasm.c
> @@ -838,28 +838,13 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
>    return length;
>  }
>
> -static void
> -do_ui_file_delete (void *arg)
> -{
> -  ui_file_delete ((struct ui_file *) arg);
> -}
> -
>  /* Return the length in bytes of the instruction at address MEMADDR in
>     debugged memory.  */
>
>  int
>  gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
>  {
> -  static struct ui_file *null_stream = NULL;
> -
> -  /* Dummy file descriptor for the disassembler.  */
> -  if (!null_stream)
> -    {
> -      null_stream = ui_file_new ();
> -      make_final_cleanup (do_ui_file_delete, null_stream);
> -    }
> -
> -  return gdb_print_insn (gdbarch, addr, null_stream, NULL);
> +  return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
>  }
>
>  /* fprintf-function for gdb_buffered_insn_length.  This function is a
> diff --git a/gdb/utils.c b/gdb/utils.c
> index f142ffe..7bad193 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -199,6 +199,19 @@ make_cleanup_ui_file_delete (struct ui_file *arg)
>    return make_cleanup (do_ui_file_delete, arg);
>  }
>
> +struct ui_file *
> +null_stream (void)
> +{
> +  static struct ui_file *stream = NULL;
> +
> +  if (stream == NULL)
> +    {
> +      stream = ui_file_new ();
> +      make_final_cleanup (do_ui_file_delete, stream);
> +    }

Since we're explicitly setting stream to NULL, we will always execute 
the conditional block, so it is not needed. Unless this is supposed to 
reuse a stream, but in that case the code would be incorrect.

> +  return stream;
> +}
> +
>  /* Helper function for make_cleanup_ui_out_redirect_pop.  */
>
>  static void
> diff --git a/gdb/utils.h b/gdb/utils.h
> index c548a50..26e60af 100644
> --- a/gdb/utils.h
> +++ b/gdb/utils.h
> @@ -189,6 +189,10 @@ extern struct ui_file *gdb_stdtarg;
>  extern struct ui_file *gdb_stdtargerr;
>  extern struct ui_file *gdb_stdtargin;
>
> +/* Return a null stream.  */
> +

Spurious newline between comment and prototype.

https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Empty_line_between_subprogram_description_and_the_subprogram_implementation

> +extern struct ui_file *null_stream (void);
> +
>  /* Set the screen dimensions to WIDTH and HEIGHT.  */
>
>  extern void set_screen_width_and_height (int width, int height);
>

Otherwise looks fine.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 2/6] Refactor disassembly code
  2017-01-16 10:03   ` [PATCH 2/6] Refactor disassembly code Yao Qi
@ 2017-01-17 14:14     ` Luis Machado
  2017-01-18 16:34       ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-17 14:14 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> This patch addes class gdb_disassembler, and refactor
> code to use it.  The gdb_disassembler object is saved
> in disassember_info.application_data.  However,
> disassember_info.application_data is already used by
> gdb for arm, mips spu, and scm-disasm.  In arm and mips,
> .application_data is gdbarch, but we can still get gdbarch
> from gdb_disassember.
>
> The use of application_data in spu is a little bit
> complicated.  It creates its own disassemble_info, and
> save spu_dis_asm_data in .application_data.  This will
> overwrite the pointer to gdb_disassembler, so we need
> to find another place to save spu_dis_asm_data.  I
> extend disassemble_info, and put "id" there.
>
> v2:
>  - Merge to print_insn functions into one, with default
>    parameter value,
>
> gdb:
>
> 2017-01-13  Pedro Alves  <palves@redhat.com>
> 	    Yao Qi  <yao.qi@linaro.org>
>
> 	* arm-tdep.c: Include "disasm.h".
> 	(gdb_print_insn_arm): Update code to get gdbarch.
> 	* disasm.c (dis_asm_read_memory): Change it to
> 	gdb_disassembler::dis_asm_read_memory.
> 	(dis_asm_memory_error): Likewise.
> 	(dis_asm_print_address): Likewise.
> 	(gdb_pretty_print_insn): Change it to
> 	gdb_disassembler::pretty_print_insn.
> 	(dump_insns): Add one argument gdb_disassemlber.  All
> 	callers updated.
> 	(do_mixed_source_and_assembly_deprecated): Likewise.
> 	(do_mixed_source_and_assembly): Likewise.
> 	(do_assembly_only): Likewise.
> 	(gdb_disassembler::gdb_disassembler): New.
> 	(gdb_disassembler::print_insn): New.
> 	* disasm.h (class gdb_disassembler): New.
> 	(gdb_pretty_print_insn): Remove declaration.
> 	(gdb_disassemble_info): Likewise.
> 	* guile/scm-disasm.c (class gdbscm_disassembler): New.
> 	(gdbscm_disasm_read_memory_worker): Update.
> 	(gdbscm_disasm_read_memory): Update.
> 	(gdbscm_disasm_memory_error): Remove.
> 	(gdbscm_disasm_print_address): Remove.
> 	(gdbscm_disassembler::gdbscm_disassembler): New.
> 	(gdbscm_print_insn_from_port): Update.
> 	* mips-tdep.c: Include disasm.h.
> 	(gdb_print_insn_mips): Update code to get gdbarch.
> 	* record-btrace.c (btrace_insn_history): Update.
> 	* spu-tdep.c: Include disasm.h.
> 	(struct spu_dis_asm_data): Remove.
> 	(struct spu_dis_asm_info): New.
> 	(spu_dis_asm_print_address): Use spu_dis_asm_info to get
> 	SPU id.
> 	(gdb_print_insn_spu): Cast disassemble_info to
> 	spu_dis_asm_info.
> ---
>  gdb/arm-tdep.c         |   5 +-
>  gdb/disasm.c           | 151 +++++++++++++++++++++++++++----------------------
>  gdb/disasm.h           |  53 ++++++++++++-----
>  gdb/guile/scm-disasm.c |  77 +++++++------------------
>  gdb/mips-tdep.c        |   5 +-
>  gdb/record-btrace.c    |   5 +-
>  gdb/spu-tdep.c         |  20 +++----
>  7 files changed, 162 insertions(+), 154 deletions(-)
>
> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 2bdfa57..0ae311f 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -27,6 +27,7 @@
>  #include "gdbcmd.h"
>  #include "gdbcore.h"
>  #include "dis-asm.h"		/* For register styles.  */
> +#include "disasm.h"

I just noticed this. Unfortunate naming of these two files.

>  #include "regcache.h"
>  #include "reggroups.h"
>  #include "doublest.h"
> @@ -7739,7 +7740,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
>  static int
>  gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
>  {
> -  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
> +  gdb_disassembler *di
> +    = static_cast<gdb_disassembler *>(info->application_data);
> +  struct gdbarch *gdbarch = di->arch ();
>
>    if (arm_pc_is_thumb (gdbarch, memaddr))
>      {
> diff --git a/gdb/disasm.c b/gdb/disasm.c
> index ae3a2f1..f31d8d3 100644
> --- a/gdb/disasm.c
> +++ b/gdb/disasm.c
> @@ -120,28 +120,34 @@ line_has_code_p (htab_t table, struct symtab *symtab, int line)
>  }
>
>  /* Like target_read_memory, but slightly different parameters.  */

Should we update these comments to a more useful version? "slightly 
different parameters" doesn't explain much, as it is obvious they are 
slightly different. Other uses below have the same problem.

> -static int
> -dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
> -		     struct disassemble_info *info)
> +
> +int
> +gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +				       unsigned int len,
> +				       struct disassemble_info *info)
>  {
>    return target_read_code (memaddr, myaddr, len);
>  }
>
>  /* Like memory_error with slightly different parameters.  */
> -static void
> -dis_asm_memory_error (int err, bfd_vma memaddr,
> -		      struct disassemble_info *info)
> +
> +void
> +gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
> +					struct disassemble_info *info)
>  {
>    memory_error (TARGET_XFER_E_IO, memaddr);
>  }
>
>  /* Like print_address with slightly different parameters.  */
> -static void
> -dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
> +
> +void
> +gdb_disassembler::dis_asm_print_address (bfd_vma addr,
> +					 struct disassemble_info *info)
>  {
> -  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
> +  gdb_disassembler *self
> +    = static_cast<gdb_disassembler *>(info->application_data);
>
> -  print_address (gdbarch, addr, (struct ui_file *) info->stream);
> +  print_address (self->arch (), addr, self->stream ());
>  }
>
>  static int
> @@ -173,10 +179,9 @@ compare_lines (const void *mle1p, const void *mle2p)
>  /* 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)
> +gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
> +				     const struct disasm_insn *insn,
> +				     int flags)
>  {
>    /* parts of the symbolic representation of the address */
>    int unmapped;
> @@ -187,6 +192,8 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>    char *filename = NULL;
>    char *name = NULL;
>    CORE_ADDR pc;
> +  struct ui_file *stb = stream ();
> +  struct gdbarch *gdbarch = arch ();
>
>    ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
>    pc = insn->addr;
> @@ -254,14 +261,14 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>        struct cleanup *cleanups =
>  	make_cleanup_ui_file_delete (opcode_stream);
>
> -      size = gdbarch_print_insn (gdbarch, pc, di);
> +      size = print_insn (pc);
>        end_pc = pc + size;
>
>        for (;pc < end_pc; ++pc)
>  	{
> -	  err = (*di->read_memory_func) (pc, &data, 1, di);
> +	  err = m_di.read_memory_func (pc, &data, 1, &m_di);
>  	  if (err != 0)
> -	    (*di->memory_error_func) (err, pc, di);
> +	    m_di.memory_error_func (err, pc, &m_di);
>  	  fprintf_filtered (opcode_stream, "%s%02x",
>  			    spacer, (unsigned) data);
>  	  spacer = " ";
> @@ -273,7 +280,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>        do_cleanups (cleanups);
>      }
>    else
> -    size = gdbarch_print_insn (gdbarch, pc, di);
> +    size = print_insn (pc);
>
>    uiout->field_stream ("inst", stb);
>    ui_file_rewind (stb);
> @@ -284,10 +291,9 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
>  }
>
>  static int
> -dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
> -	    struct disassemble_info * di,
> +dump_insns (struct ui_out *uiout, gdb_disassembler *di,
>  	    CORE_ADDR low, CORE_ADDR high,
> -	    int how_many, int flags, struct ui_file *stb,
> +	    int how_many, int flags,
>  	    CORE_ADDR *end_pc)
>  {
>    struct disasm_insn insn;
> @@ -300,7 +306,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
>      {
>        int size;
>
> -      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
> +      size = di->pretty_print_insn (uiout, &insn, flags);
>        if (size <= 0)
>  	break;
>
> @@ -326,10 +332,10 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
>
>  static void
>  do_mixed_source_and_assembly_deprecated
> -  (struct gdbarch *gdbarch, struct ui_out *uiout,
> -   struct disassemble_info *di, struct symtab *symtab,
> +  (struct ui_out *uiout,
> +   gdb_disassembler *di, struct symtab *symtab,
>     CORE_ADDR low, CORE_ADDR high,
> -   int how_many, int flags, struct ui_file *stb)
> +   int how_many, int flags)
>  {
>    int newlines = 0;
>    int nlines;
> @@ -462,9 +468,9 @@ do_mixed_source_and_assembly_deprecated
>  	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
>  	}
>
> -      num_displayed += dump_insns (gdbarch, uiout, di,
> +      num_displayed += dump_insns (uiout, di,
>  				   mle[i].start_pc, mle[i].end_pc,
> -				   how_many, flags, stb, NULL);
> +				   how_many, flags, NULL);
>
>        /* 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.  */
> @@ -488,11 +494,12 @@ do_mixed_source_and_assembly_deprecated
>     immediately following.  */
>
>  static void
> -do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
> -			      struct disassemble_info *di,
> +do_mixed_source_and_assembly (struct gdbarch *gdbarch,
> +			      struct ui_out *uiout,
> +			      gdb_disassembler *di,
>  			      struct symtab *main_symtab,
>  			      CORE_ADDR low, CORE_ADDR high,
> -			      int how_many, int flags, struct ui_file *stb)
> +			      int how_many, int flags)
>  {
>    const struct linetable_entry *le, *first_le;
>    int i, nlines;
> @@ -711,8 +718,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
>  	end_pc = std::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);
> +      num_displayed += dump_insns (uiout, di, pc, end_pc,
> +				   how_many, flags, &end_pc);
>        pc = end_pc;
>
>        if (how_many >= 0 && num_displayed >= how_many)
> @@ -726,16 +733,16 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
>  }
>
>  static void
> -do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
> -		  struct disassemble_info * di,
> +do_assembly_only (struct ui_out *uiout,
> +		  gdb_disassembler *di,
>  		  CORE_ADDR low, CORE_ADDR high,
> -		  int how_many, int flags, struct ui_file *stb)
> +		  int how_many, int flags)
>  {
>    struct cleanup *ui_out_chain;
>
>    ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
>
> -  dump_insns (gdbarch, uiout, di, low, high, how_many, flags, stb, NULL);
> +  dump_insns (uiout, di, low, high, how_many, flags, NULL);
>
>    do_cleanups (ui_out_chain);
>  }
> @@ -755,15 +762,15 @@ fprintf_disasm (void *stream, const char *format, ...)
>    return 0;
>  }
>
> -struct disassemble_info
> -gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
> +gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
> +				    struct ui_file *file,
> +				    di_read_memory_ftype read_memory_func)
> +  : m_gdbarch (gdbarch)
>  {
> -  struct disassemble_info di;
> -
> -  init_disassemble_info (&di, file, fprintf_disasm);
> -  di.flavour = bfd_target_unknown_flavour;
> -  di.memory_error_func = dis_asm_memory_error;
> -  di.print_address_func = dis_asm_print_address;
> +  init_disassemble_info (&m_di, file, fprintf_disasm);
> +  m_di.flavour = bfd_target_unknown_flavour;
> +  m_di.memory_error_func = dis_asm_memory_error;
> +  m_di.print_address_func = dis_asm_print_address;
>    /* NOTE: cagney/2003-04-28: The original code, from the old Insight
>       disassembler had a local optomization here.  By default it would
>       access the executable file, instead of the target memory (there
> @@ -772,14 +779,29 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
>       didn't work as they relied on the access going to the target.
>       Further, it has been supperseeded by trust-read-only-sections
>       (although that should be superseeded by target_trust..._p()).  */
> -  di.read_memory_func = dis_asm_read_memory;
> -  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
> -  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
> -  di.endian = gdbarch_byte_order (gdbarch);
> -  di.endian_code = gdbarch_byte_order_for_code (gdbarch);
> -  di.application_data = gdbarch;
> -  disassemble_init_for_target (&di);
> -  return di;
> +  m_di.read_memory_func = read_memory_func;
> +  m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
> +  m_di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
> +  m_di.endian = gdbarch_byte_order (gdbarch);
> +  m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
> +  m_di.application_data = this;
> +  disassemble_init_for_target (&m_di);
> +}
> +
> +int
> +gdb_disassembler::print_insn (CORE_ADDR memaddr,
> +			      int *branch_delay_insns)
> +{
> +  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
> +
> +  if (branch_delay_insns != NULL)
> +    {
> +      if (m_di.insn_info_valid)
> +	*branch_delay_insns = m_di.branch_delay_insns;
> +      else
> +	*branch_delay_insns = 0;
> +    }
> +  return length;

length doesn't seem to have a purpose other than being returned. So just 
return gdbarch_print_insn (arch (), memaddr, &m_di)?

>  }
>
>  void
> @@ -789,7 +811,7 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
>  {
>    struct ui_file *stb = mem_fileopen ();
>    struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
> -  struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
> +  gdb_disassembler di (gdbarch, stb);
>    struct symtab *symtab;
>    int nlines = -1;
>
> @@ -801,15 +823,15 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
>
>    if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
>        || nlines <= 0)
> -    do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
> +    do_assembly_only (uiout, &di, low, high, how_many, flags);
>
>    else if (flags & DISASSEMBLY_SOURCE)
>      do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
> -				  how_many, flags, stb);
> +				  how_many, flags);
>
>    else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
> -    do_mixed_source_and_assembly_deprecated (gdbarch, uiout, &di, symtab,
> -					     low, high, how_many, flags, stb);
> +    do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
> +					     low, high, how_many, flags);
>
>    do_cleanups (cleanups);
>    gdb_flush (gdb_stdout);
> @@ -823,19 +845,10 @@ int
>  gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
>  		struct ui_file *stream, int *branch_delay_insns)
>  {
> -  struct disassemble_info di;
> -  int length;
>
> -  di = gdb_disassemble_info (gdbarch, stream);
> -  length = gdbarch_print_insn (gdbarch, memaddr, &di);
> -  if (branch_delay_insns)
> -    {
> -      if (di.insn_info_valid)
> -	*branch_delay_insns = di.branch_delay_insns;
> -      else
> -	*branch_delay_insns = 0;
> -    }
> -  return length;
> +  gdb_disassembler di (gdbarch, stream);
> +
> +  return di.print_insn (memaddr, branch_delay_insns);
>  }
>
>  /* Return the length in bytes of the instruction at address MEMADDR in
> diff --git a/gdb/disasm.h b/gdb/disasm.h
> index 4c6fd54..5122fa3 100644
> --- a/gdb/disasm.h
> +++ b/gdb/disasm.h
> @@ -33,6 +33,46 @@ struct gdbarch;
>  struct ui_out;
>  struct ui_file;
>
> +class gdb_disassembler
> +{
> +  using di_read_memory_ftype = decltype (disassemble_info::read_memory_func);
> +
> +public:
> +  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
> +    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
> +  {}
> +
> +  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns = NULL);
> +
> +  /* Prints the instruction INSN into UIOUT and returns the length of
> +     the printed instruction in bytes.  */
> +  int pretty_print_insn (struct ui_out *uiout,
> +			 const struct disasm_insn *insn, int flags);

Can this function return negative? If not, use unsigned?

> +
> +  /* Return the gdbarch of gdb_disassembler.  */
> +  struct gdbarch *arch ()
> +  { return m_gdbarch; }
> +
> +protected:
> +  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
> +		    di_read_memory_ftype func);
> +
> +  struct ui_file *stream ()
> +  { return (struct ui_file *) m_di.stream; }
> +
> +private:
> +  struct gdbarch *m_gdbarch;
> +  struct disassemble_info m_di;

Add comments explaining what m_gdbarch and m_di are used for and/or how?

> +
> +  static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +				  unsigned int len,
> +				  struct disassemble_info *info);
> +  static void dis_asm_memory_error (int err, bfd_vma memaddr,
> +				    struct disassemble_info *info);
> +  static void dis_asm_print_address (bfd_vma addr,
> +				     struct disassemble_info *info);
> +};
> +
>  /* An instruction to be disassembled.  */
>
>  struct disasm_insn
> @@ -47,19 +87,6 @@ struct disasm_insn
>    unsigned int is_speculative:1;
>  };
>
> -/* Prints the instruction INSN into UIOUT and returns the length of the
> -   printed instruction in bytes.  */
> -
> -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);
> -
> -/* Return a filled in disassemble_info object for use by gdb.  */
> -
> -extern struct disassemble_info gdb_disassemble_info (struct gdbarch *gdbarch,
> -						     struct ui_file *file);
> -
>  extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
>  			     char *file_string, int flags, int how_many,
>  			     CORE_ADDR low, CORE_ADDR high);
> diff --git a/gdb/guile/scm-disasm.c b/gdb/guile/scm-disasm.c
> index d06c481..25cae5a 100644
> --- a/gdb/guile/scm-disasm.c
> +++ b/gdb/guile/scm-disasm.c
> @@ -37,11 +37,13 @@ static SCM address_symbol;
>  static SCM asm_symbol;
>  static SCM length_symbol;
>
> -/* Struct used to pass "application data" in disassemble_info.  */
> -
> -struct gdbscm_disasm_data
> +class gdbscm_disassembler : public gdb_disassembler
>  {
> -  struct gdbarch *gdbarch;
> +public:
> +  gdbscm_disassembler (struct gdbarch *gdbarch,
> +		       struct ui_file *stream,
> +		       SCM port, ULONGEST offset);
> +
>    SCM port;
>    /* The offset of the address of the first instruction in PORT.  */
>    ULONGEST offset;
> @@ -55,7 +57,7 @@ struct gdbscm_disasm_read_data
>    bfd_vma memaddr;
>    bfd_byte *myaddr;
>    unsigned int length;
> -  struct disassemble_info *dinfo;
> +  gdbscm_disassembler *dinfo;
>  };
>  \f
>  /* Subroutine of gdbscm_arch_disassemble to simplify it.
> @@ -81,13 +83,11 @@ gdbscm_disasm_read_memory_worker (void *datap)
>  {
>    struct gdbscm_disasm_read_data *data
>      = (struct gdbscm_disasm_read_data *) datap;
> -  struct disassemble_info *dinfo = data->dinfo;
> -  struct gdbscm_disasm_data *disasm_data
> -    = (struct gdbscm_disasm_data *) dinfo->application_data;
> -  SCM seekto, newpos, port = disasm_data->port;
> +  gdbscm_disassembler *dinfo = data->dinfo;
> +  SCM seekto, newpos, port = dinfo->port;
>    size_t bytes_read;
>
> -  seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->offset);
> +  seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
>    newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
>    if (!scm_is_eq (seekto, newpos))
>      return "seek error";
> @@ -108,13 +108,15 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
>  			   unsigned int length,
>  			   struct disassemble_info *dinfo)
>  {
> +  gdbscm_disassembler *self
> +    = static_cast<gdbscm_disassembler *> (dinfo->application_data);
>    struct gdbscm_disasm_read_data data;
>    const char *status;
>
>    data.memaddr = memaddr;
>    data.myaddr = myaddr;
>    data.length = length;
> -  data.dinfo = dinfo;
> +  data.dinfo = self;
>
>    status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
>
> @@ -123,30 +125,12 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
>    return status != NULL ? -1 : 0;
>  }
>
> -/* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
> -   Technically speaking, we don't need our own memory_error_func,
> -   but to not provide one would leave a subtle dependency in the code.
> -   This function exists to keep a clear boundary.  */
> -
> -static void
> -gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
> -			    struct disassemble_info *info)
> -{
> -  memory_error (TARGET_XFER_E_IO, memaddr);
> -}
> -
> -/* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
> -   Since we need to use our own application_data value, we need to supply
> -   this routine as well.  */
> -
> -static void
> -gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
> +gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
> +					  struct ui_file *stream,
> +					  SCM port_, ULONGEST offset_)
> +  : gdb_disassembler (gdbarch, stream, gdbscm_disasm_read_memory),
> +    port (port_), offset (offset_)
>  {
> -  struct gdbscm_disasm_data *data
> -    = (struct gdbscm_disasm_data *) info->application_data;
> -  struct gdbarch *gdbarch = data->gdbarch;
> -
> -  print_address (gdbarch, addr, (struct ui_file *) info->stream);
>  }
>
>  /* Subroutine of gdbscm_arch_disassemble to simplify it.
> @@ -164,30 +148,9 @@ gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
>  			     SCM port, ULONGEST offset, CORE_ADDR memaddr,
>  			     struct ui_file *stream, int *branch_delay_insns)
>  {
> -  struct disassemble_info di;
> -  int length;
> -  struct gdbscm_disasm_data data;
> -
> -  di = gdb_disassemble_info (gdbarch, stream);
> -  data.gdbarch = gdbarch;
> -  data.port = port;
> -  data.offset = offset;
> -  di.application_data = &data;
> -  di.read_memory_func = gdbscm_disasm_read_memory;
> -  di.memory_error_func = gdbscm_disasm_memory_error;
> -  di.print_address_func = gdbscm_disasm_print_address;
> -
> -  length = gdbarch_print_insn (gdbarch, memaddr, &di);
> -
> -  if (branch_delay_insns)
> -    {
> -      if (di.insn_info_valid)
> -	*branch_delay_insns = di.branch_delay_insns;
> -      else
> -	*branch_delay_insns = 0;
> -    }
> +  gdbscm_disassembler di (gdbarch, stream, port, offset);
>
> -  return length;
> +  return di.print_insn (memaddr, branch_delay_insns);
>  }
>
>  /* (arch-disassemble <gdb:arch> address
> diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
> index 637b34e..41cb9d8 100644
> --- a/gdb/mips-tdep.c
> +++ b/gdb/mips-tdep.c
> @@ -44,6 +44,7 @@
>  #include "symcat.h"
>  #include "sim-regno.h"
>  #include "dis-asm.h"
> +#include "disasm.h"
>  #include "frame-unwind.h"
>  #include "frame-base.h"
>  #include "trad-frame.h"
> @@ -6982,7 +6983,9 @@ reinit_frame_cache_sfunc (char *args, int from_tty,
>  static int
>  gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
>  {
> -  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
> +  gdb_disassembler *di
> +    = static_cast<gdb_disassembler *>(info->application_data);
> +  struct gdbarch *gdbarch = di->arch ();
>
>    /* FIXME: cagney/2003-06-26: Is this even necessary?  The
>       disassembler needs to be able to locally determine the ISA, and
> diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
> index 6cba1d2..8896241 100644
> --- a/gdb/record-btrace.c
> +++ b/gdb/record-btrace.c
> @@ -698,7 +698,6 @@ btrace_insn_history (struct ui_out *uiout,
>  {
>    struct ui_file *stb;
>    struct cleanup *cleanups, *ui_item_chain;
> -  struct disassemble_info di;
>    struct gdbarch *gdbarch;
>    struct btrace_insn_iterator it;
>    struct btrace_line_range last_lines;
> @@ -711,7 +710,7 @@ btrace_insn_history (struct ui_out *uiout,
>    gdbarch = target_gdbarch ();
>    stb = mem_fileopen ();
>    cleanups = make_cleanup_ui_file_delete (stb);
> -  di = gdb_disassemble_info (gdbarch, stb);
> +  gdb_disassembler di (gdbarch, stb);
>    last_lines = btrace_mk_line_range (NULL, 0, 0);
>
>    make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
> @@ -773,7 +772,7 @@ 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);
> +	  di.pretty_print_insn (uiout, &dinsn, flags);
>  	}
>      }
>
> diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
> index 8756256..70d7f6f 100644
> --- a/gdb/spu-tdep.c
> +++ b/gdb/spu-tdep.c
> @@ -33,6 +33,7 @@
>  #include "value.h"
>  #include "inferior.h"
>  #include "dis-asm.h"
> +#include "disasm.h"
>  #include "objfiles.h"
>  #include "language.h"
>  #include "regcache.h"
> @@ -1693,18 +1694,19 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
>
>  /* Disassembler.  */
>
> -struct spu_dis_asm_data
> +struct spu_dis_asm_info : disassemble_info
>  {
> -  struct gdbarch *gdbarch;
>    int id;
>  };
>
>  static void
>  spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
>  {
> -  struct spu_dis_asm_data *data
> -    = (struct spu_dis_asm_data *) info->application_data;
> -  print_address (data->gdbarch, SPUADDR (data->id, addr),
> +  struct spu_dis_asm_info *data = (struct spu_dis_asm_info *) info;
> +  gdb_disassembler *di
> +    = static_cast<gdb_disassembler *>(info->application_data);
> +
> +  print_address (di->arch (), SPUADDR (data->id, addr),
>  		 (struct ui_file *) info->stream);
>  }
>
> @@ -1714,12 +1716,10 @@ gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
>    /* The opcodes disassembler does 18-bit address arithmetic.  Make
>       sure the SPU ID encoded in the high bits is added back when we
>       call print_address.  */
> -  struct disassemble_info spu_info = *info;
> -  struct spu_dis_asm_data data;
> -  data.gdbarch = (struct gdbarch *) info->application_data;
> -  data.id = SPUADDR_SPU (memaddr);
> +  struct spu_dis_asm_info spu_info;
>
> -  spu_info.application_data = &data;
> +  memcpy (&spu_info, info, sizeof (*info));
> +  spu_info.id = SPUADDR_SPU (memaddr);
>    spu_info.print_address_func = spu_dis_asm_print_address;
>    return print_insn_spu (memaddr, &spu_info);
>  }
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn
  2017-01-16 10:03   ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
@ 2017-01-17 14:19     ` Luis Machado
  2017-01-24 10:08       ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-17 14:19 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> opcodes/mep-dis.c:mep_print_insn has already had the code to
> handle the case when info->section is NULL,
>
>   /* Picking the right ISA bitmask for the current context is tricky.  */
>   if (info->section)
>     {
>     }
>   else /* sid or gdb */
>     {
>     }
>
> so that we can still cal print_insn_mep even section can't be found.
> On the other hand, user can disassemble an arbitrary address which
> doesn't map to any section at all.
>
> gdb:
>
> 2017-01-10  Yao Qi  <yao.qi@linaro.org>
>
> 	* mep-tdep.c (mep_gdb_print_insn): Set info->arch
> 	to bfd_arch_mep.  Don't return 0 if section is not
> 	found.  Call print_insn_mep.
> ---
>  gdb/mep-tdep.c | 10 +++-------
>  1 file changed, 3 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
> index 68b0c4b..b1dcc86 100644
> --- a/gdb/mep-tdep.c
> +++ b/gdb/mep-tdep.c
> @@ -1266,13 +1266,12 @@ mep_pseudo_register_write (struct gdbarch *gdbarch,
>  \f
>  /* Disassembly.  */
>
> -/* The mep disassembler needs to know about the section in order to
> -   work correctly.  */

Instead of removing the comment, should we point out what the effects of 
having/not having section info will be?

>  static int
>  mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
>  {
>    struct obj_section * s = find_pc_section (pc);
>
> +  info->arch = bfd_arch_mep;
>    if (s)
>      {
>        /* The libopcodes disassembly code uses the section to find the
> @@ -1280,12 +1279,9 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
>           the me_module index, and the me_module index to select the
>           right instructions to print.  */
>        info->section = s->the_bfd_section;
> -      info->arch = bfd_arch_mep;
> -	
> -      return print_insn_mep (pc, info);
>      }
> -
> -  return 0;
> +
> +  return print_insn_mep (pc, info);
>  }
>
>  \f
>

Otherwise looks OK.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-16 10:03   ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
@ 2017-01-17 14:33     ` Luis Machado
  2017-01-20  0:04     ` Pedro Alves
  1 sibling, 0 replies; 80+ messages in thread
From: Luis Machado @ 2017-01-17 14:33 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> This patch adds one unit test, which disassemble one instruction for
> every gdbarch if available.  The test needs one valid instruction of
> each gdbarch, and most of them are got from breakpoint instruction.
> For the rest gdbarch whose breakpoint instruction isn't a valid
> instruction, I copy one instruction from the gas/testsuite/gas/
> directory.
>
> I get the valid instruction of most gdbarch except ia64, mep, mips,
> tic6x, and xtensa.  People familiar with these arch should be easy
> to extend the test.
>
> In order to achieve "do the unit test for every gdbarch", I add
> selftest-arch.[c,h], so that we can register a function pointer,
> which has one argument gdbarch.  selftest.c will iterate over all
> gdbarches to call the registered function pointer.
>
> v2:
>  - Add comments for getting breakpoint instructions for score and
>    nios2,
>  - Provide more contents in gdb_disassembler_test::read_memory if
>    caller requests more than one instruction,
>  - Stop using compound literal,
>  - Use null_stream,
>  - Split "selftest for each gdbarch" out of selftest.{c,h},
>
> gdb:
>
> 2017-01-13  Yao Qi  <yao.qi@linaro.org>
>
> 	* Makefile.in (SFILES): Add disasm-selftests.c and
> 	selftest-arch.c.
> 	(COMMON_OBS): Add disasm-selftests.o and selftest-arch.o.
> 	* disasm-selftests.c: New file.
> 	* selftest-arch.c: New file.
> 	* selftest-arch.h: New file.
> ---
>  gdb/Makefile.in        |   5 ++
>  gdb/disasm-selftests.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/selftest-arch.c    | 103 ++++++++++++++++++++++++++++
>  gdb/selftest-arch.h    |  26 ++++++++
>  4 files changed, 312 insertions(+)
>  create mode 100644 gdb/disasm-selftests.c
>  create mode 100644 gdb/selftest-arch.c
>  create mode 100644 gdb/selftest-arch.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3ce7d69..e0fe442 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1039,6 +1039,7 @@ SFILES = \
>  	dfp.c \
>  	dictionary.c \
>  	disasm.c \
> +	disasm-selftests.c \
>  	doublest.c \
>  	dtrace-probe.c \
>  	dummy-frame.c \
> @@ -1140,6 +1141,7 @@ SFILES = \
>  	rust-exp.y \
>  	rust-lang.c \
>  	selftest.c \
> +	selftest-arch.c \
>  	sentinel-frame.c \
>  	ser-base.c \
>  	ser-event.c \
> @@ -1396,6 +1398,7 @@ HFILES_NO_SRCDIR = \
>  	rs6000-tdep.h \
>  	s390-linux-tdep.h \
>  	score-tdep.h \
> +	selftest-arch.h \
>  	sentinel-frame.h \
>  	ser-base.h \
>  	ser-event.h \
> @@ -1643,6 +1646,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	dfp.o \
>  	dictionary.o \
>  	disasm.o \
> +	disasm-selftests.o \
>  	doublest.o \
>  	dummy-frame.o \
>  	dwarf2-frame.o \
> @@ -1744,6 +1748,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	run-time-clock.o \
>  	rust-lang.o \
>  	selftest.o \
> +	selftest-arch.o \
>  	sentinel-frame.o \
>  	ser-event.o \
>  	serial.o \
> diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
> new file mode 100644
> index 0000000..46a0a21
> --- /dev/null
> +++ b/gdb/disasm-selftests.c
> @@ -0,0 +1,178 @@
> +/* Self tests for disassembler for GDB, the GNU debugger.
> +
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#include "defs.h"
> +#include "disasm.h"
> +
> +#if GDB_SELF_TEST
> +#include "selftest.h"
> +#include "selftest-arch.h"
> +
> +namespace selftests {
> +
> +/* Test disassembly of one instruction.  */
> +
> +static void
> +gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)

One suggestion. Do you think it is worth repeating the context of the 
test in the function names? We already know this is a gdb disassembler 
selftest from the name of the source file.

If we don't think it is worth it, we could significantly reduce the 
length of the name of these functions.

> +{
> +  size_t len = 0;
> +  const gdb_byte *insn = NULL;
> +
> +  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
> +    {
> +    case bfd_arch_bfin:
> +      /* M3.L = 0xe117 */
> +      static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
> +
> +      insn = bfin_insn;
> +      len = sizeof (bfin_insn);
> +      break;
> +    case bfd_arch_arm:
> +      /* mov     r0, #0 */
> +      static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
> +
> +      insn = arm_insn;
> +      len = sizeof (arm_insn);
> +      break;
> +    case bfd_arch_ia64:
> +    case bfd_arch_mep:
> +    case bfd_arch_mips:
> +    case bfd_arch_tic6x:
> +    case bfd_arch_xtensa:
> +      return;
> +    case bfd_arch_s390:
> +      /* nopr %r7 */
> +      static const gdb_byte s390_insn[] = {0x07, 0x07};
> +
> +      insn = s390_insn;
> +      len = sizeof (s390_insn);
> +      break;
> +    case bfd_arch_xstormy16:
> +      /* nop */
> +      static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
> +
> +      insn = xstormy16_insn;
> +      len = sizeof (xstormy16_insn);
> +      break;
> +    case bfd_arch_arc:
> +      {
> +	/* PR 21003 */
> +	if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
> +	  return;
> +      }
> +    case bfd_arch_nios2:
> +    case bfd_arch_score:
> +      /* nios2 and score need to know the current instruction to select
> +	 breakpoint instruction.  Give the breakpoint instruction kind
> +	 explicitly.  */
> +      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, (int *) &len);
> +      break;
> +    default:
> +      {
> +	/* Test disassemble breakpoint instruction.  */
> +	CORE_ADDR pc = 0;
> +	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
> +
> +	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind,
> +						(int *) &len);
> +
> +	break;
> +      }
> +    }
> +  SELF_CHECK (len > 0);
> +
> +  /* Test gdb_disassembler for a given gdbarch by reading data from a
> +     pre-allocated buffer.  If you want to see the disassembled
> +     instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
> +     to true.  */
> +
> +  class gdb_disassembler_test : public gdb_disassembler
> +  {
> +  public:
> +
> +    const bool DISASSEMBLER_TEST_VERBOSE = false;
> +
> +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> +				    const gdb_byte *insn,
> +				    size_t len)
> +      : gdb_disassembler (gdbarch,
> +			  (DISASSEMBLER_TEST_VERBOSE
> +			   ? gdb_stdout : null_stream ()),
> +			  gdb_disassembler_test::read_memory),
> +	m_insn (insn), m_len (len)
> +    {
> +    }
> +
> +    int

Can this ever return negative? If not, then unsigned? This ties down 
with the comment on the other patch.

> +    print_insn (CORE_ADDR memaddr)
> +    {
> +      if (DISASSEMBLER_TEST_VERBOSE)
> +	{
> +	  fprintf_unfiltered (stream (), "%s ",
> +			      gdbarch_bfd_arch_info (arch ())->arch_name);
> +	}
> +
> +      int len = gdb_disassembler::print_insn (memaddr);
> +
> +      if (DISASSEMBLER_TEST_VERBOSE)
> +	fprintf_unfiltered (stream (), "\n");
> +
> +      return len;
> +    }
> +
> +  private:
> +    /* A buffer contain one instruction.  */

"A buffer containing..." or "A buffer contains ..."

> +    const gdb_byte *m_insn;
> +
> +    /* Length of the buffer.  */
> +    size_t m_len;
> +
> +    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +			    unsigned int len, struct disassemble_info *info)
> +    {
> +      gdb_disassembler_test *self
> +	= static_cast<gdb_disassembler_test *>(info->application_data);
> +
> +      /* The disassembler in opcodes may read more data than one
> +	 instruction.  */
> +      for (unsigned int i = 0; i < len; i++)
> +	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
> +
> +      return 0;
> +    }
> +  };
> +
> +  gdb_disassembler_test di (gdbarch, insn, len);
> +
> +  SELF_CHECK (di.print_insn (0) == len);
> +}
> +
> +} // namespace selftests
> +#endif /* GDB_SELF_TEST */
> +
> +/* Suppress warning from -Wmissing-prototypes.  */
> +extern initialize_file_ftype _initialize_disasm_test;
> +
> +void
> +_initialize_disasm_test (void)
> +{
> +#if GDB_SELF_TEST
> +  register_self_test (selftests::gdb_disassembler_print_one_insn_test);
> +#endif
> +}
> diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
> new file mode 100644
> index 0000000..aa716be
> --- /dev/null
> +++ b/gdb/selftest-arch.c
> @@ -0,0 +1,103 @@
> +/* GDB self-test for each gdbarch.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#include "defs.h"
> +
> +#if GDB_SELF_TEST
> +#include "selftest.h"
> +#include "selftest-arch.h"
> +#include "arch-utils.h"
> +
> +static std::vector<self_test_function_with_gdbarch *> gdbarch_tests;
> +
> +void
> +register_self_test (self_test_function_with_gdbarch *function)
> +{
> +  gdbarch_tests.push_back (function);
> +}
> +
> +namespace selftests {
> +
> +static void
> +tests_with_arch (void)
> +{
> +  int failed = 0;
> +
> +  for (const auto &f : gdbarch_tests)
> +    {
> +      const char **arches = gdbarch_printable_names ();
> +      int i;
> +
> +      for (i = 0; arches[i] != NULL; i++)
> +	{
> +	  if (strcmp ("fr300", arches[i]) == 0)
> +	    {
> +	      /* PR 20946 */
> +	      continue;
> +	    }
> +	  else if (strcmp ("powerpc:EC603e", arches[i]) == 0
> +		   || strcmp ("powerpc:e500mc", arches[i]) == 0
> +		   || strcmp ("powerpc:e500mc64", arches[i]) == 0
> +		   || strcmp ("powerpc:titan", arches[i]) == 0
> +		   || strcmp ("powerpc:vle", arches[i]) == 0
> +		   || strcmp ("powerpc:e5500", arches[i]) == 0
> +		   || strcmp ("powerpc:e6500", arches[i]) == 0)
> +	    {
> +	      /* PR 19797 */
> +	      continue;
> +	    }
> +
> +	  QUIT;
> +
> +	  TRY
> +	    {
> +	      struct gdbarch_info info;
> +
> +	      gdbarch_info_init (&info);
> +	      info.bfd_arch_info = bfd_scan_arch (arches[i]);
> +
> +	      struct gdbarch *gdbarch = gdbarch_find_by_info (info);
> +	      SELF_CHECK (gdbarch != NULL);
> +	      f (gdbarch);
> +	    }
> +	  CATCH (ex, RETURN_MASK_ERROR)
> +	    {
> +	      ++failed;
> +	      exception_fprintf (gdb_stderr, ex,
> +				 _("Self test failed: arch %s: "), arches[i]);
> +	    }
> +	  END_CATCH
> +	}
> +    }
> +
> +  SELF_CHECK (failed == 0);
> +}
> +
> +} // namespace selftests
> +#endif /* GDB_SELF_TEST */
> +
> +/* Suppress warning from -Wmissing-prototypes.  */
> +extern initialize_file_ftype _initialize_selftests_with_arch;
> +
> +void
> +_initialize_selftests_with_arch (void)
> +{
> +#if GDB_SELF_TEST
> +  register_self_test (selftests::tests_with_arch);
> +#endif
> +}
> diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h
> new file mode 100644
> index 0000000..d63c2d2
> --- /dev/null
> +++ b/gdb/selftest-arch.h
> @@ -0,0 +1,26 @@
> +/* GDB self-test for each gdbarch.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef SELFTEST_ARCH_H
> +#define SELFTEST_ARCH_H
> +
> +typedef void self_test_function_with_gdbarch (struct gdbarch *);
> +
> +extern void register_self_test (self_test_function_with_gdbarch *function);
> +
> +#endif /* SELFTEST_ARCH_H */
>

Otherwise looks OK

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 5/6] Disassembly unit test: memory error
  2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
@ 2017-01-17 14:38     ` Luis Machado
  2017-01-24 15:33       ` Yao Qi
  2017-01-20  0:08     ` Pedro Alves
  1 sibling, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-17 14:38 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> This patch adds a unit test about memory error occurs on reading
> memory, and check MEMORY_ERROR exception is always thrown.
>
> v2:
>  - use null_stream,
>
> gdb:
>
> 2017-01-10  Yao Qi  <yao.qi@linaro.org>
>
> 	* disasm-selftests.c (gdb_disassembler_memory_error_test): New function.
> 	(_initialize_disasm_test): Register
> 	gdb_disassembler_memory_error_test.
> ---
>  gdb/disasm-selftests.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>
> diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
> index 46a0a21..ad2b4eb 100644
> --- a/gdb/disasm-selftests.c
> +++ b/gdb/disasm-selftests.c
> @@ -163,6 +163,48 @@ gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
>    SELF_CHECK (di.print_insn (0) == len);
>  }
>
> +/* Test disassembly on memory error.  */
> +
> +static void
> +gdb_disassembler_memory_error_test (struct gdbarch *gdbarch)

Same comment as the other patch. Do we need to repeat the context of the 
test in the function name?

> +{
> +  class gdb_disassembler_test : public gdb_disassembler
> +  {
> +  public:
> +    gdb_disassembler_test (struct gdbarch *gdbarch)
> +      : gdb_disassembler (gdbarch, null_stream (),
> +			  gdb_disassembler_test::read_memory)
> +    {
> +    }
> +
> +    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +			    unsigned int len,
> +			    struct disassemble_info *info)
> +    {
> +      /* Always get an error.  */

/* Always return an error.  */

Also, should we return an explicit error like TARGET_XFER_E_IO or 
MEMORY_ERROR?

> +      return -1;
> +    }
> +  };
> +
> +  gdb_disassembler_test di (gdbarch);
> +  bool see_memory_error = false;
> +
> +  TRY
> +    {
> +      di.print_insn (0);
> +    }
> +  CATCH (ex, RETURN_MASK_ERROR)
> +    {
> +      if (ex.error == MEMORY_ERROR)
> +	see_memory_error = true;
> +    }
> +  END_CATCH
> +
> +  /* Expect MEMORY_ERROR.   */

Too many spaces after period.

> +  SELF_CHECK (see_memory_error);
> +

Spurious newline?

> +}
> +
>  } // namespace selftests
>  #endif /* GDB_SELF_TEST */
>
> @@ -174,5 +216,6 @@ _initialize_disasm_test (void)
>  {
>  #if GDB_SELF_TEST
>    register_self_test (selftests::gdb_disassembler_print_one_insn_test);
> +  register_self_test (selftests::gdb_disassembler_memory_error_test);
>  #endif
>  }
>

Otherwise OK.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/6] Don't throw exception in dis_asm_memory_error
  2017-01-16 10:03   ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
@ 2017-01-17 14:42     ` Luis Machado
  2017-01-18 14:54       ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-17 14:42 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 04:02 AM, Yao Qi wrote:
> Hi,
> GDB calls some APIs from opcodes to do disassembly and provide some
> call backs.  This model makes troubles on C++ exception unwinding,
> because GDB is a C++ program, and opcodes is still compiled as C.
> As we can see, frame #10 and #12 are C++, while #frame 11 is C,
>
>  #10 0x0000000000544228 in memory_error (err=TARGET_XFER_E_IO, memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:237
>  #11 0x00000000006b0a54 in print_insn_aarch64 (pc=0, info=0xffffffffeeb0) at ../../binutils-gdb/opcodes/aarch64-dis.c:3185
>  #12 0x0000000000553590 in gdb_pretty_print_insn (gdbarch=gdbarch@entry=0xbbceb0, uiout=uiout@entry=0xbc73d0, di=di@entry=0xffffffffeeb0,
>     insn=0xffffffffed40, insn@entry=0xffffffffed90, flags=flags@entry=0,
>
> C++ exception unwinder can't go across frame #11 unless it has
> unwind table.  However, C program on many architectures doesn't
> have it in default.  As a result, GDB aborts, which is described
> in PR 20939.
>
> This is not the first time we see this kind of problem.  We've
> had a commit 89525768cd086a0798a504c81fdf7ebcd4c904e1
> "Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH".
> We can fix the disassembly bug in a similar way, this is the option one.
>
> Since opcodes is built with gdb, we fix this problem in a different
> way as we did for the same issue with readline.  Instead of throwing
> exception in dis_asm_memory_error, we record the failed memory
> address, and throw exception when GDB returns from opcodes disassemblers.
>
> gdb:
>
> 2017-01-10  Yao Qi  <yao.qi@linaro.org>
> 	    Pedro Alves  <palves@redhat.com>
>
> 	PR gdb/20939
> 	* disasm.c (gdb_disassembler::dis_asm_memory_error): Don't
> 	call memory_error, save memaddr instead.
> 	(gdb_disassembler::print_insn): If gdbarch_print_insn returns
> 	negative, cal memory_error.
> 	* disasm.h (gdb_disassembler) <m_err_memaddr>: New field.
>
> gdb/testsuite:
>
> 2017-01-10  Yao Qi  <yao.qi@linaro.org>
>
> 	* gdb.base/all-architectures.exp.in (do_arch_tests): Test
> 	disassemble on address 0.
> ---
>  gdb/disasm.c                                    | 13 +++++++++++--
>  gdb/disasm.h                                    |  1 +
>  gdb/testsuite/gdb.base/all-architectures.exp.in |  3 +++
>  3 files changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/gdb/disasm.c b/gdb/disasm.c
> index f31d8d3..8c8c42e 100644
> --- a/gdb/disasm.c
> +++ b/gdb/disasm.c
> @@ -135,7 +135,10 @@ void
>  gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
>  					struct disassemble_info *info)
>  {
> -  memory_error (TARGET_XFER_E_IO, memaddr);
> +  gdb_disassembler *self
> +    = static_cast<gdb_disassembler *>(info->application_data);
> +
> +  self->m_err_memaddr = memaddr;
>  }
>
>  /* Like print_address with slightly different parameters.  */
> @@ -765,7 +768,8 @@ fprintf_disasm (void *stream, const char *format, ...)
>  gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
>  				    struct ui_file *file,
>  				    di_read_memory_ftype read_memory_func)
> -  : m_gdbarch (gdbarch)
> +  : m_gdbarch (gdbarch),
> +    m_err_memaddr (0)
>  {
>    init_disassemble_info (&m_di, file, fprintf_disasm);
>    m_di.flavour = bfd_target_unknown_flavour;
> @@ -792,8 +796,13 @@ int
>  gdb_disassembler::print_insn (CORE_ADDR memaddr,
>  			      int *branch_delay_insns)
>  {
> +  m_err_memaddr = 0;
> +
>    int length = gdbarch_print_insn (arch (), memaddr, &m_di);
>
> +  if (length < 0)
> +    memory_error (TARGET_XFER_E_IO, m_err_memaddr);
> +
>    if (branch_delay_insns != NULL)
>      {
>        if (m_di.insn_info_valid)
> diff --git a/gdb/disasm.h b/gdb/disasm.h
> index 5122fa3..8e0b9f9 100644
> --- a/gdb/disasm.h
> +++ b/gdb/disasm.h
> @@ -63,6 +63,7 @@ protected:
>  private:
>    struct gdbarch *m_gdbarch;
>    struct disassemble_info m_di;
> +  CORE_ADDR m_err_memaddr;
>
>    static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
>  				  unsigned int len,
> diff --git a/gdb/testsuite/gdb.base/all-architectures.exp.in b/gdb/testsuite/gdb.base/all-architectures.exp.in
> index c7615ac..50a615c 100644
> --- a/gdb/testsuite/gdb.base/all-architectures.exp.in
> +++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
> @@ -152,6 +152,9 @@ proc print_floats {} {
>
>  proc do_arch_tests {} {
>      print_floats
> +
> +    gdb_test_internal "disassemble 0x0,+4" \
> +	"Cannot access memory at address 0x0"

I think you missed the comment you had proposed?

# GDB can't access any memory because there is no live inferior.

I take it we have no loaded executable as well? Otherwise we could 
eventually read data from the executable file, which wouldn't yield an 
error.

>  }
>
>  # Given we can't change arch, osabi, endianness, etc. atomically, we
>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-17 13:49     ` Luis Machado
@ 2017-01-18 14:45       ` Yao Qi
  2017-01-18 14:53         ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-18 14:45 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On 17-01-17 07:49:07, Luis Machado wrote:
> >
> >+struct ui_file *
> >+null_stream (void)
> >+{
> >+  static struct ui_file *stream = NULL;
> >+
> >+  if (stream == NULL)
> >+    {
> >+      stream = ui_file_new ();
> >+      make_final_cleanup (do_ui_file_delete, stream);
> >+    }
> 
> Since we're explicitly setting stream to NULL, we will always
> execute the conditional block, so it is not needed. Unless this is
> supposed to reuse a stream, but in that case the code would be
> incorrect.
> 

It is a reused null stream.  Different parts of gdb can use it.  Why
is it incorrect?

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 14:45       ` Yao Qi
@ 2017-01-18 14:53         ` Luis Machado
  2017-01-18 14:57           ` Simon Marchi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-18 14:53 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 01/18/2017 08:45 AM, Yao Qi wrote:
> On 17-01-17 07:49:07, Luis Machado wrote:
>>>
>>> +struct ui_file *
>>> +null_stream (void)
>>> +{
>>> +  static struct ui_file *stream = NULL;
>>> +
>>> +  if (stream == NULL)
>>> +    {
>>> +      stream = ui_file_new ();
>>> +      make_final_cleanup (do_ui_file_delete, stream);
>>> +    }
>>
>> Since we're explicitly setting stream to NULL, we will always
>> execute the conditional block, so it is not needed. Unless this is
>> supposed to reuse a stream, but in that case the code would be
>> incorrect.
>>
>
> It is a reused null stream.  Different parts of gdb can use it.  Why
> is it incorrect?
>

We're setting stream to NULL at the top of the function and then 
checking if it is NULL (it obviously is) right after that? Am i missing 
something?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/6] Don't throw exception in dis_asm_memory_error
  2017-01-17 14:42     ` Luis Machado
@ 2017-01-18 14:54       ` Yao Qi
  2017-01-18 14:58         ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-18 14:54 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On 17-01-17 08:42:24, Luis Machado wrote:
> >+    gdb_test_internal "disassemble 0x0,+4" \
> >+	"Cannot access memory at address 0x0"
> 
> I think you missed the comment you had proposed?
>

Sorry.
 
> # GDB can't access any memory because there is no live inferior.
> 
> I take it we have no loaded executable as well? Otherwise we could
> eventually read data from the executable file, which wouldn't yield
> an error.

How about this?

    # GDB can't access memory because there is no loaded executable
    # nor live inferior.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 14:53         ` Luis Machado
@ 2017-01-18 14:57           ` Simon Marchi
  2017-01-18 15:02             ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Simon Marchi @ 2017-01-18 14:57 UTC (permalink / raw)
  To: Luis Machado; +Cc: Yao Qi, gdb-patches

On 2017-01-18 09:53, Luis Machado wrote:
> We're setting stream to NULL at the top of the function and then
> checking if it is NULL (it obviously is) right after that? Am i
> missing something?

The "static" :).

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 6/6] Don't throw exception in dis_asm_memory_error
  2017-01-18 14:54       ` Yao Qi
@ 2017-01-18 14:58         ` Luis Machado
  0 siblings, 0 replies; 80+ messages in thread
From: Luis Machado @ 2017-01-18 14:58 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 01/18/2017 08:54 AM, Yao Qi wrote:
> On 17-01-17 08:42:24, Luis Machado wrote:
>>> +    gdb_test_internal "disassemble 0x0,+4" \
>>> +	"Cannot access memory at address 0x0"
>>
>> I think you missed the comment you had proposed?
>>
>
> Sorry.
>
>> # GDB can't access any memory because there is no live inferior.
>>
>> I take it we have no loaded executable as well? Otherwise we could
>> eventually read data from the executable file, which wouldn't yield
>> an error.
>
> How about this?
>
>     # GDB can't access memory because there is no loaded executable
>     # nor live inferior.
>

Looks good to me.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 14:57           ` Simon Marchi
@ 2017-01-18 15:02             ` Luis Machado
  2017-01-18 15:18               ` Simon Marchi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-18 15:02 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Yao Qi, gdb-patches

On 01/18/2017 08:57 AM, Simon Marchi wrote:
> On 2017-01-18 09:53, Luis Machado wrote:
>> We're setting stream to NULL at the top of the function and then
>> checking if it is NULL (it obviously is) right after that? Am i
>> missing something?
>
> The "static" :).

Oh, that's what i was missing!

Can't we have a clearer way of reusing this stream? It looks cryptic 
this way (at least i think it looks cryptic).

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 15:02             ` Luis Machado
@ 2017-01-18 15:18               ` Simon Marchi
  2017-01-18 15:29                 ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Simon Marchi @ 2017-01-18 15:18 UTC (permalink / raw)
  To: Luis Machado; +Cc: Yao Qi, gdb-patches

On 2017-01-18 10:01, Luis Machado wrote:
> On 01/18/2017 08:57 AM, Simon Marchi wrote:
>> On 2017-01-18 09:53, Luis Machado wrote:
>>> We're setting stream to NULL at the top of the function and then
>>> checking if it is NULL (it obviously is) right after that? Am i
>>> missing something?
>> 
>> The "static" :).
> 
> Oh, that's what i was missing!
> 
> Can't we have a clearer way of reusing this stream? It looks cryptic
> this way (at least i think it looks cryptic).

With Pedro's ui_file c++ification series, there is a null_file 
specialization of ui_file, and it's just a global object that you can 
reference.

Search for "null_file null_stream" in

   https://sourceware.org/ml/gdb-patches/2017-01/msg00312.html

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 15:18               ` Simon Marchi
@ 2017-01-18 15:29                 ` Luis Machado
  2017-01-18 15:54                   ` Simon Marchi
  0 siblings, 1 reply; 80+ messages in thread
From: Luis Machado @ 2017-01-18 15:29 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Yao Qi, gdb-patches

On 01/18/2017 09:18 AM, Simon Marchi wrote:
> On 2017-01-18 10:01, Luis Machado wrote:
>> On 01/18/2017 08:57 AM, Simon Marchi wrote:
>>> On 2017-01-18 09:53, Luis Machado wrote:
>>>> We're setting stream to NULL at the top of the function and then
>>>> checking if it is NULL (it obviously is) right after that? Am i
>>>> missing something?
>>>
>>> The "static" :).
>>
>> Oh, that's what i was missing!
>>
>> Can't we have a clearer way of reusing this stream? It looks cryptic
>> this way (at least i think it looks cryptic).
>
> With Pedro's ui_file c++ification series, there is a null_file
> specialization of ui_file, and it's just a global object that you can
> reference.
>
> Search for "null_file null_stream" in
>
>   https://sourceware.org/ml/gdb-patches/2017-01/msg00312.html

That is perfectly fine. The cryptic bit i was referring to was 
declaring/initializing a static variable inside this particular function.

It ought to be possible to initialize the static variable somewhere else 
and only do the null check/allocation in the function? Compilers will 
often zero these out too, so initializing to NULL may not even be needed?

The fact that the initialization only happens once but the source line 
is there forever can cause some confusion.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 15:29                 ` Luis Machado
@ 2017-01-18 15:54                   ` Simon Marchi
  2017-01-18 16:36                     ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Simon Marchi @ 2017-01-18 15:54 UTC (permalink / raw)
  To: Luis Machado; +Cc: Yao Qi, gdb-patches

On 2017-01-18 10:28, Luis Machado wrote:
> That is perfectly fine. The cryptic bit i was referring to was
> declaring/initializing a static variable inside this particular
> function.

Indeed, and I pointed to Pedro's patch because it removes that.  The 
global object is statically allocated and is constructed at startup, so 
there's no more checking if it's initialized nor static variable inside 
a function.

> It ought to be possible to initialize the static variable somewhere
> else and only do the null check/allocation in the function? Compilers
> will often zero these out too, so initializing to NULL may not even be
> needed?

I think this is a common pattern when you want to have a singleton with 
lazy initialization, but I agree that it can be confusing.  The 
variables with static storage duration are put in .bss (since they are 
not in .data), so yes they'd be initialized to 0 automatically, I 
believe.  I prefer to see the = NULL though.

Of course we could move the variable outside the scope of the function, 
but then it would be possible to reference it from other functions.  The 
goal of declaring it in the function is that the only way to reach it is 
by calling the function it's in.

> The fact that the initialization only happens once but the source line
> is there forever can cause some confusion.

Well, you can thank Mr Ritchie & friends I suppose :).

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 2/6] Refactor disassembly code
  2017-01-17 14:14     ` Luis Machado
@ 2017-01-18 16:34       ` Yao Qi
  2017-01-18 16:53         ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-18 16:34 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On 17-01-17 08:14:27, Luis Machado wrote:
> >
> > /* Like target_read_memory, but slightly different parameters.  */
> 
> Should we update these comments to a more useful version? "slightly
> different parameters" doesn't explain much, as it is obvious they
> are slightly different. Other uses below have the same problem.

How about this?

  /* Wrapper of target_read_code.  */

> 
> >-static int
> >-dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
> >-		     struct disassemble_info *info)
> >+
> >+int
> >+gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> >+				       unsigned int len,
> >+				       struct disassemble_info *info)
> > {
> >   return target_read_code (memaddr, myaddr, len);
> > }
> >
> > /* Like memory_error with slightly different parameters.  */

and how about

/* Wrapper of memory_error.  */

> >-static void
> >-dis_asm_memory_error (int err, bfd_vma memaddr,
> >-		      struct disassemble_info *info)
> >+
> >+

> >+int
> >+gdb_disassembler::print_insn (CORE_ADDR memaddr,
> >+			      int *branch_delay_insns)
> >+{
> >+  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
> >+
> >+  if (branch_delay_insns != NULL)
> >+    {
> >+      if (m_di.insn_info_valid)
> >+	*branch_delay_insns = m_di.branch_delay_insns;
> >+      else
> >+	*branch_delay_insns = 0;
> >+    }
> >+  return length;
> 
> length doesn't seem to have a purpose other than being returned. So
> just return gdbarch_print_insn (arch (), memaddr, &m_di)?
> 

branch_delay_insns needs update after gdbarch_print_insn call.

> >+
> >+  /* Prints the instruction INSN into UIOUT and returns the length of
> >+     the printed instruction in bytes.  */
> >+  int pretty_print_insn (struct ui_out *uiout,
> >+			 const struct disasm_insn *insn, int flags);
> 
> Can this function return negative? If not, use unsigned?
> 

I don't think pretty_print_insn can return negative, and we can change
it to size_t.  However, this patch is a code refactor.  I want to avoid
change like this in this patch.  I can change 'int' to 'size_t' later.

> >+
> >+  /* Return the gdbarch of gdb_disassembler.  */
> >+  struct gdbarch *arch ()
> >+  { return m_gdbarch; }
> >+
> >+protected:
> >+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
> >+		    di_read_memory_ftype func);
> >+
> >+  struct ui_file *stream ()
> >+  { return (struct ui_file *) m_di.stream; }
> >+
> >+private:
> >+  struct gdbarch *m_gdbarch;
> >+  struct disassemble_info m_di;
> 
> Add comments explaining what m_gdbarch and m_di are used for and/or how?

I don't know what kind of comments I can add for m_gdbarch.  Something
like "gdbarch of gdb_disassembler" looks useless.  We've already had
method arch(with comments) which returns m_gdbarch.

I can think of the comments to m_di

  /* Pass it to opcodes disassembler and collect some outputs
     from opcodes disassembler.  */

  struct disassemble_info m_di;

What do you think?

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 1/6] New function null_stream
  2017-01-18 15:54                   ` Simon Marchi
@ 2017-01-18 16:36                     ` Luis Machado
  0 siblings, 0 replies; 80+ messages in thread
From: Luis Machado @ 2017-01-18 16:36 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Yao Qi, gdb-patches

On 01/18/2017 09:54 AM, Simon Marchi wrote:
> On 2017-01-18 10:28, Luis Machado wrote:
>> That is perfectly fine. The cryptic bit i was referring to was
>> declaring/initializing a static variable inside this particular
>> function.
>
> Indeed, and I pointed to Pedro's patch because it removes that.  The
> global object is statically allocated and is constructed at startup, so
> there's no more checking if it's initialized nor static variable inside
> a function.
>
>> It ought to be possible to initialize the static variable somewhere
>> else and only do the null check/allocation in the function? Compilers
>> will often zero these out too, so initializing to NULL may not even be
>> needed?
>
> I think this is a common pattern when you want to have a singleton with
> lazy initialization, but I agree that it can be confusing.  The
> variables with static storage duration are put in .bss (since they are
> not in .data), so yes they'd be initialized to 0 automatically, I
> believe.  I prefer to see the = NULL though.
>
> Of course we could move the variable outside the scope of the function,
> but then it would be possible to reference it from other functions.  The
> goal of declaring it in the function is that the only way to reach it is
> by calling the function it's in.
>
>> The fact that the initialization only happens once but the source line
>> is there forever can cause some confusion.
>
> Well, you can thank Mr Ritchie & friends I suppose :).
>

That's fine. If we're sticking with it, i'd at least add a comment for 
the sake of making it more obvious what the intentions for such a 
variable are and the fact it will outlive the function itself.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 2/6] Refactor disassembly code
  2017-01-18 16:34       ` Yao Qi
@ 2017-01-18 16:53         ` Luis Machado
  0 siblings, 0 replies; 80+ messages in thread
From: Luis Machado @ 2017-01-18 16:53 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 01/18/2017 10:33 AM, Yao Qi wrote:
> On 17-01-17 08:14:27, Luis Machado wrote:
>>>
>>> /* Like target_read_memory, but slightly different parameters.  */
>>
>> Should we update these comments to a more useful version? "slightly
>> different parameters" doesn't explain much, as it is obvious they
>> are slightly different. Other uses below have the same problem.
>
> How about this?
>
>   /* Wrapper of target_read_code.  */
>

I think that's better than the previous one.

>>> +int
>>> +gdb_disassembler::print_insn (CORE_ADDR memaddr,
>>> +			      int *branch_delay_insns)
>>> +{
>>> +  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
>>> +
>>> +  if (branch_delay_insns != NULL)
>>> +    {
>>> +      if (m_di.insn_info_valid)
>>> +	*branch_delay_insns = m_di.branch_delay_insns;
>>> +      else
>>> +	*branch_delay_insns = 0;
>>> +    }
>>> +  return length;
>>
>> length doesn't seem to have a purpose other than being returned. So
>> just return gdbarch_print_insn (arch (), memaddr, &m_di)?
>>
>
> branch_delay_insns needs update after gdbarch_print_insn call.
>

Indeed. Missed the m_di.

>>> +
>>> +  /* Prints the instruction INSN into UIOUT and returns the length of
>>> +     the printed instruction in bytes.  */
>>> +  int pretty_print_insn (struct ui_out *uiout,
>>> +			 const struct disasm_insn *insn, int flags);
>>
>> Can this function return negative? If not, use unsigned?
>>
>
> I don't think pretty_print_insn can return negative, and we can change
> it to size_t.  However, this patch is a code refactor.  I want to avoid
> change like this in this patch.  I can change 'int' to 'size_t' later.
>

Sounds good.

>>> +
>>> +  /* Return the gdbarch of gdb_disassembler.  */
>>> +  struct gdbarch *arch ()
>>> +  { return m_gdbarch; }
>>> +
>>> +protected:
>>> +  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
>>> +		    di_read_memory_ftype func);
>>> +
>>> +  struct ui_file *stream ()
>>> +  { return (struct ui_file *) m_di.stream; }
>>> +
>>> +private:
>>> +  struct gdbarch *m_gdbarch;
>>> +  struct disassemble_info m_di;
>>
>> Add comments explaining what m_gdbarch and m_di are used for and/or how?
>
> I don't know what kind of comments I can add for m_gdbarch.  Something
> like "gdbarch of gdb_disassembler" looks useless.  We've already had

I can still see value in describing it as a "Pointer to the target's 
gdbarch". But feel free not to document it if you don't think it's worth it.

The documentation is likely not for us (experienced gdb developers), but 
for people getting started on gdb's code.

> method arch(with comments) which returns m_gdbarch.
>
> I can think of the comments to m_di
>
>   /* Pass it to opcodes disassembler and collect some outputs
>      from opcodes disassembler.  */
>
>   struct disassemble_info m_di;
>
> What do you think?
>

I think something along the lines of:

/* Stores disassembler data.  */

or

/* Stores data required for disassembling instructions.  */

... is good enough, as trivial as it may seem.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-16 10:03   ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
  2017-01-17 14:33     ` Luis Machado
@ 2017-01-20  0:04     ` Pedro Alves
  2017-01-24 15:23       ` Yao Qi
  1 sibling, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-20  0:04 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 10:02 AM, Yao Qi wrote:

> +static void
> +gdb_disassembler_print_one_insn_test (struct gdbarch *gdbarch)
> +{
> +  size_t len = 0;
> +  const gdb_byte *insn = NULL;
> +

> +      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, (int *) &len);

That "(int *) &len" is invalid code.  It's an aliasing violation.
And even if that weren't a problem, consider what happens when
sizeof size_t != sizeof int, on big endian and little endian.

Use a temporary variable of the right type, like e.g.:

      int bplen;
      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
      len = bplen;

> +      break;
> +    default:
> +      {
> +	/* Test disassemble breakpoint instruction.  */
> +	CORE_ADDR pc = 0;
> +	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
> +
> +	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind,
> +						(int *) &len);

Ditto.


> +      len = sizeof (xstormy16_insn);
> +      break;
> +    case bfd_arch_arc:
> +      {
> +	/* PR 21003 */
> +	if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
> +	  return;
> +      }

Odd that this case got braces when it doesn't declare any variable,
and when other cases don't.  Also, is the fallthrough intended?
If so, add a comment otherwise we may get a warning with GCC 7.

> +    case bfd_arch_nios2:
> +    case bfd_arch_score:
> +      /* nios2 and score need to know the current instruction to select
> +	 breakpoint instruction.  Give the breakpoint instruction kind
> +	 explicitly.  */
> +      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, (int *) &len);
> +      break;
> +    default:


> +
> +	break;
> +      }
> +    }
> +  SELF_CHECK (len > 0);
> +
> +  /* Test gdb_disassembler for a given gdbarch by reading data from a
> +     pre-allocated buffer.  If you want to see the disassembled
> +     instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
> +     to true.  */
> +
> +  class gdb_disassembler_test : public gdb_disassembler
> +  {
> +  public:
> +
> +    const bool DISASSEMBLER_TEST_VERBOSE = false;

static.  We give macros long unique names in order to
avoid naming conflicts, but if this is no longer a macro,
the name could be shortened, to e.g., just:

 static const bool verbose = false;

> +
> +    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
> +				    const gdb_byte *insn,
> +				    size_t len)
> +      : gdb_disassembler (gdbarch,
> +			  (DISASSEMBLER_TEST_VERBOSE
> +			   ? gdb_stdout : null_stream ()),
> +			  gdb_disassembler_test::read_memory),
> +	m_insn (insn), m_len (len)
> +    {
> +    }
> +
> +    int
> +    print_insn (CORE_ADDR memaddr)
> +    {
> +      if (DISASSEMBLER_TEST_VERBOSE)
> +	{
> +	  fprintf_unfiltered (stream (), "%s ",
> +			      gdbarch_bfd_arch_info (arch ())->arch_name);
> +	}
> +
> +      int len = gdb_disassembler::print_insn (memaddr);
> +
> +      if (DISASSEMBLER_TEST_VERBOSE)
> +	fprintf_unfiltered (stream (), "\n");
> +
> +      return len;
> +    }
> +
> +  private:
> +    /* A buffer contain one instruction.  */
> +    const gdb_byte *m_insn;
> +
> +    /* Length of the buffer.  */
> +    size_t m_len;
> +
> +    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> +			    unsigned int len, struct disassemble_info *info)
> +    {
> +      gdb_disassembler_test *self
> +	= static_cast<gdb_disassembler_test *>(info->application_data);
> +
> +      /* The disassembler in opcodes may read more data than one
> +	 instruction.  */

I suggest:

      /* The opcodes disassembler may read more data than one
         instruction.  Supply infinite consecutive copies
         of the same instruction.

> +      for (unsigned int i = 0; i < len; i++)

size_t.

> +	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];

Clever.  :-)

> +
> +      return 0;
> +    }
> +  };
> +
> +  gdb_disassembler_test di (gdbarch, insn, len);
> +
> +  SELF_CHECK (di.print_insn (0) == len);
> +}
> +
> +} // namespace selftests
> +#endif /* GDB_SELF_TEST */
> +
> +/* Suppress warning from -Wmissing-prototypes.  */
> +extern initialize_file_ftype _initialize_disasm_test;
> +
> +void
> +_initialize_disasm_test (void)

The standard is to name the _initialize_foo function after
the file/module name:

 _initialize_disasm_selftests

> +
> +static void
> +tests_with_arch (void)

We longer need the "void" in C++.

> +{
> +  int failed = 0;
> +
> +  for (const auto &f : gdbarch_tests)
> +    {
> +      const char **arches = gdbarch_printable_names ();
> +      int i;
> +
> +      for (i = 0; arches[i] != NULL; i++)

Can be "for (int i ..." now.


> +/* Suppress warning from -Wmissing-prototypes.  */
> +extern initialize_file_ftype _initialize_selftests_with_arch;
> +
> +void
> +_initialize_selftests_with_arch (void)

Likewise (naming / void).

> +#ifndef SELFTEST_ARCH_H
> +#define SELFTEST_ARCH_H
> +
> +typedef void self_test_function_with_gdbarch (struct gdbarch *);
> +
> +extern void register_self_test (self_test_function_with_gdbarch *function);

IMO, overloading the "register_self_test" function is confusing.
This function and the register_self_test() function in selftest.c
are semantically different, not two ways to do the same
thing (like e.g. const char * vs std::string).

If nothing else, it makes it a bit harder to grep for / find
arch self tests (only) in the future.

I'd prefer calling this something else that indicates more clearly
what the selftest being registered is about.  That's why I had
suggested before the distinct:

  register_arch_self_test

Perhaps better would be:

  register_self_test_foreach_arch

And then self_test_function_with_gdbarch -> self_test_foreach_arch_function.

WDYT?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 5/6] Disassembly unit test: memory error
  2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
  2017-01-17 14:38     ` Luis Machado
@ 2017-01-20  0:08     ` Pedro Alves
  1 sibling, 0 replies; 80+ messages in thread
From: Pedro Alves @ 2017-01-20  0:08 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

On 01/16/2017 10:02 AM, Yao Qi wrote:
> +  bool see_memory_error = false;

seen_memory_error or saw_memory_error.  "see" reads like an order.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn
  2017-01-17 14:19     ` Luis Machado
@ 2017-01-24 10:08       ` Yao Qi
  2017-01-24 13:41         ` Luis Machado
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-24 10:08 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On 17-01-17 08:19:18, Luis Machado wrote:
> On 01/16/2017 04:02 AM, Yao Qi wrote:
> >
> >-/* The mep disassembler needs to know about the section in order to
> >-   work correctly.  */
> 
> Instead of removing the comment, should we point out what the
> effects of having/not having section info will be?
> 

That is the implementation detail of print_insn_mep (provided by opcodes),
and gdb should not know about.  Both gdb and objdump are the clients of
opcodes, and they need to provide precise information as much as it can.
However, they shouldn't know that what should print_insn_mep do.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn
  2017-01-24 10:08       ` Yao Qi
@ 2017-01-24 13:41         ` Luis Machado
  0 siblings, 0 replies; 80+ messages in thread
From: Luis Machado @ 2017-01-24 13:41 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 01/24/2017 04:08 AM, Yao Qi wrote:
> On 17-01-17 08:19:18, Luis Machado wrote:
>> On 01/16/2017 04:02 AM, Yao Qi wrote:
>>>
>>> -/* The mep disassembler needs to know about the section in order to
>>> -   work correctly.  */
>>
>> Instead of removing the comment, should we point out what the
>> effects of having/not having section info will be?
>>
>
> That is the implementation detail of print_insn_mep (provided by opcodes),
> and gdb should not know about.  Both gdb and objdump are the clients of
> opcodes, and they need to provide precise information as much as it can.
> However, they shouldn't know that what should print_insn_mep do.
>

Fair enough. But in that case we still have a chunk of code in that 
function explaining why the section is being used. Should that go away too?

       /* The libopcodes disassembly code uses the section to find the
          BFD, the BFD to find the ELF header, the ELF header to find
          the me_module index, and the me_module index to select the
          right instructions to print.  */

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-20  0:04     ` Pedro Alves
@ 2017-01-24 15:23       ` Yao Qi
  2017-02-02 16:46         ` Pedro Alves
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-01-24 15:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 17-01-20 00:03:48, Pedro Alves wrote:
> > +  /* Test gdb_disassembler for a given gdbarch by reading data from a
> > +     pre-allocated buffer.  If you want to see the disassembled
> > +     instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
> > +     to true.  */
> > +
> > +  class gdb_disassembler_test : public gdb_disassembler
> > +  {
> > +  public:
> > +
> > +    const bool DISASSEMBLER_TEST_VERBOSE = false;
> 
> static.  We give macros long unique names in order to
> avoid naming conflicts, but if this is no longer a macro,
> the name could be shortened, to e.g., just:
> 
>  static const bool verbose = false;
> 

gdb_disassembler_test is a local class, so it can't have a static data
member.

I'll update patch to address your other comments.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 5/6] Disassembly unit test: memory error
  2017-01-17 14:38     ` Luis Machado
@ 2017-01-24 15:33       ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-24 15:33 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On 17-01-17 08:37:48, Luis Machado wrote:
> >+
> >+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
> >+			    unsigned int len,
> >+			    struct disassemble_info *info)
> >+    {
> >+      /* Always get an error.  */
> 
> /* Always return an error.  */
> 
> Also, should we return an explicit error like TARGET_XFER_E_IO or
> MEMORY_ERROR?

-1 is what target_read_code returned on error, and -1 is expected by
disassembler in opcodes.  We need to define the error number in
include/dis-asm.h.  I'll do it later.

> 
> >+      return -1;
> >+    }
> >+  };
> >+

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 5/6] Disassembly unit test: memory error
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
                       ` (2 preceding siblings ...)
  2017-01-25  8:38     ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-25  8:38     ` [PATCH 1/6] New function null_stream Yao Qi
                       ` (2 subsequent siblings)
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

This patch adds a unit test about memory error occurs on reading
memory, and check MEMORY_ERROR exception is always thrown.

v3:
 - shorten the function name,
 - see_memory_error -> saw_memory_error,

v2:
 - use null_stream,

gdb:

2017-01-24  Yao Qi  <yao.qi@linaro.org>

	* disasm-selftests.c (memory_error_test): New function.
	(_initialize_disasm_test): Register memory_error_test.
---
 gdb/disasm-selftests.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
index 3d68abd..c89c5ed 100644
--- a/gdb/disasm-selftests.c
+++ b/gdb/disasm-selftests.c
@@ -164,6 +164,47 @@ print_one_insn_test (struct gdbarch *gdbarch)
   SELF_CHECK (di.print_insn (0) == len);
 }
 
+/* Test disassembly on memory error.  */
+
+static void
+memory_error_test (struct gdbarch *gdbarch)
+{
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+    gdb_disassembler_test (struct gdbarch *gdbarch)
+      : gdb_disassembler (gdbarch, null_stream (),
+			  gdb_disassembler_test::read_memory)
+    {
+    }
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len,
+			    struct disassemble_info *info)
+    {
+      /* Always return an error.  */
+      return -1;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch);
+  bool saw_memory_error = false;
+
+  TRY
+    {
+      di.print_insn (0);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == MEMORY_ERROR)
+	saw_memory_error = true;
+    }
+  END_CATCH
+
+  /* Expect MEMORY_ERROR.  */
+  SELF_CHECK (saw_memory_error);
+}
+
 } // namespace selftests
 #endif /* GDB_SELF_TEST */
 
@@ -175,5 +216,6 @@ _initialize_disasm_selftests (void)
 {
 #if GDB_SELF_TEST
   register_self_test_foreach_arch (selftests::print_one_insn_test);
+  register_self_test_foreach_arch (selftests::memory_error_test);
 #endif
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
  2017-01-25  8:38     ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-25  8:38     ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
                       ` (4 subsequent siblings)
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

This patch adds one unit test, which disassemble one instruction for
every gdbarch if available.  The test needs one valid instruction of
each gdbarch, and most of them are got from breakpoint instruction.
For the rest gdbarch whose breakpoint instruction isn't a valid
instruction, I copy one instruction from the gas/testsuite/gas/
directory.

I get the valid instruction of most gdbarch except ia64, mep, mips,
tic6x, and xtensa.  People familiar with these arch should be easy
to extend the test.

In order to achieve "do the unit test for every gdbarch", I add
selftest-arch.[c,h], so that we can register a function pointer,
which has one argument gdbarch.  selftest.c will iterate over all
gdbarches to call the registered function pointer.

v3:
 - Fix some function names,

v2:
 - Add comments for getting breakpoint instructions for score and
   nios2,
 - Provide more contents in gdb_disassembler_test::read_memory if
   caller requests more than one instruction,
 - Stop using compound literal,
 - Use null_stream,
 - Split "selftest for each gdbarch" out of selftest.{c,h},

gdb:

2017-01-24  Yao Qi  <yao.qi@linaro.org>

	* Makefile.in (SFILES): Add disasm-selftests.c and
	selftest-arch.c.
	(COMMON_OBS): Add disasm-selftests.o and selftest-arch.o.
	* disasm-selftests.c: New file.
	* selftest-arch.c: New file.
	* selftest-arch.h: New file.
---
 gdb/Makefile.in        |   5 ++
 gdb/disasm-selftests.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/selftest-arch.c    | 102 ++++++++++++++++++++++++++++
 gdb/selftest-arch.h    |  27 ++++++++
 4 files changed, 313 insertions(+)
 create mode 100644 gdb/disasm-selftests.c
 create mode 100644 gdb/selftest-arch.c
 create mode 100644 gdb/selftest-arch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3ce7d69..e0fe442 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1039,6 +1039,7 @@ SFILES = \
 	dfp.c \
 	dictionary.c \
 	disasm.c \
+	disasm-selftests.c \
 	doublest.c \
 	dtrace-probe.c \
 	dummy-frame.c \
@@ -1140,6 +1141,7 @@ SFILES = \
 	rust-exp.y \
 	rust-lang.c \
 	selftest.c \
+	selftest-arch.c \
 	sentinel-frame.c \
 	ser-base.c \
 	ser-event.c \
@@ -1396,6 +1398,7 @@ HFILES_NO_SRCDIR = \
 	rs6000-tdep.h \
 	s390-linux-tdep.h \
 	score-tdep.h \
+	selftest-arch.h \
 	sentinel-frame.h \
 	ser-base.h \
 	ser-event.h \
@@ -1643,6 +1646,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	dfp.o \
 	dictionary.o \
 	disasm.o \
+	disasm-selftests.o \
 	doublest.o \
 	dummy-frame.o \
 	dwarf2-frame.o \
@@ -1744,6 +1748,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	run-time-clock.o \
 	rust-lang.o \
 	selftest.o \
+	selftest-arch.o \
 	sentinel-frame.o \
 	ser-event.o \
 	serial.o \
diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
new file mode 100644
index 0000000..3d68abd
--- /dev/null
+++ b/gdb/disasm-selftests.c
@@ -0,0 +1,179 @@
+/* Self tests for disassembler for GDB, the GNU debugger.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "disasm.h"
+
+#if GDB_SELF_TEST
+#include "selftest.h"
+#include "selftest-arch.h"
+
+namespace selftests {
+
+/* Test disassembly of one instruction.  */
+
+static void
+print_one_insn_test (struct gdbarch *gdbarch)
+{
+  size_t len = 0;
+  const gdb_byte *insn = NULL;
+
+  switch (gdbarch_bfd_arch_info (gdbarch)->arch)
+    {
+    case bfd_arch_bfin:
+      /* M3.L = 0xe117 */
+      static const gdb_byte bfin_insn[] = {0x17, 0xe1, 0xff, 0xff};
+
+      insn = bfin_insn;
+      len = sizeof (bfin_insn);
+      break;
+    case bfd_arch_arm:
+      /* mov     r0, #0 */
+      static const gdb_byte arm_insn[] = {0x0, 0x0, 0xa0, 0xe3};
+
+      insn = arm_insn;
+      len = sizeof (arm_insn);
+      break;
+    case bfd_arch_ia64:
+    case bfd_arch_mep:
+    case bfd_arch_mips:
+    case bfd_arch_tic6x:
+    case bfd_arch_xtensa:
+      return;
+    case bfd_arch_s390:
+      /* nopr %r7 */
+      static const gdb_byte s390_insn[] = {0x07, 0x07};
+
+      insn = s390_insn;
+      len = sizeof (s390_insn);
+      break;
+    case bfd_arch_xstormy16:
+      /* nop */
+      static const gdb_byte xstormy16_insn[] = {0x0, 0x0};
+
+      insn = xstormy16_insn;
+      len = sizeof (xstormy16_insn);
+      break;
+    case bfd_arch_arc:
+      /* PR 21003 */
+      if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arc601)
+	return;
+      /* fall through */
+    case bfd_arch_nios2:
+    case bfd_arch_score:
+      /* nios2 and score need to know the current instruction to select
+	 breakpoint instruction.  Give the breakpoint instruction kind
+	 explicitly.  */
+      int bplen;
+      insn = gdbarch_sw_breakpoint_from_kind (gdbarch, 4, &bplen);
+      len = bplen;
+      break;
+    default:
+      {
+	/* Test disassemble breakpoint instruction.  */
+	CORE_ADDR pc = 0;
+	int kind = gdbarch_breakpoint_kind_from_pc (gdbarch, &pc);
+	int bplen;
+
+	insn = gdbarch_sw_breakpoint_from_kind (gdbarch, kind, &bplen);
+	len = bplen;
+
+	break;
+      }
+    }
+  SELF_CHECK (len > 0);
+
+  /* Test gdb_disassembler for a given gdbarch by reading data from a
+     pre-allocated buffer.  If you want to see the disassembled
+     instruction printed to gdb_stdout, set verbose to true.  */
+
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+
+    const bool verbose = false;
+
+    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
+				    const gdb_byte *insn,
+				    size_t len)
+      : gdb_disassembler (gdbarch,
+			  (verbose ? gdb_stdout : null_stream ()),
+			  gdb_disassembler_test::read_memory),
+	m_insn (insn), m_len (len)
+    {
+    }
+
+    int
+    print_insn (CORE_ADDR memaddr)
+    {
+      if (verbose)
+	{
+	  fprintf_unfiltered (stream (), "%s ",
+			      gdbarch_bfd_arch_info (arch ())->arch_name);
+	}
+
+      int len = gdb_disassembler::print_insn (memaddr);
+
+      if (verbose)
+	fprintf_unfiltered (stream (), "\n");
+
+      return len;
+    }
+
+  private:
+    /* A buffer contain one instruction.  */
+    const gdb_byte *m_insn;
+
+    /* Length of the buffer.  */
+    size_t m_len;
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len, struct disassemble_info *info)
+    {
+      gdb_disassembler_test *self
+	= static_cast<gdb_disassembler_test *>(info->application_data);
+
+      /* The disassembler in opcodes may read more data than one
+	 instruction.  Supply infinite consecutive copies
+	 of the same instruction.  */
+      for (size_t i = 0; i < len; i++)
+	myaddr[i] = self->m_insn[(memaddr + i) % self->m_len];
+
+      return 0;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch, insn, len);
+
+  SELF_CHECK (di.print_insn (0) == len);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_disasm_selftests;
+
+void
+_initialize_disasm_selftests (void)
+{
+#if GDB_SELF_TEST
+  register_self_test_foreach_arch (selftests::print_one_insn_test);
+#endif
+}
diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
new file mode 100644
index 0000000..cbc8c50
--- /dev/null
+++ b/gdb/selftest-arch.c
@@ -0,0 +1,102 @@
+/* GDB self-test for each gdbarch.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+
+#if GDB_SELF_TEST
+#include "selftest.h"
+#include "selftest-arch.h"
+#include "arch-utils.h"
+
+static std::vector<self_test_foreach_arch_function *> gdbarch_tests;
+
+void
+register_self_test_foreach_arch (self_test_foreach_arch_function *function)
+{
+  gdbarch_tests.push_back (function);
+}
+
+namespace selftests {
+
+static void
+tests_with_arch ()
+{
+  int failed = 0;
+
+  for (const auto &f : gdbarch_tests)
+    {
+      const char **arches = gdbarch_printable_names ();
+
+      for (int i = 0; arches[i] != NULL; i++)
+	{
+	  if (strcmp ("fr300", arches[i]) == 0)
+	    {
+	      /* PR 20946 */
+	      continue;
+	    }
+	  else if (strcmp ("powerpc:EC603e", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc", arches[i]) == 0
+		   || strcmp ("powerpc:e500mc64", arches[i]) == 0
+		   || strcmp ("powerpc:titan", arches[i]) == 0
+		   || strcmp ("powerpc:vle", arches[i]) == 0
+		   || strcmp ("powerpc:e5500", arches[i]) == 0
+		   || strcmp ("powerpc:e6500", arches[i]) == 0)
+	    {
+	      /* PR 19797 */
+	      continue;
+	    }
+
+	  QUIT;
+
+	  TRY
+	    {
+	      struct gdbarch_info info;
+
+	      gdbarch_info_init (&info);
+	      info.bfd_arch_info = bfd_scan_arch (arches[i]);
+
+	      struct gdbarch *gdbarch = gdbarch_find_by_info (info);
+	      SELF_CHECK (gdbarch != NULL);
+	      f (gdbarch);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      ++failed;
+	      exception_fprintf (gdb_stderr, ex,
+				 _("Self test failed: arch %s: "), arches[i]);
+	    }
+	  END_CATCH
+	}
+    }
+
+  SELF_CHECK (failed == 0);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_selftests_foreach_arch;
+
+void
+_initialize_selftests_foreach_arch ()
+{
+#if GDB_SELF_TEST
+  register_self_test (selftests::tests_with_arch);
+#endif
+}
diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h
new file mode 100644
index 0000000..d1725cd
--- /dev/null
+++ b/gdb/selftest-arch.h
@@ -0,0 +1,27 @@
+/* GDB self-test for each gdbarch.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef SELFTEST_ARCH_H
+#define SELFTEST_ARCH_H
+
+typedef void self_test_foreach_arch_function (struct gdbarch *);
+
+extern void
+  register_self_test_foreach_arch (self_test_foreach_arch_function *function);
+
+#endif /* SELFTEST_ARCH_H */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 1/6] New function null_stream
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
                       ` (3 preceding siblings ...)
  2017-01-25  8:38     ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-25  8:38     ` [PATCH 2/6] Refactor disassembly code Yao Qi
  2017-01-26 11:34     ` [PATCH 0/6 v3] Handle memory error on disassembly Pedro Alves
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

This patch adds a new function null_stream, which returns a null
stream.  The null stream can be used in multiple places.  It is
used in gdb_insn_length, and the following patches will use it too.

gdb:

2017-01-24  Yao Qi  <yao.qi@linaro.org>

	* disasm.c (do_ui_file_delete): Delete.
	(gdb_insn_length): Move code creating stream to ...
	* utils.c (null_stream): ... here.  New function.
	* utils.h (null_stream): Declare.
---
 gdb/disasm.c | 17 +----------------
 gdb/utils.c  | 15 +++++++++++++++
 gdb/utils.h  |  3 +++
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index f419501..ae3a2f1 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -838,28 +838,13 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
   return length;
 }
 
-static void
-do_ui_file_delete (void *arg)
-{
-  ui_file_delete ((struct ui_file *) arg);
-}
-
 /* Return the length in bytes of the instruction at address MEMADDR in
    debugged memory.  */
 
 int
 gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
-  static struct ui_file *null_stream = NULL;
-
-  /* Dummy file descriptor for the disassembler.  */
-  if (!null_stream)
-    {
-      null_stream = ui_file_new ();
-      make_final_cleanup (do_ui_file_delete, null_stream);
-    }
-
-  return gdb_print_insn (gdbarch, addr, null_stream, NULL);
+  return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
 }
 
 /* fprintf-function for gdb_buffered_insn_length.  This function is a
diff --git a/gdb/utils.c b/gdb/utils.c
index f142ffe..ab87143 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -199,6 +199,21 @@ make_cleanup_ui_file_delete (struct ui_file *arg)
   return make_cleanup (do_ui_file_delete, arg);
 }
 
+struct ui_file *
+null_stream (void)
+{
+  /* A simple implementation of singleton pattern.  */
+  static struct ui_file *stream = NULL;
+
+  if (stream == NULL)
+    {
+      stream = ui_file_new ();
+      /* Delete it on gdb exit.  */
+      make_final_cleanup (do_ui_file_delete, stream);
+    }
+  return stream;
+}
+
 /* Helper function for make_cleanup_ui_out_redirect_pop.  */
 
 static void
diff --git a/gdb/utils.h b/gdb/utils.h
index c548a50..9e71cc2 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -189,6 +189,9 @@ extern struct ui_file *gdb_stdtarg;
 extern struct ui_file *gdb_stdtargerr;
 extern struct ui_file *gdb_stdtargin;
 
+/* Return a null stream.  */
+extern struct ui_file *null_stream (void);
+
 /* Set the screen dimensions to WIDTH and HEIGHT.  */
 
 extern void set_screen_width_and_height (int width, int height);
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
  2017-01-25  8:38     ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
  2017-01-25  8:38     ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-25  8:38     ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

opcodes/mep-dis.c:mep_print_insn has already had the code to
handle the case when info->section is NULL,

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
    }
  else /* sid or gdb */
    {
    }

so that we can still cal print_insn_mep even section can't be found.
On the other hand, user can disassemble an arbitrary address which
doesn't map to any section at all.

gdb:

2017-01-10  Yao Qi  <yao.qi@linaro.org>

	* mep-tdep.c (mep_gdb_print_insn): Set info->arch
	to bfd_arch_mep.  Don't return 0 if section is not
	found.  Call print_insn_mep.
---
 gdb/mep-tdep.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
index 68b0c4b..b1dcc86 100644
--- a/gdb/mep-tdep.c
+++ b/gdb/mep-tdep.c
@@ -1266,13 +1266,12 @@ mep_pseudo_register_write (struct gdbarch *gdbarch,
 \f
 /* Disassembly.  */
 
-/* The mep disassembler needs to know about the section in order to
-   work correctly.  */
 static int
 mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
 {
   struct obj_section * s = find_pc_section (pc);
 
+  info->arch = bfd_arch_mep;
   if (s)
     {
       /* The libopcodes disassembly code uses the section to find the
@@ -1280,12 +1279,9 @@ mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
          the me_module index, and the me_module index to select the
          right instructions to print.  */
       info->section = s->the_bfd_section;
-      info->arch = bfd_arch_mep;
-	
-      return print_insn_mep (pc, info);
     }
-  
-  return 0;
+
+  return print_insn_mep (pc, info);
 }
 
 \f
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 2/6] Refactor disassembly code
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
                       ` (4 preceding siblings ...)
  2017-01-25  8:38     ` [PATCH 1/6] New function null_stream Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-26 11:34     ` [PATCH 0/6 v3] Handle memory error on disassembly Pedro Alves
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

This patch addes class gdb_disassembler, and refactor
code to use it.  The gdb_disassembler object is saved
in disassember_info.application_data.  However,
disassember_info.application_data is already used by
gdb for arm, mips spu, and scm-disasm.  In arm and mips,
.application_data is gdbarch, but we can still get gdbarch
from gdb_disassember.

The use of application_data in spu is a little bit
complicated.  It creates its own disassemble_info, and
save spu_dis_asm_data in .application_data.  This will
overwrite the pointer to gdb_disassembler, so we need
to find another place to save spu_dis_asm_data.  I
extend disassemble_info, and put "id" there.

v3:
 - Update comments,

v2:
 - Merge to print_insn functions into one, with default
   parameter value,

gdb:

2017-01-24  Pedro Alves  <palves@redhat.com>
	    Yao Qi  <yao.qi@linaro.org>

	* arm-tdep.c: Include "disasm.h".
	(gdb_print_insn_arm): Update code to get gdbarch.
	* disasm.c (dis_asm_read_memory): Change it to
	gdb_disassembler::dis_asm_read_memory.
	(dis_asm_memory_error): Likewise.
	(dis_asm_print_address): Likewise.
	(gdb_pretty_print_insn): Change it to
	gdb_disassembler::pretty_print_insn.
	(dump_insns): Add one argument gdb_disassemlber.  All
	callers updated.
	(do_mixed_source_and_assembly_deprecated): Likewise.
	(do_mixed_source_and_assembly): Likewise.
	(do_assembly_only): Likewise.
	(gdb_disassembler::gdb_disassembler): New.
	(gdb_disassembler::print_insn): New.
	* disasm.h (class gdb_disassembler): New.
	(gdb_pretty_print_insn): Remove declaration.
	(gdb_disassemble_info): Likewise.
	* guile/scm-disasm.c (class gdbscm_disassembler): New.
	(gdbscm_disasm_read_memory_worker): Update.
	(gdbscm_disasm_read_memory): Update.
	(gdbscm_disasm_memory_error): Remove.
	(gdbscm_disasm_print_address): Remove.
	(gdbscm_disassembler::gdbscm_disassembler): New.
	(gdbscm_print_insn_from_port): Update.
	* mips-tdep.c: Include disasm.h.
	(gdb_print_insn_mips): Update code to get gdbarch.
	* record-btrace.c (btrace_insn_history): Update.
	* spu-tdep.c: Include disasm.h.
	(struct spu_dis_asm_data): Remove.
	(struct spu_dis_asm_info): New.
	(spu_dis_asm_print_address): Use spu_dis_asm_info to get
	SPU id.
	(gdb_print_insn_spu): Cast disassemble_info to
	spu_dis_asm_info.
---
 gdb/arm-tdep.c         |   5 +-
 gdb/disasm.c           | 157 ++++++++++++++++++++++++++-----------------------
 gdb/disasm.h           |  56 ++++++++++++++----
 gdb/guile/scm-disasm.c |  77 +++++++-----------------
 gdb/mips-tdep.c        |   5 +-
 gdb/record-btrace.c    |   5 +-
 gdb/spu-tdep.c         |  20 +++----
 7 files changed, 168 insertions(+), 157 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 2bdfa57..0ae311f 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -27,6 +27,7 @@
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "dis-asm.h"		/* For register styles.  */
+#include "disasm.h"
 #include "regcache.h"
 #include "reggroups.h"
 #include "doublest.h"
@@ -7739,7 +7740,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
 static int
 gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   if (arm_pc_is_thumb (gdbarch, memaddr))
     {
diff --git a/gdb/disasm.c b/gdb/disasm.c
index ae3a2f1..b58da0f 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -119,29 +119,35 @@ line_has_code_p (htab_t table, struct symtab *symtab, int 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,
-		     struct disassemble_info *info)
+/* Wrapper of target_read_code.  */
+
+int
+gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				       unsigned int len,
+				       struct disassemble_info *info)
 {
   return target_read_code (memaddr, myaddr, len);
 }
 
-/* Like memory_error with slightly different parameters.  */
-static void
-dis_asm_memory_error (int err, bfd_vma memaddr,
-		      struct disassemble_info *info)
+/* Wrapper of memory_error.  */
+
+void
+gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
+					struct disassemble_info *info)
 {
   memory_error (TARGET_XFER_E_IO, memaddr);
 }
 
-/* Like print_address with slightly different parameters.  */
-static void
-dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+/* Wrapper of print_address.  */
+
+void
+gdb_disassembler::dis_asm_print_address (bfd_vma addr,
+					 struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
 
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
+  print_address (self->arch (), addr, self->stream ());
 }
 
 static int
@@ -173,10 +179,9 @@ compare_lines (const void *mle1p, const void *mle2p)
 /* 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)
+gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
+				     const struct disasm_insn *insn,
+				     int flags)
 {
   /* parts of the symbolic representation of the address */
   int unmapped;
@@ -187,6 +192,8 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
   char *filename = NULL;
   char *name = NULL;
   CORE_ADDR pc;
+  struct ui_file *stb = stream ();
+  struct gdbarch *gdbarch = arch ();
 
   ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
   pc = insn->addr;
@@ -254,14 +261,14 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       struct cleanup *cleanups =
 	make_cleanup_ui_file_delete (opcode_stream);
 
-      size = gdbarch_print_insn (gdbarch, pc, di);
+      size = print_insn (pc);
       end_pc = pc + size;
 
       for (;pc < end_pc; ++pc)
 	{
-	  err = (*di->read_memory_func) (pc, &data, 1, di);
+	  err = m_di.read_memory_func (pc, &data, 1, &m_di);
 	  if (err != 0)
-	    (*di->memory_error_func) (err, pc, di);
+	    m_di.memory_error_func (err, pc, &m_di);
 	  fprintf_filtered (opcode_stream, "%s%02x",
 			    spacer, (unsigned) data);
 	  spacer = " ";
@@ -273,7 +280,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
       do_cleanups (cleanups);
     }
   else
-    size = gdbarch_print_insn (gdbarch, pc, di);
+    size = print_insn (pc);
 
   uiout->field_stream ("inst", stb);
   ui_file_rewind (stb);
@@ -284,10 +291,9 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static int
-dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
-	    struct disassemble_info * di,
+dump_insns (struct ui_out *uiout, gdb_disassembler *di,
 	    CORE_ADDR low, CORE_ADDR high,
-	    int how_many, int flags, struct ui_file *stb,
+	    int how_many, int flags,
 	    CORE_ADDR *end_pc)
 {
   struct disasm_insn insn;
@@ -300,7 +306,7 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
     {
       int size;
 
-      size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
+      size = di->pretty_print_insn (uiout, &insn, flags);
       if (size <= 0)
 	break;
 
@@ -326,10 +332,10 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
 
 static void
 do_mixed_source_and_assembly_deprecated
-  (struct gdbarch *gdbarch, struct ui_out *uiout,
-   struct disassemble_info *di, struct symtab *symtab,
+  (struct ui_out *uiout,
+   gdb_disassembler *di, struct symtab *symtab,
    CORE_ADDR low, CORE_ADDR high,
-   int how_many, int flags, struct ui_file *stb)
+   int how_many, int flags)
 {
   int newlines = 0;
   int nlines;
@@ -462,9 +468,9 @@ do_mixed_source_and_assembly_deprecated
 	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
 	}
 
-      num_displayed += dump_insns (gdbarch, uiout, di,
+      num_displayed += dump_insns (uiout, di,
 				   mle[i].start_pc, mle[i].end_pc,
-				   how_many, flags, stb, NULL);
+				   how_many, flags, NULL);
 
       /* 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.  */
@@ -488,11 +494,12 @@ do_mixed_source_and_assembly_deprecated
    immediately following.  */
 
 static void
-do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
-			      struct disassemble_info *di,
+do_mixed_source_and_assembly (struct gdbarch *gdbarch,
+			      struct ui_out *uiout,
+			      gdb_disassembler *di,
 			      struct symtab *main_symtab,
 			      CORE_ADDR low, CORE_ADDR high,
-			      int how_many, int flags, struct ui_file *stb)
+			      int how_many, int flags)
 {
   const struct linetable_entry *le, *first_le;
   int i, nlines;
@@ -711,8 +718,8 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 	end_pc = std::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);
+      num_displayed += dump_insns (uiout, di, pc, end_pc,
+				   how_many, flags, &end_pc);
       pc = end_pc;
 
       if (how_many >= 0 && num_displayed >= how_many)
@@ -726,16 +733,16 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 }
 
 static void
-do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
-		  struct disassemble_info * di,
+do_assembly_only (struct ui_out *uiout,
+		  gdb_disassembler *di,
 		  CORE_ADDR low, CORE_ADDR high,
-		  int how_many, int flags, struct ui_file *stb)
+		  int how_many, int flags)
 {
   struct cleanup *ui_out_chain;
 
   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
 
-  dump_insns (gdbarch, uiout, di, low, high, how_many, flags, stb, NULL);
+  dump_insns (uiout, di, low, high, how_many, flags, NULL);
 
   do_cleanups (ui_out_chain);
 }
@@ -755,15 +762,15 @@ fprintf_disasm (void *stream, const char *format, ...)
   return 0;
 }
 
-struct disassemble_info
-gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
+gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
+				    struct ui_file *file,
+				    di_read_memory_ftype read_memory_func)
+  : m_gdbarch (gdbarch)
 {
-  struct disassemble_info di;
-
-  init_disassemble_info (&di, file, fprintf_disasm);
-  di.flavour = bfd_target_unknown_flavour;
-  di.memory_error_func = dis_asm_memory_error;
-  di.print_address_func = dis_asm_print_address;
+  init_disassemble_info (&m_di, file, fprintf_disasm);
+  m_di.flavour = bfd_target_unknown_flavour;
+  m_di.memory_error_func = dis_asm_memory_error;
+  m_di.print_address_func = dis_asm_print_address;
   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
      disassembler had a local optomization here.  By default it would
      access the executable file, instead of the target memory (there
@@ -772,14 +779,29 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
      didn't work as they relied on the access going to the target.
      Further, it has been supperseeded by trust-read-only-sections
      (although that should be superseeded by target_trust..._p()).  */
-  di.read_memory_func = dis_asm_read_memory;
-  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
-  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
-  di.endian = gdbarch_byte_order (gdbarch);
-  di.endian_code = gdbarch_byte_order_for_code (gdbarch);
-  di.application_data = gdbarch;
-  disassemble_init_for_target (&di);
-  return di;
+  m_di.read_memory_func = read_memory_func;
+  m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  m_di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  m_di.endian = gdbarch_byte_order (gdbarch);
+  m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
+  m_di.application_data = this;
+  disassemble_init_for_target (&m_di);
+}
+
+int
+gdb_disassembler::print_insn (CORE_ADDR memaddr,
+			      int *branch_delay_insns)
+{
+  int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+
+  if (branch_delay_insns != NULL)
+    {
+      if (m_di.insn_info_valid)
+	*branch_delay_insns = m_di.branch_delay_insns;
+      else
+	*branch_delay_insns = 0;
+    }
+  return length;
 }
 
 void
@@ -789,7 +811,7 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 {
   struct ui_file *stb = mem_fileopen ();
   struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
-  struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   struct symtab *symtab;
   int nlines = -1;
 
@@ -801,15 +823,15 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 
   if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
       || nlines <= 0)
-    do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
+    do_assembly_only (uiout, &di, low, high, how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE)
     do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
-				  how_many, flags, stb);
+				  how_many, flags);
 
   else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
-    do_mixed_source_and_assembly_deprecated (gdbarch, uiout, &di, symtab,
-					     low, high, how_many, flags, stb);
+    do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+					     low, high, how_many, flags);
 
   do_cleanups (cleanups);
   gdb_flush (gdb_stdout);
@@ -823,19 +845,10 @@ int
 gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
 		struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
 
-  di = gdb_disassemble_info (gdbarch, stream);
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
-  return length;
+  gdb_disassembler di (gdbarch, stream);
+
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 /* Return the length in bytes of the instruction at address MEMADDR in
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 4c6fd54..c6cb13b 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -33,6 +33,49 @@ struct gdbarch;
 struct ui_out;
 struct ui_file;
 
+class gdb_disassembler
+{
+  using di_read_memory_ftype = decltype (disassemble_info::read_memory_func);
+
+public:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file)
+    : gdb_disassembler (gdbarch, file, dis_asm_read_memory)
+  {}
+
+  int print_insn (CORE_ADDR memaddr, int *branch_delay_insns = NULL);
+
+  /* Prints the instruction INSN into UIOUT and returns the length of
+     the printed instruction in bytes.  */
+  int pretty_print_insn (struct ui_out *uiout,
+			 const struct disasm_insn *insn, int flags);
+
+  /* Return the gdbarch of gdb_disassembler.  */
+  struct gdbarch *arch ()
+  { return m_gdbarch; }
+
+protected:
+  gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file,
+		    di_read_memory_ftype func);
+
+  struct ui_file *stream ()
+  { return (struct ui_file *) m_di.stream; }
+
+private:
+  struct gdbarch *m_gdbarch;
+
+  /* Stores data required for disassembling instructions in
+     opcodes.  */
+  struct disassemble_info m_di;
+
+  static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+				  unsigned int len,
+				  struct disassemble_info *info);
+  static void dis_asm_memory_error (int err, bfd_vma memaddr,
+				    struct disassemble_info *info);
+  static void dis_asm_print_address (bfd_vma addr,
+				     struct disassemble_info *info);
+};
+
 /* An instruction to be disassembled.  */
 
 struct disasm_insn
@@ -47,19 +90,6 @@ struct disasm_insn
   unsigned int is_speculative:1;
 };
 
-/* Prints the instruction INSN into UIOUT and returns the length of the
-   printed instruction in bytes.  */
-
-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);
-
-/* Return a filled in disassemble_info object for use by gdb.  */
-
-extern struct disassemble_info gdb_disassemble_info (struct gdbarch *gdbarch,
-						     struct ui_file *file);
-
 extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
 			     char *file_string, int flags, int how_many,
 			     CORE_ADDR low, CORE_ADDR high);
diff --git a/gdb/guile/scm-disasm.c b/gdb/guile/scm-disasm.c
index d06c481..25cae5a 100644
--- a/gdb/guile/scm-disasm.c
+++ b/gdb/guile/scm-disasm.c
@@ -37,11 +37,13 @@ static SCM address_symbol;
 static SCM asm_symbol;
 static SCM length_symbol;
 
-/* Struct used to pass "application data" in disassemble_info.  */
-
-struct gdbscm_disasm_data
+class gdbscm_disassembler : public gdb_disassembler
 {
-  struct gdbarch *gdbarch;
+public:
+  gdbscm_disassembler (struct gdbarch *gdbarch,
+		       struct ui_file *stream,
+		       SCM port, ULONGEST offset);
+
   SCM port;
   /* The offset of the address of the first instruction in PORT.  */
   ULONGEST offset;
@@ -55,7 +57,7 @@ struct gdbscm_disasm_read_data
   bfd_vma memaddr;
   bfd_byte *myaddr;
   unsigned int length;
-  struct disassemble_info *dinfo;
+  gdbscm_disassembler *dinfo;
 };
 \f
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -81,13 +83,11 @@ gdbscm_disasm_read_memory_worker (void *datap)
 {
   struct gdbscm_disasm_read_data *data
     = (struct gdbscm_disasm_read_data *) datap;
-  struct disassemble_info *dinfo = data->dinfo;
-  struct gdbscm_disasm_data *disasm_data
-    = (struct gdbscm_disasm_data *) dinfo->application_data;
-  SCM seekto, newpos, port = disasm_data->port;
+  gdbscm_disassembler *dinfo = data->dinfo;
+  SCM seekto, newpos, port = dinfo->port;
   size_t bytes_read;
 
-  seekto = gdbscm_scm_from_ulongest (data->memaddr - disasm_data->offset);
+  seekto = gdbscm_scm_from_ulongest (data->memaddr - dinfo->offset);
   newpos = scm_seek (port, seekto, scm_from_int (SEEK_SET));
   if (!scm_is_eq (seekto, newpos))
     return "seek error";
@@ -108,13 +108,15 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
 			   unsigned int length,
 			   struct disassemble_info *dinfo)
 {
+  gdbscm_disassembler *self
+    = static_cast<gdbscm_disassembler *> (dinfo->application_data);
   struct gdbscm_disasm_read_data data;
   const char *status;
 
   data.memaddr = memaddr;
   data.myaddr = myaddr;
   data.length = length;
-  data.dinfo = dinfo;
+  data.dinfo = self;
 
   status = gdbscm_with_guile (gdbscm_disasm_read_memory_worker, &data);
 
@@ -123,30 +125,12 @@ gdbscm_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr,
   return status != NULL ? -1 : 0;
 }
 
-/* disassemble_info.memory_error_func for gdbscm_print_insn_from_port.
-   Technically speaking, we don't need our own memory_error_func,
-   but to not provide one would leave a subtle dependency in the code.
-   This function exists to keep a clear boundary.  */
-
-static void
-gdbscm_disasm_memory_error (int status, bfd_vma memaddr,
-			    struct disassemble_info *info)
-{
-  memory_error (TARGET_XFER_E_IO, memaddr);
-}
-
-/* disassemble_info.print_address_func for gdbscm_print_insn_from_port.
-   Since we need to use our own application_data value, we need to supply
-   this routine as well.  */
-
-static void
-gdbscm_disasm_print_address (bfd_vma addr, struct disassemble_info *info)
+gdbscm_disassembler::gdbscm_disassembler (struct gdbarch *gdbarch,
+					  struct ui_file *stream,
+					  SCM port_, ULONGEST offset_)
+  : gdb_disassembler (gdbarch, stream, gdbscm_disasm_read_memory),
+    port (port_), offset (offset_)
 {
-  struct gdbscm_disasm_data *data
-    = (struct gdbscm_disasm_data *) info->application_data;
-  struct gdbarch *gdbarch = data->gdbarch;
-
-  print_address (gdbarch, addr, (struct ui_file *) info->stream);
 }
 
 /* Subroutine of gdbscm_arch_disassemble to simplify it.
@@ -164,30 +148,9 @@ gdbscm_print_insn_from_port (struct gdbarch *gdbarch,
 			     SCM port, ULONGEST offset, CORE_ADDR memaddr,
 			     struct ui_file *stream, int *branch_delay_insns)
 {
-  struct disassemble_info di;
-  int length;
-  struct gdbscm_disasm_data data;
-
-  di = gdb_disassemble_info (gdbarch, stream);
-  data.gdbarch = gdbarch;
-  data.port = port;
-  data.offset = offset;
-  di.application_data = &data;
-  di.read_memory_func = gdbscm_disasm_read_memory;
-  di.memory_error_func = gdbscm_disasm_memory_error;
-  di.print_address_func = gdbscm_disasm_print_address;
-
-  length = gdbarch_print_insn (gdbarch, memaddr, &di);
-
-  if (branch_delay_insns)
-    {
-      if (di.insn_info_valid)
-	*branch_delay_insns = di.branch_delay_insns;
-      else
-	*branch_delay_insns = 0;
-    }
+  gdbscm_disassembler di (gdbarch, stream, port, offset);
 
-  return length;
+  return di.print_insn (memaddr, branch_delay_insns);
 }
 
 /* (arch-disassemble <gdb:arch> address
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 637b34e..41cb9d8 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -44,6 +44,7 @@
 #include "symcat.h"
 #include "sim-regno.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
 #include "trad-frame.h"
@@ -6982,7 +6983,9 @@ reinit_frame_cache_sfunc (char *args, int from_tty,
 static int
 gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
 {
-  struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+  struct gdbarch *gdbarch = di->arch ();
 
   /* FIXME: cagney/2003-06-26: Is this even necessary?  The
      disassembler needs to be able to locally determine the ISA, and
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 6cba1d2..8896241 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -698,7 +698,6 @@ btrace_insn_history (struct ui_out *uiout,
 {
   struct ui_file *stb;
   struct cleanup *cleanups, *ui_item_chain;
-  struct disassemble_info di;
   struct gdbarch *gdbarch;
   struct btrace_insn_iterator it;
   struct btrace_line_range last_lines;
@@ -711,7 +710,7 @@ btrace_insn_history (struct ui_out *uiout,
   gdbarch = target_gdbarch ();
   stb = mem_fileopen ();
   cleanups = make_cleanup_ui_file_delete (stb);
-  di = gdb_disassemble_info (gdbarch, stb);
+  gdb_disassembler di (gdbarch, stb);
   last_lines = btrace_mk_line_range (NULL, 0, 0);
 
   make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
@@ -773,7 +772,7 @@ 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);
+	  di.pretty_print_insn (uiout, &dinsn, flags);
 	}
     }
 
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 8756256..70d7f6f 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -33,6 +33,7 @@
 #include "value.h"
 #include "inferior.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "objfiles.h"
 #include "language.h"
 #include "regcache.h"
@@ -1693,18 +1694,19 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 
 /* Disassembler.  */
 
-struct spu_dis_asm_data
+struct spu_dis_asm_info : disassemble_info
 {
-  struct gdbarch *gdbarch;
   int id;
 };
 
 static void
 spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
 {
-  struct spu_dis_asm_data *data
-    = (struct spu_dis_asm_data *) info->application_data;
-  print_address (data->gdbarch, SPUADDR (data->id, addr),
+  struct spu_dis_asm_info *data = (struct spu_dis_asm_info *) info;
+  gdb_disassembler *di
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  print_address (di->arch (), SPUADDR (data->id, addr),
 		 (struct ui_file *) info->stream);
 }
 
@@ -1714,12 +1716,10 @@ gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
   /* The opcodes disassembler does 18-bit address arithmetic.  Make
      sure the SPU ID encoded in the high bits is added back when we
      call print_address.  */
-  struct disassemble_info spu_info = *info;
-  struct spu_dis_asm_data data;
-  data.gdbarch = (struct gdbarch *) info->application_data;
-  data.id = SPUADDR_SPU (memaddr);
+  struct spu_dis_asm_info spu_info;
 
-  spu_info.application_data = &data;
+  memcpy (&spu_info, info, sizeof (*info));
+  spu_info.id = SPUADDR_SPU (memaddr);
   spu_info.print_address_func = spu_dis_asm_print_address;
   return print_insn_spu (memaddr, &spu_info);
 }
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 0/6 v3] Handle memory error on disassembly
  2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
                     ` (5 preceding siblings ...)
  2017-01-16 10:03   ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
@ 2017-01-25  8:38   ` Yao Qi
  2017-01-25  8:38     ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
                       ` (6 more replies)
  6 siblings, 7 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

Hi,
Nowadays, we can set function pointer
disassemble_info.memory_error_func to throw error or exception when
disassembler gets an error, and the caller can/may catch the exception.
Both gdb and objdump use this interface for many years.  After GDB is
switched to C++, this stops working due to the "foreign frame" from
opcodes.  That is to say, a C++ program calls a C function
(print_insn_XXX from opcodes) and this function calls a C++ code which
throws exception.  DW2 C++ exception unwinder can unwind across the C
function frame, unless the C code is compiled with -fexceptions.  As
a result, GDB aborts on memory error during disassembly on some hosts.

This is the v3 of the patch series, and V2 can be found
https://sourceware.org/ml/gdb-patches/2017-01/msg00288.html
V3 addressed all comments on function names and code comments in V2.

*** BLURB HERE ***

Yao Qi (6):
  New function null_stream
  Refactor disassembly code
  Call print_insn_mep in mep_gdb_print_insn
  Disassembly unit test: disassemble one instruction
  Disassembly unit test: memory error
  Don't throw exception in dis_asm_memory_error

 gdb/Makefile.in                                 |   5 +
 gdb/arm-tdep.c                                  |   5 +-
 gdb/disasm-selftests.c                          | 221 ++++++++++++++++++++++++
 gdb/disasm.c                                    | 183 ++++++++++----------
 gdb/disasm.h                                    |  57 ++++--
 gdb/guile/scm-disasm.c                          |  77 +++------
 gdb/mep-tdep.c                                  |  10 +-
 gdb/mips-tdep.c                                 |   5 +-
 gdb/record-btrace.c                             |   5 +-
 gdb/selftest-arch.c                             | 102 +++++++++++
 gdb/selftest-arch.h                             |  27 +++
 gdb/spu-tdep.c                                  |  20 +--
 gdb/testsuite/gdb.base/all-architectures.exp.in |   5 +
 gdb/utils.c                                     |  15 ++
 gdb/utils.h                                     |   3 +
 15 files changed, 560 insertions(+), 180 deletions(-)
 create mode 100644 gdb/disasm-selftests.c
 create mode 100644 gdb/selftest-arch.c
 create mode 100644 gdb/selftest-arch.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH 6/6] Don't throw exception in dis_asm_memory_error
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
@ 2017-01-25  8:38     ` Yao Qi
  2017-01-25  8:38     ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-25  8:38 UTC (permalink / raw)
  To: gdb-patches

Hi,
GDB calls some APIs from opcodes to do disassembly and provide some
call backs.  This model makes troubles on C++ exception unwinding,
because GDB is a C++ program, and opcodes is still compiled as C.
As we can see, frame #10 and #12 are C++, while #frame 11 is C,

 #10 0x0000000000544228 in memory_error (err=TARGET_XFER_E_IO, memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:237
 #11 0x00000000006b0a54 in print_insn_aarch64 (pc=0, info=0xffffffffeeb0) at ../../binutils-gdb/opcodes/aarch64-dis.c:3185
 #12 0x0000000000553590 in gdb_pretty_print_insn (gdbarch=gdbarch@entry=0xbbceb0, uiout=uiout@entry=0xbc73d0, di=di@entry=0xffffffffeeb0,
    insn=0xffffffffed40, insn@entry=0xffffffffed90, flags=flags@entry=0,

C++ exception unwinder can't go across frame #11 unless it has
unwind table.  However, C program on many architectures doesn't
have it in default.  As a result, GDB aborts, which is described
in PR 20939.

This is not the first time we see this kind of problem.  We've
had a commit 89525768cd086a0798a504c81fdf7ebcd4c904e1
"Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH".
We can fix the disassembly bug in a similar way, this is the option one.

Since opcodes is built with gdb, we fix this problem in a different
way as we did for the same issue with readline.  Instead of throwing
exception in dis_asm_memory_error, we record the failed memory
address, and throw exception when GDB returns from opcodes disassemblers.

gdb:

2017-01-24  Yao Qi  <yao.qi@linaro.org>
	    Pedro Alves  <palves@redhat.com>

	PR gdb/20939
	* disasm.c (gdb_disassembler::dis_asm_memory_error): Don't
	call memory_error, save memaddr instead.
	(gdb_disassembler::print_insn): If gdbarch_print_insn returns
	negative, cal memory_error.
	* disasm.h (gdb_disassembler) <m_err_memaddr>: New field.

gdb/testsuite:

2017-01-24  Yao Qi  <yao.qi@linaro.org>

	* gdb.base/all-architectures.exp.in (do_arch_tests): Test
	disassemble on address 0.
---
 gdb/disasm.c                                    | 13 +++++++++++--
 gdb/disasm.h                                    |  1 +
 gdb/testsuite/gdb.base/all-architectures.exp.in |  5 +++++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/gdb/disasm.c b/gdb/disasm.c
index b58da0f..897f2f1 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -135,7 +135,10 @@ void
 gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
 					struct disassemble_info *info)
 {
-  memory_error (TARGET_XFER_E_IO, memaddr);
+  gdb_disassembler *self
+    = static_cast<gdb_disassembler *>(info->application_data);
+
+  self->m_err_memaddr = memaddr;
 }
 
 /* Wrapper of print_address.  */
@@ -765,7 +768,8 @@ fprintf_disasm (void *stream, const char *format, ...)
 gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
 				    struct ui_file *file,
 				    di_read_memory_ftype read_memory_func)
-  : m_gdbarch (gdbarch)
+  : m_gdbarch (gdbarch),
+    m_err_memaddr (0)
 {
   init_disassemble_info (&m_di, file, fprintf_disasm);
   m_di.flavour = bfd_target_unknown_flavour;
@@ -792,8 +796,13 @@ int
 gdb_disassembler::print_insn (CORE_ADDR memaddr,
 			      int *branch_delay_insns)
 {
+  m_err_memaddr = 0;
+
   int length = gdbarch_print_insn (arch (), memaddr, &m_di);
 
+  if (length < 0)
+    memory_error (TARGET_XFER_E_IO, m_err_memaddr);
+
   if (branch_delay_insns != NULL)
     {
       if (m_di.insn_info_valid)
diff --git a/gdb/disasm.h b/gdb/disasm.h
index c6cb13b..7bbfa31 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -66,6 +66,7 @@ private:
   /* Stores data required for disassembling instructions in
      opcodes.  */
   struct disassemble_info m_di;
+  CORE_ADDR m_err_memaddr;
 
   static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
 				  unsigned int len,
diff --git a/gdb/testsuite/gdb.base/all-architectures.exp.in b/gdb/testsuite/gdb.base/all-architectures.exp.in
index c7615ac..b07caf5 100644
--- a/gdb/testsuite/gdb.base/all-architectures.exp.in
+++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
@@ -152,6 +152,11 @@ proc print_floats {} {
 
 proc do_arch_tests {} {
     print_floats
+
+    # GDB can't access memory because there is no loaded executable
+    # nor live inferior.
+    gdb_test_internal "disassemble 0x0,+4" \
+	"Cannot access memory at address 0x0"
 }
 
 # Given we can't change arch, osabi, endianness, etc. atomically, we
-- 
1.9.1

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 0/6 v3] Handle memory error on disassembly
  2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
                       ` (5 preceding siblings ...)
  2017-01-25  8:38     ` [PATCH 2/6] Refactor disassembly code Yao Qi
@ 2017-01-26 11:34     ` Pedro Alves
  2017-01-26 15:00       ` Yao Qi
  6 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-01-26 11:34 UTC (permalink / raw)
  To: Yao Qi, gdb-patches

This version LGTM.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 0/6 v3] Handle memory error on disassembly
  2017-01-26 11:34     ` [PATCH 0/6 v3] Handle memory error on disassembly Pedro Alves
@ 2017-01-26 15:00       ` Yao Qi
  0 siblings, 0 replies; 80+ messages in thread
From: Yao Qi @ 2017-01-26 15:00 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 17-01-26 11:34:06, Pedro Alves wrote:
> This version LGTM.
> 

I pushed them in.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-01-24 15:23       ` Yao Qi
@ 2017-02-02 16:46         ` Pedro Alves
  2017-02-02 22:12           ` Yao Qi
  0 siblings, 1 reply; 80+ messages in thread
From: Pedro Alves @ 2017-02-02 16:46 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 01/24/2017 03:23 PM, Yao Qi wrote:
> On 17-01-20 00:03:48, Pedro Alves wrote:
>>> +  /* Test gdb_disassembler for a given gdbarch by reading data from a
>>> +     pre-allocated buffer.  If you want to see the disassembled
>>> +     instruction printed to gdb_stdout, set DISASSEMBLER_TEST_VERBOSE
>>> +     to true.  */
>>> +
>>> +  class gdb_disassembler_test : public gdb_disassembler
>>> +  {
>>> +  public:
>>> +
>>> +    const bool DISASSEMBLER_TEST_VERBOSE = false;
>>
>> static.  We give macros long unique names in order to
>> avoid naming conflicts, but if this is no longer a macro,
>> the name could be shortened, to e.g., just:
>>
>>  static const bool verbose = false;
>>
> 
> gdb_disassembler_test is a local class, so it can't have a static data
> member.

The end result is broken then, unfortunately.  I didn't realize it
either until I saw a spurious fail in the gdb.base/unittest.exp test
today.

Running

  gdb -ex "maintenance selftest"

manually I see:

~~~
Type "apropos word" to search for commands related to "word".
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default ARC600 settings.

.long 0x256f003fwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default ARC600 settings.

.long 0x256f003fwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default A6 settings.

.long 0x256f003fwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default ARC601 settings.

warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default ARC700 settings.

brkwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default A7 settings.

brkwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default ARCv2 settings.

brkwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default EM settings.

brkwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default HS settings.


brkmov  r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov   r0, #0mov       r0, #0mov       r0, #0mov       r0, #0breakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakM3.L = 0xffff;/* ( -1) M3=0x0xffff(65535) */break 8break 8warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default cris:common_v10_v32 settings.
~~~

etc.  (this is what shows up in the gdb.log too).

Note the odd bits of instructions printed.

They appear because here:

  class gdb_disassembler_test : public gdb_disassembler
  {
  public:

    const bool verbose = false;

    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
				    const gdb_byte *insn,
				    size_t len)
      : gdb_disassembler (gdbarch,
			  (verbose ? gdb_stdout : &null_stream),
			  gdb_disassembler_test::read_memory),


specifically in this line:

			  (verbose ? gdb_stdout : &null_stream),

"verbose" has not been initialized yet, because the order of initialization
is always base classes first.  I.e. "verbose" is only initialized after
the base constructor is called.  Since the gdb_disassembler_test object
is created on the stack, "verbose" has garbage at that point, and
thus we end up with the stream incorrectly pointing to gdb_stdout.

I was surprised that GCC doesn't warn about this.  I filed a GCC 
bug here:
  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79345

I'm not sure whether this was the reason for the unittest.exp
random failure, but I suspect so.  (I failed to save the log,
and also forgot to check whether all selftests had passed.)

The patchlet below fixes the spurious insn printing.  OK?

diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
index 7d0b006..9eb80b4 100644
--- a/gdb/disasm-selftests.c
+++ b/gdb/disasm-selftests.c
@@ -102,13 +102,12 @@ print_one_insn_test (struct gdbarch *gdbarch)
   /* Test gdb_disassembler for a given gdbarch by reading data from a
      pre-allocated buffer.  If you want to see the disassembled
      instruction printed to gdb_stdout, set verbose to true.  */
+  static const bool verbose = false;
 
   class gdb_disassembler_test : public gdb_disassembler
   {
   public:
 
-    const bool verbose = false;
-
     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
 				    const gdb_byte *insn,
 				    size_t len)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction
  2017-02-02 16:46         ` Pedro Alves
@ 2017-02-02 22:12           ` Yao Qi
  2017-02-02 23:39             ` [pushed] Fix "maintenance selftest" printing stray instructions (Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction) Pedro Alves
  0 siblings, 1 reply; 80+ messages in thread
From: Yao Qi @ 2017-02-02 22:12 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Thu, Feb 2, 2017 at 4:46 PM, Pedro Alves <palves@redhat.com> wrote:
>
> I'm not sure whether this was the reason for the unittest.exp
> random failure, but I suspect so.  (I failed to save the log,
> and also forgot to check whether all selftests had passed.)
>
> The patchlet below fixes the spurious insn printing.  OK?
>

Yes.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [pushed] Fix "maintenance selftest" printing stray instructions (Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction)
  2017-02-02 22:12           ` Yao Qi
@ 2017-02-02 23:39             ` Pedro Alves
  0 siblings, 0 replies; 80+ messages in thread
From: Pedro Alves @ 2017-02-02 23:39 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 02/02/2017 10:12 PM, Yao Qi wrote:
> On Thu, Feb 2, 2017 at 4:46 PM, Pedro Alves <palves@redhat.com> wrote:
>>
>> I'm not sure whether this was the reason for the unittest.exp
>> random failure, but I suspect so.  (I failed to save the log,
>> and also forgot to check whether all selftests had passed.)
>>
>> The patchlet below fixes the spurious insn printing.  OK?
>>
> 
> Yes.
> 

Alright, pushed, like this:

Subject: [PATCH] Fix "maintenance selftest" printing stray instructions

The "maintenance selftest" command is printing odd bits of stray
instructions like:

~~~
brkwarning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default HS settings.


brkmov  r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov       r0, #0mov   r0, #0mov       r0, #0mov       r0, #0mov       r0, #0breakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakbreakM3.L = 0xffff;/* ( -1) M3=0x0xffff(65535) */break 8break 8warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default cris:common_v10_v32 settings.
~~~

etc.  Those appear because here:

  class gdb_disassembler_test : public gdb_disassembler
  {
  public:

    const bool verbose = false;

    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
				    const gdb_byte *insn,
				    size_t len)
      : gdb_disassembler (gdbarch,
			  (verbose ? gdb_stdout : &null_stream),
			  gdb_disassembler_test::read_memory),


specifically in this line:

			  (verbose ? gdb_stdout : &null_stream),

"verbose" has not been initialized yet, because the order of
initialization is base classes first, then members.  I.e. "verbose" is
only initialized after the base constructor is called.  Since the
gdb_disassembler_test object is created on the stack, "verbose" has
garbage at that point.  If the gargage is non-zero, then we end up
with the gdb_disassembler_test's stream incorrectly pointing to
gdb_stdout.

gdb/ChangeLog:
2017-02-02  Pedro Alves  <palves@redhat.com>

	* disasm-selftests.c (print_one_insn_test): Move the "verbose"
	field out of gdb_disassembler_test and make it static.
---
 gdb/disasm-selftests.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
index 7d0b006..9eb80b4 100644
--- a/gdb/disasm-selftests.c
+++ b/gdb/disasm-selftests.c
@@ -102,13 +102,12 @@ print_one_insn_test (struct gdbarch *gdbarch)
   /* Test gdb_disassembler for a given gdbarch by reading data from a
      pre-allocated buffer.  If you want to see the disassembled
      instruction printed to gdb_stdout, set verbose to true.  */
+  static const bool verbose = false;
 
   class gdb_disassembler_test : public gdb_disassembler
   {
   public:
 
-    const bool verbose = false;
-
     explicit gdb_disassembler_test (struct gdbarch *gdbarch,
 				    const gdb_byte *insn,
 				    size_t len)
-- 
2.5.5


^ permalink raw reply	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2017-02-02 23:39 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-10 12:26 [PATCH 0/8] Handle memory error on disassemble Yao Qi
2017-01-10 12:26 ` [PATCH 4/8] Return -1 on memory error in print_insn_msp430 Yao Qi
2017-01-11 21:54   ` Alan Modra
2017-01-12  9:43     ` Yao Qi
2017-01-10 12:26 ` [PATCH 6/8] Return -1 on memory error in print_insn_m68k Yao Qi
2017-01-11 22:15   ` Alan Modra
2017-01-12 11:50     ` Yao Qi
2017-01-12 14:38       ` Alan Modra
2017-01-12 14:52         ` Yao Qi
2017-01-13  1:54           ` Alan Modra
2017-01-13 12:29             ` Yao Qi
2017-01-10 12:26 ` [PATCH 7/8] Disassembly unit test: memory error Yao Qi
2017-01-10 12:26 ` [PATCH 3/8] Disassembly unit test: disassemble one instruction Yao Qi
2017-01-11 21:15   ` Simon Marchi
2017-01-12 13:06   ` Pedro Alves
2017-01-12 17:03     ` Yao Qi
2017-01-12 17:43       ` Pedro Alves
2017-01-12 21:04         ` Yao Qi
2017-01-12 14:35   ` Pedro Alves
2017-01-12 15:15   ` Pedro Alves
2017-01-12 15:35     ` Yao Qi
2017-01-12 15:44       ` Pedro Alves
2017-01-12 16:06     ` Pedro Alves
2017-01-10 12:26 ` [PATCH 5/8] Remove magic numbers in m68k-dis.c:print_insn_arg Yao Qi
2017-01-11 22:14   ` Alan Modra
2017-01-13 12:23     ` Yao Qi
2017-01-10 12:27 ` [PATCH 2/8] Call print_insn_mep in mep_gdb_print_insn Yao Qi
2017-01-11 20:50   ` Simon Marchi
2017-01-12 12:21     ` Yao Qi
2017-01-10 12:27 ` [PATCH 1/8] Refactor disassembly code Yao Qi
2017-01-11 20:43   ` Simon Marchi
2017-01-12 12:19     ` Yao Qi
2017-01-12 12:36       ` Pedro Alves
2017-01-12 15:29         ` Simon Marchi
2017-01-10 12:27 ` [PATCH 8/8] Don't throw exception in dis_asm_memory_error Yao Qi
2017-01-12 16:40   ` Pedro Alves
2017-01-12 21:09     ` Yao Qi
2017-01-16 10:03 ` [PATCH 0/6 v2] Handle memory error on disassemble Yao Qi
2017-01-16 10:03   ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
2017-01-17 14:38     ` Luis Machado
2017-01-24 15:33       ` Yao Qi
2017-01-20  0:08     ` Pedro Alves
2017-01-16 10:03   ` [PATCH 1/6] New function null_stream Yao Qi
2017-01-17 13:49     ` Luis Machado
2017-01-18 14:45       ` Yao Qi
2017-01-18 14:53         ` Luis Machado
2017-01-18 14:57           ` Simon Marchi
2017-01-18 15:02             ` Luis Machado
2017-01-18 15:18               ` Simon Marchi
2017-01-18 15:29                 ` Luis Machado
2017-01-18 15:54                   ` Simon Marchi
2017-01-18 16:36                     ` Luis Machado
2017-01-16 10:03   ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
2017-01-17 14:42     ` Luis Machado
2017-01-18 14:54       ` Yao Qi
2017-01-18 14:58         ` Luis Machado
2017-01-16 10:03   ` [PATCH 2/6] Refactor disassembly code Yao Qi
2017-01-17 14:14     ` Luis Machado
2017-01-18 16:34       ` Yao Qi
2017-01-18 16:53         ` Luis Machado
2017-01-16 10:03   ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
2017-01-17 14:19     ` Luis Machado
2017-01-24 10:08       ` Yao Qi
2017-01-24 13:41         ` Luis Machado
2017-01-16 10:03   ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
2017-01-17 14:33     ` Luis Machado
2017-01-20  0:04     ` Pedro Alves
2017-01-24 15:23       ` Yao Qi
2017-02-02 16:46         ` Pedro Alves
2017-02-02 22:12           ` Yao Qi
2017-02-02 23:39             ` [pushed] Fix "maintenance selftest" printing stray instructions (Re: [PATCH 4/6] Disassembly unit test: disassemble one instruction) Pedro Alves
2017-01-25  8:38   ` [PATCH 0/6 v3] Handle memory error on disassembly Yao Qi
2017-01-25  8:38     ` [PATCH 6/6] Don't throw exception in dis_asm_memory_error Yao Qi
2017-01-25  8:38     ` [PATCH 4/6] Disassembly unit test: disassemble one instruction Yao Qi
2017-01-25  8:38     ` [PATCH 3/6] Call print_insn_mep in mep_gdb_print_insn Yao Qi
2017-01-25  8:38     ` [PATCH 5/6] Disassembly unit test: memory error Yao Qi
2017-01-25  8:38     ` [PATCH 1/6] New function null_stream Yao Qi
2017-01-25  8:38     ` [PATCH 2/6] Refactor disassembly code Yao Qi
2017-01-26 11:34     ` [PATCH 0/6 v3] Handle memory error on disassembly Pedro Alves
2017-01-26 15:00       ` Yao Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).