[3/8] Disassembly unit test: disassemble one instruction

Message ID 1484051178-16013-4-git-send-email-yao.qi@linaro.org
State New, archived
Headers

Commit Message

Yao Qi Jan. 10, 2017, 12:26 p.m. UTC
  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(+)
  

Comments

Simon Marchi Jan. 11, 2017, 9:15 p.m. UTC | #1
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.
  
Pedro Alves Jan. 12, 2017, 1:06 p.m. UTC | #2
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
  
Pedro Alves Jan. 12, 2017, 2:35 p.m. UTC | #3
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
  
Pedro Alves Jan. 12, 2017, 3:15 p.m. UTC | #4
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
  
Yao Qi Jan. 12, 2017, 3:34 p.m. UTC | #5
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).
  
Pedro Alves Jan. 12, 2017, 3:44 p.m. UTC | #6
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
  
Pedro Alves Jan. 12, 2017, 4:06 p.m. UTC | #7
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)
>     {}
  
Yao Qi Jan. 12, 2017, 5:03 p.m. UTC | #8
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".
  
Pedro Alves Jan. 12, 2017, 5:43 p.m. UTC | #9
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
  
Yao Qi Jan. 12, 2017, 9:04 p.m. UTC | #10
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.
  

Patch

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.  */