Improve the MSP430 disassembler's handling of memory read errors.
authorNick Clifton <nickc@redhat.com>
Fri, 27 May 2016 12:49:58 +0000 (13:49 +0100)
committerNick Clifton <nickc@redhat.com>
Fri, 27 May 2016 12:49:58 +0000 (13:49 +0100)
PR target/20150
* msp430-dis.c (msp430dis_read_two_bytes): New function.
(msp430dis_opcode_unsigned): New function.
(msp430dis_opcode_signed): New function.
(msp430_singleoperand): Use the new opcode reading functions.
Only disassenmble bytes if they were successfully read.
(msp430_doubleoperand): Likewise.
(msp430_branchinstr): Likewise.
(msp430x_callx_instr): Likewise.
(print_insn_msp430): Check that it is safe to read bytes before
attempting disassembly.  Use the new opcode reading functions.

opcodes/ChangeLog
opcodes/msp430-dis.c

index 2b98764a7f7982892c770df0e035d5c010cad3e6..82e3143e1ed39bf9dcd71f09fdbba73e03d4a0b9 100644 (file)
@@ -1,3 +1,17 @@
+2016-05-27  Nick Clifton  <nickc@redhat.com>
+
+       PR target/20150
+       * msp430-dis.c (msp430dis_read_two_bytes): New function.
+       (msp430dis_opcode_unsigned): New function.
+       (msp430dis_opcode_signed): New function.
+       (msp430_singleoperand): Use the new opcode reading functions.
+       Only disassenmble bytes if they were successfully read.
+       (msp430_doubleoperand): Likewise.
+       (msp430_branchinstr): Likewise.
+       (msp430x_callx_instr): Likewise.
+       (print_insn_msp430): Check that it is safe to read bytes before
+       attempting disassembly.  Use the new opcode reading functions.
+
 2016-05-26  Peter Bergner <bergner@vnet.ibm.com>
 
        * ppc-opc.c (CY): New define.  Document it.
index 676a2d855efbc720b440e94359e00d3a9cbfaee6..c057c9bde7ec1eb2a1338c943be8884d448e0a53 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/types.h>
+#include <errno.h>
 
 #include "dis-asm.h"
 #include "opintl.h"
 
 #define PS(x)   (0xffff & (x))
 
-static unsigned short
-msp430dis_opcode (bfd_vma addr, disassemble_info *info)
+static bfd_boolean
+msp430dis_read_two_bytes (bfd_vma            addr,
+                         disassemble_info * info,
+                         bfd_byte *         buffer,
+                         char *             comm)
 {
-  bfd_byte buffer[2];
   int status;
 
   status = info->read_memory_func (addr, buffer, 2, info);
-  if (status != 0)
+  if (status == 0)
+    return TRUE;
+
+  /* PR 20150: A status of EIO means that there were no more bytes left
+     to read in the current section.  This can happen when disassembling
+     interrupt vectors for example.  Avoid cluttering the output with
+     unhelpful error messages in this case.  */
+  if (status == EIO)
+    {
+      if (comm)
+       sprintf (comm, _("Warning: disassembly unreliable - not enough bytes available"));
+    }
+  else
     {
       info->memory_error_func (status, addr, info);
-      return -1;
+      if (comm)
+       sprintf (comm, _("Error: read from memory failed"));
+    }
+
+  return FALSE;
+}
+
+static bfd_boolean
+msp430dis_opcode_unsigned (bfd_vma            addr,
+                          disassemble_info * info,
+                          unsigned short *   return_val,
+                          char *             comm)
+{
+  bfd_byte buffer[2];
+
+  if (msp430dis_read_two_bytes (addr, info, buffer, comm))
+    {
+      * return_val = bfd_getl16 (buffer);
+      return TRUE;
+    }
+  else
+    {
+      * return_val = 0;
+      return FALSE;
+    }
+}
+
+static bfd_boolean
+msp430dis_opcode_signed (bfd_vma            addr,
+                        disassemble_info * info,
+                        signed int *       return_val,
+                        char *             comm)
+{
+  bfd_byte buffer[2];
+
+  if (msp430dis_read_two_bytes (addr, info, buffer, comm))
+    {
+      int status;
+
+      status = bfd_getl_signed_16 (buffer);
+      if (status & 0x8000)
+       status |= -1U << 16;
+      * return_val = status;
+      return TRUE;
+    }
+  else
+    {
+      * return_val = 0;
+      return FALSE;
     }
-  return bfd_getl16 (buffer);
 }
 
 static int
