X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Fmips-dis.c;h=984fcbb8026e4b1c2262581fce761670c148ffff;hb=0b65c07b97c43e8891c2e14061270878a85222c8;hp=3f874e72f5e3443b7b88eb3da79d321bdef359bc;hpb=1401d2fe675c5b0634a97e84e6b094eea527e63e;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 3f874e72f5..984fcbb802 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -1,5 +1,5 @@ /* Print mips instructions for GDB, the GNU debugger, or for objdump. - Copyright (C) 1989-2016 Free Software Foundation, Inc. + Copyright (C) 1989-2018 Free Software Foundation, Inc. Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). This file is part of the GNU opcodes library. @@ -20,7 +20,7 @@ MA 02110-1301, USA. */ #include "sysdep.h" -#include "dis-asm.h" +#include "disassemble.h" #include "libiberty.h" #include "opcode/mips.h" #include "opintl.h" @@ -607,6 +607,13 @@ const struct mips_arch_choice mips_arch_choices[] = mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + { "interaptiv-mr2", 1, bfd_mach_mips_interaptiv_mr2, CPU_INTERAPTIV_MR2, + ISA_MIPS32R3, + ASE_MT | ASE_EVA | ASE_DSP | ASE_DSPR2 | ASE_MIPS16E2 | ASE_MIPS16E2_MT, + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, ISA_MIPS64 | INSN_SB1, ASE_MIPS3D, mips_cp0_names_sb1, @@ -658,7 +665,8 @@ const struct mips_arch_choice mips_arch_choices[] = /* This entry, mips16, is here only for ISA/processor selection; do not print its name. */ - { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3, 0, + { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64, + ASE_MIPS16E2 | ASE_MIPS16E2_MT, mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric, mips_hwr_names_numeric }, }; @@ -764,6 +772,56 @@ is_micromips (Elf_Internal_Ehdr *header) return 0; } +/* Convert ASE flags from .MIPS.abiflags to internal values. */ + +static unsigned long +mips_convert_abiflags_ases (unsigned long afl_ases) +{ + unsigned long opcode_ases = 0; + + if (afl_ases & AFL_ASE_DSP) + opcode_ases |= ASE_DSP; + if (afl_ases & AFL_ASE_DSPR2) + opcode_ases |= ASE_DSPR2; + if (afl_ases & AFL_ASE_EVA) + opcode_ases |= ASE_EVA; + if (afl_ases & AFL_ASE_MCU) + opcode_ases |= ASE_MCU; + if (afl_ases & AFL_ASE_MDMX) + opcode_ases |= ASE_MDMX; + if (afl_ases & AFL_ASE_MIPS3D) + opcode_ases |= ASE_MIPS3D; + if (afl_ases & AFL_ASE_MT) + opcode_ases |= ASE_MT; + if (afl_ases & AFL_ASE_SMARTMIPS) + opcode_ases |= ASE_SMARTMIPS; + if (afl_ases & AFL_ASE_VIRT) + opcode_ases |= ASE_VIRT; + if (afl_ases & AFL_ASE_MSA) + opcode_ases |= ASE_MSA; + if (afl_ases & AFL_ASE_XPA) + opcode_ases |= ASE_XPA; + if (afl_ases & AFL_ASE_DSPR3) + opcode_ases |= ASE_DSPR3; + if (afl_ases & AFL_ASE_MIPS16E2) + opcode_ases |= ASE_MIPS16E2; + return opcode_ases; +} + +/* Calculate combination ASE flags from regular ASE flags. */ + +static unsigned long +mips_calculate_combination_ases (unsigned long opcode_ases) +{ + unsigned long combination_ases = 0; + + if ((opcode_ases & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT)) + combination_ases |= ASE_XPA_VIRT; + if ((opcode_ases & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT)) + combination_ases |= ASE_MIPS16E2_MT; + return combination_ases; +} + static void set_default_mips_dis_options (struct disassemble_info *info) { @@ -785,19 +843,6 @@ set_default_mips_dis_options (struct disassemble_info *info) mips_hwr_names = mips_hwr_names_numeric; no_aliases = 0; - /* Update settings according to the ELF file header flags. */ - if (info->flavour == bfd_target_elf_flavour && info->section != NULL) - { - Elf_Internal_Ehdr *header; - - header = elf_elfheader (info->section->owner); - /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ - if (is_newabi (header)) - mips_gpr_names = mips_gpr_names_newabi; - /* If a microMIPS binary, then don't use MIPS16 bindings. */ - micromips_ase = is_micromips (header); - } - /* Set ISA, architecture, and cp0 register names as best we can. */ #if ! SYMTAB_AVAILABLE /* This is running out on a target machine, not in a host tool. @@ -818,24 +863,43 @@ set_default_mips_dis_options (struct disassemble_info *info) mips_cp1_names = chosen_arch->cp1_names; mips_hwr_names = chosen_arch->hwr_names; } -#endif -} -static void -parse_mips_dis_option (const char *option, unsigned int len) -{ - unsigned int i, optionlen, vallen; - const char *val; - const struct mips_abi_choice *chosen_abi; - const struct mips_arch_choice *chosen_arch; - - /* Try to match options that are simple flags */ - if (CONST_STRNEQ (option, "no-aliases")) + /* Update settings according to the ELF file header flags. */ + if (info->flavour == bfd_target_elf_flavour && info->section != NULL) { - no_aliases = 1; - return; + struct bfd *abfd = info->section->owner; + Elf_Internal_Ehdr *header = elf_elfheader (abfd); + Elf_Internal_ABIFlags_v0 *abiflags = NULL; + + /* We won't ever get here if !HAVE_BFD_MIPS_ELF_GET_ABIFLAGS, + because we won't then have a MIPS/ELF BFD, however we need + to guard against a link error in a `--enable-targets=...' + configuration with a 32-bit host where the MIPS target is + a secondary, or with MIPS/ECOFF configurations. */ +#ifdef HAVE_BFD_MIPS_ELF_GET_ABIFLAGS + abiflags = bfd_mips_elf_get_abiflags (abfd); +#endif + /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ + if (is_newabi (header)) + mips_gpr_names = mips_gpr_names_newabi; + /* If a microMIPS binary, then don't use MIPS16 bindings. */ + micromips_ase = is_micromips (header); + /* OR in any extra ASE flags set in ELF file structures. */ + if (abiflags) + mips_ase |= mips_convert_abiflags_ases (abiflags->ases); + else if (header->e_flags & EF_MIPS_ARCH_ASE_MDMX) + mips_ase |= ASE_MDMX; } +#endif + mips_ase |= mips_calculate_combination_ases (mips_ase); +} + +/* Parse an ASE disassembler option and set the corresponding global + ASE flag(s). Return TRUE if successful, FALSE otherwise. */ +static bfd_boolean +parse_mips_ase_option (const char *option) +{ if (CONST_STRNEQ (option, "msa")) { mips_ase |= ASE_MSA; @@ -844,7 +908,7 @@ parse_mips_dis_option (const char *option, unsigned int len) || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5 || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6) mips_ase |= ASE_MSA64; - return; + return TRUE; } if (CONST_STRNEQ (option, "virt")) @@ -855,15 +919,38 @@ parse_mips_dis_option (const char *option, unsigned int len) || mips_isa & ISA_MIPS64R5 || mips_isa & ISA_MIPS64R6) mips_ase |= ASE_VIRT64; - return; + return TRUE; } if (CONST_STRNEQ (option, "xpa")) { mips_ase |= ASE_XPA; + return TRUE; + } + + return FALSE; +} + +static void +parse_mips_dis_option (const char *option, unsigned int len) +{ + unsigned int i, optionlen, vallen; + const char *val; + const struct mips_abi_choice *chosen_abi; + const struct mips_arch_choice *chosen_arch; + + /* Try to match options that are simple flags */ + if (CONST_STRNEQ (option, "no-aliases")) + { + no_aliases = 1; return; } + if (parse_mips_ase_option (option)) + { + mips_ase |= mips_calculate_combination_ases (mips_ase); + return; + } /* Look for the = that delimits the end of the option name. */ for (i = 0; i < len; i++) @@ -1143,6 +1230,81 @@ mips_seen_register (struct mips_print_arg_state *state, } } +/* Print SAVE/RESTORE instruction operands according to the argument + register mask AMASK, the number of static registers saved NSREG, + the $ra, $s0 and $s1 register specifiers RA, S0 and S1 respectively, + and the frame size FRAME_SIZE. */ + +static void +mips_print_save_restore (struct disassemble_info *info, unsigned int amask, + unsigned int nsreg, unsigned int ra, + unsigned int s0, unsigned int s1, + unsigned int frame_size) +{ + const fprintf_ftype infprintf = info->fprintf_func; + unsigned int nargs, nstatics, smask, i, j; + void *is = info->stream; + const char *sep; + + if (amask == MIPS_SVRS_ALL_ARGS) + { + nargs = 4; + nstatics = 0; + } + else if (amask == MIPS_SVRS_ALL_STATICS) + { + nargs = 0; + nstatics = 4; + } + else + { + nargs = amask >> 2; + nstatics = amask & 3; + } + + sep = ""; + if (nargs > 0) + { + infprintf (is, "%s", mips_gpr_names[4]); + if (nargs > 1) + infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]); + sep = ","; + } + + infprintf (is, "%s%d", sep, frame_size); + + if (ra) /* $ra */ + infprintf (is, ",%s", mips_gpr_names[31]); + + smask = 0; + if (s0) /* $s0 */ + smask |= 1 << 0; + if (s1) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + for (i = 0; i < 9; i++) + if (smask & (1 << i)) + { + infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + /* Statics $ax - $a3. */ + if (nstatics == 1) + infprintf (is, ",%s", mips_gpr_names[7]); + else if (nstatics > 0) + infprintf (is, ",%s-%s", + mips_gpr_names[7 - nstatics + 1], + mips_gpr_names[7]); +} + + /* Print operand OPERAND of OPCODE, using STATE to track inter-operand state. UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is the base address for OP_PCREL operands. */ @@ -1233,9 +1395,10 @@ print_insn_arg (struct disassemble_info *info, pcrel_op = (const struct mips_pcrel_operand *) operand; info->target = mips_decode_pcrel_operand (pcrel_op, base_pc, uval); - /* Preserve the ISA bit for the GDB disassembler, - otherwise clear it. */ - if (info->flavour != bfd_target_unknown_flavour) + /* For jumps and branches clear the ISA bit except for + the GDB disassembler. */ + if (pcrel_op->include_isa_bit + && info->flavour != bfd_target_unknown_flavour) info->target &= -2; (*info->print_address_func) (info->target, info); @@ -1374,7 +1537,7 @@ print_insn_arg (struct disassemble_info *info, break; case OP_SAVE_RESTORE_LIST: - /* Should be handled by the caller due to extend behavior. */ + /* Should be handled by the caller due to complex behavior. */ abort (); case OP_MDMX_IMM_REG: @@ -1413,6 +1576,10 @@ print_insn_arg (struct disassemble_info *info, infprintf (is, "$pc"); break; + case OP_REG28: + print_reg (info, opcode, OP_REG_GP, 28); + break; + case OP_VU0_SUFFIX: case OP_VU0_MATCH_SUFFIX: print_vu0_channel (info, operand, uval); @@ -1526,15 +1693,13 @@ validate_insn_args (const struct mips_opcode *opcode, case OP_REPEAT_PREV_REG: case OP_REPEAT_DEST_REG: case OP_PC: + case OP_REG28: case OP_VU0_SUFFIX: case OP_VU0_MATCH_SUFFIX: case OP_IMM_INDEX: case OP_REG_INDEX: - break; - case OP_SAVE_RESTORE_LIST: - /* Should be handled by the caller due to extend behavior. */ - abort (); + break; } } if (*s == 'm' || *s == '+' || *s == '-') @@ -1587,12 +1752,26 @@ print_insn_args (struct disassemble_info *info, opcode->name, opcode->args); return; } - if (operand->type == OP_REG - && s[1] == ',' - && s[2] == 'H' - && opcode->name[strlen (opcode->name) - 1] == '0') + + if (operand->type == OP_SAVE_RESTORE_LIST) { - /* Coprocessor register 0 with sel field (MT ASE). */ + /* Handle this case here because of the complex behavior. */ + unsigned int amask = (insn >> 15) & 0xf; + unsigned int nsreg = (insn >> 23) & 0x7; + unsigned int ra = insn & 0x1000; /* $ra */ + unsigned int s0 = insn & 0x800; /* $s0 */ + unsigned int s1 = insn & 0x400; /* $s1 */ + unsigned int frame_size = (((insn >> 15) & 0xf0) + | ((insn >> 6) & 0x0f)) * 8; + mips_print_save_restore (info, amask, nsreg, ra, s0, s1, + frame_size); + } + else if (operand->type == OP_REG + && s[1] == ',' + && s[2] == 'H' + && opcode->name[strlen (opcode->name) - 1] == '0') + { + /* Coprocessor register 0 with sel field. */ const struct mips_cp0sel_name *n; unsigned int reg, sel; @@ -1775,6 +1954,7 @@ print_mips16_insn_arg (struct disassemble_info *info, const fprintf_ftype infprintf = info->fprintf_func; void *is = info->stream; const struct mips_operand *operand, *ext_operand; + unsigned short ext_size; unsigned int uval; bfd_vma baseaddr; @@ -1801,72 +1981,17 @@ print_mips16_insn_arg (struct disassemble_info *info, if (operand->type == OP_SAVE_RESTORE_LIST) { - /* Handle this case here because of the complex interation + /* Handle this case here because of the complex interaction with the EXTEND opcode. */ - unsigned int amask, nargs, nstatics, nsreg, smask, frame_size, i, j; - const char *sep; - - amask = extend & 0xf; - if (amask == MIPS16_ALL_ARGS) - { - nargs = 4; - nstatics = 0; - } - else if (amask == MIPS16_ALL_STATICS) - { - nargs = 0; - nstatics = 4; - } - else - { - nargs = amask >> 2; - nstatics = amask & 3; - } - - sep = ""; - if (nargs > 0) - { - infprintf (is, "%s", mips_gpr_names[4]); - if (nargs > 1) - infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]); - sep = ","; - } - - frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8; + unsigned int amask = extend & 0xf; + unsigned int nsreg = (extend >> 8) & 0x7; + unsigned int ra = insn & 0x40; /* $ra */ + unsigned int s0 = insn & 0x20; /* $s0 */ + unsigned int s1 = insn & 0x10; /* $s1 */ + unsigned int frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8; if (frame_size == 0 && !use_extend) frame_size = 128; - infprintf (is, "%s%d", sep, frame_size); - - if (insn & 0x40) /* $ra */ - infprintf (is, ",%s", mips_gpr_names[31]); - - nsreg = (extend >> 8) & 0x7; - smask = 0; - if (insn & 0x20) /* $s0 */ - smask |= 1 << 0; - if (insn & 0x10) /* $s1 */ - smask |= 1 << 1; - if (nsreg > 0) /* $s2-$s8 */ - smask |= ((1 << nsreg) - 1) << 2; - - for (i = 0; i < 9; i++) - if (smask & (1 << i)) - { - infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]); - /* Skip over string of set bits. */ - for (j = i; smask & (2 << j); j++) - continue; - if (j > i) - infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]); - i = j + 1; - } - /* Statics $ax - $a3. */ - if (nstatics == 1) - infprintf (is, ",%s", mips_gpr_names[7]); - else if (nstatics > 0) - infprintf (is, ",%s-%s", - mips_gpr_names[7 - nstatics + 1], - mips_gpr_names[7]); + mips_print_save_restore (info, amask, nsreg, ra, s0, s1, frame_size); break; } @@ -1879,31 +2004,30 @@ print_mips16_insn_arg (struct disassemble_info *info, info->data_size = 1 << int_op->shift; } - if (operand->size == 26) - /* In this case INSN is the first two bytes of the instruction - and EXTEND is the second two bytes. */ - uval = ((insn & 0x1f) << 21) | ((insn & 0x3e0) << 11) | extend; - else + ext_size = 0; + if (use_extend) { - /* Calculate the full field value. */ - uval = mips_extract_operand (operand, insn); - if (use_extend) + ext_operand = decode_mips16_operand (type, TRUE); + if (ext_operand != operand + || (operand->type == OP_INT && operand->lsb == 0 + && mips_opcode_32bit_p (opcode))) { - ext_operand = decode_mips16_operand (type, TRUE); - if (ext_operand != operand) - { - operand = ext_operand; - if (operand->size == 16) - uval = (((extend & 0x1f) << 11) | (extend & 0x7e0) - | (uval & 0x1f)); - else if (operand->size == 15) - uval |= ((extend & 0xf) << 11) | (extend & 0x7f0); - else - uval = ((((extend >> 6) & 0x1f) | (extend & 0x20)) - & ((1U << operand->size) - 1)); - } + ext_size = ext_operand->size; + operand = ext_operand; } } + if (operand->size == 26) + uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn; + else if (ext_size == 16 || ext_size == 9) + uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f); + else if (ext_size == 15) + uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf); + else if (ext_size == 6) + uval = ((extend >> 6) & 0x1f) | (extend & 0x20); + else + uval = mips_extract_operand (operand, (extend << 16) | insn); + if (ext_size == 9) + uval &= (1U << ext_size) - 1; baseaddr = memaddr + 2; if (operand->type == OP_PCREL) @@ -1914,32 +2038,36 @@ print_mips16_insn_arg (struct disassemble_info *info, if (!pcrel_op->include_isa_bit && use_extend) baseaddr = memaddr - 2; else if (!pcrel_op->include_isa_bit) - { - bfd_byte buffer[2]; - - /* If this instruction is in the delay slot of a JR - instruction, the base address is the address of the - JR instruction. If it is in the delay slot of a JALR - instruction, the base address is the address of the - JALR instruction. This test is unreliable: we have - no way of knowing whether the previous word is - instruction or data. */ - if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0 - && (((info->endian == BFD_ENDIAN_BIG - ? bfd_getb16 (buffer) - : bfd_getl16 (buffer)) - & 0xf800) == 0x1800)) - baseaddr = memaddr - 4; - else if (info->read_memory_func (memaddr - 2, buffer, 2, - info) == 0 - && (((info->endian == BFD_ENDIAN_BIG - ? bfd_getb16 (buffer) - : bfd_getl16 (buffer)) - & 0xf81f) == 0xe800)) - baseaddr = memaddr - 2; - else - baseaddr = memaddr; - } + { + bfd_byte buffer[2]; + + /* If this instruction is in the delay slot of a JAL/JALX + instruction, the base address is the address of the + JAL/JALX instruction. If it is in the delay slot of + a JR/JALR instruction, the base address is the address + of the JR/JALR instruction. This test is unreliable: + we have no way of knowing whether the previous word is + instruction or data. */ + if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else if (info->read_memory_func (memaddr - 2, buffer, 2, + info) == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf89f) == 0xe800) + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0x0060) != 0x0060)) + baseaddr = memaddr - 2; + else + baseaddr = memaddr; + } } print_insn_arg (info, state, opcode, operand, baseaddr + 1, uval); @@ -1964,6 +2092,15 @@ is_mips16_plt_tail (struct disassemble_info *info, bfd_vma addr) return FALSE; } +/* Whether none, a 32-bit or a 16-bit instruction match has been done. */ + +enum match_kind +{ + MATCH_NONE, + MATCH_FULL, + MATCH_SHORT +}; + /* Disassemble mips16 instructions. */ static int @@ -1972,13 +2109,14 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) const fprintf_ftype infprintf = info->fprintf_func; int status; bfd_byte buffer[4]; - int length; - int insn; - bfd_boolean use_extend; - int extend = 0; const struct mips_opcode *op, *opend; struct mips_print_arg_state state; void *is = info->stream; + bfd_boolean have_second; + bfd_boolean extend_only; + unsigned int second; + unsigned int first; + unsigned int full; info->bytes_per_chunk = 2; info->display_endian = info->endian; @@ -2019,44 +2157,28 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) return -1; } - length = 2; + extend_only = FALSE; if (info->endian == BFD_ENDIAN_BIG) - insn = bfd_getb16 (buffer); + first = bfd_getb16 (buffer); else - insn = bfd_getl16 (buffer); + first = bfd_getl16 (buffer); - /* Handle the extend opcode specially. */ - use_extend = FALSE; - if ((insn & 0xf800) == 0xf000) + status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); + if (status == 0) { - use_extend = TRUE; - extend = insn & 0x7ff; - - memaddr += 2; - - status = (*info->read_memory_func) (memaddr, buffer, 2, info); - if (status != 0) - { - infprintf (is, "extend 0x%x", (unsigned int) extend); - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - + have_second = TRUE; if (info->endian == BFD_ENDIAN_BIG) - insn = bfd_getb16 (buffer); + second = bfd_getb16 (buffer); else - insn = bfd_getl16 (buffer); - - /* Check for an extend opcode followed by an extend opcode. */ - if ((insn & 0xf800) == 0xf000) - { - infprintf (is, "extend 0x%x", (unsigned int) extend); - info->insn_type = dis_noninsn; - return length; - } - - length += 2; + second = bfd_getl16 (buffer); + full = (first << 16) | second; + } + else + { + have_second = FALSE; + second = 0; + full = first; } /* FIXME: Should probably use a hash table on the major opcode here. */ @@ -2064,37 +2186,47 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) opend = mips16_opcodes + bfd_mips16_num_opcodes; for (op = mips16_opcodes; op < opend; op++) { - if (op->pinfo != INSN_MACRO - && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) - && (insn & op->mask) == op->match) - { - const char *s; - - if (op->args[0] == 'a' || op->args[0] == 'i') - { - if (use_extend) - { - infprintf (is, "extend 0x%x", (unsigned int) extend); - info->insn_type = dis_noninsn; - return length - 2; - } - - use_extend = FALSE; + enum match_kind match; - memaddr += 2; + if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor)) + continue; - status = (*info->read_memory_func) (memaddr, buffer, 2, - info); - if (status == 0) - { - use_extend = TRUE; - if (info->endian == BFD_ENDIAN_BIG) - extend = bfd_getb16 (buffer); - else - extend = bfd_getl16 (buffer); - length += 2; - } + if (op->pinfo == INSN_MACRO + || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) + match = MATCH_NONE; + else if (mips_opcode_32bit_p (op)) + { + if (have_second + && (full & op->mask) == op->match) + match = MATCH_FULL; + else + match = MATCH_NONE; + } + else if ((first & op->mask) == op->match) + { + match = MATCH_SHORT; + second = 0; + full = first; + } + else if ((first & 0xf800) == 0xf000 + && have_second + && !extend_only + && (second & op->mask) == op->match) + { + if (op->pinfo2 & INSN2_SHORT_ONLY) + { + match = MATCH_NONE; + extend_only = TRUE; } + else + match = MATCH_FULL; + } + else + match = MATCH_NONE; + + if (match != MATCH_NONE) + { + const char *s; infprintf (is, "%s", op->name); if (op->args[0] != '\0') @@ -2105,7 +2237,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) { if (*s == ',' && s[1] == 'w' - && GET_OP (insn, RX) == GET_OP (insn, RY)) + && GET_OP (full, RX) == GET_OP (full, RY)) { /* Skip the register and the comma. */ ++s; @@ -2113,14 +2245,55 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) } if (*s == ',' && s[1] == 'v' - && GET_OP (insn, RZ) == GET_OP (insn, RX)) + && GET_OP (full, RZ) == GET_OP (full, RX)) { /* Skip the register and the comma. */ ++s; continue; } - print_mips16_insn_arg (info, &state, op, *s, memaddr, insn, - use_extend, extend, s[1] == '('); + if (s[0] == 'N' + && s[1] == ',' + && s[2] == 'O' + && op->name[strlen (op->name) - 1] == '0') + { + /* Coprocessor register 0 with sel field. */ + const struct mips_cp0sel_name *n; + const struct mips_operand *operand; + unsigned int reg, sel; + + operand = decode_mips16_operand (*s, TRUE); + reg = mips_extract_operand (operand, (first << 16) | second); + s += 2; + operand = decode_mips16_operand (*s, TRUE); + sel = mips_extract_operand (operand, (first << 16) | second); + + /* CP0 register including 'sel' code for mftc0, to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name (mips_cp0sel_names, + mips_cp0sel_names_len, + reg, sel); + if (n != NULL) + infprintf (is, "%s", n->name); + else + infprintf (is, "$%d,%d", reg, sel); + } + else + switch (match) + { + case MATCH_FULL: + print_mips16_insn_arg (info, &state, op, *s, memaddr + 2, + second, TRUE, first, s[1] == '('); + break; + case MATCH_SHORT: + print_mips16_insn_arg (info, &state, op, *s, memaddr, + first, FALSE, 0, s[1] == '('); + break; + case MATCH_NONE: /* Stop the compiler complaining. */ + break; + } } /* Figure out branch instruction type and delay slot information. */ @@ -2137,17 +2310,15 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0) info->insn_type = dis_condbranch; - return length; + return match == MATCH_FULL ? 4 : 2; } } #undef GET_OP - if (use_extend) - infprintf (is, "0x%x", extend | 0xf000); - infprintf (is, "0x%x", insn); + infprintf (is, "0x%x", first); info->insn_type = dis_noninsn; - return length; + return 2; } /* Disassemble microMIPS instructions. */ @@ -2384,16 +2555,20 @@ The following MIPS specific disassembler options are supported for use\n\ with the -M switch (multiple options should be separated by commas):\n")); fprintf (stream, _("\n\ - msa Recognize MSA instructions.\n")); + no-aliases Use canonical instruction forms.\n")); + + fprintf (stream, _("\n\ + msa Recognize MSA instructions.\n")); fprintf (stream, _("\n\ - virt Recognize the virtualization ASE instructions.\n")); + virt Recognize the virtualization ASE instructions.\n")); fprintf (stream, _("\n\ - xpa Recognize the eXtended Physical Address (XPA) ASE instructions.\n")); + xpa Recognize the eXtended Physical Address (XPA)\n\ + ASE instructions.\n")); fprintf (stream, _("\n\ - gpr-names=ABI Print GPR names according to specified ABI.\n\ + gpr-names=ABI Print GPR names according to specified ABI.\n\ Default: based on binary being disassembled.\n")); fprintf (stream, _("\n\ @@ -2407,7 +2582,7 @@ with the -M switch (multiple options should be separated by commas):\n")); fprintf (stream, _("\n\ hwr-names=ARCH Print HWR names according to specified \n\ - architecture.\n\ + architecture.\n\ Default: based on binary being disassembled.\n")); fprintf (stream, _("\n\