gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / opcodes / m68k-dis.c
index 8fc70152663d0d74a9196335f9fc36f853e04d21..ec896433f27076718c7f5e5d5c8b725592119303 100644 (file)
@@ -1,17 +1,17 @@
 /* Print Motorola 68k instructions.
-   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
+   Copyright (C) 1986-2020 Free Software Foundation, Inc.
 
-   This file is free software; you can redistribute it and/or modify
+   This file is part of the GNU opcodes library.
+
+   This library 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 2 of the License, or
-   (at your option) any later version.
+   the Free Software Foundation; either version 3, 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.
+   It 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, write to the Free Software
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
-#include "dis-asm.h"
+#include "disassemble.h"
 #include "floatformat.h"
 #include "libiberty.h"
 #include "opintl.h"
-
+#include "cpu-m68k.h"
 #include "opcode/m68k.h"
 
 /* Local function prototypes.  */
@@ -57,65 +57,135 @@ 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)  (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
+#define NEXTBYTE(p, val)                       \
+  do                                           \
+    {                                          \
+      p += 2;                                  \
+      if (!FETCH_DATA (info, p))               \
+       return PRINT_INSN_ARG_MEMORY_ERROR;     \
+      val = COERCE_SIGNED_CHAR (p[-1]);                \
+    }                                          \
+  while (0)
 
 /* Get a 2 byte signed integer.  */
 #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
-#define NEXTWORD(p)  \
-  (p += 2, FETCH_DATA (info, p), \
-   COERCE16 ((p[-2] << 8) + p[-1]))
+
+#define NEXTWORD(p, val, ret_val)              \
+  do                                           \
+    {                                          \
+      p += 2;                                  \
+      if (!FETCH_DATA (info, p))               \
+       return ret_val;                         \
+      val = COERCE16 ((p[-2] << 8) + p[-1]);   \
+    }                                          \
+  while (0)
 
 /* Get a 4 byte signed integer.  */
-#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
-#define NEXTLONG(p)  \
-  (p += 4, FETCH_DATA (info, p), \
-   (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
+#define COERCE32(x) (((bfd_vma) (x) ^ 0x80000000) - 0x80000000)
+
+#define NEXTLONG(p, val, ret_val)                                      \
+  do                                                                   \
+    {                                                                  \
+      p += 4;                                                          \
+      if (!FETCH_DATA (info, p))                                       \
+       return ret_val;                                                 \
+      val = COERCE32 (((((((unsigned) p[-4] << 8) + p[-3]) << 8)       \
+                       + p[-2]) << 8) + p[-1]);                        \
+    }                                                                  \
+  while (0)
 
 /* Get a 4 byte unsigned integer.  */
-#define NEXTULONG(p)  \
-  (p += 4, FETCH_DATA (info, p), \
-   (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
+#define NEXTULONG(p, val)                                              \
+  do                                                                   \
+    {                                                                  \
+      p += 4;                                                          \
+      if (!FETCH_DATA (info, p))                                       \
+       return PRINT_INSN_ARG_MEMORY_ERROR;                             \
+      val = (((((((unsigned) p[-4] << 8) + p[-3]) << 8)                        \
+              + p[-2]) << 8) + p[-1]);                                 \
+    }                                                                  \
+  while (0)
 
 /* Get a single precision float.  */
-#define NEXTSINGLE(val, p) \
-  (p += 4, FETCH_DATA (info, p), \
-   floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
+#define NEXTSINGLE(val, p)                                     \
+  do                                                           \
+    {                                                          \
+      p += 4;                                                  \
+      if (!FETCH_DATA (info, p))                               \
+       return PRINT_INSN_ARG_MEMORY_ERROR;                     \
+      floatformat_to_double (& floatformat_ieee_single_big,    \
+                            (char *) p - 4, & val);            \
+    }                                                          \
+  while (0)
 
 /* Get a double precision float.  */
-#define NEXTDOUBLE(val, p) \
-  (p += 8, FETCH_DATA (info, p), \
-   floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
+#define NEXTDOUBLE(val, p)                                     \
+  do                                                           \
+    {                                                          \
+      p += 8;                                                  \
+      if (!FETCH_DATA (info, p))                               \
+       return PRINT_INSN_ARG_MEMORY_ERROR;                     \
+      floatformat_to_double (& floatformat_ieee_double_big,    \
+                            (char *) p - 8, & val);            \
+    }                                                          \
+  while (0)
 
 /* Get an extended precision float.  */
-#define NEXTEXTEND(val, p) \
-  (p += 12, FETCH_DATA (info, p), \
-   floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
+#define NEXTEXTEND(val, p)                             \
+  do                                                   \
+    {                                                  \
+      p += 12;                                         \
+      if (!FETCH_DATA (info, p))                       \
+       return PRINT_INSN_ARG_MEMORY_ERROR;             \
+      floatformat_to_double (& floatformat_m68881_ext, \
+                            (char *) p - 12, & val);   \
+    }                                                  \
+  while (0)
 
 /* Need a function to convert from packed to double
    precision.   Actually, it's easier to print a
    packed number than a double anyway, so maybe
    there should be a special case to handle this... */
-#define NEXTPACKED(p) \
-  (p += 12, FETCH_DATA (info, p), 0.0)
+#define NEXTPACKED(p, val)                     \
+  do                                           \
+    {                                          \
+      p += 12;                                 \
+      if (!FETCH_DATA (info, p))               \
+       return PRINT_INSN_ARG_MEMORY_ERROR;     \
+      val = 0.0;                               \
+    }                                          \
+  while (0)
+
 \f
 /* Maximum length of an instruction.  */
 #define MAXLEN 22
 
-#include <setjmp.h>
-
 struct private
 {
   /* Points to first byte not fetched.  */
   bfd_byte *max_fetched;
   bfd_byte the_buffer[MAXLEN];
   bfd_vma insn_start;
-  jmp_buf bailout;
 };
 
 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
-   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
-   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)))
@@ -134,7 +204,7 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr)
   if (status != 0)
     {
       (*info->memory_error_func) (status, start, info);
-      longjmp (priv->bailout, 1);
+      return 0;
     }
   else
     priv->max_fetched = addr;
@@ -159,7 +229,8 @@ dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED,
 /* Fetch BITS bits from a position in the instruction specified by CODE.
    CODE is a "place to put an argument", or 'x' for a destination
    that is a general address (mode and register).
-   BUFFER contains the instruction.  */
+   BUFFER contains the instruction.
+   Returns -1 on failure.  */
 
 static int
 fetch_arg (unsigned char *buffer,
@@ -214,64 +285,75 @@ fetch_arg (unsigned char *buffer,
       break;
 
     case 'k':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[3] >> 4);
       break;
 
     case 'C':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = buffer[3];
       break;
 
     case '1':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       val >>= 12;
       break;
 
     case '2':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       val >>= 6;
       break;
 
     case '3':
     case 'j':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       break;
 
     case '4':
-      FETCH_DATA (info, buffer + 5);
+      if (! FETCH_DATA (info, buffer + 5))
+       return -1;
       val = (buffer[4] << 8) + buffer[5];
       val >>= 12;
       break;
 
     case '5':
-      FETCH_DATA (info, buffer + 5);
+      if (! FETCH_DATA (info, buffer + 5))
+       return -1;
       val = (buffer[4] << 8) + buffer[5];
       val >>= 6;
       break;
 
     case '6':
-      FETCH_DATA (info, buffer + 5);
+      if (! FETCH_DATA (info, buffer + 5))
+       return -1;
       val = (buffer[4] << 8) + buffer[5];
       break;
 
     case '7':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       val >>= 7;
       break;
 
     case '8':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       val >>= 10;
       break;
 
     case '9':
-      FETCH_DATA (info, buffer + 3);
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
       val = (buffer[2] << 8) + buffer[3];
       val >>= 5;
       break;
@@ -280,6 +362,12 @@ fetch_arg (unsigned char *buffer,
       val = (buffer[1] >> 6);
       break;
 
+    case 'E':
+      if (! FETCH_DATA (info, buffer + 3))
+       return -1;
+      val = (buffer[2] >> 1);
+      break;
+
     case 'm':
       val = (buffer[1] & 0x40 ? 0x8 : 0)
        | ((buffer[0] >> 1) & 0x7)
@@ -310,29 +398,8 @@ fetch_arg (unsigned char *buffer,
       abort ();
     }
 
-  switch (bits)
-    {
-    case 1:
-      return val & 1;
-    case 2:
-      return val & 3;
-    case 3:
-      return val & 7;
-    case 4:
-      return val & 017;
-    case 5:
-      return val & 037;
-    case 6:
-      return val & 077;
-    case 7:
-      return val & 0177;
-    case 8:
-      return val & 0377;
-    case 12:
-      return val & 07777;
-    default:
-      abort ();
-    }
+  /* bits is never too big.  */
+  return val & ((1 << bits) - 1);
 }
 
 /* Check if an EA is valid for a particular code.  This is required
@@ -464,7 +531,8 @@ print_base (int regno, bfd_vma disp, disassemble_info *info)
 
 /* Print an indexed argument.  The base register is BASEREG (-1 for pc).
    P points to extension word, in buffer.
-   ADDR is the nominal core address of that extension word.  */
+   ADDR is the nominal core address of that extension word.
+   Returns NULL upon error.  */
 
 static unsigned char *
 print_indexed (int basereg,
@@ -479,7 +547,7 @@ print_indexed (int basereg,
   char buf[40];
   char vmabuf[50];
 
-  word = NEXTWORD (p);
+  NEXTWORD (p, word, NULL);
 
   /* Generate the text for the index register.
      Where this will be output is not yet determined.  */
@@ -517,10 +585,10 @@ print_indexed (int basereg,
   switch ((word >> 4) & 3)
     {
     case 2:
-      base_disp = NEXTWORD (p);
+      NEXTWORD (p, base_disp, NULL);
       break;
     case 3:
-      base_disp = NEXTLONG (p);
+      NEXTLONG (p, base_disp, NULL);
     }
   if (basereg == -1)
     base_disp += addr;
@@ -540,10 +608,10 @@ print_indexed (int basereg,
   switch (word & 3)
     {
     case 2:
-      outer_disp = NEXTWORD (p);
+      NEXTWORD (p, outer_disp, NULL);
       break;
     case 3:
-      outer_disp = NEXTLONG (p);
+      NEXTLONG (p, outer_disp, NULL);
     }
 
   print_base (basereg, base_disp, info);
@@ -561,10 +629,18 @@ print_indexed (int basereg,
   return p;
 }
 
+#define FETCH_ARG(size, val)                           \
+  do                                                   \
+    {                                                  \
+      val = fetch_arg (buffer, place, size, info);     \
+      if (val < 0)                                     \
+       return PRINT_INSN_ARG_MEMORY_ERROR;             \
+    }                                                  \
+  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.
-   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,
@@ -589,23 +665,21 @@ print_insn_arg (const char *d,
     case 'c':          /* Cache identifier.  */
       {
         static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
-        val = fetch_arg (buffer, place, 2, info);
-        (*info->fprintf_func) (info->stream, cacheFieldName[val]);
+        FETCH_ARG (2, val);
+       (*info->fprintf_func) (info->stream, "%s", cacheFieldName[val]);
         break;
       }
 
     case 'a':          /* Address register indirect only. Cf. case '+'.  */
       {
-        (*info->fprintf_func)
-         (info->stream,
-          "%s@",
-          reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+       FETCH_ARG (3, val);
+       (*info->fprintf_func) (info->stream, "%s@", reg_names[val + 8]);
         break;
       }
 
     case '_':          /* 32-bit absolute address for move16.  */
       {
-        uval = NEXTULONG (p);
+        NEXTULONG (p, uval);
        (*info->print_address_func) (uval, info);
         break;
       }
@@ -637,35 +711,69 @@ print_insn_arg (const char *d,
     case 'J':
       {
        /* FIXME: There's a problem here, different m68k processors call the
-          same address different names. This table can't get it right
-          because it doesn't know which processor it's disassembling for.  */
-       static const struct { char *name; int value; } names[]
-         = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
-            {"%tc",  0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
-             {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
-            {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
-            {"%msp", 0x803}, {"%isp", 0x804},
-            {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these.  */
-
-            /* Should we be calling this psr like we do in case 'Y'?  */
-            {"%mmusr",0x805},
-
-             {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}};
-
-       val = fetch_arg (buffer, place, 12, info);
-       for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+          same address different names.  The tables below try to get it right
+          using info->mach, but only for v4e.  */
+       struct regname { char * name; int value; };
+       static const struct regname names[] =
+         {
+           {"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
+           {"%tc",  0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
+           {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
+           {"%rgpiobar", 0x009}, {"%acr4",0x00c},
+           {"%acr5",0x00d}, {"%acr6",0x00e}, {"%acr7", 0x00f},
+           {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
+           {"%msp", 0x803}, {"%isp", 0x804},
+           {"%pc", 0x80f},
+           /* Reg c04 is sometimes called flashbar or rambar.
+              Reg c05 is also sometimes called rambar.  */
+           {"%rambar0", 0xc04}, {"%rambar1", 0xc05},
+
+           /* reg c0e is sometimes called mbar2 or secmbar.
+              reg c0f is sometimes called mbar.  */
+           {"%mbar0", 0xc0e}, {"%mbar1", 0xc0f},
+
+           /* Should we be calling this psr like we do in case 'Y'?  */
+           {"%mmusr",0x805},
+
+           {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808},
+
+           /* Fido added these.  */
+           {"%cac", 0xffe}, {"%mbo", 0xfff}
+       };
+       /* Alternate names for v4e (MCF5407/5445x/MCF547x/MCF548x), at least.  */
+       static const struct regname names_v4e[] =
+         {
+           {"%asid",0x003}, {"%acr0",0x004}, {"%acr1",0x005},
+           {"%acr2",0x006}, {"%acr3",0x007}, {"%mmubar",0x008},
+         };
+       unsigned int arch_mask;
+
+       arch_mask = bfd_m68k_mach_to_features (info->mach);
+       FETCH_ARG (12, val);
+       if (arch_mask & (mcfisa_b | mcfisa_c))
+         {
+           for (regno = ARRAY_SIZE (names_v4e); --regno >= 0;)
+             if (names_v4e[regno].value == val)
+               {
+                 (*info->fprintf_func) (info->stream, "%s", names_v4e[regno].name);
+                 break;
+               }
+           if (regno >= 0)
+             break;
+         }
+       for (regno = ARRAY_SIZE (names) - 1; regno >= 0; regno--)
          if (names[regno].value == val)
            {
              (*info->fprintf_func) (info->stream, "%s", names[regno].name);
              break;
            }
        if (regno < 0)
-         (*info->fprintf_func) (info->stream, "%d", val);
+         (*info->fprintf_func) (info->stream, "0x%x", val);
       }
       break;
 
     case 'Q':
-      val = fetch_arg (buffer, place, 3, info);
+      FETCH_ARG (3, val);
       /* 0 means 8, except for the bkpt instruction... */
       if (val == 0 && d[1] != 's')
        val = 8;
@@ -673,23 +781,34 @@ print_insn_arg (const char *d,
       break;
 
     case 'x':
-      val = fetch_arg (buffer, place, 3, info);
+      FETCH_ARG (3, val);
       /* 0 means -1.  */
       if (val == 0)
        val = -1;
       (*info->fprintf_func) (info->stream, "#%d", val);
       break;
 
+    case 'j':
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "#%d", val+1);
+      break;
+
+    case 'K':
+      FETCH_ARG (9, val);
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
     case 'M':
       if (place == 'h')
        {
          static char *const scalefactor_name[] = { "<<", ">>" };
-         val = fetch_arg (buffer, place, 1, info);
-         (*info->fprintf_func) (info->stream, scalefactor_name[val]);
+
+         FETCH_ARG (1, val);
+         (*info->fprintf_func) (info->stream, "%s", scalefactor_name[val]);
        }
       else
        {
-         val = fetch_arg (buffer, place, 8, info);
+         FETCH_ARG (8, val);
          if (val & 0x80)
            val = val - 0x100;
          (*info->fprintf_func) (info->stream, "#%d", val);
@@ -697,29 +816,27 @@ print_insn_arg (const char *d,
       break;
 
     case 'T':
-      val = fetch_arg (buffer, place, 4, info);
+      FETCH_ARG (4, val);
       (*info->fprintf_func) (info->stream, "#%d", val);
       break;
 
     case 'D':
-      (*info->fprintf_func) (info->stream, "%s",
-                            reg_names[fetch_arg (buffer, place, 3, info)]);
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
       break;
 
     case 'A':
-      (*info->fprintf_func)
-       (info->stream, "%s",
-        reg_names[fetch_arg (buffer, place, 3, info) + 010]);
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%s", reg_names[val + 010]);
       break;
 
     case 'R':
-      (*info->fprintf_func)
-       (info->stream, "%s",
-        reg_names[fetch_arg (buffer, place, 4, info)]);
+      FETCH_ARG (4, val);
+      (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
       break;
 
     case 'r':
-      regno = fetch_arg (buffer, place, 4, info);
+      FETCH_ARG (4, regno);
       if (regno > 7)
        (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
       else
@@ -727,13 +844,12 @@ print_insn_arg (const char *d,
       break;
 
     case 'F':
-      (*info->fprintf_func)
-       (info->stream, "%%fp%d",
-        fetch_arg (buffer, place, 3, info));
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%%fp%d", val);
       break;
 
     case 'O':
-      val = fetch_arg (buffer, place, 6, info);
+      FETCH_ARG (6, val);
       if (val & 0x20)
        (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
       else
@@ -741,121 +857,125 @@ print_insn_arg (const char *d,
       break;
 
     case '+':
-      (*info->fprintf_func)
-       (info->stream, "%s@+",
-        reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%s@+", reg_names[val + 8]);
       break;
 
     case '-':
-      (*info->fprintf_func)
-       (info->stream, "%s@-",
-        reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%s@-", reg_names[val + 8]);
       break;
 
     case 'k':
       if (place == 'k')
-       (*info->fprintf_func)
-         (info->stream, "{%s}",
-          reg_names[fetch_arg (buffer, place, 3, info)]);
+       {
+         FETCH_ARG (3, val);
+         (*info->fprintf_func) (info->stream, "{%s}", reg_names[val]);
+       }
       else if (place == 'C')
        {
-         val = fetch_arg (buffer, place, 7, info);
+         FETCH_ARG (7, val);
          if (val > 63)         /* This is a signed constant.  */
            val -= 128;
          (*info->fprintf_func) (info->stream, "{#%d}", val);
        }
       else
-       return -2;
+       return PRINT_INSN_ARG_INVALID_OPERAND;
       break;
 
     case '#':
     case '^':
       p1 = buffer + (*d == '#' ? 2 : 4);
       if (place == 's')
-       val = fetch_arg (buffer, place, 4, info);
+       FETCH_ARG (4, val);
       else if (place == 'C')
-       val = fetch_arg (buffer, place, 7, info);
+       FETCH_ARG (7, val);
       else if (place == '8')
-       val = fetch_arg (buffer, place, 3, info);
+       FETCH_ARG (3, val);
       else if (place == '3')
-       val = fetch_arg (buffer, place, 8, info);
+       FETCH_ARG (8, val);
       else if (place == 'b')
-       val = NEXTBYTE (p1);
+       NEXTBYTE (p1, val);
       else if (place == 'w' || place == 'W')
-       val = NEXTWORD (p1);
+       NEXTWORD (p1, val, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'l')
-       val = NEXTLONG (p1);
+       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;
 
     case 'B':
       if (place == 'b')
-       disp = NEXTBYTE (p);
+       NEXTBYTE (p, disp);
       else if (place == 'B')
        disp = COERCE_SIGNED_CHAR (buffer[1]);
       else if (place == 'w' || place == 'W')
-       disp = NEXTWORD (p);
+       NEXTWORD (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'l' || place == 'L' || place == 'C')
-       disp = NEXTLONG (p);
+       NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
       else if (place == 'g')
        {
-         disp = NEXTBYTE (buffer);
+         NEXTBYTE (buffer, disp);
          if (disp == 0)
-           disp = NEXTWORD (p);
+           NEXTWORD (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
          else if (disp == -1)
-           disp = NEXTLONG (p);
+           NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
        }
       else if (place == 'c')
        {
          if (buffer[1] & 0x40)         /* If bit six is one, long offset.  */
-           disp = NEXTLONG (p);
+           NEXTLONG (p, disp, PRINT_INSN_ARG_MEMORY_ERROR);
          else
-           disp = NEXTWORD (p);
+           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;
 
     case 'd':
-      val = NEXTWORD (p);
-      (*info->fprintf_func)
-       (info->stream, "%s@(%d)",
-        reg_names[fetch_arg (buffer, place, 3, info) + 8], val);
-      break;
+      {
+       int val1;
+
+       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;
+      }
 
     case 's':
-      (*info->fprintf_func) (info->stream, "%s",
-                            fpcr_names[fetch_arg (buffer, place, 3, info)]);
+      FETCH_ARG (3, val);
+      (*info->fprintf_func) (info->stream, "%s", fpcr_names[val]);
       break;
 
     case 'e':
-      val = fetch_arg(buffer, place, 2, info);
+      FETCH_ARG (2, val);
       (*info->fprintf_func) (info->stream, "%%acc%d", val);
       break;
 
     case 'g':
-      val = fetch_arg(buffer, place, 1, info);
-      (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
+      FETCH_ARG (1, val);
+      (*info->fprintf_func) (info->stream, "%%accext%s", val == 0 ? "01" : "23");
       break;
 
     case 'i':
-      val = fetch_arg(buffer, place, 2, info);
+      FETCH_ARG (2, val);
       if (val == 1)
        (*info->fprintf_func) (info->stream, "<<");
       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 PRINT_INSN_ARG_MEMORY_ERROR;
       if (val != 1)                            /* Unusual coprocessor ID?  */
        (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
       break;
@@ -887,14 +1007,20 @@ print_insn_arg (const char *d,
       if (place == 'd')
        {
          val = fetch_arg (buffer, 'x', 6, info);
+         if (val < 0)
+           return PRINT_INSN_ARG_MEMORY_ERROR;
          val = ((val & 7) << 3) + ((val >> 3) & 7);
        }
       else
-       val = fetch_arg (buffer, 's', 6, info);
+       {
+         val = fetch_arg (buffer, 's', 6, info);
+         if (val < 0)
+           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;
@@ -922,29 +1048,31 @@ print_insn_arg (const char *d,
          break;
 
        case 5:
-         val = NEXTWORD (p);
+         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 PRINT_INSN_ARG_MEMORY_ERROR;
          break;
 
        case 7:
          switch (val & 7)
            {
            case 0:
-             val = NEXTWORD (p);
+             NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
              (*info->print_address_func) (val, info);
              break;
 
            case 1:
-             uval = NEXTULONG (p);
+             NEXTULONG (p, uval);
              (*info->print_address_func) (uval, info);
              break;
 
            case 2:
-             val = NEXTWORD (p);
+             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, ")");
@@ -952,6 +1080,8 @@ print_insn_arg (const char *d,
 
            case 3:
              p = print_indexed (-1, p, addr, info);
+             if (p == NULL)
+               return PRINT_INSN_ARG_MEMORY_ERROR;
              break;
 
            case 4:
@@ -959,17 +1089,17 @@ print_insn_arg (const char *d,
              switch (place)
              {
                case 'b':
-                 val = NEXTBYTE (p);
+                 NEXTBYTE (p, val);
                  flt_p = 0;
                  break;
 
                case 'w':
-                 val = NEXTWORD (p);
+                 NEXTWORD (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
                  flt_p = 0;
                  break;
 
                case 'l':
-                 val = NEXTLONG (p);
+                 NEXTLONG (p, val, PRINT_INSN_ARG_MEMORY_ERROR);
                  flt_p = 0;
                  break;
 
@@ -986,20 +1116,20 @@ print_insn_arg (const char *d,
                  break;
 
                case 'p':
-                 flval = NEXTPACKED (p);
+                 NEXTPACKED (p, flval);
                  break;
 
                default:
-                 return -1;
+                 return PRINT_INSN_ARG_INVALID_OPERAND;
              }
              if (flt_p)        /* Print a float? */
-               (*info->fprintf_func) (info->stream, "#%g", flval);
+               (*info->fprintf_func) (info->stream, "#0e%g", flval);
              else
                (*info->fprintf_func) (info->stream, "#%d", val);
              break;
 
            default:
-             return -1;
+             return PRINT_INSN_ARG_INVALID_OPERAND;
            }
        }
 
@@ -1008,7 +1138,7 @@ print_insn_arg (const char *d,
         mask bit and if set, add a '&' to the arg.  */
       if (place == '/')
        {
-         val = fetch_arg (buffer, place, 1, info);
+         FETCH_ARG (1, val);
          if (val)
            info->fprintf_func (info->stream, "&");
        }
@@ -1020,7 +1150,7 @@ print_insn_arg (const char *d,
          {
            char doneany;
            p1 = buffer + 2;
-           val = NEXTWORD (p1);
+           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;
@@ -1061,7 +1191,8 @@ print_insn_arg (const char *d,
          {
            /* `fmovem' insn.  */
            char doneany;
-           val = fetch_arg (buffer, place, 8, info);
+
+           FETCH_ARG (8, val);
            if (val == 0)
              {
                (*info->fprintf_func) (info->stream, "#0");
@@ -1095,17 +1226,17 @@ print_insn_arg (const char *d,
          }
        else if (place == '8')
          {
+           FETCH_ARG (3, val);
            /* fmoveml for FP status registers.  */
-           (*info->fprintf_func) (info->stream, "%s",
-                                  fpcr_names[fetch_arg (buffer, place, 3,
-                                                        info)]);
+           (*info->fprintf_func) (info->stream, "%s", fpcr_names[val]);
          }
        else
-         return -2;
+         return PRINT_INSN_ARG_INVALID_OP_TABLE;
       break;
 
     case 'X':
       place = '8';
+      /* Fall through.  */
     case 'Y':
     case 'Z':
     case 'W':
@@ -1114,9 +1245,9 @@ print_insn_arg (const char *d,
     case '2':
     case '3':
       {
-       int val = fetch_arg (buffer, place, 5, info);
        char *name = 0;
 
+       FETCH_ARG (5, val);
        switch (val)
          {
          case 2: name = "%tt0"; break;
@@ -1151,8 +1282,9 @@ print_insn_arg (const char *d,
 
     case 'f':
       {
-       int fc = fetch_arg (buffer, place, 5, info);
+       int fc;
 
+       FETCH_ARG (5, fc);
        if (fc == 1)
          (*info->fprintf_func) (info->stream, "%%dfc");
        else if (fc == 0)
@@ -1169,8 +1301,9 @@ print_insn_arg (const char *d,
 
     case 't':
       {
-       int level = fetch_arg (buffer, place, 3, info);
+       int level;
 
+       FETCH_ARG (3, level);
        (*info->fprintf_func) (info->stream, "%d", level);
       }
       break;
@@ -1178,8 +1311,9 @@ print_insn_arg (const char *d,
     case 'u':
       {
        short is_upper = 0;
-       int reg = fetch_arg (buffer, place, 5, info);
+       int reg;
 
+       FETCH_ARG (5, reg);
        if (reg & 0x10)
          {
            is_upper = 1;
@@ -1192,30 +1326,35 @@ print_insn_arg (const char *d,
       break;
 
     default:
-      return -2;
+      return PRINT_INSN_ARG_INVALID_OP_TABLE;
     }
 
   return p - p0;
 }
 
 /* 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,
                 disassemble_info * info,
-                const struct m68k_opcode * best,
-                struct private * priv)
+                const struct m68k_opcode * best)
 {
   unsigned char *save_p;
   unsigned char *p;
   const char *d;
+  const char *args = best->args;
 
+  struct private *priv = (struct private *) info->private_data;
   bfd_byte *buffer = priv->the_buffer;
   fprintf_ftype save_printer = info->fprintf_func;
   void (* save_print_address) (bfd_vma, struct disassemble_info *)
     = info->print_address_func;
 
+  if (*args == '.')
+    args++;
+
   /* Point at first word of argument data,
      and at descriptor for first argument.  */
   p = buffer + 2;
@@ -1224,7 +1363,7 @@ match_insn_m68k (bfd_vma memaddr,
      The only place this is stored in the opcode table is
      in the arguments--look for arguments which specify fields in the 2nd
      or 3rd words of the instruction.  */
-  for (d = best->args; *d; d += 2)
+  for (d = args; *d; d += 2)
     {
       /* I don't think it is necessary to be checking d[0] here;
         I suspect all this could be moved to the case statement below.  */
@@ -1271,22 +1410,22 @@ match_insn_m68k (bfd_vma memaddr,
      three words long.  */
   if (p - buffer < 6
       && (best->match & 0xffff) == 0xffff
-      && best->args[0] == '#'
-      && best->args[1] == 'w')
+      && args[0] == '#'
+      && args[1] == 'w')
     {
       /* Copy the one word argument into the usual location for a one
         word argument, to simplify printing it.  We can get away with
         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);
-
-  d = best->args;
+  if (!FETCH_DATA (info, p))
+    return -1;
 
   save_p = p;
   info->print_address_func = dummy_print_address;
@@ -1294,26 +1433,29 @@ match_insn_m68k (bfd_vma memaddr,
 
   /* We scan the operands twice.  The first time we don't print anything,
      but look for errors.  */
-  for (; *d; d += 2)
+  for (d = args; *d; d += 2)
     {
       int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
 
       if (eaten >= 0)
        p += eaten;
-      else if (eaten == -1)
+      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;
-         return 0;
+         return eaten == PRINT_INSN_ARG_MEMORY_ERROR ? -1 : 0;
        }
       else
        {
+         /* We must restore the print functions before trying to print the
+            error message.  */
+         info->fprintf_func = save_printer;
+         info->print_address_func = save_print_address;
          info->fprintf_func (info->stream,
                              /* xgettext:c-format */
                              _("<internal error in opcode table: %s %s>\n"),
-                             best->name,  best->args);
-         info->fprintf_func = save_printer;
-         info->print_address_func = save_print_address;
+                             best->name, best->args);
          return 2;
        }
     }
@@ -1322,7 +1464,7 @@ match_insn_m68k (bfd_vma memaddr,
   info->fprintf_func = save_printer;
   info->print_address_func = save_print_address;
 
-  d = best->args;
+  d = args;
 
   info->fprintf_func (info->stream, "%s", best->name);
 
@@ -1341,21 +1483,25 @@ match_insn_m68k (bfd_vma memaddr,
   return p - buffer;
 }
 
-/* Print the m68k instruction at address MEMADDR in debugged memory,
-   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
+/* 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.  Return -1 on memory
+   error.  */
 
-int
-print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
+static int
+m68k_scan_mask (bfd_vma memaddr, disassemble_info *info,
+               unsigned int arch_mask)
 {
   int i;
   const char *d;
-  unsigned int arch_mask;
-  struct private priv;
-  bfd_byte *buffer = priv.the_buffer;
-  int major_opcode;
-  static int numopcodes[16];
   static const struct m68k_opcode **opcodes[16];
+  static int numopcodes[16];
   int val;
+  int major_opcode;
+
+  struct private *priv = (struct private *) info->private_data;
+  bfd_byte *buffer = priv->the_buffer;
 
   if (!opcodes[0])
     {
@@ -1383,24 +1529,8 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
        *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
     }
 
-  info->private_data = (PTR) &priv;
-  /* Tell objdump to use two bytes per chunk
-     and six bytes per line for displaying raw data.  */
-  info->bytes_per_chunk = 2;
-  info->bytes_per_line = 6;
-  info->display_endian = BFD_ENDIAN_BIG;
-  priv.max_fetched = priv.the_buffer;
-  priv.insn_start = memaddr;
-
-  if (setjmp (priv.bailout) != 0)
-    /* Error return.  */
+  if (!FETCH_DATA (info, buffer + 2))
     return -1;
-
-  arch_mask = bfd_m68k_mach_to_features (info->mach);
-  if (!arch_mask)
-    arch_mask = ~(unsigned int)0;
-
-  FETCH_DATA (info, buffer + 2);
   major_opcode = (buffer[0] >> 4) & 15;
 
   for (i = 0; i < numopcodes[major_opcode]; i++)
@@ -1408,6 +1538,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
       const struct m68k_opcode *opc = opcodes[major_opcode][i];
       unsigned long opcode = opc->opcode;
       unsigned long match = opc->match;
+      const char *args = opc->args;
+
+      if (*args == '.')
+       args++;
 
       if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
          && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
@@ -1423,7 +1557,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
          /* Don't use for printout the variants of divul and divsl
             that have the same register number in two places.
             The more general variants will match instead.  */
-         for (d = opc->args; *d; d += 2)
+         for (d = args; *d; d += 2)
            if (d[1] == 'D')
              break;
 
@@ -1431,7 +1565,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
             point coprocessor instructions which use the same
             register number in two places, as above.  */
          if (*d == '\0')
-           for (d = opc->args; *d; d += 2)
+           for (d = args; *d; d += 2)
              if (d[1] == 't')
                break;
 
@@ -1439,11 +1573,13 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
             wait for fmoveml.  */
          if (*d == '\0')
            {
-             for (d = opc->args; *d; d += 2)
+             for (d = args; *d; d += 2)
                {
                  if (d[0] == 's' && d[1] == '8')
                    {
                      val = fetch_arg (buffer, d[1], 3, info);
+                     if (val < 0)
+                       return 0;
                      if ((val & (val - 1)) != 0)
                        break;
                    }
@@ -1453,7 +1589,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
          /* Don't match FPU insns with non-default coprocessor ID.  */
          if (*d == '\0')
            {
-             for (d = opc->args; *d; d += 2)
+             for (d = args; *d; d += 2)
                {
                  if (d[0] == 'I')
                    {
@@ -1465,12 +1601,51 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
            }
 
          if (*d == '\0')
-           if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
+           if ((val = match_insn_m68k (memaddr, info, opc)))
              return val;
        }
     }
+  return 0;
+}
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
+{
+  unsigned int arch_mask;
+  struct private priv;
+  int val;
+
+  bfd_byte *buffer = priv.the_buffer;
+
+  info->private_data = & priv;
+  /* Tell objdump to use two bytes per chunk
+     and six bytes per line for displaying raw data.  */
+  info->bytes_per_chunk = 2;
+  info->bytes_per_line = 6;
+  info->display_endian = BFD_ENDIAN_BIG;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = memaddr;
+
+  arch_mask = bfd_m68k_mach_to_features (info->mach);
+  if (!arch_mask)
+    {
+      /* 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)
+       val = m68k_scan_mask (memaddr, info, mcf_mask);
+    }
+  else
+    {
+      val = m68k_scan_mask (memaddr, info, arch_mask);
+    }
+
+  if (val == 0)
+    /* Handle undefined instructions.  */
+    info->fprintf_func (info->stream, ".short 0x%04x", (buffer[0] << 8) + buffer[1]);
 
-  /* Handle undefined instructions.  */
-  info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
-  return 2;
+  return val ? val : 2;
 }
This page took 0.045449 seconds and 4 git commands to generate.