@@ -193,47 +255,51 @@ msp430_singleoperand (disassemble_info *info,
          if (regd == 0)
            {
              /* PC relative.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             *cycles = 4;
-             sprintf (op, "0x%04x", dst);
-             sprintf (comm, "PC rel. abs addr 0x%04x",
-                      PS ((short) (addr + 2) + dst));
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 sprintf (op, "0x%05x", dst);
-                 sprintf (comm, "PC rel. abs addr 0x%05lx",
-                          (long)((addr + 2 + dst) & 0xfffff));
+                 cmd_len += 2;
+                 *cycles = 4;
+                 sprintf (op, "0x%04x", dst);
+                 sprintf (comm, "PC rel. abs addr 0x%04x",
+                          PS ((short) (addr + 2) + dst));
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     sprintf (op, "0x%05x", dst);
+                     sprintf (comm, "PC rel. abs addr 0x%05lx",
+                              (long)((addr + 2 + dst) & 0xfffff));
+                   }
                }
            }
          else if (regd == 2)
            {
              /* Absolute.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             *cycles = 4;
-             sprintf (op, "&0x%04x", PS (dst));
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 sprintf (op, "&0x%05x", dst & 0xfffff);
+                 cmd_len += 2;
+                 *cycles = 4;
+                 sprintf (op, "&0x%04x", PS (dst));
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     sprintf (op, "&0x%05x", dst & 0xfffff);
+                   }
                }
            }
          else
            {
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             *cycles = 4;
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 if (dst & 0x80000)
-                   dst |= -1U << 20;
+                 cmd_len += 2;
+                 *cycles = 4;
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     if (dst & 0x80000)
+                       dst |= -1U << 20;
+                   }
+                 sprintf (op, "%d(r%d)", dst, regd);
                }
-             else if (dst & 0x8000)
-               dst |= -1U << 16;
-             sprintf (op, "%d(r%d)", dst, regd);
            }
        }
       break;
@@ -264,19 +330,21 @@ msp430_singleoperand (disassemble_info *info,
            {
              *cycles = 3;
              /* absolute. @pc+ */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             sprintf (op, "#%d", dst);
-             if (dst > 9 || dst < 0)
-               sprintf (comm, "#0x%04x", PS (dst));
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 if (dst & 0x80000)
-                   dst |= -1U << 20;
+                 cmd_len += 2;
                  sprintf (op, "#%d", dst);
                  if (dst > 9 || dst < 0)
-                   sprintf (comm, "#0x%05x", dst);
+                   sprintf (comm, "#0x%04x", PS (dst));
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     if (dst & 0x80000)
+                       dst |= -1U << 20;
+                     sprintf (op, "#%d", dst);
+                     if (dst > 9 || dst < 0)
+                       sprintf (comm, "#0x%05x", dst);
+                   }
                }
            }
          else
