X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Fmips-dis.c;h=849f9f2003020762aa92b5aebde4c87c44c894bd;hb=f48ff60ac89f36934e814ee3ffffa46914af0870;hp=673dbfe6971fcdf8476a5cb571e0210834fcd9fc;hpb=88b38f0c3c59ccfcf2dab95f780360f6e7714a4a;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 673dbfe697..849f9f2003 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -1,5 +1,6 @@ /* Print mips instructions for GDB, the GNU debugger, or for objdump. - Copyright 1989, 91-97, 1998 Free Software Foundation, Inc. + Copyright (c) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). This file is part of GDB, GAS, and the GNU binutils. @@ -18,15 +19,21 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #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 @@ -43,7 +50,7 @@ static int _print_insn_mips PARAMS ((bfd_vma, unsigned long int, /* FIXME: This should be shared with gdb somehow. */ -#define REGISTER_NAMES \ +#define STD_REGISTER_NAMES \ { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ @@ -57,13 +64,17 @@ static int _print_insn_mips PARAMS ((bfd_vma, unsigned long int, "epc", "prid"\ } -static CONST char * CONST reg_names[] = REGISTER_NAMES; +static CONST char * CONST std_reg_names[] = STD_REGISTER_NAMES; /* The mips16 register names. */ static const char * const mips16_reg_names[] = { "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3" }; + +/* Scalar register names. set_mips_isa_type() decides which register name + table to use. */ +static CONST char * CONST *reg_names = NULL; /* subroutine */ static void @@ -80,10 +91,6 @@ print_insn_arg (d, l, pc, info) case ',': case '(': case ')': - /* start-sanitize-vr5400 */ - case '[': - case ']': - /* end-sanitize-vr5400 */ (*info->fprintf_func) (info->stream, "%c", *d); break; @@ -130,7 +137,8 @@ print_insn_arg (d, l, pc, info) case 'a': (*info->print_address_func) - (((pc & 0xF0000000) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)), + ((((pc + 4) & ~ (bfd_vma) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)), info); break; @@ -149,6 +157,30 @@ print_insn_arg (d, l, pc, info) reg_names[(l >> OP_SH_RD) & OP_MASK_RD]); break; + case 'U': + { + /* First check for both rd and rt being equal. */ + int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + (*info->fprintf_func) (info->stream, "$%s", + reg_names[reg]); + else + { + /* If one is zero use the other. */ + if (reg == 0) + (*info->fprintf_func) (info->stream, "$%s", + reg_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + (*info->fprintf_func) (info->stream, "$%s", + reg_names[reg]); + else /* Bogus, result depends on processor. */ + (*info->fprintf_func) (info->stream, "$%s or $%s", + reg_names[reg], + reg_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + case 'z': (*info->fprintf_func) (info->stream, "$%s", reg_names[0]); break; @@ -163,6 +195,11 @@ print_insn_arg (d, l, pc, info) (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); @@ -170,7 +207,12 @@ print_insn_arg (d, l, pc, info) case 'B': (*info->fprintf_func) (info->stream, "0x%x", - (l >> OP_SH_SYSCALL) & OP_MASK_SYSCALL); + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); break; case 'S': @@ -220,25 +262,131 @@ print_insn_arg (d, l, pc, info) (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); break; - /* start-sanitize-vr5400 */ - case 'e': - (*info->fprintf_func) (info->stream, "%d", - (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); - break; - - case '%': - (*info->fprintf_func) (info->stream, "%d", - (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + case 'H': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_SEL) & OP_MASK_SEL); break; - /* end-sanitize-vr5400 */ default: + /* xgettext:c-format */ (*info->fprintf_func) (info->stream, - "# internal error, undefined modifier(%c)", *d); + _("# internal error, undefined modifier(%c)"), + *d); break; } } +#if SYMTAB_AVAILABLE + +/* Figure out the MIPS ISA and CPU based on the machine number. + FIXME: What does this have to do with SYMTAB_AVAILABLE? */ + +static void +set_mips_isa_type (mach, isa, cputype) + int mach; + int *isa; + int *cputype; +{ + int target_processor = CPU_UNKNOWN; + int mips_isa = ISA_UNKNOWN; + + /* Use standard MIPS register names by default. */ + reg_names = std_reg_names; + + switch (mach) + { + case bfd_mach_mips3000: + target_processor = CPU_R3000; + mips_isa = ISA_MIPS1; + break; + case bfd_mach_mips3900: + target_processor = CPU_R3900; + mips_isa = ISA_MIPS1; + break; + case bfd_mach_mips4000: + target_processor = CPU_R4000; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4010: + target_processor = CPU_R4010; + mips_isa = ISA_MIPS2; + break; + case bfd_mach_mips4100: + target_processor = CPU_VR4100; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4111: + target_processor = CPU_VR4100; /* FIXME: Shouldn't this be CPU_R4111 ??? */ + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4300: + target_processor = CPU_R4300; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4400: + target_processor = CPU_R4400; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4600: + target_processor = CPU_R4600; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips4650: + target_processor = CPU_R4650; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips5000: + target_processor = CPU_R5000; + mips_isa = ISA_MIPS4; + break; + case bfd_mach_mips6000: + target_processor = CPU_R6000; + mips_isa = ISA_MIPS2; + break; + case bfd_mach_mips8000: + target_processor = CPU_R8000; + mips_isa = ISA_MIPS4; + break; + case bfd_mach_mips10000: + target_processor = CPU_R10000; + mips_isa = ISA_MIPS4; + break; + case bfd_mach_mips16: + target_processor = CPU_MIPS16; + mips_isa = ISA_MIPS3; + break; + case bfd_mach_mips32: + target_processor = CPU_MIPS32; + mips_isa = ISA_MIPS32; + break; + case bfd_mach_mips32_4k: + target_processor = CPU_MIPS32_4K; + mips_isa = ISA_MIPS32; + break; + case bfd_mach_mips5: + target_processor = CPU_MIPS5; + mips_isa = ISA_MIPS5; + break; + case bfd_mach_mips64: + target_processor = CPU_MIPS64; + mips_isa = ISA_MIPS64; + break; + case bfd_mach_mips_sb1: + target_processor = CPU_SB1; + mips_isa = ISA_MIPS64; + break; + default: + target_processor = CPU_R3000; + mips_isa = ISA_MIPS3; + break; + } + + *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 @@ -277,94 +425,14 @@ _print_insn_mips (memaddr, word, info) init = 1; } - switch (info->mach) - { - /* start-sanitize-tx19 */ - case bfd_mach_mips1900: - target_processor = 1900; - mips_isa = 1; - break; - /* end-sanitize-tx19 */ - case bfd_mach_mips3000: - target_processor = 3000; - mips_isa = 1; - break; - case bfd_mach_mips3900: - target_processor = 3900; - mips_isa = 1; - break; - case bfd_mach_mips4000: - target_processor = 4000; - mips_isa = 3; - break; - case bfd_mach_mips4010: - target_processor = 4010; - mips_isa = 2; - break; - case bfd_mach_mips4100: - target_processor = 4100; - mips_isa = 3; - break; - case bfd_mach_mips4300: - target_processor = 4300; - mips_isa = 3; - break; - case bfd_mach_mips4400: - target_processor = 4400; - mips_isa = 3; - break; - case bfd_mach_mips4600: - target_processor = 4600; - mips_isa = 3; - break; - case bfd_mach_mips4650: - target_processor = 4650; - mips_isa = 3; - break; - /* start-sanitize-tx49 */ - case bfd_mach_mips4900: - target_processor = 4900; - mips_isa = 3; - break; - /* end-sanitize-tx49 */ - case bfd_mach_mips5000: - target_processor = 5000; - mips_isa = 4; - break; - /* start-sanitize-vr5400 */ - case bfd_mach_mips5400: - target_processor = 5400; - mips_isa = 3; - break; - /* end-sanitize-vr5400 */ - /* start-sanitize-r5900 */ - case bfd_mach_mips5900: - target_processor = 5900; - mips_isa = 3; - break; - /* end-sanitize-r5900 */ - case bfd_mach_mips6000: - target_processor = 6000; - mips_isa = 2; - break; - case bfd_mach_mips8000: - target_processor = 8000; - mips_isa = 4; - break; - case bfd_mach_mips10000: - target_processor = 10000; - mips_isa = 4; - break; - case bfd_mach_mips16: - target_processor = 16; - mips_isa = 3; - break; - default: - target_processor = 3000; - mips_isa = 3; - break; - - } +#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; @@ -377,40 +445,8 @@ _print_insn_mips (memaddr, word, info) if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match) { register const char *d; - int insn_isa; - - if ((op->membership & INSN_ISA) == INSN_ISA1) - insn_isa = 1; - else if ((op->membership & INSN_ISA) == INSN_ISA2) - insn_isa = 2; - else if ((op->membership & INSN_ISA) == INSN_ISA3) - insn_isa = 3; - else if ((op->membership & INSN_ISA) == INSN_ISA4) - insn_isa = 4; - else - insn_isa = 15; - - if (insn_isa > mips_isa - && (target_processor == 4650 - && op->membership & INSN_4650) == 0 - && (target_processor == 4010 - && op->membership & INSN_4010) == 0 - && (target_processor == 4100 - && op->membership & INSN_4100) == 0 - /* start-sanitize-vr5400 */ - && (target_processor == 5400 - && op->membership & INSN_5400) == 0 - /* end-sanitize-vr5400 */ - /* start-sanitize-r5900 */ - && (target_processor == 5900 - && op->membership & INSN_5900) == 0 - /* end-sanitize-r5900 */ - /* start-sanitize-tx49 */ - && (target_processor == 4900 - && op->membership & INSN_4900) == 0 - /* end-sanitize-tx49 */ - && (target_processor == 3900 - && op->membership & INSN_3900) == 0) + + if (! OPCODE_IS_MEMBER (op, mips_isa, target_processor, 0)) continue; (*info->fprintf_func) (info->stream, "%s", op->name); @@ -418,9 +454,9 @@ _print_insn_mips (memaddr, word, info) d = op->args; if (d != NULL && *d != '\0') { - (*info->fprintf_func) (info->stream, "\t"); + (*info->fprintf_func) (info->stream, "\t"); for (; *d != '\0'; d++) - print_insn_arg (d, word, memaddr, info); + print_insn_arg (d, word, memaddr, info); } return 4; @@ -433,6 +469,13 @@ _print_insn_mips (memaddr, word, info) 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; @@ -441,12 +484,21 @@ print_insn_big_mips (memaddr, info) 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->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) @@ -467,27 +519,20 @@ print_insn_little_mips (memaddr, info) bfd_byte buffer[4]; int status; - /* start-sanitize-sky */ -#ifdef ARCH_dvp - { - /* 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->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) @@ -512,7 +557,7 @@ print_insn_mips16 (memaddr, info) int length; int insn; boolean use_extend; - int extend; + int extend = 0; const struct mips_opcode *op, *opend; info->bytes_per_chunk = 2; @@ -917,7 +962,7 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) 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; } @@ -993,9 +1038,9 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) if (! use_extend) extend = 0; l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); - (*info->print_address_func) ((memaddr & 0xf0000000) | l, info); + (*info->print_address_func) (((memaddr + 4) & 0xf0000000) | l, info); info->insn_type = dis_jsr; - info->target = (memaddr & 0xf0000000) | l; + info->target = ((memaddr + 4) & 0xf0000000) | l; info->branch_delay_insns = 1; break;