summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2012-03-15 12:58:47 +0000
committerAlan Modra <amodra@bigpond.net.au>2012-03-15 12:58:47 +0000
commitaadc18b9ac4f423e586d8e0227d8fcd234e2a1e9 (patch)
treee915965a746e3055fcbb59df366aa73b4f0ce183
parent2b646300521883b7477174928e761b4d58dbf508 (diff)
downloadbinutils-redhat-aadc18b9ac4f423e586d8e0227d8fcd234e2a1e9.tar.gz
include/
* dis-asm.h (disassemble_init_powerpc): Declare. opcodes/ * disassemble.c (disassemble_init_for_target): Handle ppc init. * ppc-dis.c (private): New var. (powerpc_init_dialect): Don't return calloc failure, instead use private. (PPC_OPCD_SEGS, PPC_OP_TO_SEG): Define. (powerpc_opcd_indices): New array. (disassemble_init_powerpc): New function. (print_insn_big_powerpc): Don't init dialect here. (print_insn_little_powerpc): Likewise. (print_insn_powerpc): Start search using powerpc_opcd_indices.
-rw-r--r--include/ChangeLog4
-rw-r--r--include/dis-asm.h3
-rw-r--r--opcodes/ChangeLog14
-rw-r--r--opcodes/disassemble.c13
-rw-r--r--opcodes/ppc-dis.c51
5 files changed, 70 insertions, 15 deletions
diff --git a/include/ChangeLog b/include/ChangeLog
index e722835785..c5b84b5799 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2012-03-15 Alan Modra <amodra@gmail.com>
+
+ * dis-asm.h (disassemble_init_powerpc): Declare.
+
2009-11-06 Jonas Maebe <jonas.maebe@elis.ugent.be>
Add DWARF attribute value for the "Borland fastcall" calling
diff --git a/include/dis-asm.h b/include/dis-asm.h
index d2334c63c4..c9cbfbb321 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -1,7 +1,7 @@
/* Interface between the opcode library and its callers.
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010,
- 2011 Free Software Foundation, Inc.
+ 2011, 2012 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -314,6 +314,7 @@ extern int get_arm_regname_num_options (void);
extern int set_arm_regname_option (int);
extern int get_arm_regnames (int, const char **, const char **, const char *const **);
extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
+extern void disassemble_init_powerpc (struct disassemble_info *);
/* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler (bfd *);
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 42a099692e..3595faf528 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,17 @@
+2012-03-15 Alan Modra <amodra@gmail.com>
+ James Lemke <jwlemke@codesourcery.com>
+
+ * disassemble.c (disassemble_init_for_target): Handle ppc init.
+ * ppc-dis.c (private): New var.
+ (powerpc_init_dialect): Don't return calloc failure, instead use
+ private.
+ (PPC_OPCD_SEGS, PPC_OP_TO_SEG): Define.
+ (powerpc_opcd_indices): New array.
+ (disassemble_init_powerpc): New function.
+ (print_insn_big_powerpc): Don't init dialect here.
+ (print_insn_little_powerpc): Likewise.
+ (print_insn_powerpc): Start search using powerpc_opcd_indices.
+
2012-03-10 Edmar Wienskoski <edmar@freescale.com>
* ppc-dis.c (ppc_opts): Add entries for "e5500" and "e6500".
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index 0b6313537c..43e1d53eb4 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -1,6 +1,7 @@
/* Select disassembly routine for specified architecture.
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+ Free Software Foundation, Inc.
This file is part of the GNU opcodes library.
@@ -566,6 +567,16 @@ disassemble_init_for_target (struct disassemble_info * info)
}
break;
#endif
+#ifdef ARCH_powerpc
+ case bfd_arch_powerpc:
+#endif
+#ifdef ARCH_rs6000
+ case bfd_arch_rs6000:
+#endif
+#if defined (ARCH_powerpc) || defined (ARCH_rs6000)
+ disassemble_init_powerpc (info);
+ break;
+#endif
default:
break;
}
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index e1c9f1b05c..d2cd2e5916 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -38,7 +38,7 @@ struct dis_private
{
/* Stash the result of parsing disassembler_options here. */
ppc_cpu_t dialect;
-};
+} private;
#define POWERPC_DIALECT(INFO) \
(((struct dis_private *) ((INFO)->private_data))->dialect)
@@ -217,7 +217,7 @@ ppc_parse_cpu (ppc_cpu_t ppc_cpu, const char *arg)
/* Determine which set of machines to disassemble for. */
-static int
+static void
powerpc_init_dialect (struct disassemble_info *info)
{
ppc_cpu_t dialect = 0;
@@ -225,7 +225,7 @@ powerpc_init_dialect (struct disassemble_info *info)
struct dis_private *priv = calloc (sizeof (*priv), 1);
if (priv == NULL)
- return FALSE;
+ priv = &private;
arg = info->disassembler_options;
while (arg != NULL)
@@ -263,8 +263,34 @@ powerpc_init_dialect (struct disassemble_info *info)
info->private_data = priv;
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];
+
+/* Calculate opcode table indices to speed up disassembly,
+ and init dialect. */
+
+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;
- return TRUE;
+ 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;
+ }
+
+ if (info->arch == bfd_arch_powerpc)
+ powerpc_init_dialect (info);
}
/* Print a big endian PowerPC instruction. */
@@ -272,8 +298,6 @@ powerpc_init_dialect (struct disassemble_info *info)
int
print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- if (info->private_data == NULL && !powerpc_init_dialect (info))
- return -1;
return print_insn_powerpc (memaddr, info, 1, POWERPC_DIALECT(info));
}
@@ -282,8 +306,6 @@ print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
int
print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- if (info->private_data == NULL && !powerpc_init_dialect (info))
- return -1;
return print_insn_powerpc (memaddr, info, 0, POWERPC_DIALECT(info));
}
@@ -375,11 +397,14 @@ print_insn_powerpc (bfd_vma memaddr,
/* Get the major opcode of the instruction. */
op = PPC_OP (insn);
- /* Find the first match in the opcode table. We could speed this up
- a bit by doing a binary search on the major opcode. */
+ /* 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; opcode < opcode_end; opcode++)
+ for (opcode = powerpc_opcodes + powerpc_opcd_indices[PPC_OP_TO_SEG (op)];
+ opcode < opcode_end;
+ ++opcode)
{
unsigned long table_op;
const unsigned char *opindex;
@@ -390,10 +415,10 @@ print_insn_powerpc (bfd_vma memaddr,
int skip_optional;
table_op = PPC_OP (opcode->opcode);
- if (op < table_op)
- break;
if (op > table_op)
continue;
+ if (op < table_op)
+ break;
if ((insn & opcode->mask) != opcode->opcode
|| (opcode->flags & dialect) == 0