/* Print mips instructions for GDB, the GNU debugger, or for objdump.
- Copyright 1989, 91-97, 1998 Free Software Foundation, Inc.
+ Copyright (c) 1989, 91-97, 1998 Free Software Foundation, Inc.
Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
This file is part of GDB, GAS, and the GNU binutils.
#include "sysdep.h"
#include "dis-asm.h"
#include "opcode/mips.h"
+#include "opintl.h"
-/* FIXME: These are needed to figure out if this is a mips16 symbol or
- not. It would be better to think of a cleaner way to do this. */
+/* FIXME: These are needed to figure out if the code is mips16 or
+ not. The low bit of the address is often a good indicator. No
+ symbol table is available when this code runs out in an embedded
+ system as when it is used for disassembler support in a monitor. */
+
+#if !defined(EMBEDDED_ENV)
+#define SYMTAB_AVAILABLE 1
#include "elf-bfd.h"
#include "elf/mips.h"
+#endif
static int print_insn_mips16 PARAMS ((bfd_vma, struct disassemble_info *));
static void print_mips16_insn_arg
case ',':
case '(':
case ')':
- /* start-sanitize-vr5400 */
+ /* start-sanitize-cygnus */
case '[':
case ']':
- /* end-sanitize-vr5400 */
+ /* end-sanitize-cygnus */
+ /* start-sanitize-r5900 */
+ case '+':
+ case '-':
+ /* end-sanitize-r5900 */
(*info->fprintf_func) (info->stream, "%c", *d);
break;
(l >> OP_SH_CODE) & OP_MASK_CODE);
break;
+
+ case 'q':
+ (*info->fprintf_func) (info->stream, "0x%x",
+ (l >> OP_SH_CODE2) & OP_MASK_CODE2);
+ break;
+
case 'C':
(*info->fprintf_func) (info->stream, "0x%x",
(l >> OP_SH_COPZ) & OP_MASK_COPZ);
(l >> OP_SH_FS) & OP_MASK_FS);
break;
+ /* start-sanitize-r5900 */
+ case '0':
+ (*info->fprintf_func) (info->stream, "0x%x",
+ (l >> 6) & 0x1f);
+ break;
+
+ case '9':
+ (*info->fprintf_func) (info->stream, "vi27");
+ break;
+
+ case '1':
+ (*info->fprintf_func) (info->stream, "vf%d",
+ (l >> OP_SH_FT) & OP_MASK_FT);
+ break;
+ case '2':
+ (*info->fprintf_func) (info->stream, "vf%d",
+ (l >> OP_SH_FS) & OP_MASK_FS);
+ break;
+ case '3':
+ (*info->fprintf_func) (info->stream, "vf%d",
+ (l >> OP_SH_FD) & OP_MASK_FD);
+ break;
+
+ case '4':
+ (*info->fprintf_func) (info->stream, "vi%d",
+ (l >> OP_SH_FT) & OP_MASK_FT);
+ break;
+ case '5':
+ (*info->fprintf_func) (info->stream, "vi%d",
+ (l >> OP_SH_FS) & OP_MASK_FS);
+ break;
+ case '6':
+ (*info->fprintf_func) (info->stream, "vi%d",
+ (l >> OP_SH_FD) & OP_MASK_FD);
+ break;
+
+ case '7':
+ (*info->fprintf_func) (info->stream, "vf%d",
+ (l >> OP_SH_FT) & OP_MASK_FT);
+ switch ((l >> 23) & 0x3)
+ {
+ case 0:
+ (*info->fprintf_func) (info->stream, "x");
+ break;
+ case 1:
+ (*info->fprintf_func) (info->stream, "y");
+ break;
+ case 2:
+ (*info->fprintf_func) (info->stream, "z");
+ break;
+ case 3:
+ (*info->fprintf_func) (info->stream, "w");
+ break;
+ }
+ break;
+ case 'K':
+ break;
+
+ case ';':
+ (*info->fprintf_func) (info->stream, ".xyz\t");
+ break;
+
+ case '&':
+ (*info->fprintf_func) (info->stream, ".");
+ if (l & (1 << 21))
+ (*info->fprintf_func) (info->stream, "w");
+ if (l & (1 << 24))
+ (*info->fprintf_func) (info->stream, "x");
+ if (l & (1 << 23))
+ (*info->fprintf_func) (info->stream, "y");
+ if (l & (1 << 22))
+ (*info->fprintf_func) (info->stream, "z");
+ (*info->fprintf_func) (info->stream, "\t");
+ break;
+
+ case '8':
+ (*info->fprintf_func) (info->stream, "vf%d",
+ (l >> OP_SH_FS) & OP_MASK_FS);
+ switch ((l >> 21) & 0x3)
+ {
+ case 0:
+ (*info->fprintf_func) (info->stream, "x");
+ break;
+ case 1:
+ (*info->fprintf_func) (info->stream, "y");
+ break;
+ case 2:
+ (*info->fprintf_func) (info->stream, "z");
+ break;
+ case 3:
+ (*info->fprintf_func) (info->stream, "w");
+ break;
+ }
+ break;
+ case 'J':
+ (*info->fprintf_func) (info->stream, "I");
+ break;
+
+ case 'Q':
+ (*info->fprintf_func) (info->stream, "Q");
+ break;
+
+ case 'X':
+ (*info->fprintf_func) (info->stream, "R");
+ break;
+
+ case 'U':
+ (*info->fprintf_func) (info->stream, "ACC");
+ break;
+
+ case 'O':
+ delta = (l >> 6) & 0x7fff;
+ delta <<= 3;
+ (*info->print_address_func) (delta, info);
+ break;
+
+ /* end-sanitize-r5900 */
+
case 'T':
case 'W':
(*info->fprintf_func) (info->stream, "$f%d",
(l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
break;
- /* start-sanitize-vr5400 */
+ /* start-sanitize-cygnus */
case 'e':
(*info->fprintf_func) (info->stream, "%d",
(l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
(*info->fprintf_func) (info->stream, "%d",
(l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
break;
- /* end-sanitize-vr5400 */
+ /* end-sanitize-cygnus */
default:
+ /* xgettext:c-format */
(*info->fprintf_func) (info->stream,
- "# internal error, undefined modifier(%c)", *d);
+ _("# internal error, undefined modifier(%c)"),
+ *d);
break;
}
}
\f
-/* Print the mips instruction at address MEMADDR in debugged memory,
- on using INFO. Returns length of the instruction, in bytes, which is
- always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
- this is little-endian code. */
+#if SYMTAB_AVAILABLE
-static int
-_print_insn_mips (memaddr, word, info)
- bfd_vma memaddr;
- unsigned long int word;
- struct disassemble_info *info;
-{
- register const struct mips_opcode *op;
- int target_processor, mips_isa;
- static boolean init = 0;
- static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
-
- /* Build a hash table to shorten the search time. */
- if (! init)
- {
- unsigned int i;
-
- for (i = 0; i <= OP_MASK_OP; i++)
- {
- for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
- {
- if (op->pinfo == INSN_MACRO)
- continue;
- if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
- {
- mips_hash[i] = op;
- break;
- }
- }
- }
+/* Figure out the MIPS ISA and CPU based on the machine number.
+ FIXME: What does this have to do with SYMTAB_AVAILABLE? */
- init = 1;
- }
+static void
+set_mips_isa_type (mach, isa, cputype)
+ int mach;
+ int *isa;
+ int *cputype;
+{
+ int target_processor = 0;
+ int mips_isa = 0;
- switch (info->mach)
+ switch (mach)
{
/* start-sanitize-tx19 */
case bfd_mach_mips1900:
target_processor = 4100;
mips_isa = 3;
break;
+ /* start-sanitize-vr4xxx */
+ case bfd_mach_mips4121:
+ target_processor = 4121;
+ mips_isa = 3;
+ break;
+ /* end-sanitize-vr4xxx */
case bfd_mach_mips4300:
target_processor = 4300;
mips_isa = 3;
break;
+ /* start-sanitize-vr4320 */
+ case bfd_mach_mips4320:
+ target_processor = 4320;
+ mips_isa = 3;
+ break;
+ /* end-sanitize-vr4320 */
case bfd_mach_mips4400:
target_processor = 4400;
mips_isa = 3;
target_processor = 5000;
mips_isa = 4;
break;
- /* start-sanitize-vr5400 */
+ /* start-sanitize-cygnus */
case bfd_mach_mips5400:
target_processor = 5400;
mips_isa = 3;
break;
- /* end-sanitize-vr5400 */
+ /* end-sanitize-cygnus */
/* start-sanitize-r5900 */
case bfd_mach_mips5900:
target_processor = 5900;
}
+ *isa = mips_isa;
+ *cputype = target_processor;
+}
+
+#endif /* SYMTAB_AVAILABLE */
+
+/* Print the mips instruction at address MEMADDR in debugged memory,
+ on using INFO. Returns length of the instruction, in bytes, which is
+ always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
+ this is little-endian code. */
+
+static int
+_print_insn_mips (memaddr, word, info)
+ bfd_vma memaddr;
+ unsigned long int word;
+ struct disassemble_info *info;
+{
+ register const struct mips_opcode *op;
+ int target_processor, mips_isa;
+ static boolean init = 0;
+ static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
+
+ /* Build a hash table to shorten the search time. */
+ if (! init)
+ {
+ unsigned int i;
+
+ for (i = 0; i <= OP_MASK_OP; i++)
+ {
+ for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
+ {
+ if (op->pinfo == INSN_MACRO)
+ continue;
+ if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
+ {
+ mips_hash[i] = op;
+ break;
+ }
+ }
+ }
+
+ init = 1;
+ }
+
+#if ! SYMTAB_AVAILABLE
+ /* This is running out on a target machine, not in a host tool.
+ FIXME: Where does mips_target_info come from? */
+ target_processor = mips_target_info.processor;
+ mips_isa = mips_target_info.isa;
+#else
+ set_mips_isa_type (info->mach, &mips_isa, &target_processor);
+#endif
+
info->bytes_per_chunk = 4;
info->display_endian = info->endian;
&& op->membership & INSN_4010) == 0
&& (target_processor == 4100
&& op->membership & INSN_4100) == 0
- /* start-sanitize-vr5400 */
+ /* start-sanitize-vr4xxx */
+ && (target_processor == 4121
+ && op->membership & INSN_4121) == 0
+ /* end-sanitize-vr4xxx */
+ /* start-sanitize-vr4320 */
+ && (target_processor == 4320
+ && op->membership & INSN_4320) == 0
+ /* end-sanitize-vr4320 */
+ /* start-sanitize-cygnus */
&& (target_processor == 5400
&& op->membership & INSN_5400) == 0
- /* end-sanitize-vr5400 */
+ /* end-sanitize-cygnus */
/* start-sanitize-r5900 */
&& (target_processor == 5900
&& op->membership & INSN_5900) == 0
d = op->args;
if (d != NULL && *d != '\0')
{
- (*info->fprintf_func) (info->stream, "\t");
+ /* start-sanitize-r5900 */
+ /* If this is an opcode completer, then do not emit
+ a tab after the opcode. */
+ if (*d != '&' && *d != ';')
+ /* end-sanitize-r5900 */
+ (*info->fprintf_func) (info->stream, "\t");
for (; *d != '\0'; d++)
- print_insn_arg (d, word, memaddr, info);
+ /* start-sanitize-r5900 */
+ /* If this is an escape character, go ahead and print the
+ next character in the arg string verbatim. */
+ if (*d == '#')
+ {
+ d++;
+ (*info->fprintf_func) (info->stream, "%c", *d);
+ }
+ else
+ /* end-sanitize-r5900 */
+ print_insn_arg (d, word, memaddr, info);
}
return 4;
return 4;
}
+
+/* In an environment where we do not know the symbol type of the
+ instruction we are forced to assume that the low order bit of the
+ instructions' address may mark it as a mips16 instruction. If we
+ are single stepping, or the pc is within the disassembled function,
+ this works. Otherwise, we need a clue. Sometimes. */
+
int
print_insn_big_mips (memaddr, info)
bfd_vma memaddr;
bfd_byte buffer[4];
int status;
+#if 1
+ /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */
+ /* Only a few tools will work this way. */
+ if (memaddr & 0x01)
+ return print_insn_mips16 (memaddr, info);
+#endif
+
+#if SYMTAB_AVAILABLE
if (info->mach == 16
|| (info->flavour == bfd_target_elf_flavour
- && info->symbol != NULL
- && (((elf_symbol_type *) info->symbol)->internal_elf_sym.st_other
+ && info->symbols != NULL
+ && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
== STO_MIPS16)))
return print_insn_mips16 (memaddr, info);
+#endif
status = (*info->read_memory_func) (memaddr, buffer, 4, info);
if (status == 0)
/* start-sanitize-sky */
#ifdef ARCH_dvp
- if (bfd_mach_dvp_p (info->mach)
- || (info->flavour == bfd_target_elf_flavour
- && info->symbol != NULL
- && STO_DVP_P (((elf_symbol_type *) info->symbol)->internal_elf_sym.st_other)))
- return print_insn_dvp (memaddr, info);
+ {
+ /* bfd_mach_dvp_p is a macro which may evaluate its arguments more than
+ once. Since dvp_mach_type is a function, ensure it's only called
+ once. */
+ int mach = dvp_info_mach_type (info);
+
+ if (bfd_mach_dvp_p (info->mach)
+ || bfd_mach_dvp_p (mach))
+ return print_insn_dvp (memaddr, info);
+ }
#endif
/* end-sanitize-sky */
+#if 1
+ if (memaddr & 0x01)
+ return print_insn_mips16 (memaddr, info);
+#endif
+
+#if SYMTAB_AVAILABLE
if (info->mach == 16
|| (info->flavour == bfd_target_elf_flavour
- && info->symbol != NULL
- && (((elf_symbol_type *) info->symbol)->internal_elf_sym.st_other
+ && info->symbols != NULL
+ && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
== STO_MIPS16)))
return print_insn_mips16 (memaddr, info);
+#endif
status = (*info->read_memory_func) (memaddr, buffer, 4, info);
if (status == 0)
int length;
int insn;
boolean use_extend;
- int extend;
+ int extend = 0;
const struct mips_opcode *op, *opend;
info->bytes_per_chunk = 2;
if (signedp && immed >= (1 << (nbits - 1)))
immed -= 1 << nbits;
immed <<= shift;
- if ((type == '<' || type == '>' || type == '[' || type == '[')
+ if ((type == '<' || type == '>' || type == '[' || type == ']')
&& immed == 0)
immed = 8;
}