mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 11:04:18 +08:00
2480b6fa94
The arc fix in create_map avoiding signed overflow by casting an unsigned char to unsigned int before shifting, shows one of the dangers of blinding doing that. The problem in this case was that the variable storing the value, newAuxRegister->address, was a long. Using the unsigned cast meant that the 32-bit value was zero extended when long is 64 bits. Previously we had a sign extension. Net result was that comparisons in arcExtMap_auxRegName didn't match. Of course, I could have cast the 32-bit unsigned value back to signed before storing in a long, but it's neater to just use an unsigned int for the address. opcodes/ * alpha-opc.c (OP): Avoid signed overflow. * arm-dis.c (print_insn): Likewise. * mcore-dis.c (print_insn_mcore): Likewise. * pj-dis.c (get_int): Likewise. * ppc-opc.c (EBD15, EBD15BI): Likewise. * score7-dis.c (s7_print_insn): Likewise. * tic30-dis.c (print_insn_tic30): Likewise. * v850-opc.c (insert_SELID): Likewise. * vax-dis.c (print_insn_vax): Likewise. * arc-ext.c (create_map): Likewise. (struct ExtAuxRegister): Make "address" field unsigned int. (arcExtMap_auxRegName): Pass unsigned address. (dump_ARC_extmap): Adjust. * arc-ext.h (arcExtMap_auxRegName): Update prototype.
319 lines
7.6 KiB
C
319 lines
7.6 KiB
C
/* Disassemble Motorola M*Core instructions.
|
|
Copyright (C) 1993-2019 Free Software Foundation, Inc.
|
|
|
|
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 3, or (at your option)
|
|
any later version.
|
|
|
|
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
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "sysdep.h"
|
|
#include <stdio.h>
|
|
#include "libiberty.h"
|
|
#define STATIC_TABLE
|
|
#define DEFINE_TABLE
|
|
|
|
#include "mcore-opc.h"
|
|
#include "disassemble.h"
|
|
|
|
/* Mask for each mcore_opclass: */
|
|
static const unsigned short imsk[] = {
|
|
/* O0 */ 0xFFFF,
|
|
/* OT */ 0xFFFC,
|
|
/* O1 */ 0xFFF0,
|
|
/* OC */ 0xFE00,
|
|
/* O2 */ 0xFF00,
|
|
/* X1 */ 0xFFF0,
|
|
/* OI */ 0xFE00,
|
|
/* OB */ 0xFE00,
|
|
|
|
/* OMa */ 0xFFF0,
|
|
/* SI */ 0xFE00,
|
|
/* I7 */ 0xF800,
|
|
/* LS */ 0xF000,
|
|
/* BR */ 0xF800,
|
|
/* BL */ 0xFF00,
|
|
/* LR */ 0xF000,
|
|
/* LJ */ 0xFF00,
|
|
|
|
/* RM */ 0xFFF0,
|
|
/* RQ */ 0xFFF0,
|
|
/* JSR */ 0xFFF0,
|
|
/* JMP */ 0xFFF0,
|
|
/* OBRa*/ 0xFFF0,
|
|
/* OBRb*/ 0xFF80,
|
|
/* OBRc*/ 0xFF00,
|
|
/* OBR2*/ 0xFE00,
|
|
|
|
/* O1R1*/ 0xFFF0,
|
|
/* OMb */ 0xFF80,
|
|
/* OMc */ 0xFF00,
|
|
/* SIa */ 0xFE00,
|
|
|
|
/* MULSH */ 0xFF00,
|
|
/* OPSR */ 0xFFF8, /* psrset/psrclr */
|
|
|
|
/* JC */ 0, /* JC,JU,JL don't appear in object */
|
|
/* JU */ 0,
|
|
/* JL */ 0,
|
|
/* RSI */ 0,
|
|
/* DO21*/ 0,
|
|
/* OB2 */ 0 /* OB2 won't appear in object. */
|
|
};
|
|
|
|
static const char *grname[] = {
|
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
|
|
};
|
|
|
|
static const char X[] = "??";
|
|
|
|
static const char *crname[] = {
|
|
"psr", "vbr", "epsr", "fpsr", "epc", "fpc", "ss0", "ss1",
|
|
"ss2", "ss3", "ss4", "gcr", "gsr", X, X, X,
|
|
X, X, X, X, X, X, X, X,
|
|
X, X, X, X, X, X, X, X
|
|
};
|
|
|
|
static const unsigned isiz[] = { 2, 0, 1, 0 };
|
|
|
|
int
|
|
print_insn_mcore (bfd_vma memaddr,
|
|
struct disassemble_info *info)
|
|
{
|
|
unsigned char ibytes[4];
|
|
fprintf_ftype print_func = info->fprintf_func;
|
|
void *stream = info->stream;
|
|
unsigned short inst;
|
|
unsigned int i;
|
|
int status;
|
|
|
|
info->bytes_per_chunk = 2;
|
|
|
|
status = info->read_memory_func (memaddr, ibytes, 2, info);
|
|
|
|
if (status != 0)
|
|
{
|
|
info->memory_error_func (status, memaddr, info);
|
|
return -1;
|
|
}
|
|
|
|
if (info->endian == BFD_ENDIAN_BIG)
|
|
inst = (ibytes[0] << 8) | ibytes[1];
|
|
else if (info->endian == BFD_ENDIAN_LITTLE)
|
|
inst = (ibytes[1] << 8) | ibytes[0];
|
|
else
|
|
abort ();
|
|
|
|
/* Just a linear search of the table. */
|
|
for (i = 0; i < ARRAY_SIZE (mcore_table); i++)
|
|
if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass]))
|
|
break;
|
|
|
|
if (i == ARRAY_SIZE (mcore_table))
|
|
(*print_func) (stream, ".short 0x%04x", inst);
|
|
else
|
|
{
|
|
const char *name = grname[inst & 0x0F];
|
|
|
|
(*print_func) (stream, "%s", mcore_table[i].name);
|
|
|
|
switch (mcore_table[i].opclass)
|
|
{
|
|
case O0:
|
|
break;
|
|
|
|
case OT:
|
|
(*print_func) (stream, "\t%d", inst & 0x3);
|
|
break;
|
|
|
|
case O1:
|
|
case JMP:
|
|
case JSR:
|
|
(*print_func) (stream, "\t%s", name);
|
|
break;
|
|
|
|
case OC:
|
|
(*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]);
|
|
break;
|
|
|
|
case O1R1:
|
|
(*print_func) (stream, "\t%s, r1", name);
|
|
break;
|
|
|
|
case MULSH:
|
|
case O2:
|
|
(*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]);
|
|
break;
|
|
|
|
case X1:
|
|
(*print_func) (stream, "\tr1, %s", name);
|
|
break;
|
|
|
|
case OI:
|
|
(*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1);
|
|
break;
|
|
|
|
case RM:
|
|
(*print_func) (stream, "\t%s-r15, (r0)", name);
|
|
break;
|
|
|
|
case RQ:
|
|
(*print_func) (stream, "\tr4-r7, (%s)", name);
|
|
break;
|
|
|
|
case OB:
|
|
case OBRa:
|
|
case OBRb:
|
|
case OBRc:
|
|
case SI:
|
|
case SIa:
|
|
case OMa:
|
|
case OMb:
|
|
case OMc:
|
|
(*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F);
|
|
break;
|
|
|
|
case I7:
|
|
(*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F);
|
|
break;
|
|
|
|
case LS:
|
|
(*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF],
|
|
name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]);
|
|
break;
|
|
|
|
case BR:
|
|
{
|
|
uint32_t val = ((inst & 0x3FF) ^ 0x400) - 0x400;
|
|
|
|
val = memaddr + 2 + (val << 1);
|
|
(*print_func) (stream, "\t0x%x", val);
|
|
|
|
if (strcmp (mcore_table[i].name, "bsr") == 0)
|
|
{
|
|
/* For bsr, we'll try to get a symbol for the target. */
|
|
if (info->print_address_func && val != 0)
|
|
{
|
|
(*print_func) (stream, "\t// ");
|
|
info->print_address_func (val, info);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BL:
|
|
{
|
|
uint32_t val = inst & 0x000F;
|
|
(*print_func) (stream, "\t%s, 0x%x",
|
|
grname[(inst >> 4) & 0xF],
|
|
(uint32_t) (memaddr - (val << 1)));
|
|
}
|
|
break;
|
|
|
|
case LR:
|
|
{
|
|
uint32_t val;
|
|
|
|
val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3;
|
|
|
|
/* We are not reading an instruction, so allow
|
|
reads to extend beyond the next symbol. */
|
|
info->stop_vma = 0;
|
|
status = info->read_memory_func (val, ibytes, 4, info);
|
|
if (status != 0)
|
|
{
|
|
info->memory_error_func (status, memaddr, info);
|
|
break;
|
|
}
|
|
|
|
if (info->endian == BFD_ENDIAN_LITTLE)
|
|
val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
|
|
| (ibytes[1] << 8) | (ibytes[0]));
|
|
else
|
|
val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
|
|
| (ibytes[2] << 8) | (ibytes[3]));
|
|
|
|
/* Removed [] around literal value to match ABI syntax 12/95. */
|
|
(*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val);
|
|
|
|
if (val == 0)
|
|
(*print_func) (stream, "\t// from address pool at 0x%x",
|
|
(uint32_t) (memaddr + 2
|
|
+ ((inst & 0xFF) << 2)) & ~3);
|
|
}
|
|
break;
|
|
|
|
case LJ:
|
|
{
|
|
uint32_t val;
|
|
|
|
val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3;
|
|
|
|
/* We are not reading an instruction, so allow
|
|
reads to extend beyond the next symbol. */
|
|
info->stop_vma = 0;
|
|
status = info->read_memory_func (val, ibytes, 4, info);
|
|
if (status != 0)
|
|
{
|
|
info->memory_error_func (status, memaddr, info);
|
|
break;
|
|
}
|
|
|
|
if (info->endian == BFD_ENDIAN_LITTLE)
|
|
val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
|
|
| (ibytes[1] << 8) | (ibytes[0]));
|
|
else
|
|
val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
|
|
| (ibytes[2] << 8) | (ibytes[3]));
|
|
|
|
/* Removed [] around literal value to match ABI syntax 12/95. */
|
|
(*print_func) (stream, "\t0x%X", val);
|
|
/* For jmpi/jsri, we'll try to get a symbol for the target. */
|
|
if (info->print_address_func && val != 0)
|
|
{
|
|
(*print_func) (stream, "\t// ");
|
|
info->print_address_func (val, info);
|
|
}
|
|
else
|
|
{
|
|
(*print_func) (stream, "\t// from address pool at 0x%x",
|
|
(uint32_t) (memaddr + 2
|
|
+ ((inst & 0xFF) << 2)) & ~3);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OPSR:
|
|
{
|
|
static char *fields[] = {
|
|
"af", "ie", "fe", "fe,ie",
|
|
"ee", "ee,ie", "ee,fe", "ee,fe,ie"
|
|
};
|
|
|
|
(*print_func) (stream, "\t%s", fields[inst & 0x7]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* If the disassembler lags the instruction set. */
|
|
(*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Say how many bytes we consumed. */
|
|
return 2;
|
|
}
|