diff options
Diffstat (limited to 'opcodes/xtensa-dis.c')
-rw-r--r-- | opcodes/xtensa-dis.c | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/opcodes/xtensa-dis.c b/opcodes/xtensa-dis.c new file mode 100644 index 0000000..bf5f5bf --- /dev/null +++ b/opcodes/xtensa-dis.c @@ -0,0 +1,526 @@ +/* xtensa-dis.c. Disassembly functions for Xtensa. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this file; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include "xtensa-isa.h" +#include "ansidecl.h" +#include "sysdep.h" +#include "dis-asm.h" + +#include <setjmp.h> + +#ifndef MAX +#define MAX(a,b) (a > b ? a : b) +#endif + +static char* state_names[256] = +{ + "lbeg", /* 0 */ + "lend", /* 1 */ + "lcount", /* 2 */ + "sar", /* 3 */ + "br", /* 4 */ + + "reserved_5", /* 5 */ + "reserved_6", /* 6 */ + "reserved_7", /* 7 */ + + "av", /* 8 */ + "avh", /* 9 */ + "bv", /* 10 */ + "sav", /* 11 */ + "scompare1", /* 12 */ + + "reserved_13", /* 13 */ + "reserved_14", /* 14 */ + "reserved_15", /* 15 */ + + "acclo", /* 16 */ + "acchi", /* 17 */ + + "reserved_18", /* 18 */ + "reserved_19", /* 19 */ + "reserved_20", /* 20 */ + "reserved_21", /* 21 */ + "reserved_22", /* 22 */ + "reserved_23", /* 23 */ + "reserved_24", /* 24 */ + "reserved_25", /* 25 */ + "reserved_26", /* 26 */ + "reserved_27", /* 27 */ + "reserved_28", /* 28 */ + "reserved_29", /* 29 */ + "reserved_30", /* 30 */ + "reserved_31", /* 31 */ + + "mr0", /* 32 */ + "mr1", /* 33 */ + "mr2", /* 34 */ + "mr3", /* 35 */ + + "reserved_36", /* 36 */ + "reserved_37", /* 37 */ + "reserved_38", /* 38 */ + "reserved_39", /* 39 */ + "reserved_40", /* 40 */ + "reserved_41", /* 41 */ + "reserved_42", /* 42 */ + "reserved_43", /* 43 */ + "reserved_44", /* 44 */ + "reserved_45", /* 45 */ + "reserved_46", /* 46 */ + "reserved_47", /* 47 */ + "reserved_48", /* 48 */ + "reserved_49", /* 49 */ + "reserved_50", /* 50 */ + "reserved_51", /* 51 */ + "reserved_52", /* 52 */ + "reserved_53", /* 53 */ + "reserved_54", /* 54 */ + "reserved_55", /* 55 */ + "reserved_56", /* 56 */ + "reserved_57", /* 57 */ + "reserved_58", /* 58 */ + "reserved_59", /* 59 */ + "reserved_60", /* 60 */ + "reserved_61", /* 61 */ + "reserved_62", /* 62 */ + "reserved_63", /* 63 */ + + "reserved_64", /* 64 */ + "reserved_65", /* 65 */ + "reserved_66", /* 66 */ + "reserved_67", /* 67 */ + "reserved_68", /* 68 */ + "reserved_69", /* 69 */ + "reserved_70", /* 70 */ + "reserved_71", /* 71 */ + + "wb", /* 72 */ + "ws", /* 73 */ + + "reserved_74", /* 74 */ + "reserved_75", /* 75 */ + "reserved_76", /* 76 */ + "reserved_77", /* 77 */ + "reserved_78", /* 78 */ + "reserved_79", /* 79 */ + "reserved_80", /* 80 */ + "reserved_81", /* 81 */ + "reserved_82", /* 82 */ + + "ptevaddr", /* 83 */ + + "reserved_84", /* 84 */ + "reserved_85", /* 85 */ + "reserved_86", /* 86 */ + "reserved_87", /* 87 */ + "reserved_88", /* 88 */ + "reserved_89", /* 89 */ + + "rasid", /* 90 */ + "itlbcfg", /* 91 */ + "dtlbcfg", /* 92 */ + + "reserved_93", /* 93 */ + "reserved_94", /* 94 */ + "reserved_95", /* 95 */ + + "ibreakenable", /* 96 */ + + "reserved_97", /* 97 */ + + "cacheattr", /* 98 */ + + "reserved_99", /* 99 */ + "reserved_100", /* 100 */ + "reserved_101", /* 101 */ + "reserved_102", /* 102 */ + "reserved_103", /* 103 */ + + "ddr", /* 104 */ + + "reserved_105", /* 105 */ + "reserved_106", /* 106 */ + "reserved_107", /* 107 */ + "reserved_108", /* 108 */ + "reserved_109", /* 109 */ + "reserved_110", /* 110 */ + "reserved_111", /* 111 */ + "reserved_112", /* 112 */ + "reserved_113", /* 113 */ + "reserved_114", /* 114 */ + "reserved_115", /* 115 */ + "reserved_116", /* 116 */ + "reserved_117", /* 117 */ + "reserved_118", /* 118 */ + "reserved_119", /* 119 */ + "reserved_120", /* 120 */ + "reserved_121", /* 121 */ + "reserved_122", /* 122 */ + "reserved_123", /* 123 */ + "reserved_124", /* 124 */ + "reserved_125", /* 125 */ + "reserved_126", /* 126 */ + "reserved_127", /* 127 */ + + "ibreaka0", /* 128 */ + "ibreaka1", /* 129 */ + "ibreaka2", /* 130 */ + "ibreaka3", /* 131 */ + "ibreaka4", /* 132 */ + "ibreaka5", /* 133 */ + "ibreaka6", /* 134 */ + "ibreaka7", /* 135 */ + "ibreaka8", /* 136 */ + "ibreaka9", /* 137 */ + "ibreaka10", /* 138 */ + "ibreaka11", /* 139 */ + "ibreaka12", /* 140 */ + "ibreaka13", /* 141 */ + "ibreaka14", /* 142 */ + "ibreaka15", /* 143 */ + + "dbreaka0", /* 144 */ + "dbreaka1", /* 145 */ + "dbreaka2", /* 146 */ + "dbreaka3", /* 147 */ + "dbreaka4", /* 148 */ + "dbreaka5", /* 149 */ + "dbreaka6", /* 150 */ + "dbreaka7", /* 151 */ + "dbreaka8", /* 152 */ + "dbreaka9", /* 153 */ + "dbreaka10", /* 154 */ + "dbreaka11", /* 155 */ + "dbreaka12", /* 156 */ + "dbreaka13", /* 157 */ + "dbreaka14", /* 158 */ + "dbreaka15", /* 159 */ + + "dbreakc0", /* 160 */ + "dbreakc1", /* 161 */ + "dbreakc2", /* 162 */ + "dbreakc3", /* 163 */ + "dbreakc4", /* 164 */ + "dbreakc5", /* 165 */ + "dbreakc6", /* 166 */ + "dbreakc7", /* 167 */ + "dbreakc8", /* 168 */ + "dbreakc9", /* 169 */ + "dbreakc10", /* 170 */ + "dbreakc11", /* 171 */ + "dbreakc12", /* 172 */ + "dbreakc13", /* 173 */ + "dbreakc14", /* 174 */ + "dbreakc15", /* 175 */ + + "reserved_176", /* 176 */ + + "epc1", /* 177 */ + "epc2", /* 178 */ + "epc3", /* 179 */ + "epc4", /* 180 */ + "epc5", /* 181 */ + "epc6", /* 182 */ + "epc7", /* 183 */ + "epc8", /* 184 */ + "epc9", /* 185 */ + "epc10", /* 186 */ + "epc11", /* 187 */ + "epc12", /* 188 */ + "epc13", /* 189 */ + "epc14", /* 190 */ + "epc15", /* 191 */ + "depc", /* 192 */ + + "reserved_193", /* 193 */ + + "eps2", /* 194 */ + "eps3", /* 195 */ + "eps4", /* 196 */ + "eps5", /* 197 */ + "eps6", /* 198 */ + "eps7", /* 199 */ + "eps8", /* 200 */ + "eps9", /* 201 */ + "eps10", /* 202 */ + "eps11", /* 203 */ + "eps12", /* 204 */ + "eps13", /* 205 */ + "eps14", /* 206 */ + "eps15", /* 207 */ + + "reserved_208", /* 208 */ + + "excsave1", /* 209 */ + "excsave2", /* 210 */ + "excsave3", /* 211 */ + "excsave4", /* 212 */ + "excsave5", /* 213 */ + "excsave6", /* 214 */ + "excsave7", /* 215 */ + "excsave8", /* 216 */ + "excsave9", /* 217 */ + "excsave10", /* 218 */ + "excsave11", /* 219 */ + "excsave12", /* 220 */ + "excsave13", /* 221 */ + "excsave14", /* 222 */ + "excsave15", /* 223 */ + "cpenable", /* 224 */ + + "reserved_225", /* 225 */ + + "interrupt", /* 226 */ + "interrupt2", /* 227 */ + "intenable", /* 228 */ + + "reserved_229", /* 229 */ + + "ps", /* 230 */ + + "reserved_231", /* 231 */ + + "exccause", /* 232 */ + "debugcause", /* 233 */ + "ccount", /* 234 */ + "prid", /* 235 */ + "icount", /* 236 */ + "icountlvl", /* 237 */ + "excvaddr", /* 238 */ + + "reserved_239", /* 239 */ + + "ccompare0", /* 240 */ + "ccompare1", /* 241 */ + "ccompare2", /* 242 */ + "ccompare3", /* 243 */ + + "misc0", /* 244 */ + "misc1", /* 245 */ + "misc2", /* 246 */ + "misc3", /* 247 */ + + "reserved_248", /* 248 */ + "reserved_249", /* 249 */ + "reserved_250", /* 250 */ + "reserved_251", /* 251 */ + "reserved_252", /* 252 */ + "reserved_253", /* 253 */ + "reserved_254", /* 254 */ + "reserved_255", /* 255 */ +}; + + +int show_raw_fields; + +static int fetch_data + PARAMS ((struct disassemble_info *info, bfd_vma memaddr, int numBytes)); +static void print_xtensa_operand + PARAMS ((bfd_vma, struct disassemble_info *, xtensa_operand, + unsigned operand_val, int print_sr_name)); + +struct dis_private { + bfd_byte *byte_buf; + jmp_buf bailout; +}; + +static int +fetch_data (info, memaddr, numBytes) + struct disassemble_info *info; + bfd_vma memaddr; + int numBytes; +{ + int length, status = 0; + struct dis_private *priv = (struct dis_private *) info->private_data; + int insn_size = (numBytes != 0 ? numBytes : + xtensa_insn_maxlength (xtensa_default_isa)); + + /* Read the maximum instruction size, padding with zeros if we go past + the end of the text section. This code will automatically adjust + length when we hit the end of the buffer. */ + + memset (priv->byte_buf, 0, insn_size); + for (length = insn_size; length > 0; length--) + { + status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, + info); + if (status == 0) + return length; + } + (*info->memory_error_func) (status, memaddr, info); + longjmp (priv->bailout, 1); + /*NOTREACHED*/ +} + + +static void +print_xtensa_operand (memaddr, info, opnd, operand_val, print_sr_name) + bfd_vma memaddr; + struct disassemble_info *info; + xtensa_operand opnd; + unsigned operand_val; + int print_sr_name; +{ + char *kind = xtensa_operand_kind (opnd); + int signed_operand_val; + + if (show_raw_fields) + { + if (operand_val < 0xa) + (*info->fprintf_func) (info->stream, "%u", operand_val); + else + (*info->fprintf_func) (info->stream, "0x%x", operand_val); + return; + } + + operand_val = xtensa_operand_decode (opnd, operand_val); + signed_operand_val = (int) operand_val; + + if (xtensa_operand_isPCRelative (opnd)) + { + operand_val = xtensa_operand_undo_reloc (opnd, operand_val, memaddr); + info->target = operand_val; + (*info->print_address_func) (info->target, info); + } + else if (!strcmp (kind, "i")) + { + if (print_sr_name + && signed_operand_val >= 0 + && signed_operand_val <= 255) + (*info->fprintf_func) (info->stream, "%s", + state_names[signed_operand_val]); + else if ((signed_operand_val > -256) && (signed_operand_val < 256)) + (*info->fprintf_func) (info->stream, "%d", signed_operand_val); + else + (*info->fprintf_func) (info->stream, "0x%x",signed_operand_val); + } + else + (*info->fprintf_func) (info->stream, "%s%u", kind, operand_val); +} + + +/* Print the Xtensa instruction at address MEMADDR on info->stream. + Returns length of the instruction in bytes. */ + +int +print_insn_xtensa (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + unsigned operand_val; + int bytes_fetched, size, maxsize, i, noperands; + xtensa_isa isa; + xtensa_opcode opc; + char *op_name; + int print_sr_name; + struct dis_private priv; + static bfd_byte *byte_buf = NULL; + static xtensa_insnbuf insn_buffer = NULL; + + if (!xtensa_default_isa) + (void) xtensa_isa_init (); + + info->target = 0; + maxsize = xtensa_insn_maxlength (xtensa_default_isa); + + /* Set bytes_per_line to control the amount of whitespace between the hex + values and the opcode. For Xtensa, we always print one "chunk" and we + vary bytes_per_chunk to determine how many bytes to print. (objdump + would apparently prefer that we set bytes_per_chunk to 1 and vary + bytes_per_line but that makes it hard to fit 64-bit instructions on + an 80-column screen.) The value of bytes_per_line here is not exactly + right, because objdump adds an extra space for each chunk so that the + amount of whitespace depends on the chunk size. Oh well, it's good + enough.... Note that we set the minimum size to 4 to accomodate + literal pools. */ + info->bytes_per_line = MAX (maxsize, 4); + + /* Allocate buffers the first time through. */ + if (!insn_buffer) + insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); + if (!byte_buf) + byte_buf = (bfd_byte *) malloc (MAX (maxsize, 4)); + + priv.byte_buf = byte_buf; + + info->private_data = (PTR) &priv; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + /* Don't set "isa" before the setjmp to keep the compiler from griping. */ + isa = xtensa_default_isa; + + /* Fetch the maximum size instruction. */ + bytes_fetched = fetch_data (info, memaddr, 0); + + /* Copy the bytes into the decode buffer. */ + memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * + sizeof (xtensa_insnbuf_word))); + xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf); + + opc = xtensa_decode_insn (isa, insn_buffer); + if (opc == XTENSA_UNDEFINED + || ((size = xtensa_insn_length (isa, opc)) > bytes_fetched)) + { + (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); + return 1; + } + + op_name = (char *) xtensa_opcode_name (isa, opc); + (*info->fprintf_func) (info->stream, "%s", op_name); + + print_sr_name = (!strcasecmp (op_name, "wsr") + || !strcasecmp (op_name, "xsr") + || !strcasecmp (op_name, "rsr")); + + /* Print the operands (if any). */ + noperands = xtensa_num_operands (isa, opc); + if (noperands > 0) + { + int first = 1; + + (*info->fprintf_func) (info->stream, "\t"); + for (i = 0; i < noperands; i++) + { + xtensa_operand opnd = xtensa_get_operand (isa, opc, i); + + if (first) + first = 0; + else + (*info->fprintf_func) (info->stream, ", "); + operand_val = xtensa_operand_get_field (opnd, insn_buffer); + print_xtensa_operand (memaddr, info, opnd, operand_val, + print_sr_name); + } + } + + info->bytes_per_chunk = size; + info->display_endian = info->endian; + + return size; +} + |