diff options
Diffstat (limited to 'opcodes/ppc-dis.c')
-rw-r--r-- | opcodes/ppc-dis.c | 115 |
1 files changed, 61 insertions, 54 deletions
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index d2cd2e5..da72fcf 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -265,9 +265,7 @@ powerpc_init_dialect (struct disassemble_info *info) POWERPC_DIALECT(info) = dialect; } -#define PPC_OPCD_SEGS 64 -#define PPC_OP_TO_SEG(i) (i) -static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS]; +static unsigned short powerpc_opcd_indices[65]; /* Calculate opcode table indices to speed up disassembly, and init dialect. */ @@ -276,17 +274,22 @@ void disassemble_init_powerpc (struct disassemble_info *info) { int i; - - for (i = 0; i < PPC_OPCD_SEGS; ++i) - powerpc_opcd_indices[i] = powerpc_num_opcodes; + unsigned short last; i = powerpc_num_opcodes; while (--i >= 0) { unsigned op = PPC_OP (powerpc_opcodes[i].opcode); - unsigned seg = PPC_OP_TO_SEG (op); - powerpc_opcd_indices[seg] = i; + powerpc_opcd_indices[op] = i; + } + + last = powerpc_num_opcodes; + for (i = 64; i > 0; --i) + { + if (powerpc_opcd_indices[i] == 0) + powerpc_opcd_indices[i] = last; + last = powerpc_opcd_indices[i]; } if (info->arch == bfd_arch_powerpc) @@ -367,6 +370,52 @@ skip_optional_operands (const unsigned char *opindex, return 1; } +/* Find a match for INSN in the opcode table, given machine DIALECT. + A DIALECT of -1 is special, matching all machine opcode variations. */ + +static const struct powerpc_opcode * +lookup_powerpc (unsigned long insn, ppc_cpu_t dialect) +{ + const struct powerpc_opcode *opcode; + const struct powerpc_opcode *opcode_end; + unsigned long op; + + /* Get the major opcode of the instruction. */ + op = PPC_OP (insn); + + /* Find the first match in the opcode table for this major opcode. */ + opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1]; + for (opcode = powerpc_opcodes + powerpc_opcd_indices[op]; + opcode < opcode_end; + ++opcode) + { + const unsigned char *opindex; + const struct powerpc_operand *operand; + int invalid; + + if ((insn & opcode->mask) != opcode->opcode + || (dialect != (ppc_cpu_t) -1 + && ((opcode->flags & dialect) == 0 + || (opcode->deprecated & dialect) != 0))) + continue; + + /* Check validity of operands. */ + invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + operand = powerpc_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, dialect, &invalid); + } + if (invalid) + continue; + + return opcode; + } + + return NULL; +} + /* Print a PowerPC or POWER instruction. */ static int @@ -379,8 +428,6 @@ print_insn_powerpc (bfd_vma memaddr, int status; unsigned long insn; const struct powerpc_opcode *opcode; - const struct powerpc_opcode *opcode_end; - unsigned long op; status = (*info->read_memory_func) (memaddr, buffer, 4, info); if (status != 0) @@ -394,52 +441,18 @@ print_insn_powerpc (bfd_vma memaddr, else insn = bfd_getl32 (buffer); - /* Get the major opcode of the instruction. */ - op = PPC_OP (insn); + opcode = lookup_powerpc (insn, dialect); + if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) + opcode = lookup_powerpc (insn, (ppc_cpu_t) -1); - /* Find the first match in the opcode table. - We speed this up by segmenting the opcode table and starting the search - at one of the segment boundaries. */ - opcode_end = powerpc_opcodes + powerpc_num_opcodes; - again: - for (opcode = powerpc_opcodes + powerpc_opcd_indices[PPC_OP_TO_SEG (op)]; - opcode < opcode_end; - ++opcode) + if (opcode != NULL) { - unsigned long table_op; const unsigned char *opindex; const struct powerpc_operand *operand; - int invalid; int need_comma; int need_paren; int skip_optional; - table_op = PPC_OP (opcode->opcode); - if (op > table_op) - continue; - if (op < table_op) - break; - - if ((insn & opcode->mask) != opcode->opcode - || (opcode->flags & dialect) == 0 - || (dialect != ~(ppc_cpu_t) PPC_OPCODE_ANY - && (opcode->deprecated & dialect) != 0)) - continue; - - /* Make two passes over the operands. First see if any of them - have extraction functions, and, if they do, make sure the - instruction is valid. */ - invalid = 0; - for (opindex = opcode->operands; *opindex != 0; opindex++) - { - operand = powerpc_operands + *opindex; - if (operand->extract) - (*operand->extract) (insn, dialect, &invalid); - } - if (invalid) - continue; - - /* The instruction is valid. */ if (opcode->operands[0] != 0) (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); else @@ -540,12 +553,6 @@ print_insn_powerpc (bfd_vma memaddr, return 4; } - if ((dialect & PPC_OPCODE_ANY) != 0) - { - dialect = ~(ppc_cpu_t) PPC_OPCODE_ANY; - goto again; - } - /* We could not find a match. */ (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); |