00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "sysdep.h"
00028 #include "dis-asm.h"
00029 #include "libiberty.h"
00030 #include "opcode/mips.h"
00031 #include "opintl.h"
00032
00033
00034
00035
00036
00037
00038 #if !defined(EMBEDDED_ENV)
00039 #define SYMTAB_AVAILABLE 1
00040 #include "elf-bfd.h"
00041 #include "elf/mips.h"
00042 #endif
00043
00044
00045 #define INSNLEN 4
00046
00047 static void set_default_mips_dis_options
00048 PARAMS ((struct disassemble_info *));
00049 static void parse_mips_dis_option
00050 PARAMS ((const char *, unsigned int));
00051 static void parse_mips_dis_options
00052 PARAMS ((const char *));
00053 static int _print_insn_mips
00054 PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
00055 static int print_insn_mips
00056 PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
00057 static void print_insn_args
00058 PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
00059 static int print_insn_mips16
00060 PARAMS ((bfd_vma, struct disassemble_info *));
00061 static int is_newabi
00062 PARAMS ((Elf_Internal_Ehdr *));
00063 static void print_mips16_insn_arg
00064 PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma,
00065 struct disassemble_info *));
00066
00067
00068
00069 struct mips_cp0sel_name {
00070 unsigned int cp0reg;
00071 unsigned int sel;
00072 const char * const name;
00073 };
00074
00075
00076 static const char * const mips16_reg_names[] = {
00077 "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
00078 };
00079
00080 static const char * const mips_gpr_names_numeric[32] = {
00081 "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
00082 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
00083 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
00084 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
00085 };
00086
00087 static const char * const mips_gpr_names_oldabi[32] = {
00088 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
00089 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
00090 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
00091 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
00092 };
00093
00094 static const char * const mips_gpr_names_newabi[32] = {
00095 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
00096 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
00097 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
00098 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
00099 };
00100
00101 static const char * const mips_fpr_names_numeric[32] = {
00102 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
00103 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
00104 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
00105 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
00106 };
00107
00108 static const char * const mips_fpr_names_32[32] = {
00109 "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f",
00110 "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f",
00111 "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f",
00112 "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f"
00113 };
00114
00115 static const char * const mips_fpr_names_n32[32] = {
00116 "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3",
00117 "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
00118 "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9",
00119 "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13"
00120 };
00121
00122 static const char * const mips_fpr_names_64[32] = {
00123 "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3",
00124 "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
00125 "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11",
00126 "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"
00127 };
00128
00129 static const char * const mips_cp0_names_numeric[32] = {
00130 "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
00131 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
00132 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
00133 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
00134 };
00135
00136 static const char * const mips_cp0_names_mips3264[32] = {
00137 "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
00138 "c0_context", "c0_pagemask", "c0_wired", "$7",
00139 "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
00140 "c0_status", "c0_cause", "c0_epc", "c0_prid",
00141 "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
00142 "c0_xcontext", "$21", "$22", "c0_debug",
00143 "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
00144 "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
00145 };
00146
00147 static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = {
00148 { 16, 1, "c0_config1" },
00149 { 16, 2, "c0_config2" },
00150 { 16, 3, "c0_config3" },
00151 { 18, 1, "c0_watchlo,1" },
00152 { 18, 2, "c0_watchlo,2" },
00153 { 18, 3, "c0_watchlo,3" },
00154 { 18, 4, "c0_watchlo,4" },
00155 { 18, 5, "c0_watchlo,5" },
00156 { 18, 6, "c0_watchlo,6" },
00157 { 18, 7, "c0_watchlo,7" },
00158 { 19, 1, "c0_watchhi,1" },
00159 { 19, 2, "c0_watchhi,2" },
00160 { 19, 3, "c0_watchhi,3" },
00161 { 19, 4, "c0_watchhi,4" },
00162 { 19, 5, "c0_watchhi,5" },
00163 { 19, 6, "c0_watchhi,6" },
00164 { 19, 7, "c0_watchhi,7" },
00165 { 25, 1, "c0_perfcnt,1" },
00166 { 25, 2, "c0_perfcnt,2" },
00167 { 25, 3, "c0_perfcnt,3" },
00168 { 25, 4, "c0_perfcnt,4" },
00169 { 25, 5, "c0_perfcnt,5" },
00170 { 25, 6, "c0_perfcnt,6" },
00171 { 25, 7, "c0_perfcnt,7" },
00172 { 27, 1, "c0_cacheerr,1" },
00173 { 27, 2, "c0_cacheerr,2" },
00174 { 27, 3, "c0_cacheerr,3" },
00175 { 28, 1, "c0_datalo" },
00176 { 29, 1, "c0_datahi" }
00177 };
00178
00179 static const char * const mips_cp0_names_mips3264r2[32] = {
00180 "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
00181 "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena",
00182 "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
00183 "c0_status", "c0_cause", "c0_epc", "c0_prid",
00184 "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
00185 "c0_xcontext", "$21", "$22", "c0_debug",
00186 "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
00187 "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
00188 };
00189
00190 static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = {
00191 { 4, 1, "c0_contextconfig" },
00192 { 5, 1, "c0_pagegrain" },
00193 { 12, 1, "c0_intctl" },
00194 { 12, 2, "c0_srsctl" },
00195 { 12, 3, "c0_srsmap" },
00196 { 15, 1, "c0_ebase" },
00197 { 16, 1, "c0_config1" },
00198 { 16, 2, "c0_config2" },
00199 { 16, 3, "c0_config3" },
00200 { 18, 1, "c0_watchlo,1" },
00201 { 18, 2, "c0_watchlo,2" },
00202 { 18, 3, "c0_watchlo,3" },
00203 { 18, 4, "c0_watchlo,4" },
00204 { 18, 5, "c0_watchlo,5" },
00205 { 18, 6, "c0_watchlo,6" },
00206 { 18, 7, "c0_watchlo,7" },
00207 { 19, 1, "c0_watchhi,1" },
00208 { 19, 2, "c0_watchhi,2" },
00209 { 19, 3, "c0_watchhi,3" },
00210 { 19, 4, "c0_watchhi,4" },
00211 { 19, 5, "c0_watchhi,5" },
00212 { 19, 6, "c0_watchhi,6" },
00213 { 19, 7, "c0_watchhi,7" },
00214 { 23, 1, "c0_tracecontrol" },
00215 { 23, 2, "c0_tracecontrol2" },
00216 { 23, 3, "c0_usertracedata" },
00217 { 23, 4, "c0_tracebpc" },
00218 { 25, 1, "c0_perfcnt,1" },
00219 { 25, 2, "c0_perfcnt,2" },
00220 { 25, 3, "c0_perfcnt,3" },
00221 { 25, 4, "c0_perfcnt,4" },
00222 { 25, 5, "c0_perfcnt,5" },
00223 { 25, 6, "c0_perfcnt,6" },
00224 { 25, 7, "c0_perfcnt,7" },
00225 { 27, 1, "c0_cacheerr,1" },
00226 { 27, 2, "c0_cacheerr,2" },
00227 { 27, 3, "c0_cacheerr,3" },
00228 { 28, 1, "c0_datalo" },
00229 { 28, 2, "c0_taglo1" },
00230 { 28, 3, "c0_datalo1" },
00231 { 28, 4, "c0_taglo2" },
00232 { 28, 5, "c0_datalo2" },
00233 { 28, 6, "c0_taglo3" },
00234 { 28, 7, "c0_datalo3" },
00235 { 29, 1, "c0_datahi" },
00236 { 29, 2, "c0_taghi1" },
00237 { 29, 3, "c0_datahi1" },
00238 { 29, 4, "c0_taghi2" },
00239 { 29, 5, "c0_datahi2" },
00240 { 29, 6, "c0_taghi3" },
00241 { 29, 7, "c0_datahi3" },
00242 };
00243
00244
00245 static const char * const mips_cp0_names_sb1[32] = {
00246 "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
00247 "c0_context", "c0_pagemask", "c0_wired", "$7",
00248 "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
00249 "c0_status", "c0_cause", "c0_epc", "c0_prid",
00250 "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
00251 "c0_xcontext", "$21", "$22", "c0_debug",
00252 "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i",
00253 "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave",
00254 };
00255
00256 static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = {
00257 { 16, 1, "c0_config1" },
00258 { 18, 1, "c0_watchlo,1" },
00259 { 19, 1, "c0_watchhi,1" },
00260 { 22, 0, "c0_perftrace" },
00261 { 23, 3, "c0_edebug" },
00262 { 25, 1, "c0_perfcnt,1" },
00263 { 25, 2, "c0_perfcnt,2" },
00264 { 25, 3, "c0_perfcnt,3" },
00265 { 25, 4, "c0_perfcnt,4" },
00266 { 25, 5, "c0_perfcnt,5" },
00267 { 25, 6, "c0_perfcnt,6" },
00268 { 25, 7, "c0_perfcnt,7" },
00269 { 26, 1, "c0_buserr_pa" },
00270 { 27, 1, "c0_cacheerr_d" },
00271 { 27, 3, "c0_cacheerr_d_pa" },
00272 { 28, 1, "c0_datalo_i" },
00273 { 28, 2, "c0_taglo_d" },
00274 { 28, 3, "c0_datalo_d" },
00275 { 29, 1, "c0_datahi_i" },
00276 { 29, 2, "c0_taghi_d" },
00277 { 29, 3, "c0_datahi_d" },
00278 };
00279
00280 static const char * const mips_hwr_names_numeric[32] = {
00281 "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
00282 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
00283 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
00284 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
00285 };
00286
00287 static const char * const mips_hwr_names_mips3264r2[32] = {
00288 "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres",
00289 "$4", "$5", "$6", "$7",
00290 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
00291 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
00292 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
00293 };
00294
00295 struct mips_abi_choice {
00296 const char *name;
00297 const char * const *gpr_names;
00298 const char * const *fpr_names;
00299 };
00300
00301 struct mips_abi_choice mips_abi_choices[] = {
00302 { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
00303 { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
00304 { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
00305 { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
00306 };
00307
00308 struct mips_arch_choice {
00309 const char *name;
00310 int bfd_mach_valid;
00311 unsigned long bfd_mach;
00312 int processor;
00313 int isa;
00314 const char * const *cp0_names;
00315 const struct mips_cp0sel_name *cp0sel_names;
00316 unsigned int cp0sel_names_len;
00317 const char * const *hwr_names;
00318 };
00319
00320 const struct mips_arch_choice mips_arch_choices[] = {
00321 { "numeric", 0, 0, 0, 0,
00322 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00323
00324 { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
00325 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00326 { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
00327 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00328 { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
00329 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00330 { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
00331 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00332 { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
00333 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00334 { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
00335 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00336 { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
00337 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00338 { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
00339 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00340 { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
00341 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00342 { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
00343 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00344 { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
00345 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00346 { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
00347 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00348 { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
00349 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00350 { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
00351 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00352 { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
00353 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00354 { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
00355 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00356 { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
00357 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00358 { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
00359 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00360 { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
00361 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00362 { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
00363 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00364 { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
00365 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00366
00367
00368
00369
00370
00371
00372 { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32,
00373 ISA_MIPS32 | INSN_MIPS16,
00374 mips_cp0_names_mips3264,
00375 mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
00376 mips_hwr_names_numeric },
00377
00378 { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
00379 ISA_MIPS32R2 | INSN_MIPS16,
00380 mips_cp0_names_mips3264r2,
00381 mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
00382 mips_hwr_names_mips3264r2 },
00383
00384
00385 { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
00386 ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
00387 mips_cp0_names_mips3264,
00388 mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
00389 mips_hwr_names_numeric },
00390
00391 { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
00392 ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
00393 mips_cp0_names_mips3264r2,
00394 mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
00395 mips_hwr_names_mips3264r2 },
00396
00397 { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
00398 ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
00399 mips_cp0_names_sb1,
00400 mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
00401 mips_hwr_names_numeric },
00402
00403
00404
00405 { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
00406 mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
00407 };
00408
00409
00410
00411
00412 static int mips_processor;
00413 static int mips_isa;
00414 static const char * const *mips_gpr_names;
00415 static const char * const *mips_fpr_names;
00416 static const char * const *mips_cp0_names;
00417 static const struct mips_cp0sel_name *mips_cp0sel_names;
00418 static int mips_cp0sel_names_len;
00419 static const char * const *mips_hwr_names;
00420
00421
00422 static int no_aliases;
00423
00424 static const struct mips_abi_choice *choose_abi_by_name
00425 PARAMS ((const char *, unsigned int));
00426 static const struct mips_arch_choice *choose_arch_by_name
00427 PARAMS ((const char *, unsigned int));
00428 static const struct mips_arch_choice *choose_arch_by_number
00429 PARAMS ((unsigned long));
00430 static const struct mips_cp0sel_name *lookup_mips_cp0sel_name
00431 PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int,
00432 unsigned int));
00433
00434 static const struct mips_abi_choice *
00435 choose_abi_by_name (name, namelen)
00436 const char *name;
00437 unsigned int namelen;
00438 {
00439 const struct mips_abi_choice *c;
00440 unsigned int i;
00441
00442 for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
00443 {
00444 if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
00445 && strlen (mips_abi_choices[i].name) == namelen)
00446 c = &mips_abi_choices[i];
00447 }
00448 return c;
00449 }
00450
00451 static const struct mips_arch_choice *
00452 choose_arch_by_name (name, namelen)
00453 const char *name;
00454 unsigned int namelen;
00455 {
00456 const struct mips_arch_choice *c = NULL;
00457 unsigned int i;
00458
00459 for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
00460 {
00461 if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
00462 && strlen (mips_arch_choices[i].name) == namelen)
00463 c = &mips_arch_choices[i];
00464 }
00465 return c;
00466 }
00467
00468 static const struct mips_arch_choice *
00469 choose_arch_by_number (mach)
00470 unsigned long mach;
00471 {
00472 static unsigned long hint_bfd_mach;
00473 static const struct mips_arch_choice *hint_arch_choice;
00474 const struct mips_arch_choice *c;
00475 unsigned int i;
00476
00477
00478
00479 if (hint_bfd_mach == mach
00480 && hint_arch_choice != NULL
00481 && hint_arch_choice->bfd_mach == hint_bfd_mach)
00482 return hint_arch_choice;
00483
00484 for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
00485 {
00486 if (mips_arch_choices[i].bfd_mach_valid
00487 && mips_arch_choices[i].bfd_mach == mach)
00488 {
00489 c = &mips_arch_choices[i];
00490 hint_bfd_mach = mach;
00491 hint_arch_choice = c;
00492 }
00493 }
00494 return c;
00495 }
00496
00497 void
00498 set_default_mips_dis_options (info)
00499 struct disassemble_info *info;
00500 {
00501 const struct mips_arch_choice *chosen_arch;
00502
00503
00504
00505 mips_isa = ISA_MIPS3;
00506 mips_processor = CPU_R3000;
00507 mips_gpr_names = mips_gpr_names_oldabi;
00508 mips_fpr_names = mips_fpr_names_numeric;
00509 mips_cp0_names = mips_cp0_names_numeric;
00510 mips_cp0sel_names = NULL;
00511 mips_cp0sel_names_len = 0;
00512 mips_hwr_names = mips_hwr_names_numeric;
00513 no_aliases = 0;
00514
00515
00516 if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
00517 {
00518 Elf_Internal_Ehdr *header;
00519
00520 header = elf_elfheader (info->section->owner);
00521 if (is_newabi (header))
00522 mips_gpr_names = mips_gpr_names_newabi;
00523 }
00524
00525
00526 #if ! SYMTAB_AVAILABLE
00527
00528
00529 target_processor = mips_target_info.processor;
00530 mips_isa = mips_target_info.isa;
00531 #else
00532 chosen_arch = choose_arch_by_number (info->mach);
00533 if (chosen_arch != NULL)
00534 {
00535 mips_processor = chosen_arch->processor;
00536 mips_isa = chosen_arch->isa;
00537 mips_cp0_names = chosen_arch->cp0_names;
00538 mips_cp0sel_names = chosen_arch->cp0sel_names;
00539 mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
00540 mips_hwr_names = chosen_arch->hwr_names;
00541 }
00542 #endif
00543 }
00544
00545 void
00546 parse_mips_dis_option (option, len)
00547 const char *option;
00548 unsigned int len;
00549 {
00550 unsigned int i, optionlen, vallen;
00551 const char *val;
00552 const struct mips_abi_choice *chosen_abi;
00553 const struct mips_arch_choice *chosen_arch;
00554
00555
00556 if (strncmp (option, "no-aliases", 10) == 0)
00557 {
00558 no_aliases = 1;
00559 return;
00560 }
00561
00562
00563 for (i = 0; i < len; i++)
00564 {
00565 if (option[i] == '=')
00566 break;
00567 }
00568 if (i == 0)
00569 return;
00570 if (i == len)
00571 return;
00572 if (i == (len - 1))
00573 return;
00574
00575 optionlen = i;
00576 val = option + (optionlen + 1);
00577 vallen = len - (optionlen + 1);
00578
00579 if (strncmp("gpr-names", option, optionlen) == 0
00580 && strlen("gpr-names") == optionlen)
00581 {
00582 chosen_abi = choose_abi_by_name (val, vallen);
00583 if (chosen_abi != NULL)
00584 mips_gpr_names = chosen_abi->gpr_names;
00585 return;
00586 }
00587
00588 if (strncmp("fpr-names", option, optionlen) == 0
00589 && strlen("fpr-names") == optionlen)
00590 {
00591 chosen_abi = choose_abi_by_name (val, vallen);
00592 if (chosen_abi != NULL)
00593 mips_fpr_names = chosen_abi->fpr_names;
00594 return;
00595 }
00596
00597 if (strncmp("cp0-names", option, optionlen) == 0
00598 && strlen("cp0-names") == optionlen)
00599 {
00600 chosen_arch = choose_arch_by_name (val, vallen);
00601 if (chosen_arch != NULL)
00602 {
00603 mips_cp0_names = chosen_arch->cp0_names;
00604 mips_cp0sel_names = chosen_arch->cp0sel_names;
00605 mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
00606 }
00607 return;
00608 }
00609
00610 if (strncmp("hwr-names", option, optionlen) == 0
00611 && strlen("hwr-names") == optionlen)
00612 {
00613 chosen_arch = choose_arch_by_name (val, vallen);
00614 if (chosen_arch != NULL)
00615 mips_hwr_names = chosen_arch->hwr_names;
00616 return;
00617 }
00618
00619 if (strncmp("reg-names", option, optionlen) == 0
00620 && strlen("reg-names") == optionlen)
00621 {
00622
00623
00624
00625
00626 chosen_abi = choose_abi_by_name (val, vallen);
00627 if (chosen_abi != NULL)
00628 {
00629 mips_gpr_names = chosen_abi->gpr_names;
00630 mips_fpr_names = chosen_abi->fpr_names;
00631 }
00632 chosen_arch = choose_arch_by_name (val, vallen);
00633 if (chosen_arch != NULL)
00634 {
00635 mips_cp0_names = chosen_arch->cp0_names;
00636 mips_cp0sel_names = chosen_arch->cp0sel_names;
00637 mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
00638 mips_hwr_names = chosen_arch->hwr_names;
00639 }
00640 return;
00641 }
00642
00643
00644 }
00645
00646 void
00647 parse_mips_dis_options (options)
00648 const char *options;
00649 {
00650 const char *option_end;
00651
00652 if (options == NULL)
00653 return;
00654
00655 while (*options != '\0')
00656 {
00657
00658 if (*options == ',')
00659 {
00660 options++;
00661 continue;
00662 }
00663
00664
00665 option_end = options + 1;
00666 while (*option_end != ',' && *option_end != '\0')
00667 option_end++;
00668
00669 parse_mips_dis_option (options, option_end - options);
00670
00671
00672
00673 options = option_end;
00674 }
00675 }
00676
00677 static const struct mips_cp0sel_name *
00678 lookup_mips_cp0sel_name(names, len, cp0reg, sel)
00679 const struct mips_cp0sel_name *names;
00680 unsigned int len, cp0reg, sel;
00681 {
00682 unsigned int i;
00683
00684 for (i = 0; i < len; i++)
00685 if (names[i].cp0reg == cp0reg && names[i].sel == sel)
00686 return &names[i];
00687 return NULL;
00688 }
00689
00690
00691
00692 static void
00693 print_insn_args (d, l, pc, info)
00694 const char *d;
00695 register unsigned long int l;
00696 bfd_vma pc;
00697 struct disassemble_info *info;
00698 {
00699 int op, delta;
00700 unsigned int lsb, msb, msbd;
00701
00702 lsb = 0;
00703
00704 for (; *d != '\0'; d++)
00705 {
00706 switch (*d)
00707 {
00708 case ',':
00709 case '(':
00710 case ')':
00711 case '[':
00712 case ']':
00713 (*info->fprintf_func) (info->stream, "%c", *d);
00714 break;
00715
00716 case '+':
00717
00718 d++;
00719 switch (*d)
00720 {
00721 case '\0':
00722
00723 (*info->fprintf_func) (info->stream,
00724 _("# internal error, incomplete extension sequence (+)"));
00725 return;
00726
00727 case 'A':
00728 lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
00729 (*info->fprintf_func) (info->stream, "0x%x", lsb);
00730 break;
00731
00732 case 'B':
00733 msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
00734 (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
00735 break;
00736
00737 case 'C':
00738 case 'H':
00739 msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
00740 (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
00741 break;
00742
00743 case 'D':
00744 {
00745 const struct mips_cp0sel_name *n;
00746 unsigned int cp0reg, sel;
00747
00748 cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
00749 sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
00750
00751
00752
00753
00754
00755
00756 n = lookup_mips_cp0sel_name(mips_cp0sel_names,
00757 mips_cp0sel_names_len, cp0reg, sel);
00758 if (n != NULL)
00759 (*info->fprintf_func) (info->stream, "%s", n->name);
00760 else
00761 (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
00762 break;
00763 }
00764
00765 case 'E':
00766 lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
00767 (*info->fprintf_func) (info->stream, "0x%x", lsb);
00768 break;
00769
00770 case 'F':
00771 msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
00772 (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
00773 break;
00774
00775 case 'G':
00776 msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
00777 (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
00778 break;
00779
00780 default:
00781
00782 (*info->fprintf_func) (info->stream,
00783 _("# internal error, undefined extension sequence (+%c)"),
00784 *d);
00785 return;
00786 }
00787 break;
00788
00789 case 's':
00790 case 'b':
00791 case 'r':
00792 case 'v':
00793 (*info->fprintf_func) (info->stream, "%s",
00794 mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
00795 break;
00796
00797 case 't':
00798 case 'w':
00799 (*info->fprintf_func) (info->stream, "%s",
00800 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
00801 break;
00802
00803 case 'i':
00804 case 'u':
00805 (*info->fprintf_func) (info->stream, "0x%x",
00806 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
00807 break;
00808
00809 case 'j':
00810 case 'o':
00811 delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
00812 if (delta & 0x8000)
00813 delta |= ~0xffff;
00814 (*info->fprintf_func) (info->stream, "%d",
00815 delta);
00816 break;
00817
00818 case 'h':
00819 (*info->fprintf_func) (info->stream, "0x%x",
00820 (unsigned int) ((l >> OP_SH_PREFX)
00821 & OP_MASK_PREFX));
00822 break;
00823
00824 case 'k':
00825 (*info->fprintf_func) (info->stream, "0x%x",
00826 (unsigned int) ((l >> OP_SH_CACHE)
00827 & OP_MASK_CACHE));
00828 break;
00829
00830 case 'a':
00831 info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
00832 | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
00833 (*info->print_address_func) (info->target, info);
00834 break;
00835
00836 case 'p':
00837
00838 delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
00839 if (delta & 0x8000)
00840 delta |= ~0xffff;
00841 info->target = (delta << 2) + pc + INSNLEN;
00842 (*info->print_address_func) (info->target, info);
00843 break;
00844
00845 case 'd':
00846 (*info->fprintf_func) (info->stream, "%s",
00847 mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
00848 break;
00849
00850 case 'U':
00851 {
00852
00853 unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
00854 if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
00855 (*info->fprintf_func) (info->stream, "%s",
00856 mips_gpr_names[reg]);
00857 else
00858 {
00859
00860 if (reg == 0)
00861 (*info->fprintf_func) (info->stream, "%s",
00862 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
00863 else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
00864 (*info->fprintf_func) (info->stream, "%s",
00865 mips_gpr_names[reg]);
00866 else
00867 (*info->fprintf_func) (info->stream, "%s or %s",
00868 mips_gpr_names[reg],
00869 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
00870 }
00871 }
00872 break;
00873
00874 case 'z':
00875 (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
00876 break;
00877
00878 case '<':
00879 (*info->fprintf_func) (info->stream, "0x%x",
00880 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
00881 break;
00882
00883 case 'c':
00884 (*info->fprintf_func) (info->stream, "0x%x",
00885 (l >> OP_SH_CODE) & OP_MASK_CODE);
00886 break;
00887
00888 case 'q':
00889 (*info->fprintf_func) (info->stream, "0x%x",
00890 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
00891 break;
00892
00893 case 'C':
00894 (*info->fprintf_func) (info->stream, "0x%x",
00895 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
00896 break;
00897
00898 case 'B':
00899 (*info->fprintf_func) (info->stream, "0x%x",
00900 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
00901 break;
00902
00903 case 'J':
00904 (*info->fprintf_func) (info->stream, "0x%x",
00905 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
00906 break;
00907
00908 case 'S':
00909 case 'V':
00910 (*info->fprintf_func) (info->stream, "%s",
00911 mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
00912 break;
00913
00914 case 'T':
00915 case 'W':
00916 (*info->fprintf_func) (info->stream, "%s",
00917 mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
00918 break;
00919
00920 case 'D':
00921 (*info->fprintf_func) (info->stream, "%s",
00922 mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
00923 break;
00924
00925 case 'R':
00926 (*info->fprintf_func) (info->stream, "%s",
00927 mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
00928 break;
00929
00930 case 'E':
00931
00932
00933
00934
00935
00936
00937
00938 (*info->fprintf_func) (info->stream, "$%d",
00939 (l >> OP_SH_RT) & OP_MASK_RT);
00940 break;
00941
00942 case 'G':
00943
00944
00945
00946
00947 op = (l >> OP_SH_OP) & OP_MASK_OP;
00948 if (op == OP_OP_COP0)
00949 (*info->fprintf_func) (info->stream, "%s",
00950 mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
00951 else
00952 (*info->fprintf_func) (info->stream, "$%d",
00953 (l >> OP_SH_RD) & OP_MASK_RD);
00954 break;
00955
00956 case 'K':
00957 (*info->fprintf_func) (info->stream, "%s",
00958 mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
00959 break;
00960
00961 case 'N':
00962 (*info->fprintf_func) (info->stream, "$fcc%d",
00963 (l >> OP_SH_BCC) & OP_MASK_BCC);
00964 break;
00965
00966 case 'M':
00967 (*info->fprintf_func) (info->stream, "$fcc%d",
00968 (l >> OP_SH_CCC) & OP_MASK_CCC);
00969 break;
00970
00971 case 'P':
00972 (*info->fprintf_func) (info->stream, "%d",
00973 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
00974 break;
00975
00976 case 'e':
00977 (*info->fprintf_func) (info->stream, "%d",
00978 (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
00979 break;
00980
00981 case '%':
00982 (*info->fprintf_func) (info->stream, "%d",
00983 (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
00984 break;
00985
00986 case 'H':
00987 (*info->fprintf_func) (info->stream, "%d",
00988 (l >> OP_SH_SEL) & OP_MASK_SEL);
00989 break;
00990
00991 case 'O':
00992 (*info->fprintf_func) (info->stream, "%d",
00993 (l >> OP_SH_ALN) & OP_MASK_ALN);
00994 break;
00995
00996 case 'Q':
00997 {
00998 unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
00999 if ((vsel & 0x10) == 0)
01000 {
01001 int fmt;
01002 vsel &= 0x0f;
01003 for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
01004 if ((vsel & 1) == 0)
01005 break;
01006 (*info->fprintf_func) (info->stream, "$v%d[%d]",
01007 (l >> OP_SH_FT) & OP_MASK_FT,
01008 vsel >> 1);
01009 }
01010 else if ((vsel & 0x08) == 0)
01011 {
01012 (*info->fprintf_func) (info->stream, "$v%d",
01013 (l >> OP_SH_FT) & OP_MASK_FT);
01014 }
01015 else
01016 {
01017 (*info->fprintf_func) (info->stream, "0x%x",
01018 (l >> OP_SH_FT) & OP_MASK_FT);
01019 }
01020 }
01021 break;
01022
01023 case 'X':
01024 (*info->fprintf_func) (info->stream, "$v%d",
01025 (l >> OP_SH_FD) & OP_MASK_FD);
01026 break;
01027
01028 case 'Y':
01029 (*info->fprintf_func) (info->stream, "$v%d",
01030 (l >> OP_SH_FS) & OP_MASK_FS);
01031 break;
01032
01033 case 'Z':
01034 (*info->fprintf_func) (info->stream, "$v%d",
01035 (l >> OP_SH_FT) & OP_MASK_FT);
01036 break;
01037
01038 default:
01039
01040 (*info->fprintf_func) (info->stream,
01041 _("# internal error, undefined modifier(%c)"),
01042 *d);
01043 return;
01044 }
01045 }
01046 }
01047
01048
01049
01050 static int
01051 is_newabi (header)
01052 Elf_Internal_Ehdr *header;
01053 {
01054
01055 if (header->e_ident[EI_CLASS] == ELFCLASS64)
01056 return 1;
01057
01058
01059 if ((header->e_flags & EF_MIPS_ABI2) != 0)
01060 return 1;
01061
01062 return 0;
01063 }
01064
01065
01066
01067
01068
01069
01070 static int
01071 print_insn_mips (memaddr, word, info)
01072 bfd_vma memaddr;
01073 unsigned long int word;
01074 struct disassemble_info *info;
01075 {
01076 register const struct mips_opcode *op;
01077 static bfd_boolean init = 0;
01078 static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
01079
01080
01081 if (! init)
01082 {
01083 unsigned int i;
01084
01085 for (i = 0; i <= OP_MASK_OP; i++)
01086 {
01087 for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
01088 {
01089 if (op->pinfo == INSN_MACRO
01090 || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
01091 continue;
01092 if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
01093 {
01094 mips_hash[i] = op;
01095 break;
01096 }
01097 }
01098 }
01099
01100 init = 1;
01101 }
01102
01103 info->bytes_per_chunk = INSNLEN;
01104 info->display_endian = info->endian;
01105 info->insn_info_valid = 1;
01106 info->branch_delay_insns = 0;
01107 info->data_size = 0;
01108 info->insn_type = dis_nonbranch;
01109 info->target = 0;
01110 info->target2 = 0;
01111
01112 op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
01113 if (op != NULL)
01114 {
01115 for (; op < &mips_opcodes[NUMOPCODES]; op++)
01116 {
01117 if (op->pinfo != INSN_MACRO
01118 && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
01119 && (word & op->mask) == op->match)
01120 {
01121 register const char *d;
01122
01123
01124 if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
01125 && strcmp (op->name, "jalx"))
01126 continue;
01127
01128
01129 if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
01130 {
01131 if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
01132 info->insn_type = dis_jsr;
01133 else
01134 info->insn_type = dis_branch;
01135 info->branch_delay_insns = 1;
01136 }
01137 else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
01138 | INSN_COND_BRANCH_LIKELY)) != 0)
01139 {
01140 if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
01141 info->insn_type = dis_condjsr;
01142 else
01143 info->insn_type = dis_condbranch;
01144 info->branch_delay_insns = 1;
01145 }
01146 else if ((op->pinfo & (INSN_STORE_MEMORY
01147 | INSN_LOAD_MEMORY_DELAY)) != 0)
01148 info->insn_type = dis_dref;
01149
01150 (*info->fprintf_func) (info->stream, "%s", op->name);
01151
01152 d = op->args;
01153 if (d != NULL && *d != '\0')
01154 {
01155 (*info->fprintf_func) (info->stream, "\t");
01156 print_insn_args (d, word, memaddr, info);
01157 }
01158
01159 return INSNLEN;
01160 }
01161 }
01162 }
01163
01164
01165 info->insn_type = dis_noninsn;
01166 (*info->fprintf_func) (info->stream, "0x%x", word);
01167 return INSNLEN;
01168 }
01169
01170
01171
01172
01173
01174
01175
01176 static int
01177 _print_insn_mips (memaddr, info, endianness)
01178 bfd_vma memaddr;
01179 struct disassemble_info *info;
01180 enum bfd_endian endianness;
01181 {
01182 bfd_byte buffer[INSNLEN];
01183 int status;
01184
01185 set_default_mips_dis_options (info);
01186 parse_mips_dis_options (info->disassembler_options);
01187
01188 #if 1
01189
01190
01191 if (memaddr & 0x01)
01192 return print_insn_mips16 (memaddr, info);
01193 #endif
01194
01195 #if SYMTAB_AVAILABLE
01196 if (info->mach == bfd_mach_mips16
01197 || (info->flavour == bfd_target_elf_flavour
01198 && info->symbols != NULL
01199 && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
01200 == STO_MIPS16)))
01201 return print_insn_mips16 (memaddr, info);
01202 #endif
01203
01204 status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
01205 if (status == 0)
01206 {
01207 unsigned long insn;
01208
01209 if (endianness == BFD_ENDIAN_BIG)
01210 insn = (unsigned long) bfd_getb32 (buffer);
01211 else
01212 insn = (unsigned long) bfd_getl32 (buffer);
01213
01214 return print_insn_mips (memaddr, insn, info);
01215 }
01216 else
01217 {
01218 (*info->memory_error_func) (status, memaddr, info);
01219 return -1;
01220 }
01221 }
01222
01223 int
01224 print_insn_big_mips (memaddr, info)
01225 bfd_vma memaddr;
01226 struct disassemble_info *info;
01227 {
01228 return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
01229 }
01230
01231 int
01232 print_insn_little_mips (memaddr, info)
01233 bfd_vma memaddr;
01234 struct disassemble_info *info;
01235 {
01236 return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
01237 }
01238
01239
01240
01241 static int
01242 print_insn_mips16 (memaddr, info)
01243 bfd_vma memaddr;
01244 struct disassemble_info *info;
01245 {
01246 int status;
01247 bfd_byte buffer[2];
01248 int length;
01249 int insn;
01250 bfd_boolean use_extend;
01251 int extend = 0;
01252 const struct mips_opcode *op, *opend;
01253
01254 info->bytes_per_chunk = 2;
01255 info->display_endian = info->endian;
01256 info->insn_info_valid = 1;
01257 info->branch_delay_insns = 0;
01258 info->data_size = 0;
01259 info->insn_type = dis_nonbranch;
01260 info->target = 0;
01261 info->target2 = 0;
01262
01263 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
01264 if (status != 0)
01265 {
01266 (*info->memory_error_func) (status, memaddr, info);
01267 return -1;
01268 }
01269
01270 length = 2;
01271
01272 if (info->endian == BFD_ENDIAN_BIG)
01273 insn = bfd_getb16 (buffer);
01274 else
01275 insn = bfd_getl16 (buffer);
01276
01277
01278 use_extend = FALSE;
01279 if ((insn & 0xf800) == 0xf000)
01280 {
01281 use_extend = TRUE;
01282 extend = insn & 0x7ff;
01283
01284 memaddr += 2;
01285
01286 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
01287 if (status != 0)
01288 {
01289 (*info->fprintf_func) (info->stream, "extend 0x%x",
01290 (unsigned int) extend);
01291 (*info->memory_error_func) (status, memaddr, info);
01292 return -1;
01293 }
01294
01295 if (info->endian == BFD_ENDIAN_BIG)
01296 insn = bfd_getb16 (buffer);
01297 else
01298 insn = bfd_getl16 (buffer);
01299
01300
01301 if ((insn & 0xf800) == 0xf000)
01302 {
01303 (*info->fprintf_func) (info->stream, "extend 0x%x",
01304 (unsigned int) extend);
01305 info->insn_type = dis_noninsn;
01306 return length;
01307 }
01308
01309 length += 2;
01310 }
01311
01312
01313
01314 opend = mips16_opcodes + bfd_mips16_num_opcodes;
01315 for (op = mips16_opcodes; op < opend; op++)
01316 {
01317 if (op->pinfo != INSN_MACRO
01318 && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
01319 && (insn & op->mask) == op->match)
01320 {
01321 const char *s;
01322
01323 if (strchr (op->args, 'a') != NULL)
01324 {
01325 if (use_extend)
01326 {
01327 (*info->fprintf_func) (info->stream, "extend 0x%x",
01328 (unsigned int) extend);
01329 info->insn_type = dis_noninsn;
01330 return length - 2;
01331 }
01332
01333 use_extend = FALSE;
01334
01335 memaddr += 2;
01336
01337 status = (*info->read_memory_func) (memaddr, buffer, 2,
01338 info);
01339 if (status == 0)
01340 {
01341 use_extend = TRUE;
01342 if (info->endian == BFD_ENDIAN_BIG)
01343 extend = bfd_getb16 (buffer);
01344 else
01345 extend = bfd_getl16 (buffer);
01346 length += 2;
01347 }
01348 }
01349
01350 (*info->fprintf_func) (info->stream, "%s", op->name);
01351 if (op->args[0] != '\0')
01352 (*info->fprintf_func) (info->stream, "\t");
01353
01354 for (s = op->args; *s != '\0'; s++)
01355 {
01356 if (*s == ','
01357 && s[1] == 'w'
01358 && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
01359 == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
01360 {
01361
01362 ++s;
01363 continue;
01364 }
01365 if (*s == ','
01366 && s[1] == 'v'
01367 && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
01368 == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
01369 {
01370
01371 ++s;
01372 continue;
01373 }
01374 print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
01375 info);
01376 }
01377
01378 if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
01379 {
01380 info->branch_delay_insns = 1;
01381 if (info->insn_type != dis_jsr)
01382 info->insn_type = dis_branch;
01383 }
01384
01385 return length;
01386 }
01387 }
01388
01389 if (use_extend)
01390 (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
01391 (*info->fprintf_func) (info->stream, "0x%x", insn);
01392 info->insn_type = dis_noninsn;
01393
01394 return length;
01395 }
01396
01397
01398
01399 static void
01400 print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
01401 char type;
01402 const struct mips_opcode *op;
01403 int l;
01404 bfd_boolean use_extend;
01405 int extend;
01406 bfd_vma memaddr;
01407 struct disassemble_info *info;
01408 {
01409 switch (type)
01410 {
01411 case ',':
01412 case '(':
01413 case ')':
01414 (*info->fprintf_func) (info->stream, "%c", type);
01415 break;
01416
01417 case 'y':
01418 case 'w':
01419 (*info->fprintf_func) (info->stream, "%s",
01420 mips16_reg_names[((l >> MIPS16OP_SH_RY)
01421 & MIPS16OP_MASK_RY)]);
01422 break;
01423
01424 case 'x':
01425 case 'v':
01426 (*info->fprintf_func) (info->stream, "%s",
01427 mips16_reg_names[((l >> MIPS16OP_SH_RX)
01428 & MIPS16OP_MASK_RX)]);
01429 break;
01430
01431 case 'z':
01432 (*info->fprintf_func) (info->stream, "%s",
01433 mips16_reg_names[((l >> MIPS16OP_SH_RZ)
01434 & MIPS16OP_MASK_RZ)]);
01435 break;
01436
01437 case 'Z':
01438 (*info->fprintf_func) (info->stream, "%s",
01439 mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
01440 & MIPS16OP_MASK_MOVE32Z)]);
01441 break;
01442
01443 case '0':
01444 (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
01445 break;
01446
01447 case 'S':
01448 (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
01449 break;
01450
01451 case 'P':
01452 (*info->fprintf_func) (info->stream, "$pc");
01453 break;
01454
01455 case 'R':
01456 (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
01457 break;
01458
01459 case 'X':
01460 (*info->fprintf_func) (info->stream, "%s",
01461 mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
01462 & MIPS16OP_MASK_REGR32)]);
01463 break;
01464
01465 case 'Y':
01466 (*info->fprintf_func) (info->stream, "%s",
01467 mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
01468 break;
01469
01470 case '<':
01471 case '>':
01472 case '[':
01473 case ']':
01474 case '4':
01475 case '5':
01476 case 'H':
01477 case 'W':
01478 case 'D':
01479 case 'j':
01480 case '6':
01481 case '8':
01482 case 'V':
01483 case 'C':
01484 case 'U':
01485 case 'k':
01486 case 'K':
01487 case 'p':
01488 case 'q':
01489 case 'A':
01490 case 'B':
01491 case 'E':
01492 {
01493 int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
01494
01495 shift = 0;
01496 signedp = 0;
01497 extbits = 16;
01498 pcrel = 0;
01499 extu = 0;
01500 branch = 0;
01501 switch (type)
01502 {
01503 case '<':
01504 nbits = 3;
01505 immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
01506 extbits = 5;
01507 extu = 1;
01508 break;
01509 case '>':
01510 nbits = 3;
01511 immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
01512 extbits = 5;
01513 extu = 1;
01514 break;
01515 case '[':
01516 nbits = 3;
01517 immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
01518 extbits = 6;
01519 extu = 1;
01520 break;
01521 case ']':
01522 nbits = 3;
01523 immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
01524 extbits = 6;
01525 extu = 1;
01526 break;
01527 case '4':
01528 nbits = 4;
01529 immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
01530 signedp = 1;
01531 extbits = 15;
01532 break;
01533 case '5':
01534 nbits = 5;
01535 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01536 info->insn_type = dis_dref;
01537 info->data_size = 1;
01538 break;
01539 case 'H':
01540 nbits = 5;
01541 shift = 1;
01542 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01543 info->insn_type = dis_dref;
01544 info->data_size = 2;
01545 break;
01546 case 'W':
01547 nbits = 5;
01548 shift = 2;
01549 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01550 if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
01551 && (op->pinfo & MIPS16_INSN_READ_SP) == 0)
01552 {
01553 info->insn_type = dis_dref;
01554 info->data_size = 4;
01555 }
01556 break;
01557 case 'D':
01558 nbits = 5;
01559 shift = 3;
01560 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01561 info->insn_type = dis_dref;
01562 info->data_size = 8;
01563 break;
01564 case 'j':
01565 nbits = 5;
01566 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01567 signedp = 1;
01568 break;
01569 case '6':
01570 nbits = 6;
01571 immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
01572 break;
01573 case '8':
01574 nbits = 8;
01575 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01576 break;
01577 case 'V':
01578 nbits = 8;
01579 shift = 2;
01580 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01581
01582
01583 info->insn_type = dis_dref;
01584 info->data_size = 4;
01585 break;
01586 case 'C':
01587 nbits = 8;
01588 shift = 3;
01589 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01590 info->insn_type = dis_dref;
01591 info->data_size = 8;
01592 break;
01593 case 'U':
01594 nbits = 8;
01595 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01596 extu = 1;
01597 break;
01598 case 'k':
01599 nbits = 8;
01600 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01601 signedp = 1;
01602 break;
01603 case 'K':
01604 nbits = 8;
01605 shift = 3;
01606 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01607 signedp = 1;
01608 break;
01609 case 'p':
01610 nbits = 8;
01611 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01612 signedp = 1;
01613 pcrel = 1;
01614 branch = 1;
01615 info->insn_type = dis_condbranch;
01616 break;
01617 case 'q':
01618 nbits = 11;
01619 immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
01620 signedp = 1;
01621 pcrel = 1;
01622 branch = 1;
01623 info->insn_type = dis_branch;
01624 break;
01625 case 'A':
01626 nbits = 8;
01627 shift = 2;
01628 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
01629 pcrel = 1;
01630
01631 info->insn_type = dis_dref;
01632 info->data_size = 4;
01633 break;
01634 case 'B':
01635 nbits = 5;
01636 shift = 3;
01637 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01638 pcrel = 1;
01639 info->insn_type = dis_dref;
01640 info->data_size = 8;
01641 break;
01642 case 'E':
01643 nbits = 5;
01644 shift = 2;
01645 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
01646 pcrel = 1;
01647 break;
01648 default:
01649 abort ();
01650 }
01651
01652 if (! use_extend)
01653 {
01654 if (signedp && immed >= (1 << (nbits - 1)))
01655 immed -= 1 << nbits;
01656 immed <<= shift;
01657 if ((type == '<' || type == '>' || type == '[' || type == ']')
01658 && immed == 0)
01659 immed = 8;
01660 }
01661 else
01662 {
01663 if (extbits == 16)
01664 immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
01665 else if (extbits == 15)
01666 immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
01667 else
01668 immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
01669 immed &= (1 << extbits) - 1;
01670 if (! extu && immed >= (1 << (extbits - 1)))
01671 immed -= 1 << extbits;
01672 }
01673
01674 if (! pcrel)
01675 (*info->fprintf_func) (info->stream, "%d", immed);
01676 else
01677 {
01678 bfd_vma baseaddr;
01679
01680 if (branch)
01681 {
01682 immed *= 2;
01683 baseaddr = memaddr + 2;
01684 }
01685 else if (use_extend)
01686 baseaddr = memaddr - 2;
01687 else
01688 {
01689 int status;
01690 bfd_byte buffer[2];
01691
01692 baseaddr = memaddr;
01693
01694
01695
01696
01697
01698
01699
01700
01701 status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
01702 info);
01703 if (status == 0
01704 && (((info->endian == BFD_ENDIAN_BIG
01705 ? bfd_getb16 (buffer)
01706 : bfd_getl16 (buffer))
01707 & 0xf800) == 0x1800))
01708 baseaddr = memaddr - 4;
01709 else
01710 {
01711 status = (*info->read_memory_func) (memaddr - 2, buffer,
01712 2, info);
01713 if (status == 0
01714 && (((info->endian == BFD_ENDIAN_BIG
01715 ? bfd_getb16 (buffer)
01716 : bfd_getl16 (buffer))
01717 & 0xf81f) == 0xe800))
01718 baseaddr = memaddr - 2;
01719 }
01720 }
01721 info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
01722 (*info->print_address_func) (info->target, info);
01723 }
01724 }
01725 break;
01726
01727 case 'a':
01728 if (! use_extend)
01729 extend = 0;
01730 l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
01731 info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
01732 (*info->print_address_func) (info->target, info);
01733 info->insn_type = dis_jsr;
01734 info->branch_delay_insns = 1;
01735 break;
01736
01737 case 'l':
01738 case 'L':
01739 {
01740 int need_comma, amask, smask;
01741
01742 need_comma = 0;
01743
01744 l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
01745
01746 amask = (l >> 3) & 7;
01747
01748 if (amask > 0 && amask < 5)
01749 {
01750 (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
01751 if (amask > 1)
01752 (*info->fprintf_func) (info->stream, "-%s",
01753 mips_gpr_names[amask + 3]);
01754 need_comma = 1;
01755 }
01756
01757 smask = (l >> 1) & 3;
01758 if (smask == 3)
01759 {
01760 (*info->fprintf_func) (info->stream, "%s??",
01761 need_comma ? "," : "");
01762 need_comma = 1;
01763 }
01764 else if (smask > 0)
01765 {
01766 (*info->fprintf_func) (info->stream, "%s%s",
01767 need_comma ? "," : "",
01768 mips_gpr_names[16]);
01769 if (smask > 1)
01770 (*info->fprintf_func) (info->stream, "-%s",
01771 mips_gpr_names[smask + 15]);
01772 need_comma = 1;
01773 }
01774
01775 if (l & 1)
01776 {
01777 (*info->fprintf_func) (info->stream, "%s%s",
01778 need_comma ? "," : "",
01779 mips_gpr_names[31]);
01780 need_comma = 1;
01781 }
01782
01783 if (amask == 5 || amask == 6)
01784 {
01785 (*info->fprintf_func) (info->stream, "%s$f0",
01786 need_comma ? "," : "");
01787 if (amask == 6)
01788 (*info->fprintf_func) (info->stream, "-$f1");
01789 }
01790 }
01791 break;
01792
01793 default:
01794
01795 (*info->fprintf_func)
01796 (info->stream,
01797 _("# internal disassembler error, unrecognised modifier (%c)"),
01798 type);
01799 abort ();
01800 }
01801 }
01802
01803 void
01804 print_mips_disassembler_options (stream)
01805 FILE *stream;
01806 {
01807 unsigned int i;
01808
01809 fprintf (stream, _("\n\
01810 The following MIPS specific disassembler options are supported for use\n\
01811 with the -M switch (multiple options should be separated by commas):\n"));
01812
01813 fprintf (stream, _("\n\
01814 gpr-names=ABI Print GPR names according to specified ABI.\n\
01815 Default: based on binary being disassembled.\n"));
01816
01817 fprintf (stream, _("\n\
01818 fpr-names=ABI Print FPR names according to specified ABI.\n\
01819 Default: numeric.\n"));
01820
01821 fprintf (stream, _("\n\
01822 cp0-names=ARCH Print CP0 register names according to\n\
01823 specified architecture.\n\
01824 Default: based on binary being disassembled.\n"));
01825
01826 fprintf (stream, _("\n\
01827 hwr-names=ARCH Print HWR names according to specified \n\
01828 architecture.\n\
01829 Default: based on binary being disassembled.\n"));
01830
01831 fprintf (stream, _("\n\
01832 reg-names=ABI Print GPR and FPR names according to\n\
01833 specified ABI.\n"));
01834
01835 fprintf (stream, _("\n\
01836 reg-names=ARCH Print CP0 register and HWR names according to\n\
01837 specified architecture.\n"));
01838
01839 fprintf (stream, _("\n\
01840 For the options above, the following values are supported for \"ABI\":\n\
01841 "));
01842 for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
01843 fprintf (stream, " %s", mips_abi_choices[i].name);
01844 fprintf (stream, _("\n"));
01845
01846 fprintf (stream, _("\n\
01847 For the options above, The following values are supported for \"ARCH\":\n\
01848 "));
01849 for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
01850 if (*mips_arch_choices[i].name != '\0')
01851 fprintf (stream, " %s", mips_arch_choices[i].name);
01852 fprintf (stream, _("\n"));
01853
01854 fprintf (stream, _("\n"));
01855 }