@@ -288,29 +356,33 @@ msp430_singleoperand (disassemble_info *info,
          if (regd == 0)
            {
              /* PC relative.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             sprintf (op, "0x%04x", PS (dst));
-             sprintf (comm, "PC rel. 0x%04x",
-                      PS ((short) addr + 2 + dst));
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 sprintf (op, "0x%05x", dst & 0xffff);
-                 sprintf (comm, "PC rel. 0x%05lx",
-                          (long)((addr + 2 + dst) & 0xfffff));
+                 cmd_len += 2;
+                 sprintf (op, "0x%04x", PS (dst));
+                 sprintf (comm, "PC rel. 0x%04x",
+                          PS ((short) addr + 2 + dst));
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     sprintf (op, "0x%05x", dst & 0xffff);
+                     sprintf (comm, "PC rel. 0x%05lx",
+                              (long)((addr + 2 + dst) & 0xfffff));
+                   }
                }
            }
          else if (regd == 2)
            {
              /* Absolute.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             sprintf (op, "&0x%04x", PS (dst));
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 sprintf (op, "&0x%05x", dst & 0xfffff);
+                 cmd_len += 2;
+                 sprintf (op, "&0x%04x", PS (dst));
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     sprintf (op, "&0x%05x", dst & 0xfffff);
+                   }
                }
            }
          else if (regd == 3)
@@ -322,19 +394,19 @@ msp430_singleoperand (disassemble_info *info,
          else
            {
              /* Indexed.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 2;
-             if (extended_dst)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
                {
-                 dst |= extended_dst << 16;
-                 if (dst & 0x80000)
-                   dst |= -1U << 20;
+                 cmd_len += 2;
+                 if (extended_dst)
+                   {
+                     dst |= extended_dst << 16;
+                     if (dst & 0x80000)
+                       dst |= -1U << 20;
+                   }
+                 sprintf (op, "%d(r%d)", dst, regd);
+                 if (dst > 9 || dst < 0)
+                   sprintf (comm, "%05x", dst);
                }
-             else if (dst & 0x8000)
-               dst |= -1U << 16;
-             sprintf (op, "%d(r%d)", dst, regd);
-             if (dst > 9 || dst < 0)
-               sprintf (comm, "%05x", dst);
            }
        }
       break;
@@ -352,6 +424,7 @@ msp430_singleoperand (disassemble_info *info,
       *cycles = 2;
       return 2;
       break;
+
     default:
       cmd_len = 0;
     }
@@ -409,7 +482,7 @@ msp430_doubleoperand (disassemble_info *info,
          /* Register mode.  */
          if (regd == 3)
            {
-             strcpy (comm1, _("Illegal as emulation instr"));
+             strcpy (comm1, _("Warning: illegal as emulation instr"));
              return -1;
            }
 
@@ -421,56 +494,65 @@ msp430_doubleoperand (disassemble_info *info,
          if (regd == 0)
            {
              /* PC relative, Symbolic.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             cmd_len += 4;
-             *cycles = 6;
-             sprintf (op1, "0x%04x", PS (dst));
-             sprintf (comm1, "PC rel. 0x%04x",
-                      PS ((short) addr + 2 + dst));
-             if (extension_word)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
                {
-                 dst |= extended_dst << 16;
-                 if (dst & 0x80000)
-                   dst |= -1U << 20;
-                 sprintf (op1, "0x%05x", dst & 0xfffff);
-                 sprintf (comm1, "PC rel. 0x%05lx",
-                          (long)((addr + 2 + dst) & 0xfffff));
+                 cmd_len += 4;
+                 *cycles = 6;
+                 sprintf (op1, "0x%04x", PS (dst));
+                 sprintf (comm1, "PC rel. 0x%04x",
+                          PS ((short) addr + 2 + dst));
+                 if (extension_word)
+                   {
+                     dst |= extended_dst << 16;
+                     if (dst & 0x80000)
+                       dst |= -1U << 20;
+                     sprintf (op1, "0x%05x", dst & 0xfffff);
+                     sprintf (comm1, "PC rel. 0x%05lx",
+                              (long)((addr + 2 + dst) & 0xfffff));
+                   }
                }
            }
          else if (regd == 2)
            {
              /* Absolute.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             /* If the 'src' field is not the same as the dst
-                then this is not an rla instruction.  */
-             if (dst != msp430dis_opcode (addr + 4, info))
-               return 0;
-             cmd_len += 4;
-             *cycles = 6;
-             sprintf (op1, "&0x%04x", PS (dst));
-             if (extension_word)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
                {
-                 dst |= extended_dst << 16;
-                 sprintf (op1, "&0x%05x", dst & 0xfffff);
+                 int src;
+
+                 /* If the 'src' field is not the same as the dst
+                    then this is not an rla instruction.  */
+                 if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
+                   {
+                     if (src != dst)
+                       return 0;
+                   }
+                 cmd_len += 4;
+                 *cycles = 6;
+                 sprintf (op1, "&0x%04x", PS (dst));
+                 if (extension_word)
+                   {
+                     dst |= extended_dst << 16;
+                     sprintf (op1, "&0x%05x", dst & 0xfffff);
+                   }
                }
            }
          else
            {
              /* Indexed.  */
-             dst = msp430dis_opcode (addr + 2, info);
-             if (extension_word)
+             if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
                {
-                 dst |= extended_dst << 16;
-                 if (dst & 0x80000)
-                   dst |= -1U << 20;
+                 if (extension_word)
+                   {
+                     dst |= extended_dst << 16;
+                     if (dst & 0x80000)
+                       dst |= -1U << 20;
+                   }
+                 cmd_len += 4;
+                 *cycles = 6;
+                 sprintf (op1, "%d(r%d)", dst, regd);
+                 if (dst > 9 || dst < -9)
+                   sprintf (comm1, "#0x%05x", dst);
                }
-             else if (dst & 0x8000)
-               dst |= -1U << 16;
-             cmd_len += 4;
-             *cycles = 6;
-             sprintf (op1, "%d(r%d)", dst, regd);
-             if (dst > 9 || dst < -9)
-               sprintf (comm1, "#0x%05x", dst);
            }
        }
 
@@ -484,7 +566,7 @@ msp430_doubleoperand (disassemble_info *info,
   if (ad == 0 && regd == 3)
     {
       /* R2/R3 are illegal as dest: may be data section.  */
-      strcpy (comm1, _("Illegal as 2-op instr"));
+      strcpy (comm1, _("Warning: illegal as 2-op instr"));
       return -1;
     }
 
@@ -514,19 +596,22 @@ msp430_doubleoperand (disassemble_info *info,
        {
          *cycles = 3;
          /* Absolute. @pc+.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         sprintf (op1, "#%d", dst);
-         if (dst > 9 || dst < 0)
-           sprintf (comm1, "#0x%04x", PS (dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
            {
-             dst |= extended_src << 16;
-             if (dst & 0x80000)
-               dst |= -1U << 20;
+             cmd_len += 2;
              sprintf (op1, "#%d", dst);
              if (dst > 9 || dst < 0)
-               sprintf (comm1, "0x%05x", dst & 0xfffff);
+               sprintf (comm1, "#0x%04x", PS (dst));
+             if (extension_word)
+               {
+                 dst &= 0xffff;
+                 dst |= extended_src << 16;
+                 if (dst & 0x80000)
+                   dst |= -1U << 20;
+                 sprintf (op1, "#%d", dst);
+                 if (dst > 9 || dst < 0)
+                   sprintf (comm1, "0x%05x", dst & 0xfffff);
+               }
            }
        }
       else
@@ -538,34 +623,40 @@ msp430_doubleoperand (disassemble_info *info,
        {
          *cycles = 4;
          /* PC relative.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         sprintf (op1, "0x%04x", PS (dst));
-         sprintf (comm1, "PC rel. 0x%04x",
-                  PS ((short) addr + 2 + dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
            {
-             dst |= extended_src << 16;
-             if (dst & 0x80000)
-               dst |= -1U << 20;
-             sprintf (op1, "0x%05x", dst & 0xfffff);
-             sprintf (comm1, "PC rel. 0x%05lx",
-                      (long) ((addr + 2 + dst) & 0xfffff));
+             cmd_len += 2;
+             sprintf (op1, "0x%04x", PS (dst));
+             sprintf (comm1, "PC rel. 0x%04x",
+                      PS ((short) addr + 2 + dst));
+             if (extension_word)
+               {
+                 dst &= 0xffff;
+                 dst |= extended_src << 16;
+                 if (dst & 0x80000)
+                   dst |= -1U << 20;
+                 sprintf (op1, "0x%05x", dst & 0xfffff);
+                 sprintf (comm1, "PC rel. 0x%05lx",
+                          (long) ((addr + 2 + dst) & 0xfffff));
+               }
            }
        }
       else if (regs == 2)
        {
          *cycles = 2;
          /* Absolute.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         sprintf (op1, "&0x%04x", PS (dst));
-         sprintf (comm1, "0x%04x", PS (dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
            {
-             dst |= extended_src << 16;
-             sprintf (op1, "&0x%05x", dst & 0xfffff);
-             * comm1 = 0;
+             cmd_len += 2;
+             sprintf (op1, "&0x%04x", PS (dst));
+             sprintf (comm1, "0x%04x", PS (dst));
+             if (extension_word)
+               {
+                 dst &= 0xffff;
+                 dst |= extended_src << 16;
+                 sprintf (op1, "&0x%05x", dst & 0xfffff);
+                 * comm1 = 0;
+               }
            }
        }
       else if (regs == 3)
@@ -578,19 +669,20 @@ msp430_doubleoperand (disassemble_info *info,
        {
          *cycles = 3;
          /* Indexed.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
            {
-             dst |= extended_src << 16;
-             if (dst & 0x80000)
-               dst |= -1U << 20;
+             cmd_len += 2;
+             if (extension_word)
+               {
+                 dst &= 0xffff;
+                 dst |= extended_src << 16;
+                 if (dst & 0x80000)
+                   dst |= -1U << 20;
+               }
+             sprintf (op1, "%d(r%d)", dst, regs);
+             if (dst > 9 || dst < -9)
+               sprintf (comm1, "0x%05x", dst);
            }
-         else if (dst & 0x8000)
-           dst |= -1U << 16;
-         sprintf (op1, "%d(r%d)", dst, regs);
-         if (dst > 9 || dst < -9)
-           sprintf (comm1, "0x%05x", dst);
        }
     }
 
@@ -621,50 +713,54 @@ msp430_doubleoperand (disassemble_info *info,
        {
          /* PC relative.  */
          *cycles += 1;
-         dst = msp430dis_opcode (addr + cmd_len, info);
-         sprintf (op2, "0x%04x", PS (dst));
-         sprintf (comm2, "PC rel. 0x%04x",
-                  PS ((short) addr + cmd_len + dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
            {
-             dst |= extended_dst << 16;
-             if (dst & 0x80000)
-               dst |= -1U << 20;
-             sprintf (op2, "0x%05x", dst & 0xfffff);
-             sprintf (comm2, "PC rel. 0x%05lx",
-                      (long)((addr + cmd_len + dst) & 0xfffff));
+             sprintf (op2, "0x%04x", PS (dst));
+             sprintf (comm2, "PC rel. 0x%04x",
+                      PS ((short) addr + cmd_len + dst));
+             if (extension_word)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1U << 20;
+                 sprintf (op2, "0x%05x", dst & 0xfffff);
+                 sprintf (comm2, "PC rel. 0x%05lx",
+                          (long)((addr + cmd_len + dst) & 0xfffff));
+               }
            }
          cmd_len += 2;
        }
       else if (regd == 2)
        {
          /* Absolute.  */
-         dst = msp430dis_opcode (addr + cmd_len, info);
-         cmd_len += 2;
-         sprintf (op2, "&0x%04x", PS (dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
            {
-             dst |= extended_dst << 16;
-             sprintf (op2, "&0x%05x", dst & 0xfffff);
+             cmd_len += 2;
+             sprintf (op2, "&0x%04x", PS (dst));
+             if (extension_word)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op2, "&0x%05x", dst & 0xfffff);
+               }
            }
        }
       else
        {
-         dst = msp430dis_opcode (addr + cmd_len, info);
-         cmd_len += 2;
-         if (dst & 0x8000)
-           dst |= -1U << 16;
-         if (dst > 9 || dst < 0)
-           sprintf (comm2, "0x%04x", PS (dst));
-         if (extension_word)
+         if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
            {
-             dst |= extended_dst << 16;
-             if (dst & 0x80000)
-               dst |= -1U << 20;
+             cmd_len += 2;
              if (dst > 9 || dst < 0)
-               sprintf (comm2, "0x%05x", dst & 0xfffff);
+               sprintf (comm2, "0x%04x", PS (dst));
+             if (extension_word)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1U << 20;
+                 if (dst > 9 || dst < 0)
+                   sprintf (comm2, "0x%05x", dst & 0xfffff);
+               }
+             sprintf (op2, "%d(r%d)", dst, regd);
            }
-         sprintf (op2, "%d(r%d)", dst, regd);
        }
     }
 
@@ -683,7 +779,8 @@ msp430_branchinstr (disassemble_info *info,
   int regs = 0, regd = 0;
   int as = 0;
   int cmd_len = 2;
-  short dst = 0;
+  int dst = 0;
+  unsigned short udst = 0;
 
   regd = insn & 0x0f;
   regs = (insn & 0x0f00) >> 8;
@@ -719,9 +816,11 @@ msp430_branchinstr (disassemble_info *info,
        {
          /* Absolute. @pc+  */
          *cycles = 3;
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         sprintf (op1, "#0x%04x", PS (dst));
+         if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
+           {
+             cmd_len += 2;
+             sprintf (op1, "#0x%04x", PS (udst));
+           }
        }
       else
        * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
@@ -733,19 +832,23 @@ msp430_branchinstr (disassemble_info *info,
       if (regs == 0)
        {
          /* PC relative.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         (*cycles)++;
-         sprintf (op1, "0x%04x", PS (dst));
-         sprintf (comm1, "PC rel. 0x%04x",
-                  PS ((short) addr + 2 + dst));
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
+           {
+             cmd_len += 2;
+             (*cycles)++;
+             sprintf (op1, "0x%04x", PS (dst));
+             sprintf (comm1, "PC rel. 0x%04x",
+                      PS ((short) addr + 2 + dst));
+           }
        }
       else if (regs == 2)
        {
          /* Absolute.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         sprintf (op1, "&0x%04x", PS (dst));
+         if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
+           {
+             cmd_len += 2;
+             sprintf (op1, "&0x%04x", PS (udst));
+           }
        }
       else if (regs == 3)
        {
@@ -756,11 +859,11 @@ msp430_branchinstr (disassemble_info *info,
       else
        {
          /* Indexed.  */
-         dst = msp430dis_opcode (addr + 2, info);
-         cmd_len += 2;
-         if (dst & 0x8000)
-           dst |= -1U << 16;
-         sprintf (op1, "%d(r%d)", dst, regs);
+         if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
+           {
+             cmd_len += 2;
+             sprintf (op1, "%d(r%d)", dst, regs);
+           }
        }
     }
 
@@ -780,7 +883,7 @@ msp430x_calla_instr (disassemble_info * info,
   int            am = (insn & 0xf0) >> 4;
   int            cmd_len = 2;
   unsigned short udst = 0;
-  short          dst = 0;
+  int            dst = 0;
 
   switch (am)
     {
@@ -791,13 +894,15 @@ msp430x_calla_instr (disassemble_info * info,
 
     case 5: /* CALLA x(Rdst) */
       *cycles = 3;
-      dst = msp430dis_opcode (addr + 2, info);
-      cmd_len += 2;
-      sprintf (op1, "%d(r%d)", dst, reg);
-      if (reg == 0)
-       sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
-      else
-       sprintf (comm1, "0x%05x", dst);
+      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
+       {
+         cmd_len += 2;
+         sprintf (op1, "%d(r%d)", dst, reg);
+         if (reg == 0)
+           sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
+         else
+           sprintf (comm1, "0x%05x", dst);
+       }
       break;
 
     case 6: /* CALLA @Rdst */
@@ -811,32 +916,38 @@ msp430x_calla_instr (disassemble_info * info,
       break;
 
     case 8: /* CALLA &abs20 */
-      udst = msp430dis_opcode (addr + 2, info);
-      cmd_len += 2;
-      *cycles = 4;
-      sprintf (op1, "&%d", (ureg << 16) + udst);
-      sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+      if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
+       {
+         cmd_len += 2;
+         *cycles = 4;
+         sprintf (op1, "&%d", (ureg << 16) + udst);
+         sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+       }
       break;
 
     case 9: /* CALLA pcrel-sym */
-      dst = msp430dis_opcode (addr + 2, info);
-      cmd_len += 2;
-      *cycles = 4;
-      sprintf (op1, "%d(PC)", (reg << 16) + dst);
-      sprintf (comm1, "PC rel. 0x%05lx",
-              (long) (addr + 2 + dst + (reg << 16)));
+      if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
+       {
+         cmd_len += 2;
+         *cycles = 4;
+         sprintf (op1, "%d(PC)", (reg << 16) + dst);
+         sprintf (comm1, "PC rel. 0x%05lx",
+                  (long) (addr + 2 + dst + (reg << 16)));
+       }
       break;
 
     case 11: /* CALLA #imm20 */
-      udst = msp430dis_opcode (addr + 2, info);
-      cmd_len += 2;
-      *cycles = 4;
-      sprintf (op1, "#%d", (ureg << 16) + udst);
-      sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+      if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
+       {
+         cmd_len += 2;
+         *cycles = 4;
+         sprintf (op1, "#%d", (ureg << 16) + udst);
+         sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+       }
       break;
 
     default:
-      strcpy (comm1, _("unrecognised CALLA addressing mode"));
+      strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
       return -1;
     }
 
@@ -855,9 +966,9 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
   int cycles = 0;
   char *bc = "";
   unsigned short extension_word = 0;
+  unsigned short bits;
 
-  insn = msp430dis_opcode (addr, info);
-  if (insn == (unsigned short) -1)
+  if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
     {
       prin (stream, ".word     0xffff; ????");
       return 2;
@@ -877,8 +988,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
     {
       extension_word = insn;
       addr += 2;
-      insn = msp430dis_opcode (addr, info);
-      if (insn == (unsigned short) -1)
+      if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
        {
          prin (stream, ".word  0x%04x, 0xffff; ????",
                extension_word);
@@ -963,10 +1073,13 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
              else
                {
                  n <<= 16;
-                 n |= msp430dis_opcode (addr + 2, info);
-                 sprintf (op1, "#%d", n);
-                 if (n > 9 || n < 0)
-                   sprintf (comm1, "0x%05x", n);
+                 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
+                   {
+                     n |= bits;
+                     sprintf (op1, "#%d", n);
+                     if (n > 9 || n < 0)
+                       sprintf (comm1, "0x%05x", n);
+                   }
                  cmd_len = 4;
                }
              sprintf (op2, "r%d", reg);
@@ -998,12 +1111,15 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
                case 2: /* MOVA &abs20, Rdst */
                  cmd_len = 4;
                  n <<= 16;
-                 n |= msp430dis_opcode (addr + 2, info);
-                 sprintf (op1, "&%d", n);
-                 if (n > 9 || n < 0)
-                   sprintf (comm1, "0x%05x", n);
-                 if (strcmp (opcode->name, "bra") != 0)
-                   sprintf (op2, "r%d", reg);
+                 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
+                   {
+                     n |= bits;
+                     sprintf (op1, "&%d", n);
+                     if (n > 9 || n < 0)
+                       sprintf (comm1, "0x%05x", n);
+                     if (strcmp (opcode->name, "bra") != 0)
+                       sprintf (op2, "r%d", reg);
+                   }
                  break;
 
                case 3: /* MOVA x(Rsrc), Rdst */
@@ -1011,58 +1127,64 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
                  if (strcmp (opcode->name, "bra") != 0)
                    sprintf (op2, "r%d", reg);
                  reg = n;
-                 n = msp430dis_opcode (addr + 2, info);
-                 if (n & 0x8000)
-                   n |= -1U << 16;
-                 sprintf (op1, "%d(r%d)", n, reg);
-                 if (n > 9 || n < 0)
+                 if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
                    {
-                     if (reg == 0)
-                       sprintf (comm1, "PC rel. 0x%05lx",
-                                (long) (addr + 2 + n));
-                     else
-                       sprintf (comm1, "0x%05x", n);
+                     sprintf (op1, "%d(r%d)", n, reg);
+                     if (n > 9 || n < 0)
+                       {
+                         if (reg == 0)
+                           sprintf (comm1, "PC rel. 0x%05lx",
+                                    (long) (addr + 2 + n));
+                         else
+                           sprintf (comm1, "0x%05x", n);
+                       }
                    }
                  break;
 
                case 6: /* MOVA Rsrc, &abs20 */
                  cmd_len = 4;
                  reg <<= 16;
-                 reg |= msp430dis_opcode (addr + 2, info);
-                 sprintf (op1, "r%d", n);
-                 sprintf (op2, "&%d", reg);
-                 if (reg > 9 || reg < 0)
-                   sprintf (comm2, "0x%05x", reg);
+                 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
+                   {
+                     reg |= bits;
+                     sprintf (op1, "r%d", n);
+                     sprintf (op2, "&%d", reg);
+                     if (reg > 9 || reg < 0)
+                       sprintf (comm2, "0x%05x", reg);
+                   }
                  break;
 
                case 7: /* MOVA Rsrc, x(Rdst) */
                  cmd_len = 4;
                  sprintf (op1, "r%d", n);
-                 n = msp430dis_opcode (addr + 2, info);
-                 if (n & 0x8000)
-                   n |= -1U << 16;
-                 sprintf (op2, "%d(r%d)", n, reg);
-                 if (n > 9 || n < 0)
+                 if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
                    {
-                     if (reg == 0)
-                       sprintf (comm2, "PC rel. 0x%05lx",
-                                (long) (addr + 2 + n));
-                     else
-                       sprintf (comm2, "0x%05x", n);
+                     sprintf (op2, "%d(r%d)", n, reg);
+                     if (n > 9 || n < 0)
+                       {
+                         if (reg == 0)
+                           sprintf (comm2, "PC rel. 0x%05lx",
+                                    (long) (addr + 2 + n));
+                         else
+                           sprintf (comm2, "0x%05x", n);
+                       }
                    }
                  break;
 
                case 8: /* MOVA #imm20, Rdst */
                  cmd_len = 4;
                  n <<= 16;
-                 n |= msp430dis_opcode (addr + 2, info);
-                 if (n & 0x80000)
-                   n |= -1U << 20;
-                 sprintf (op1, "#%d", n);
-                 if (n > 9 || n < 0)
-                   sprintf (comm1, "0x%05x", n);
-                 if (strcmp (opcode->name, "bra") != 0)
-                   sprintf (op2, "r%d", reg);
+                 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
+                   {
+                     n |= bits;
+                     if (n & 0x80000)
+                       n |= -1U << 20;
+                     sprintf (op1, "#%d", n);
+                     if (n > 9 || n < 0)
+                       sprintf (comm1, "0x%05x", n);
+                     if (strcmp (opcode->name, "bra") != 0)
+                       sprintf (op2, "r%d", reg);
+                   }
                  break;
 
                case 12: /* MOVA Rsrc, Rdst */
@@ -1107,7 +1229,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
                  else
                    {
                      bc = ".?";
-                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                     sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
                    }
                }
 
@@ -1124,7 +1246,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
                  if (insn & BYTE_OPERATION)
                    {
                      bc = ".?";
-                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                     sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
                    }
                  else if (extension_word & BYTE_OPERATION)
                    bc = ".w";
@@ -1145,7 +1267,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
                  else
                    {
                      bc = ".?";
-                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                     sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
                    }
                }
              break;