Improve the MSP430 disassembler's handling of memory read errors.

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.
This commit is contained in:
Nick Clifton 2016-05-27 13:49:58 +01:00
parent 51415b9f30
commit 77d66e7b30
2 changed files with 408 additions and 272 deletions

View 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.

View 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"
@ -36,19 +37,80 @@
#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,7 +255,8 @@ msp430_singleoperand (disassemble_info *info,
if (regd == 0)
{
/* PC relative. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
*cycles = 4;
sprintf (op, "0x%04x", dst);
@ -207,10 +270,12 @@ msp430_singleoperand (disassemble_info *info,
(long)((addr + 2 + dst) & 0xfffff));
}
}
}
else if (regd == 2)
{
/* Absolute. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
*cycles = 4;
sprintf (op, "&0x%04x", PS (dst));
@ -220,9 +285,11 @@ msp430_singleoperand (disassemble_info *info,
sprintf (op, "&0x%05x", dst & 0xfffff);
}
}
}
else
{
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
*cycles = 4;
if (extended_dst)
@ -231,11 +298,10 @@ msp430_singleoperand (disassemble_info *info,
if (dst & 0x80000)
dst |= -1U << 20;
}
else if (dst & 0x8000)
dst |= -1U << 16;
sprintf (op, "%d(r%d)", dst, regd);
}
}
}
break;
case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
@ -264,7 +330,8 @@ msp430_singleoperand (disassemble_info *info,
{
*cycles = 3;
/* absolute. @pc+ */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
sprintf (op, "#%d", dst);
if (dst > 9 || dst < 0)
@ -279,6 +346,7 @@ msp430_singleoperand (disassemble_info *info,
sprintf (comm, "#0x%05x", dst);
}
}
}
else
* cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
}
@ -288,7 +356,8 @@ msp430_singleoperand (disassemble_info *info,
if (regd == 0)
{
/* PC relative. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
sprintf (op, "0x%04x", PS (dst));
sprintf (comm, "PC rel. 0x%04x",
@ -301,10 +370,12 @@ msp430_singleoperand (disassemble_info *info,
(long)((addr + 2 + dst) & 0xfffff));
}
}
}
else if (regd == 2)
{
/* Absolute. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
sprintf (op, "&0x%04x", PS (dst));
if (extended_dst)
@ -313,6 +384,7 @@ msp430_singleoperand (disassemble_info *info,
sprintf (op, "&0x%05x", dst & 0xfffff);
}
}
}
else if (regd == 3)
{
*cycles = 1;
@ -322,7 +394,8 @@ msp430_singleoperand (disassemble_info *info,
else
{
/* Indexed. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
{
cmd_len += 2;
if (extended_dst)
{
@ -330,13 +403,12 @@ msp430_singleoperand (disassemble_info *info,
if (dst & 0x80000)
dst |= -1U << 20;
}
else if (dst & 0x8000)
dst |= -1U << 16;
sprintf (op, "%d(r%d)", dst, regd);
if (dst > 9 || dst < 0)
sprintf (comm, "%05x", dst);
}
}
}
break;
case 3: /* Jumps. */
@ -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,7 +494,8 @@ msp430_doubleoperand (disassemble_info *info,
if (regd == 0)
{
/* PC relative, Symbolic. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
cmd_len += 4;
*cycles = 6;
sprintf (op1, "0x%04x", PS (dst));
@ -437,14 +511,21 @@ msp430_doubleoperand (disassemble_info *info,
(long)((addr + 2 + dst) & 0xfffff));
}
}
}
else if (regd == 2)
{
/* Absolute. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
int src;
/* 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))
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));
@ -454,18 +535,18 @@ msp430_doubleoperand (disassemble_info *info,
sprintf (op1, "&0x%05x", dst & 0xfffff);
}
}
}
else
{
/* Indexed. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
if (extension_word)
{
dst |= extended_dst << 16;
if (dst & 0x80000)
dst |= -1U << 20;
}
else if (dst & 0x8000)
dst |= -1U << 16;
cmd_len += 4;
*cycles = 6;
sprintf (op1, "%d(r%d)", dst, regd);
@ -473,6 +554,7 @@ msp430_doubleoperand (disassemble_info *info,
sprintf (comm1, "#0x%05x", dst);
}
}
}
*op2 = 0;
*comm2 = 0;
@ -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,13 +596,15 @@ msp430_doubleoperand (disassemble_info *info,
{
*cycles = 3;
/* Absolute. @pc+. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
cmd_len += 2;
sprintf (op1, "#%d", dst);
if (dst > 9 || dst < 0)
sprintf (comm1, "#0x%04x", PS (dst));
if (extension_word)
{
dst &= 0xffff;
dst |= extended_src << 16;
if (dst & 0x80000)
dst |= -1U << 20;
@ -529,6 +613,7 @@ msp430_doubleoperand (disassemble_info *info,
sprintf (comm1, "0x%05x", dst & 0xfffff);
}
}
}
else
* cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
}
@ -538,13 +623,15 @@ msp430_doubleoperand (disassemble_info *info,
{
*cycles = 4;
/* PC relative. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
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;
@ -553,21 +640,25 @@ msp430_doubleoperand (disassemble_info *info,
(long) ((addr + 2 + dst) & 0xfffff));
}
}
}
else if (regs == 2)
{
*cycles = 2;
/* Absolute. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
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)
{
*cycles = 1;
@ -578,21 +669,22 @@ msp430_doubleoperand (disassemble_info *info,
{
*cycles = 3;
/* Indexed. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
cmd_len += 2;
if (extension_word)
{
dst &= 0xffff;
dst |= extended_src << 16;
if (dst & 0x80000)
dst |= -1U << 20;
}
else if (dst & 0x8000)
dst |= -1U << 16;
sprintf (op1, "%d(r%d)", dst, regs);
if (dst > 9 || dst < -9)
sprintf (comm1, "0x%05x", dst);
}
}
}
/* Destination. Special care needed on addr + XXXX. */
@ -621,7 +713,8 @@ msp430_doubleoperand (disassemble_info *info,
{
/* PC relative. */
*cycles += 1;
dst = msp430dis_opcode (addr + cmd_len, info);
if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
{
sprintf (op2, "0x%04x", PS (dst));
sprintf (comm2, "PC rel. 0x%04x",
PS ((short) addr + cmd_len + dst));
@ -634,12 +727,14 @@ msp430_doubleoperand (disassemble_info *info,
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);
if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
{
cmd_len += 2;
sprintf (op2, "&0x%04x", PS (dst));
if (extension_word)
@ -648,12 +743,12 @@ msp430_doubleoperand (disassemble_info *info,
sprintf (op2, "&0x%05x", dst & 0xfffff);
}
}
}
else
{
dst = msp430dis_opcode (addr + cmd_len, info);
if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
{
cmd_len += 2;
if (dst & 0x8000)
dst |= -1U << 16;
if (dst > 9 || dst < 0)
sprintf (comm2, "0x%04x", PS (dst));
if (extension_word)
@ -667,6 +762,7 @@ msp430_doubleoperand (disassemble_info *info,
sprintf (op2, "%d(r%d)", dst, regd);
}
}
}
return cmd_len;
}
@ -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);
if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
{
cmd_len += 2;
sprintf (op1, "#0x%04x", PS (dst));
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);
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);
if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
{
cmd_len += 2;
sprintf (op1, "&0x%04x", PS (dst));
sprintf (op1, "&0x%04x", PS (udst));
}
}
else if (regs == 3)
{
@ -756,13 +859,13 @@ msp430_branchinstr (disassemble_info *info,
else
{
/* Indexed. */
dst = msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
{
cmd_len += 2;
if (dst & 0x8000)
dst |= -1U << 16;
sprintf (op1, "%d(r%d)", dst, regs);
}
}
}
return cmd_len;
}
@ -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);
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);
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);
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);
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);
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);
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,9 +1127,8 @@ 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;
if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
{
sprintf (op1, "%d(r%d)", n, reg);
if (n > 9 || n < 0)
{
@ -1023,24 +1138,27 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
else
sprintf (comm1, "0x%05x", n);
}
}
break;
case 6: /* MOVA Rsrc, &abs20 */
cmd_len = 4;
reg <<= 16;
reg |= msp430dis_opcode (addr + 2, info);
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;
if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
{
sprintf (op2, "%d(r%d)", n, reg);
if (n > 9 || n < 0)
{
@ -1050,12 +1168,15 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
else
sprintf (comm2, "0x%05x", n);
}
}
break;
case 8: /* MOVA #imm20, Rdst */
cmd_len = 4;
n <<= 16;
n |= msp430dis_opcode (addr + 2, info);
if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
{
n |= bits;
if (n & 0x80000)
n |= -1U << 20;
sprintf (op1, "#%d", n);
@ -1063,6 +1184,7 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
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;