1179404Sobrien/* Print mips instructions for GDB, the GNU debugger, or for objdump. 2179404Sobrien Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 3208737Sjmallett 2000, 2001, 2002, 2003, 2005 4179404Sobrien Free Software Foundation, Inc. 5179404Sobrien Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). 6179404Sobrien 7208737Sjmallett This file is part of GDB, GAS, and the GNU binutils. 8179404Sobrien 9208737Sjmallett This program is free software; you can redistribute it and/or modify 10208737Sjmallett it under the terms of the GNU General Public License as published by 11208737Sjmallett the Free Software Foundation; either version 2 of the License, or 12208737Sjmallett (at your option) any later version. 13179404Sobrien 14208737Sjmallett This program is distributed in the hope that it will be useful, 15208737Sjmallett but WITHOUT ANY WARRANTY; without even the implied warranty of 16208737Sjmallett MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17208737Sjmallett GNU General Public License for more details. 18179404Sobrien 19208737Sjmallett You should have received a copy of the GNU General Public License 20208737Sjmallett along with this program; if not, write to the Free Software 21208737Sjmallett Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 22208737Sjmallett MA 02110-1301, USA. */ 23179404Sobrien 24179404Sobrien#include "sysdep.h" 25179404Sobrien#include "dis-asm.h" 26179404Sobrien#include "libiberty.h" 27179404Sobrien#include "opcode/mips.h" 28179404Sobrien#include "opintl.h" 29179404Sobrien 30179404Sobrien/* FIXME: These are needed to figure out if the code is mips16 or 31179404Sobrien not. The low bit of the address is often a good indicator. No 32179404Sobrien symbol table is available when this code runs out in an embedded 33179404Sobrien system as when it is used for disassembler support in a monitor. */ 34179404Sobrien 35179404Sobrien#if !defined(EMBEDDED_ENV) 36179404Sobrien#define SYMTAB_AVAILABLE 1 37179404Sobrien#include "elf-bfd.h" 38179404Sobrien#include "elf/mips.h" 39179404Sobrien#endif 40179404Sobrien 41179404Sobrien/* Mips instructions are at maximum this many bytes long. */ 42179404Sobrien#define INSNLEN 4 43179404Sobrien 44208737Sjmallett/* Generate Octeon/MIPS unaligned load and store instructions. */ 45208737Sjmallett#ifdef INCLUDE_OCTEON_USEUN 46208737Sjmallettint octeon_use_unalign = 1; 47208737Sjmallett#else 48208737Sjmallettint octeon_use_unalign = 0; 49208737Sjmallett#endif 50208737Sjmallett 51179404Sobrien 52179404Sobrien/* FIXME: These should be shared with gdb somehow. */ 53179404Sobrien 54208737Sjmallettstruct mips_cp0sel_name 55208737Sjmallett{ 56208737Sjmallett unsigned int cp0reg; 57208737Sjmallett unsigned int sel; 58208737Sjmallett const char * const name; 59179404Sobrien}; 60179404Sobrien 61218822Sdim/* The mips16 registers. */ 62218822Sdimstatic const unsigned int mips16_to_32_reg_map[] = 63208737Sjmallett{ 64218822Sdim 16, 17, 2, 3, 4, 5, 6, 7 65179404Sobrien}; 66179404Sobrien 67218822Sdim#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] 68218822Sdim 69218822Sdim 70208737Sjmallettstatic const char * const mips_gpr_names_numeric[32] = 71208737Sjmallett{ 72179404Sobrien "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 73179404Sobrien "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 74179404Sobrien "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 75179404Sobrien "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" 76179404Sobrien}; 77179404Sobrien 78208737Sjmallettstatic const char * const mips_gpr_names_oldabi[32] = 79208737Sjmallett{ 80179404Sobrien "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 81179404Sobrien "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 82179404Sobrien "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 83179404Sobrien "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 84179404Sobrien}; 85179404Sobrien 86208737Sjmallettstatic const char * const mips_gpr_names_newabi[32] = 87208737Sjmallett{ 88179404Sobrien "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 89179404Sobrien "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", 90179404Sobrien "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 91179404Sobrien "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 92179404Sobrien}; 93179404Sobrien 94208737Sjmallettstatic const char * const mips_fpr_names_numeric[32] = 95208737Sjmallett{ 96179404Sobrien "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 97179404Sobrien "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 98179404Sobrien "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 99179404Sobrien "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" 100179404Sobrien}; 101179404Sobrien 102208737Sjmallettstatic const char * const mips_fpr_names_32[32] = 103208737Sjmallett{ 104179404Sobrien "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f", 105179404Sobrien "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f", 106179404Sobrien "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f", 107179404Sobrien "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f" 108179404Sobrien}; 109179404Sobrien 110208737Sjmallettstatic const char * const mips_fpr_names_n32[32] = 111208737Sjmallett{ 112179404Sobrien "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3", 113179404Sobrien "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", 114179404Sobrien "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9", 115179404Sobrien "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13" 116179404Sobrien}; 117179404Sobrien 118208737Sjmallettstatic const char * const mips_fpr_names_64[32] = 119208737Sjmallett{ 120179404Sobrien "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", 121179404Sobrien "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", 122179404Sobrien "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", 123179404Sobrien "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" 124179404Sobrien}; 125179404Sobrien 126208737Sjmallettstatic const char * const mips_cp0_names_numeric[32] = 127208737Sjmallett{ 128179404Sobrien "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 129179404Sobrien "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 130179404Sobrien "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 131179404Sobrien "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" 132179404Sobrien}; 133179404Sobrien 134208737Sjmallettstatic const char * const mips_cp0_names_mips3264[32] = 135208737Sjmallett{ 136179404Sobrien "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", 137179404Sobrien "c0_context", "c0_pagemask", "c0_wired", "$7", 138179404Sobrien "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", 139179404Sobrien "c0_status", "c0_cause", "c0_epc", "c0_prid", 140179404Sobrien "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", 141179404Sobrien "c0_xcontext", "$21", "$22", "c0_debug", 142179404Sobrien "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", 143179404Sobrien "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", 144179404Sobrien}; 145179404Sobrien 146208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = 147208737Sjmallett{ 148179404Sobrien { 16, 1, "c0_config1" }, 149179404Sobrien { 16, 2, "c0_config2" }, 150179404Sobrien { 16, 3, "c0_config3" }, 151179404Sobrien { 18, 1, "c0_watchlo,1" }, 152179404Sobrien { 18, 2, "c0_watchlo,2" }, 153179404Sobrien { 18, 3, "c0_watchlo,3" }, 154179404Sobrien { 18, 4, "c0_watchlo,4" }, 155179404Sobrien { 18, 5, "c0_watchlo,5" }, 156179404Sobrien { 18, 6, "c0_watchlo,6" }, 157179404Sobrien { 18, 7, "c0_watchlo,7" }, 158179404Sobrien { 19, 1, "c0_watchhi,1" }, 159179404Sobrien { 19, 2, "c0_watchhi,2" }, 160179404Sobrien { 19, 3, "c0_watchhi,3" }, 161179404Sobrien { 19, 4, "c0_watchhi,4" }, 162179404Sobrien { 19, 5, "c0_watchhi,5" }, 163179404Sobrien { 19, 6, "c0_watchhi,6" }, 164179404Sobrien { 19, 7, "c0_watchhi,7" }, 165179404Sobrien { 25, 1, "c0_perfcnt,1" }, 166179404Sobrien { 25, 2, "c0_perfcnt,2" }, 167179404Sobrien { 25, 3, "c0_perfcnt,3" }, 168179404Sobrien { 25, 4, "c0_perfcnt,4" }, 169179404Sobrien { 25, 5, "c0_perfcnt,5" }, 170179404Sobrien { 25, 6, "c0_perfcnt,6" }, 171179404Sobrien { 25, 7, "c0_perfcnt,7" }, 172179404Sobrien { 27, 1, "c0_cacheerr,1" }, 173179404Sobrien { 27, 2, "c0_cacheerr,2" }, 174179404Sobrien { 27, 3, "c0_cacheerr,3" }, 175179404Sobrien { 28, 1, "c0_datalo" }, 176179404Sobrien { 29, 1, "c0_datahi" } 177179404Sobrien}; 178179404Sobrien 179208737Sjmallettstatic const char * const mips_cp0_names_mips3264r2[32] = 180208737Sjmallett{ 181179404Sobrien "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", 182179404Sobrien "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", 183179404Sobrien "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", 184179404Sobrien "c0_status", "c0_cause", "c0_epc", "c0_prid", 185179404Sobrien "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", 186179404Sobrien "c0_xcontext", "$21", "$22", "c0_debug", 187179404Sobrien "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", 188179404Sobrien "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", 189179404Sobrien}; 190179404Sobrien 191208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = 192208737Sjmallett{ 193179404Sobrien { 4, 1, "c0_contextconfig" }, 194218822Sdim { 0, 1, "c0_mvpcontrol" }, 195218822Sdim { 0, 2, "c0_mvpconf0" }, 196218822Sdim { 0, 3, "c0_mvpconf1" }, 197218822Sdim { 1, 1, "c0_vpecontrol" }, 198218822Sdim { 1, 2, "c0_vpeconf0" }, 199218822Sdim { 1, 3, "c0_vpeconf1" }, 200218822Sdim { 1, 4, "c0_yqmask" }, 201218822Sdim { 1, 5, "c0_vpeschedule" }, 202218822Sdim { 1, 6, "c0_vpeschefback" }, 203218822Sdim { 2, 1, "c0_tcstatus" }, 204218822Sdim { 2, 2, "c0_tcbind" }, 205218822Sdim { 2, 3, "c0_tcrestart" }, 206218822Sdim { 2, 4, "c0_tchalt" }, 207218822Sdim { 2, 5, "c0_tccontext" }, 208218822Sdim { 2, 6, "c0_tcschedule" }, 209218822Sdim { 2, 7, "c0_tcschefback" }, 210179404Sobrien { 5, 1, "c0_pagegrain" }, 211218822Sdim { 6, 1, "c0_srsconf0" }, 212218822Sdim { 6, 2, "c0_srsconf1" }, 213218822Sdim { 6, 3, "c0_srsconf2" }, 214218822Sdim { 6, 4, "c0_srsconf3" }, 215218822Sdim { 6, 5, "c0_srsconf4" }, 216179404Sobrien { 12, 1, "c0_intctl" }, 217179404Sobrien { 12, 2, "c0_srsctl" }, 218179404Sobrien { 12, 3, "c0_srsmap" }, 219179404Sobrien { 15, 1, "c0_ebase" }, 220179404Sobrien { 16, 1, "c0_config1" }, 221179404Sobrien { 16, 2, "c0_config2" }, 222179404Sobrien { 16, 3, "c0_config3" }, 223179404Sobrien { 18, 1, "c0_watchlo,1" }, 224179404Sobrien { 18, 2, "c0_watchlo,2" }, 225179404Sobrien { 18, 3, "c0_watchlo,3" }, 226179404Sobrien { 18, 4, "c0_watchlo,4" }, 227179404Sobrien { 18, 5, "c0_watchlo,5" }, 228179404Sobrien { 18, 6, "c0_watchlo,6" }, 229179404Sobrien { 18, 7, "c0_watchlo,7" }, 230179404Sobrien { 19, 1, "c0_watchhi,1" }, 231179404Sobrien { 19, 2, "c0_watchhi,2" }, 232179404Sobrien { 19, 3, "c0_watchhi,3" }, 233179404Sobrien { 19, 4, "c0_watchhi,4" }, 234179404Sobrien { 19, 5, "c0_watchhi,5" }, 235179404Sobrien { 19, 6, "c0_watchhi,6" }, 236179404Sobrien { 19, 7, "c0_watchhi,7" }, 237179404Sobrien { 23, 1, "c0_tracecontrol" }, 238179404Sobrien { 23, 2, "c0_tracecontrol2" }, 239179404Sobrien { 23, 3, "c0_usertracedata" }, 240179404Sobrien { 23, 4, "c0_tracebpc" }, 241179404Sobrien { 25, 1, "c0_perfcnt,1" }, 242179404Sobrien { 25, 2, "c0_perfcnt,2" }, 243179404Sobrien { 25, 3, "c0_perfcnt,3" }, 244179404Sobrien { 25, 4, "c0_perfcnt,4" }, 245179404Sobrien { 25, 5, "c0_perfcnt,5" }, 246179404Sobrien { 25, 6, "c0_perfcnt,6" }, 247179404Sobrien { 25, 7, "c0_perfcnt,7" }, 248179404Sobrien { 27, 1, "c0_cacheerr,1" }, 249179404Sobrien { 27, 2, "c0_cacheerr,2" }, 250179404Sobrien { 27, 3, "c0_cacheerr,3" }, 251179404Sobrien { 28, 1, "c0_datalo" }, 252179404Sobrien { 28, 2, "c0_taglo1" }, 253179404Sobrien { 28, 3, "c0_datalo1" }, 254179404Sobrien { 28, 4, "c0_taglo2" }, 255179404Sobrien { 28, 5, "c0_datalo2" }, 256179404Sobrien { 28, 6, "c0_taglo3" }, 257179404Sobrien { 28, 7, "c0_datalo3" }, 258179404Sobrien { 29, 1, "c0_datahi" }, 259179404Sobrien { 29, 2, "c0_taghi1" }, 260179404Sobrien { 29, 3, "c0_datahi1" }, 261179404Sobrien { 29, 4, "c0_taghi2" }, 262179404Sobrien { 29, 5, "c0_datahi2" }, 263179404Sobrien { 29, 6, "c0_taghi3" }, 264179404Sobrien { 29, 7, "c0_datahi3" }, 265179404Sobrien}; 266179404Sobrien 267179404Sobrien/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */ 268208737Sjmallettstatic const char * const mips_cp0_names_sb1[32] = 269208737Sjmallett{ 270179404Sobrien "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", 271179404Sobrien "c0_context", "c0_pagemask", "c0_wired", "$7", 272179404Sobrien "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", 273179404Sobrien "c0_status", "c0_cause", "c0_epc", "c0_prid", 274179404Sobrien "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", 275179404Sobrien "c0_xcontext", "$21", "$22", "c0_debug", 276179404Sobrien "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i", 277179404Sobrien "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave", 278179404Sobrien}; 279179404Sobrien 280208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = 281208737Sjmallett{ 282179404Sobrien { 16, 1, "c0_config1" }, 283179404Sobrien { 18, 1, "c0_watchlo,1" }, 284179404Sobrien { 19, 1, "c0_watchhi,1" }, 285179404Sobrien { 22, 0, "c0_perftrace" }, 286179404Sobrien { 23, 3, "c0_edebug" }, 287179404Sobrien { 25, 1, "c0_perfcnt,1" }, 288179404Sobrien { 25, 2, "c0_perfcnt,2" }, 289179404Sobrien { 25, 3, "c0_perfcnt,3" }, 290179404Sobrien { 25, 4, "c0_perfcnt,4" }, 291179404Sobrien { 25, 5, "c0_perfcnt,5" }, 292179404Sobrien { 25, 6, "c0_perfcnt,6" }, 293179404Sobrien { 25, 7, "c0_perfcnt,7" }, 294179404Sobrien { 26, 1, "c0_buserr_pa" }, 295179404Sobrien { 27, 1, "c0_cacheerr_d" }, 296179404Sobrien { 27, 3, "c0_cacheerr_d_pa" }, 297179404Sobrien { 28, 1, "c0_datalo_i" }, 298179404Sobrien { 28, 2, "c0_taglo_d" }, 299179404Sobrien { 28, 3, "c0_datalo_d" }, 300179404Sobrien { 29, 1, "c0_datahi_i" }, 301179404Sobrien { 29, 2, "c0_taghi_d" }, 302179404Sobrien { 29, 3, "c0_datahi_d" }, 303179404Sobrien}; 304179404Sobrien 305208737Sjmallettstatic const char * const mips_cp0_names_octeon[32] = { 306208737Sjmallett "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", 307208737Sjmallett "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", 308208737Sjmallett "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", 309208737Sjmallett "c0_status", "c0_cause", "c0_epc", "c0_prid", 310208737Sjmallett "c0_config", "$17", "c0_watchlo", "c0_watchhi", 311208737Sjmallett "c0_xcontext", "$21", "c0_mdebug", "c0_debug", 312208737Sjmallett "c0_depc", "c0_perfcnt", "$26", "c0_cacheerr", 313208737Sjmallett "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", 314208737Sjmallett}; 315208737Sjmallett 316208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_octeon[] = { 317208737Sjmallett { 5, 1, "c0_pagegrain" }, 318208737Sjmallett { 9, 6, "c0_cvmcount" }, 319208737Sjmallett { 9, 7, "c0_cvmctl" }, 320208737Sjmallett { 11, 7, "c0_cvmmemctl" }, 321208737Sjmallett { 12, 1, "c0_intctl" }, 322208737Sjmallett { 12, 2, "c0_srsctl" }, 323208737Sjmallett { 15, 1, "c0_ebase" }, 324208737Sjmallett { 16, 1, "c0_config1", }, 325208737Sjmallett { 16, 2, "c0_config2", }, 326208737Sjmallett { 16, 3, "c0_config3", }, 327208737Sjmallett { 18, 1, "c0_watchlo,1" }, 328208737Sjmallett { 19, 1, "c0_watchhi,1" }, 329208737Sjmallett { 25, 2, "c0_perfcnt,2" }, 330208737Sjmallett { 27, 1, "c0_cacheerr,1" }, 331208737Sjmallett { 28, 3, "c0_datalo" }, 332208737Sjmallett { 29, 3, "c0_datahi" }, 333208737Sjmallett}; 334208737Sjmallett 335208737Sjmallettstatic const char * const mips_hwr_names_numeric[32] = 336208737Sjmallett{ 337179404Sobrien "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 338179404Sobrien "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 339179404Sobrien "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 340179404Sobrien "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" 341179404Sobrien}; 342179404Sobrien 343208737Sjmallettstatic const char * const mips_hwr_names_mips3264r2[32] = 344208737Sjmallett{ 345179404Sobrien "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", 346179404Sobrien "$4", "$5", "$6", "$7", 347179404Sobrien "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 348179404Sobrien "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 349179404Sobrien "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" 350179404Sobrien}; 351179404Sobrien 352208737Sjmallettstruct mips_abi_choice 353208737Sjmallett{ 354208737Sjmallett const char * name; 355179404Sobrien const char * const *gpr_names; 356179404Sobrien const char * const *fpr_names; 357179404Sobrien}; 358179404Sobrien 359208737Sjmallettstruct mips_abi_choice mips_abi_choices[] = 360208737Sjmallett{ 361179404Sobrien { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, 362179404Sobrien { "32", mips_gpr_names_oldabi, mips_fpr_names_32 }, 363179404Sobrien { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 }, 364179404Sobrien { "64", mips_gpr_names_newabi, mips_fpr_names_64 }, 365179404Sobrien}; 366179404Sobrien 367208737Sjmallettstruct mips_arch_choice 368208737Sjmallett{ 369179404Sobrien const char *name; 370179404Sobrien int bfd_mach_valid; 371179404Sobrien unsigned long bfd_mach; 372179404Sobrien int processor; 373179404Sobrien int isa; 374179404Sobrien const char * const *cp0_names; 375179404Sobrien const struct mips_cp0sel_name *cp0sel_names; 376179404Sobrien unsigned int cp0sel_names_len; 377179404Sobrien const char * const *hwr_names; 378179404Sobrien}; 379179404Sobrien 380208737Sjmallettconst struct mips_arch_choice mips_arch_choices[] = 381208737Sjmallett{ 382179404Sobrien { "numeric", 0, 0, 0, 0, 383179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 384179404Sobrien 385179404Sobrien { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, 386179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 387179404Sobrien { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, 388179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 389179404Sobrien { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, 390179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 391179404Sobrien { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, 392179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 393179404Sobrien { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, 394179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 395179404Sobrien { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, 396179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 397179404Sobrien { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, 398179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 399179404Sobrien { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, 400179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 401179404Sobrien { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, 402179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 403179404Sobrien { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, 404179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 405179404Sobrien { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, 406179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 407179404Sobrien { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, 408179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 409179404Sobrien { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, 410179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 411179404Sobrien { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, 412179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 413179404Sobrien { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, 414179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 415179404Sobrien { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 416179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 417179404Sobrien { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 418179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 419179404Sobrien { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, 420179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 421179404Sobrien { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, 422179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 423179404Sobrien { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, 424179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 425179404Sobrien { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, 426179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 427179404Sobrien 428179404Sobrien /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs. 429179404Sobrien Note that MIPS-3D and MDMX are not applicable to MIPS32. (See 430179404Sobrien _MIPS32 Architecture For Programmers Volume I: Introduction to the 431179404Sobrien MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95), 432179404Sobrien page 1. */ 433179404Sobrien { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32, 434218822Sdim ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS, 435179404Sobrien mips_cp0_names_mips3264, 436179404Sobrien mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), 437179404Sobrien mips_hwr_names_numeric }, 438179404Sobrien 439179404Sobrien { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, 440218822Sdim (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 441218822Sdim | INSN_MIPS3D | INSN_MT), 442179404Sobrien mips_cp0_names_mips3264r2, 443179404Sobrien mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), 444179404Sobrien mips_hwr_names_mips3264r2 }, 445179404Sobrien 446179404Sobrien /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */ 447179404Sobrien { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64, 448218822Sdim ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, 449179404Sobrien mips_cp0_names_mips3264, 450179404Sobrien mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), 451179404Sobrien mips_hwr_names_numeric }, 452179404Sobrien 453179404Sobrien { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2, 454218822Sdim (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2 455218822Sdim | INSN_DSP64 | INSN_MT | INSN_MDMX), 456179404Sobrien mips_cp0_names_mips3264r2, 457179404Sobrien mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), 458179404Sobrien mips_hwr_names_mips3264r2 }, 459179404Sobrien 460179404Sobrien { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, 461179404Sobrien ISA_MIPS64 | INSN_MIPS3D | INSN_SB1, 462179404Sobrien mips_cp0_names_sb1, 463179404Sobrien mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1), 464179404Sobrien mips_hwr_names_numeric }, 465179404Sobrien 466208737Sjmallett { "octeon", 1, bfd_mach_mips_octeon, CPU_OCTEON, 467208737Sjmallett ISA_MIPS64R2 | INSN_OCTEON, mips_cp0_names_octeon, 468208737Sjmallett mips_cp0sel_names_octeon, ARRAY_SIZE (mips_cp0sel_names_octeon), 469208737Sjmallett mips_hwr_names_numeric }, 470208737Sjmallett 471179404Sobrien /* This entry, mips16, is here only for ISA/processor selection; do 472179404Sobrien not print its name. */ 473179404Sobrien { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16, 474179404Sobrien mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, 475179404Sobrien}; 476179404Sobrien 477179404Sobrien/* ISA and processor type to disassemble for, and register names to use. 478179404Sobrien set_default_mips_dis_options and parse_mips_dis_options fill in these 479179404Sobrien values. */ 480179404Sobrienstatic int mips_processor; 481179404Sobrienstatic int mips_isa; 482179404Sobrienstatic const char * const *mips_gpr_names; 483179404Sobrienstatic const char * const *mips_fpr_names; 484179404Sobrienstatic const char * const *mips_cp0_names; 485179404Sobrienstatic const struct mips_cp0sel_name *mips_cp0sel_names; 486179404Sobrienstatic int mips_cp0sel_names_len; 487179404Sobrienstatic const char * const *mips_hwr_names; 488179404Sobrien 489208737Sjmallett/* Other options */ 490208737Sjmallettstatic int no_aliases; /* If set disassemble as most general inst. */ 491179404Sobrien 492179404Sobrienstatic const struct mips_abi_choice * 493208737Sjmallettchoose_abi_by_name (const char *name, unsigned int namelen) 494179404Sobrien{ 495179404Sobrien const struct mips_abi_choice *c; 496179404Sobrien unsigned int i; 497179404Sobrien 498179404Sobrien for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) 499208737Sjmallett if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 500208737Sjmallett && strlen (mips_abi_choices[i].name) == namelen) 501208737Sjmallett c = &mips_abi_choices[i]; 502208737Sjmallett 503179404Sobrien return c; 504179404Sobrien} 505179404Sobrien 506179404Sobrienstatic const struct mips_arch_choice * 507208737Sjmallettchoose_arch_by_name (const char *name, unsigned int namelen) 508179404Sobrien{ 509179404Sobrien const struct mips_arch_choice *c = NULL; 510179404Sobrien unsigned int i; 511179404Sobrien 512179404Sobrien for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) 513208737Sjmallett if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 514208737Sjmallett && strlen (mips_arch_choices[i].name) == namelen) 515208737Sjmallett c = &mips_arch_choices[i]; 516208737Sjmallett 517179404Sobrien return c; 518179404Sobrien} 519179404Sobrien 520179404Sobrienstatic const struct mips_arch_choice * 521208737Sjmallettchoose_arch_by_number (unsigned long mach) 522179404Sobrien{ 523179404Sobrien static unsigned long hint_bfd_mach; 524179404Sobrien static const struct mips_arch_choice *hint_arch_choice; 525179404Sobrien const struct mips_arch_choice *c; 526179404Sobrien unsigned int i; 527179404Sobrien 528179404Sobrien /* We optimize this because even if the user specifies no 529179404Sobrien flags, this will be done for every instruction! */ 530179404Sobrien if (hint_bfd_mach == mach 531179404Sobrien && hint_arch_choice != NULL 532179404Sobrien && hint_arch_choice->bfd_mach == hint_bfd_mach) 533179404Sobrien return hint_arch_choice; 534179404Sobrien 535179404Sobrien for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) 536179404Sobrien { 537179404Sobrien if (mips_arch_choices[i].bfd_mach_valid 538179404Sobrien && mips_arch_choices[i].bfd_mach == mach) 539179404Sobrien { 540179404Sobrien c = &mips_arch_choices[i]; 541179404Sobrien hint_bfd_mach = mach; 542179404Sobrien hint_arch_choice = c; 543179404Sobrien } 544179404Sobrien } 545179404Sobrien return c; 546179404Sobrien} 547179404Sobrien 548208737Sjmallett/* Check if the object uses NewABI conventions. */ 549208737Sjmallett 550208737Sjmallettstatic int 551208737Sjmallettis_newabi (Elf_Internal_Ehdr *header) 552179404Sobrien{ 553208737Sjmallett /* There are no old-style ABIs which use 64-bit ELF. */ 554208737Sjmallett if (header->e_ident[EI_CLASS] == ELFCLASS64) 555208737Sjmallett return 1; 556208737Sjmallett 557208737Sjmallett /* If a 32-bit ELF file, n32 is a new-style ABI. */ 558208737Sjmallett if ((header->e_flags & EF_MIPS_ABI2) != 0) 559208737Sjmallett return 1; 560208737Sjmallett 561208737Sjmallett return 0; 562208737Sjmallett} 563208737Sjmallett 564208737Sjmallettstatic void 565208737Sjmallettset_default_mips_dis_options (struct disassemble_info *info) 566208737Sjmallett{ 567179404Sobrien const struct mips_arch_choice *chosen_arch; 568179404Sobrien 569179404Sobrien /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names, 570179404Sobrien and numeric FPR, CP0 register, and HWR names. */ 571179404Sobrien mips_isa = ISA_MIPS3; 572179404Sobrien mips_processor = CPU_R3000; 573179404Sobrien mips_gpr_names = mips_gpr_names_oldabi; 574179404Sobrien mips_fpr_names = mips_fpr_names_numeric; 575179404Sobrien mips_cp0_names = mips_cp0_names_numeric; 576179404Sobrien mips_cp0sel_names = NULL; 577179404Sobrien mips_cp0sel_names_len = 0; 578179404Sobrien mips_hwr_names = mips_hwr_names_numeric; 579208737Sjmallett no_aliases = 0; 580179404Sobrien 581179404Sobrien /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ 582179404Sobrien if (info->flavour == bfd_target_elf_flavour && info->section != NULL) 583179404Sobrien { 584179404Sobrien Elf_Internal_Ehdr *header; 585179404Sobrien 586179404Sobrien header = elf_elfheader (info->section->owner); 587179404Sobrien if (is_newabi (header)) 588179404Sobrien mips_gpr_names = mips_gpr_names_newabi; 589179404Sobrien } 590179404Sobrien 591179404Sobrien /* Set ISA, architecture, and cp0 register names as best we can. */ 592179404Sobrien#if ! SYMTAB_AVAILABLE 593179404Sobrien /* This is running out on a target machine, not in a host tool. 594179404Sobrien FIXME: Where does mips_target_info come from? */ 595179404Sobrien target_processor = mips_target_info.processor; 596179404Sobrien mips_isa = mips_target_info.isa; 597179404Sobrien#else 598179404Sobrien chosen_arch = choose_arch_by_number (info->mach); 599179404Sobrien if (chosen_arch != NULL) 600179404Sobrien { 601179404Sobrien mips_processor = chosen_arch->processor; 602179404Sobrien mips_isa = chosen_arch->isa; 603179404Sobrien mips_cp0_names = chosen_arch->cp0_names; 604179404Sobrien mips_cp0sel_names = chosen_arch->cp0sel_names; 605179404Sobrien mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; 606179404Sobrien mips_hwr_names = chosen_arch->hwr_names; 607179404Sobrien } 608179404Sobrien#endif 609179404Sobrien} 610179404Sobrien 611208737Sjmallettstatic void 612208737Sjmallettparse_mips_dis_option (const char *option, unsigned int len) 613179404Sobrien{ 614179404Sobrien unsigned int i, optionlen, vallen; 615179404Sobrien const char *val; 616179404Sobrien const struct mips_abi_choice *chosen_abi; 617179404Sobrien const struct mips_arch_choice *chosen_arch; 618179404Sobrien 619208737Sjmallett if (strcmp ("octeon-useun", option) == 0) 620208737Sjmallett { 621208737Sjmallett octeon_use_unalign = 1; 622208737Sjmallett return; 623208737Sjmallett } 624208737Sjmallett if (strcmp ("no-octeon-useun", option) == 0) 625208737Sjmallett { 626208737Sjmallett octeon_use_unalign = 0; 627208737Sjmallett return; 628208737Sjmallett } 629208737Sjmallett 630208737Sjmallett /* Try to match options that are simple flags */ 631218822Sdim if (CONST_STRNEQ (option, "no-aliases")) 632208737Sjmallett { 633208737Sjmallett no_aliases = 1; 634208737Sjmallett return; 635208737Sjmallett } 636208737Sjmallett 637179404Sobrien /* Look for the = that delimits the end of the option name. */ 638179404Sobrien for (i = 0; i < len; i++) 639208737Sjmallett if (option[i] == '=') 640208737Sjmallett break; 641208737Sjmallett 642179404Sobrien if (i == 0) /* Invalid option: no name before '='. */ 643179404Sobrien return; 644179404Sobrien if (i == len) /* Invalid option: no '='. */ 645179404Sobrien return; 646179404Sobrien if (i == (len - 1)) /* Invalid option: no value after '='. */ 647179404Sobrien return; 648179404Sobrien 649179404Sobrien optionlen = i; 650179404Sobrien val = option + (optionlen + 1); 651179404Sobrien vallen = len - (optionlen + 1); 652179404Sobrien 653208737Sjmallett if (strncmp ("gpr-names", option, optionlen) == 0 654208737Sjmallett && strlen ("gpr-names") == optionlen) 655179404Sobrien { 656179404Sobrien chosen_abi = choose_abi_by_name (val, vallen); 657179404Sobrien if (chosen_abi != NULL) 658179404Sobrien mips_gpr_names = chosen_abi->gpr_names; 659179404Sobrien return; 660179404Sobrien } 661179404Sobrien 662208737Sjmallett if (strncmp ("fpr-names", option, optionlen) == 0 663208737Sjmallett && strlen ("fpr-names") == optionlen) 664179404Sobrien { 665179404Sobrien chosen_abi = choose_abi_by_name (val, vallen); 666179404Sobrien if (chosen_abi != NULL) 667179404Sobrien mips_fpr_names = chosen_abi->fpr_names; 668179404Sobrien return; 669179404Sobrien } 670179404Sobrien 671208737Sjmallett if (strncmp ("cp0-names", option, optionlen) == 0 672208737Sjmallett && strlen ("cp0-names") == optionlen) 673179404Sobrien { 674179404Sobrien chosen_arch = choose_arch_by_name (val, vallen); 675179404Sobrien if (chosen_arch != NULL) 676179404Sobrien { 677179404Sobrien mips_cp0_names = chosen_arch->cp0_names; 678179404Sobrien mips_cp0sel_names = chosen_arch->cp0sel_names; 679179404Sobrien mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; 680179404Sobrien } 681179404Sobrien return; 682179404Sobrien } 683179404Sobrien 684208737Sjmallett if (strncmp ("hwr-names", option, optionlen) == 0 685208737Sjmallett && strlen ("hwr-names") == optionlen) 686179404Sobrien { 687179404Sobrien chosen_arch = choose_arch_by_name (val, vallen); 688179404Sobrien if (chosen_arch != NULL) 689179404Sobrien mips_hwr_names = chosen_arch->hwr_names; 690179404Sobrien return; 691179404Sobrien } 692179404Sobrien 693208737Sjmallett if (strncmp ("reg-names", option, optionlen) == 0 694208737Sjmallett && strlen ("reg-names") == optionlen) 695179404Sobrien { 696179404Sobrien /* We check both ABI and ARCH here unconditionally, so 697179404Sobrien that "numeric" will do the desirable thing: select 698179404Sobrien numeric register names for all registers. Other than 699179404Sobrien that, a given name probably won't match both. */ 700179404Sobrien chosen_abi = choose_abi_by_name (val, vallen); 701179404Sobrien if (chosen_abi != NULL) 702179404Sobrien { 703179404Sobrien mips_gpr_names = chosen_abi->gpr_names; 704179404Sobrien mips_fpr_names = chosen_abi->fpr_names; 705179404Sobrien } 706179404Sobrien chosen_arch = choose_arch_by_name (val, vallen); 707179404Sobrien if (chosen_arch != NULL) 708179404Sobrien { 709179404Sobrien mips_cp0_names = chosen_arch->cp0_names; 710179404Sobrien mips_cp0sel_names = chosen_arch->cp0sel_names; 711179404Sobrien mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; 712179404Sobrien mips_hwr_names = chosen_arch->hwr_names; 713179404Sobrien } 714179404Sobrien return; 715179404Sobrien } 716179404Sobrien 717179404Sobrien /* Invalid option. */ 718179404Sobrien} 719179404Sobrien 720208737Sjmallettstatic void 721208737Sjmallettparse_mips_dis_options (const char *options) 722179404Sobrien{ 723179404Sobrien const char *option_end; 724179404Sobrien 725179404Sobrien if (options == NULL) 726179404Sobrien return; 727179404Sobrien 728179404Sobrien while (*options != '\0') 729179404Sobrien { 730179404Sobrien /* Skip empty options. */ 731179404Sobrien if (*options == ',') 732179404Sobrien { 733179404Sobrien options++; 734179404Sobrien continue; 735179404Sobrien } 736179404Sobrien 737179404Sobrien /* We know that *options is neither NUL or a comma. */ 738179404Sobrien option_end = options + 1; 739179404Sobrien while (*option_end != ',' && *option_end != '\0') 740179404Sobrien option_end++; 741179404Sobrien 742179404Sobrien parse_mips_dis_option (options, option_end - options); 743179404Sobrien 744179404Sobrien /* Go on to the next one. If option_end points to a comma, it 745179404Sobrien will be skipped above. */ 746179404Sobrien options = option_end; 747179404Sobrien } 748179404Sobrien} 749179404Sobrien 750179404Sobrienstatic const struct mips_cp0sel_name * 751208737Sjmallettlookup_mips_cp0sel_name (const struct mips_cp0sel_name *names, 752208737Sjmallett unsigned int len, 753208737Sjmallett unsigned int cp0reg, 754208737Sjmallett unsigned int sel) 755179404Sobrien{ 756179404Sobrien unsigned int i; 757179404Sobrien 758179404Sobrien for (i = 0; i < len; i++) 759179404Sobrien if (names[i].cp0reg == cp0reg && names[i].sel == sel) 760179404Sobrien return &names[i]; 761179404Sobrien return NULL; 762179404Sobrien} 763179404Sobrien 764179404Sobrien/* Print insn arguments for 32/64-bit code. */ 765179404Sobrien 766179404Sobrienstatic void 767208737Sjmallettprint_insn_args (const char *d, 768208737Sjmallett register unsigned long int l, 769208737Sjmallett bfd_vma pc, 770218822Sdim struct disassemble_info *info, 771218822Sdim const struct mips_opcode *opp) 772179404Sobrien{ 773179404Sobrien int op, delta; 774179404Sobrien unsigned int lsb, msb, msbd; 775179404Sobrien 776179404Sobrien lsb = 0; 777179404Sobrien 778179404Sobrien for (; *d != '\0'; d++) 779179404Sobrien { 780179404Sobrien switch (*d) 781179404Sobrien { 782179404Sobrien case ',': 783179404Sobrien case '(': 784179404Sobrien case ')': 785179404Sobrien case '[': 786179404Sobrien case ']': 787179404Sobrien (*info->fprintf_func) (info->stream, "%c", *d); 788179404Sobrien break; 789179404Sobrien 790179404Sobrien case '+': 791179404Sobrien /* Extension character; switch for second char. */ 792179404Sobrien d++; 793179404Sobrien switch (*d) 794179404Sobrien { 795179404Sobrien case '\0': 796179404Sobrien /* xgettext:c-format */ 797179404Sobrien (*info->fprintf_func) (info->stream, 798179404Sobrien _("# internal error, incomplete extension sequence (+)")); 799179404Sobrien return; 800179404Sobrien 801179404Sobrien case 'A': 802179404Sobrien lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; 803179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", lsb); 804179404Sobrien break; 805179404Sobrien 806179404Sobrien case 'B': 807179404Sobrien msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; 808179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); 809179404Sobrien break; 810179404Sobrien 811218822Sdim case '1': 812218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 813218822Sdim (l >> OP_SH_UDI1) & OP_MASK_UDI1); 814218822Sdim break; 815218822Sdim 816218822Sdim case '2': 817218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 818218822Sdim (l >> OP_SH_UDI2) & OP_MASK_UDI2); 819218822Sdim break; 820218822Sdim 821218822Sdim case '3': 822218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 823218822Sdim (l >> OP_SH_UDI3) & OP_MASK_UDI3); 824218822Sdim break; 825218822Sdim 826218822Sdim case '4': 827218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 828218822Sdim (l >> OP_SH_UDI4) & OP_MASK_UDI4); 829218822Sdim break; 830218822Sdim 831179404Sobrien case 'C': 832179404Sobrien case 'H': 833179404Sobrien msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; 834179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); 835179404Sobrien break; 836179404Sobrien 837179404Sobrien case 'D': 838179404Sobrien { 839179404Sobrien const struct mips_cp0sel_name *n; 840179404Sobrien unsigned int cp0reg, sel; 841179404Sobrien 842179404Sobrien cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; 843179404Sobrien sel = (l >> OP_SH_SEL) & OP_MASK_SEL; 844179404Sobrien 845179404Sobrien /* CP0 register including 'sel' code for mtcN (et al.), to be 846179404Sobrien printed textually if known. If not known, print both 847179404Sobrien CP0 register name and sel numerically since CP0 register 848179404Sobrien with sel 0 may have a name unrelated to register being 849179404Sobrien printed. */ 850179404Sobrien n = lookup_mips_cp0sel_name(mips_cp0sel_names, 851179404Sobrien mips_cp0sel_names_len, cp0reg, sel); 852179404Sobrien if (n != NULL) 853179404Sobrien (*info->fprintf_func) (info->stream, "%s", n->name); 854179404Sobrien else 855179404Sobrien (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); 856179404Sobrien break; 857179404Sobrien } 858179404Sobrien 859179404Sobrien case 'E': 860179404Sobrien lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; 861179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", lsb); 862179404Sobrien break; 863179404Sobrien 864179404Sobrien case 'F': 865179404Sobrien msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; 866179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); 867179404Sobrien break; 868179404Sobrien 869179404Sobrien case 'G': 870179404Sobrien msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; 871179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); 872179404Sobrien break; 873179404Sobrien 874208737Sjmallett case 't': /* Coprocessor 0 reg name */ 875208737Sjmallett (*info->fprintf_func) (info->stream, "%s", 876208737Sjmallett mips_cp0_names[(l >> OP_SH_RT) & 877208737Sjmallett OP_MASK_RT]); 878208737Sjmallett break; 879208737Sjmallett 880208737Sjmallett case 'T': /* Coprocessor 0 reg name */ 881208737Sjmallett { 882208737Sjmallett const struct mips_cp0sel_name *n; 883208737Sjmallett unsigned int cp0reg, sel; 884208737Sjmallett 885208737Sjmallett cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; 886208737Sjmallett sel = (l >> OP_SH_SEL) & OP_MASK_SEL; 887208737Sjmallett 888208737Sjmallett /* CP0 register including 'sel' code for mftc0, to be 889208737Sjmallett printed textually if known. If not known, print both 890208737Sjmallett CP0 register name and sel numerically since CP0 register 891208737Sjmallett with sel 0 may have a name unrelated to register being 892208737Sjmallett printed. */ 893208737Sjmallett n = lookup_mips_cp0sel_name(mips_cp0sel_names, 894208737Sjmallett mips_cp0sel_names_len, cp0reg, sel); 895208737Sjmallett if (n != NULL) 896208737Sjmallett (*info->fprintf_func) (info->stream, "%s", n->name); 897208737Sjmallett else 898208737Sjmallett (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); 899208737Sjmallett break; 900208737Sjmallett } 901208737Sjmallett 902179404Sobrien default: 903179404Sobrien /* xgettext:c-format */ 904179404Sobrien (*info->fprintf_func) (info->stream, 905179404Sobrien _("# internal error, undefined extension sequence (+%c)"), 906179404Sobrien *d); 907179404Sobrien return; 908179404Sobrien } 909179404Sobrien break; 910179404Sobrien 911218822Sdim case '2': 912218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 913218822Sdim (l >> OP_SH_BP) & OP_MASK_BP); 914218822Sdim break; 915218822Sdim 916208737Sjmallett case '3': 917208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 918208737Sjmallett (l >> OP_SH_SA3) & OP_MASK_SA3); 919208737Sjmallett break; 920208737Sjmallett 921208737Sjmallett case '4': 922208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 923208737Sjmallett (l >> OP_SH_SA4) & OP_MASK_SA4); 924208737Sjmallett break; 925208737Sjmallett 926208737Sjmallett case '5': 927208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 928208737Sjmallett (l >> OP_SH_IMM8) & OP_MASK_IMM8); 929208737Sjmallett break; 930208737Sjmallett 931208737Sjmallett case '6': 932208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 933208737Sjmallett (l >> OP_SH_RS) & OP_MASK_RS); 934208737Sjmallett break; 935208737Sjmallett 936208737Sjmallett case '7': 937208737Sjmallett (*info->fprintf_func) (info->stream, "$ac%ld", 938208737Sjmallett (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); 939208737Sjmallett break; 940208737Sjmallett 941208737Sjmallett case '8': 942208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 943208737Sjmallett (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); 944208737Sjmallett break; 945208737Sjmallett 946208737Sjmallett case '9': 947208737Sjmallett (*info->fprintf_func) (info->stream, "$ac%ld", 948208737Sjmallett (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); 949208737Sjmallett break; 950208737Sjmallett 951208737Sjmallett case '0': /* dsp 6-bit signed immediate in bit 20 */ 952208737Sjmallett delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); 953208737Sjmallett if (delta & 0x20) /* test sign bit */ 954208737Sjmallett delta |= ~OP_MASK_DSPSFT; 955208737Sjmallett (*info->fprintf_func) (info->stream, "%d", delta); 956208737Sjmallett break; 957208737Sjmallett 958208737Sjmallett case ':': /* dsp 7-bit signed immediate in bit 19 */ 959208737Sjmallett delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); 960208737Sjmallett if (delta & 0x40) /* test sign bit */ 961208737Sjmallett delta |= ~OP_MASK_DSPSFT_7; 962208737Sjmallett (*info->fprintf_func) (info->stream, "%d", delta); 963208737Sjmallett break; 964208737Sjmallett 965208737Sjmallett case '\'': 966208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 967208737Sjmallett (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); 968208737Sjmallett break; 969208737Sjmallett 970208737Sjmallett case '@': /* dsp 10-bit signed immediate in bit 16 */ 971208737Sjmallett delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); 972208737Sjmallett if (delta & 0x200) /* test sign bit */ 973208737Sjmallett delta |= ~OP_MASK_IMM10; 974208737Sjmallett (*info->fprintf_func) (info->stream, "%d", delta); 975208737Sjmallett break; 976208737Sjmallett 977208737Sjmallett case '!': 978208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 979208737Sjmallett (l >> OP_SH_MT_U) & OP_MASK_MT_U); 980208737Sjmallett break; 981208737Sjmallett 982208737Sjmallett case '$': 983208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 984208737Sjmallett (l >> OP_SH_MT_H) & OP_MASK_MT_H); 985208737Sjmallett break; 986208737Sjmallett 987208737Sjmallett case '*': 988208737Sjmallett (*info->fprintf_func) (info->stream, "$ac%ld", 989208737Sjmallett (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); 990208737Sjmallett break; 991208737Sjmallett 992208737Sjmallett case '&': 993208737Sjmallett (*info->fprintf_func) (info->stream, "$ac%ld", 994208737Sjmallett (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); 995208737Sjmallett break; 996208737Sjmallett 997208737Sjmallett case 'g': 998208737Sjmallett /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ 999208737Sjmallett (*info->fprintf_func) (info->stream, "$%ld", 1000208737Sjmallett (l >> OP_SH_RD) & OP_MASK_RD); 1001208737Sjmallett break; 1002208737Sjmallett 1003179404Sobrien case 's': 1004179404Sobrien case 'b': 1005179404Sobrien case 'r': 1006179404Sobrien case 'v': 1007179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1008179404Sobrien mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); 1009179404Sobrien break; 1010179404Sobrien 1011179404Sobrien case 't': 1012179404Sobrien case 'w': 1013179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1014179404Sobrien mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); 1015179404Sobrien break; 1016179404Sobrien 1017179404Sobrien case 'i': 1018179404Sobrien case 'u': 1019208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1020179404Sobrien (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); 1021179404Sobrien break; 1022179404Sobrien 1023179404Sobrien case 'j': /* Same as i, but sign-extended. */ 1024179404Sobrien case 'o': 1025179404Sobrien delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; 1026179404Sobrien if (delta & 0x8000) 1027179404Sobrien delta |= ~0xffff; 1028179404Sobrien (*info->fprintf_func) (info->stream, "%d", 1029179404Sobrien delta); 1030179404Sobrien break; 1031179404Sobrien 1032179404Sobrien case 'h': 1033179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", 1034179404Sobrien (unsigned int) ((l >> OP_SH_PREFX) 1035179404Sobrien & OP_MASK_PREFX)); 1036179404Sobrien break; 1037179404Sobrien 1038179404Sobrien case 'k': 1039179404Sobrien (*info->fprintf_func) (info->stream, "0x%x", 1040179404Sobrien (unsigned int) ((l >> OP_SH_CACHE) 1041179404Sobrien & OP_MASK_CACHE)); 1042179404Sobrien break; 1043179404Sobrien 1044179404Sobrien case 'a': 1045179404Sobrien info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff) 1046179404Sobrien | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); 1047218822Sdim /* For gdb disassembler, force odd address on jalx. */ 1048218822Sdim if (info->flavour == bfd_target_unknown_flavour 1049218822Sdim && strcmp (opp->name, "jalx") == 0) 1050218822Sdim info->target |= 1; 1051179404Sobrien (*info->print_address_func) (info->target, info); 1052179404Sobrien break; 1053179404Sobrien 1054179404Sobrien case 'p': 1055179404Sobrien /* Sign extend the displacement. */ 1056179404Sobrien delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; 1057179404Sobrien if (delta & 0x8000) 1058179404Sobrien delta |= ~0xffff; 1059179404Sobrien info->target = (delta << 2) + pc + INSNLEN; 1060179404Sobrien (*info->print_address_func) (info->target, info); 1061179404Sobrien break; 1062179404Sobrien 1063179404Sobrien case 'd': 1064179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1065179404Sobrien mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); 1066179404Sobrien break; 1067179404Sobrien 1068179404Sobrien case 'U': 1069179404Sobrien { 1070179404Sobrien /* First check for both rd and rt being equal. */ 1071179404Sobrien unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; 1072179404Sobrien if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) 1073179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1074179404Sobrien mips_gpr_names[reg]); 1075179404Sobrien else 1076179404Sobrien { 1077179404Sobrien /* If one is zero use the other. */ 1078179404Sobrien if (reg == 0) 1079179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1080179404Sobrien mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); 1081179404Sobrien else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) 1082179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1083179404Sobrien mips_gpr_names[reg]); 1084179404Sobrien else /* Bogus, result depends on processor. */ 1085179404Sobrien (*info->fprintf_func) (info->stream, "%s or %s", 1086179404Sobrien mips_gpr_names[reg], 1087179404Sobrien mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); 1088179404Sobrien } 1089179404Sobrien } 1090179404Sobrien break; 1091179404Sobrien 1092179404Sobrien case 'z': 1093179404Sobrien (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); 1094179404Sobrien break; 1095179404Sobrien 1096179404Sobrien case '<': 1097208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1098179404Sobrien (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); 1099179404Sobrien break; 1100179404Sobrien 1101179404Sobrien case 'c': 1102208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1103179404Sobrien (l >> OP_SH_CODE) & OP_MASK_CODE); 1104179404Sobrien break; 1105179404Sobrien 1106179404Sobrien case 'q': 1107208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1108179404Sobrien (l >> OP_SH_CODE2) & OP_MASK_CODE2); 1109179404Sobrien break; 1110179404Sobrien 1111208737Sjmallett /* Display 5 bits of bbit0/1 bit index amount. */ 1112208737Sjmallett case '^': 1113218822Sdim (*info->fprintf_func) (info->stream, "0x%lx", 1114208737Sjmallett (l >> OP_SH_BITIND) & OP_MASK_BITIND); 1115208737Sjmallett break; 1116208737Sjmallett 1117208737Sjmallett /* Display 10 bits signed constant from seqi/snei instruction. */ 1118208737Sjmallett case 'y': 1119208737Sjmallett { 1120208737Sjmallett int imm = (l >> OP_SH_CODE2) & OP_MASK_CODE2; 1121208737Sjmallett imm <<= 22; 1122208737Sjmallett imm >>= 22; 1123208737Sjmallett (*info->fprintf_func) (info->stream, "%d", imm); 1124208737Sjmallett } 1125208737Sjmallett break; 1126208737Sjmallett 1127179404Sobrien case 'C': 1128208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1129179404Sobrien (l >> OP_SH_COPZ) & OP_MASK_COPZ); 1130179404Sobrien break; 1131179404Sobrien 1132179404Sobrien case 'B': 1133208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1134208737Sjmallett 1135179404Sobrien (l >> OP_SH_CODE20) & OP_MASK_CODE20); 1136179404Sobrien break; 1137179404Sobrien 1138179404Sobrien case 'J': 1139208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1140179404Sobrien (l >> OP_SH_CODE19) & OP_MASK_CODE19); 1141179404Sobrien break; 1142179404Sobrien 1143179404Sobrien case 'S': 1144179404Sobrien case 'V': 1145179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1146179404Sobrien mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); 1147179404Sobrien break; 1148179404Sobrien 1149179404Sobrien case 'T': 1150179404Sobrien case 'W': 1151179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1152179404Sobrien mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); 1153179404Sobrien break; 1154179404Sobrien 1155179404Sobrien case 'D': 1156179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1157179404Sobrien mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); 1158179404Sobrien break; 1159179404Sobrien 1160179404Sobrien case 'R': 1161179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1162179404Sobrien mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); 1163179404Sobrien break; 1164179404Sobrien 1165179404Sobrien case 'E': 1166179404Sobrien /* Coprocessor register for lwcN instructions, et al. 1167179404Sobrien 1168179404Sobrien Note that there is no load/store cp0 instructions, and 1169179404Sobrien that FPU (cp1) instructions disassemble this field using 1170179404Sobrien 'T' format. Therefore, until we gain understanding of 1171179404Sobrien cp2 register names, we can simply print the register 1172179404Sobrien numbers. */ 1173208737Sjmallett (*info->fprintf_func) (info->stream, "$%ld", 1174179404Sobrien (l >> OP_SH_RT) & OP_MASK_RT); 1175179404Sobrien break; 1176179404Sobrien 1177179404Sobrien case 'G': 1178179404Sobrien /* Coprocessor register for mtcN instructions, et al. Note 1179179404Sobrien that FPU (cp1) instructions disassemble this field using 1180179404Sobrien 'S' format. Therefore, we only need to worry about cp0, 1181179404Sobrien cp2, and cp3. */ 1182179404Sobrien op = (l >> OP_SH_OP) & OP_MASK_OP; 1183179404Sobrien if (op == OP_OP_COP0) 1184179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1185179404Sobrien mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); 1186179404Sobrien else 1187208737Sjmallett (*info->fprintf_func) (info->stream, "$%ld", 1188179404Sobrien (l >> OP_SH_RD) & OP_MASK_RD); 1189179404Sobrien break; 1190179404Sobrien 1191179404Sobrien case 'K': 1192179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1193179404Sobrien mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); 1194179404Sobrien break; 1195179404Sobrien 1196179404Sobrien case 'N': 1197218822Sdim (*info->fprintf_func) (info->stream, 1198218822Sdim ((opp->pinfo & (FP_D | FP_S)) != 0 1199218822Sdim ? "$fcc%ld" : "$cc%ld"), 1200179404Sobrien (l >> OP_SH_BCC) & OP_MASK_BCC); 1201179404Sobrien break; 1202179404Sobrien 1203179404Sobrien case 'M': 1204208737Sjmallett (*info->fprintf_func) (info->stream, "$fcc%ld", 1205179404Sobrien (l >> OP_SH_CCC) & OP_MASK_CCC); 1206179404Sobrien break; 1207179404Sobrien 1208179404Sobrien case 'P': 1209208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 1210179404Sobrien (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); 1211179404Sobrien break; 1212179404Sobrien 1213179404Sobrien case 'e': 1214208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 1215179404Sobrien (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); 1216179404Sobrien break; 1217179404Sobrien 1218179404Sobrien case '%': 1219208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 1220179404Sobrien (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); 1221179404Sobrien break; 1222179404Sobrien 1223179404Sobrien case 'H': 1224208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 1225179404Sobrien (l >> OP_SH_SEL) & OP_MASK_SEL); 1226179404Sobrien break; 1227179404Sobrien 1228179404Sobrien case 'O': 1229208737Sjmallett (*info->fprintf_func) (info->stream, "%ld", 1230179404Sobrien (l >> OP_SH_ALN) & OP_MASK_ALN); 1231179404Sobrien break; 1232179404Sobrien 1233179404Sobrien case 'Q': 1234179404Sobrien { 1235179404Sobrien unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; 1236208737Sjmallett 1237179404Sobrien if ((vsel & 0x10) == 0) 1238179404Sobrien { 1239179404Sobrien int fmt; 1240208737Sjmallett 1241179404Sobrien vsel &= 0x0f; 1242179404Sobrien for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) 1243179404Sobrien if ((vsel & 1) == 0) 1244179404Sobrien break; 1245208737Sjmallett (*info->fprintf_func) (info->stream, "$v%ld[%d]", 1246179404Sobrien (l >> OP_SH_FT) & OP_MASK_FT, 1247179404Sobrien vsel >> 1); 1248179404Sobrien } 1249179404Sobrien else if ((vsel & 0x08) == 0) 1250179404Sobrien { 1251208737Sjmallett (*info->fprintf_func) (info->stream, "$v%ld", 1252179404Sobrien (l >> OP_SH_FT) & OP_MASK_FT); 1253179404Sobrien } 1254179404Sobrien else 1255179404Sobrien { 1256208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", 1257179404Sobrien (l >> OP_SH_FT) & OP_MASK_FT); 1258179404Sobrien } 1259179404Sobrien } 1260179404Sobrien break; 1261179404Sobrien 1262179404Sobrien case 'X': 1263208737Sjmallett (*info->fprintf_func) (info->stream, "$v%ld", 1264179404Sobrien (l >> OP_SH_FD) & OP_MASK_FD); 1265179404Sobrien break; 1266179404Sobrien 1267179404Sobrien case 'Y': 1268208737Sjmallett (*info->fprintf_func) (info->stream, "$v%ld", 1269179404Sobrien (l >> OP_SH_FS) & OP_MASK_FS); 1270179404Sobrien break; 1271179404Sobrien 1272179404Sobrien case 'Z': 1273208737Sjmallett (*info->fprintf_func) (info->stream, "$v%ld", 1274179404Sobrien (l >> OP_SH_FT) & OP_MASK_FT); 1275179404Sobrien break; 1276179404Sobrien 1277179404Sobrien default: 1278179404Sobrien /* xgettext:c-format */ 1279179404Sobrien (*info->fprintf_func) (info->stream, 1280179404Sobrien _("# internal error, undefined modifier(%c)"), 1281179404Sobrien *d); 1282179404Sobrien return; 1283179404Sobrien } 1284179404Sobrien } 1285179404Sobrien} 1286179404Sobrien 1287179404Sobrien/* Print the mips instruction at address MEMADDR in debugged memory, 1288179404Sobrien on using INFO. Returns length of the instruction, in bytes, which is 1289179404Sobrien always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if 1290179404Sobrien this is little-endian code. */ 1291179404Sobrien 1292179404Sobrienstatic int 1293208737Sjmallettprint_insn_mips (bfd_vma memaddr, 1294208737Sjmallett unsigned long int word, 1295208737Sjmallett struct disassemble_info *info) 1296179404Sobrien{ 1297208737Sjmallett const struct mips_opcode *op; 1298179404Sobrien static bfd_boolean init = 0; 1299179404Sobrien static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; 1300179404Sobrien 1301179404Sobrien /* Build a hash table to shorten the search time. */ 1302179404Sobrien if (! init) 1303179404Sobrien { 1304179404Sobrien unsigned int i; 1305179404Sobrien 1306179404Sobrien for (i = 0; i <= OP_MASK_OP; i++) 1307179404Sobrien { 1308179404Sobrien for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++) 1309179404Sobrien { 1310208737Sjmallett if (op->pinfo == INSN_MACRO 1311208737Sjmallett || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) 1312179404Sobrien continue; 1313179404Sobrien if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) 1314179404Sobrien { 1315179404Sobrien mips_hash[i] = op; 1316179404Sobrien break; 1317179404Sobrien } 1318179404Sobrien } 1319179404Sobrien } 1320179404Sobrien 1321179404Sobrien init = 1; 1322179404Sobrien } 1323179404Sobrien 1324179404Sobrien info->bytes_per_chunk = INSNLEN; 1325179404Sobrien info->display_endian = info->endian; 1326179404Sobrien info->insn_info_valid = 1; 1327179404Sobrien info->branch_delay_insns = 0; 1328179404Sobrien info->data_size = 0; 1329179404Sobrien info->insn_type = dis_nonbranch; 1330179404Sobrien info->target = 0; 1331179404Sobrien info->target2 = 0; 1332179404Sobrien 1333179404Sobrien op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; 1334179404Sobrien if (op != NULL) 1335179404Sobrien { 1336179404Sobrien for (; op < &mips_opcodes[NUMOPCODES]; op++) 1337179404Sobrien { 1338208737Sjmallett if (op->pinfo != INSN_MACRO 1339208737Sjmallett && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) 1340208737Sjmallett && (word & op->mask) == op->match) 1341179404Sobrien { 1342208737Sjmallett const char *d; 1343179404Sobrien 1344179404Sobrien /* We always allow to disassemble the jalx instruction. */ 1345179404Sobrien if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor) 1346179404Sobrien && strcmp (op->name, "jalx")) 1347179404Sobrien continue; 1348179404Sobrien 1349208737Sjmallett if (info->mach == CPU_OCTEON && octeon_use_unalign) 1350208737Sjmallett { 1351208737Sjmallett if (strcmp (op->name, "lwl") == 0 1352208737Sjmallett || strcmp (op->name, "ldl") == 0 1353208737Sjmallett || strcmp (op->name, "swl") == 0 1354208737Sjmallett || strcmp (op->name, "sdl") == 0 1355208737Sjmallett || strcmp (op->name, "lcache") == 0 1356208737Sjmallett || strcmp (op->name, "scache") == 0 1357208737Sjmallett || strcmp (op->name, "flush") == 0) 1358208737Sjmallett continue; 1359208737Sjmallett 1360208737Sjmallett if (strcmp (op->name, "ldr") == 0 1361208737Sjmallett || strcmp (op->name, "lwr") == 0 1362208737Sjmallett || strcmp (op->name, "swr") == 0 1363208737Sjmallett || strcmp (op->name, "sdr") == 0) 1364208737Sjmallett { 1365208737Sjmallett (*info->fprintf_func) (info->stream, "nop"); 1366208737Sjmallett return INSNLEN; 1367208737Sjmallett } 1368208737Sjmallett } 1369208737Sjmallett 1370179404Sobrien /* Figure out instruction type and branch delay information. */ 1371179404Sobrien if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) 1372179404Sobrien { 1373179404Sobrien if ((info->insn_type & INSN_WRITE_GPR_31) != 0) 1374179404Sobrien info->insn_type = dis_jsr; 1375179404Sobrien else 1376179404Sobrien info->insn_type = dis_branch; 1377179404Sobrien info->branch_delay_insns = 1; 1378179404Sobrien } 1379179404Sobrien else if ((op->pinfo & (INSN_COND_BRANCH_DELAY 1380179404Sobrien | INSN_COND_BRANCH_LIKELY)) != 0) 1381179404Sobrien { 1382179404Sobrien if ((info->insn_type & INSN_WRITE_GPR_31) != 0) 1383179404Sobrien info->insn_type = dis_condjsr; 1384179404Sobrien else 1385179404Sobrien info->insn_type = dis_condbranch; 1386179404Sobrien info->branch_delay_insns = 1; 1387179404Sobrien } 1388179404Sobrien else if ((op->pinfo & (INSN_STORE_MEMORY 1389179404Sobrien | INSN_LOAD_MEMORY_DELAY)) != 0) 1390179404Sobrien info->insn_type = dis_dref; 1391179404Sobrien 1392179404Sobrien (*info->fprintf_func) (info->stream, "%s", op->name); 1393179404Sobrien 1394179404Sobrien d = op->args; 1395179404Sobrien if (d != NULL && *d != '\0') 1396179404Sobrien { 1397179404Sobrien (*info->fprintf_func) (info->stream, "\t"); 1398218822Sdim print_insn_args (d, word, memaddr, info, op); 1399179404Sobrien } 1400179404Sobrien 1401179404Sobrien return INSNLEN; 1402179404Sobrien } 1403179404Sobrien } 1404179404Sobrien } 1405179404Sobrien 1406179404Sobrien /* Handle undefined instructions. */ 1407179404Sobrien info->insn_type = dis_noninsn; 1408208737Sjmallett (*info->fprintf_func) (info->stream, "0x%lx", word); 1409179404Sobrien return INSNLEN; 1410179404Sobrien} 1411179404Sobrien 1412179404Sobrien/* Disassemble an operand for a mips16 instruction. */ 1413179404Sobrien 1414179404Sobrienstatic void 1415208737Sjmallettprint_mips16_insn_arg (char type, 1416208737Sjmallett const struct mips_opcode *op, 1417208737Sjmallett int l, 1418208737Sjmallett bfd_boolean use_extend, 1419208737Sjmallett int extend, 1420208737Sjmallett bfd_vma memaddr, 1421208737Sjmallett struct disassemble_info *info) 1422179404Sobrien{ 1423179404Sobrien switch (type) 1424179404Sobrien { 1425179404Sobrien case ',': 1426179404Sobrien case '(': 1427179404Sobrien case ')': 1428179404Sobrien (*info->fprintf_func) (info->stream, "%c", type); 1429179404Sobrien break; 1430179404Sobrien 1431179404Sobrien case 'y': 1432179404Sobrien case 'w': 1433179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1434218822Sdim mips16_reg_names(((l >> MIPS16OP_SH_RY) 1435218822Sdim & MIPS16OP_MASK_RY))); 1436179404Sobrien break; 1437179404Sobrien 1438179404Sobrien case 'x': 1439179404Sobrien case 'v': 1440179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1441218822Sdim mips16_reg_names(((l >> MIPS16OP_SH_RX) 1442218822Sdim & MIPS16OP_MASK_RX))); 1443179404Sobrien break; 1444179404Sobrien 1445179404Sobrien case 'z': 1446179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1447218822Sdim mips16_reg_names(((l >> MIPS16OP_SH_RZ) 1448218822Sdim & MIPS16OP_MASK_RZ))); 1449179404Sobrien break; 1450179404Sobrien 1451179404Sobrien case 'Z': 1452179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1453218822Sdim mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z) 1454218822Sdim & MIPS16OP_MASK_MOVE32Z))); 1455179404Sobrien break; 1456179404Sobrien 1457179404Sobrien case '0': 1458179404Sobrien (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); 1459179404Sobrien break; 1460179404Sobrien 1461179404Sobrien case 'S': 1462179404Sobrien (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]); 1463179404Sobrien break; 1464179404Sobrien 1465179404Sobrien case 'P': 1466179404Sobrien (*info->fprintf_func) (info->stream, "$pc"); 1467179404Sobrien break; 1468179404Sobrien 1469179404Sobrien case 'R': 1470179404Sobrien (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]); 1471179404Sobrien break; 1472179404Sobrien 1473179404Sobrien case 'X': 1474179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1475179404Sobrien mips_gpr_names[((l >> MIPS16OP_SH_REGR32) 1476179404Sobrien & MIPS16OP_MASK_REGR32)]); 1477179404Sobrien break; 1478179404Sobrien 1479179404Sobrien case 'Y': 1480179404Sobrien (*info->fprintf_func) (info->stream, "%s", 1481179404Sobrien mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); 1482179404Sobrien break; 1483179404Sobrien 1484179404Sobrien case '<': 1485179404Sobrien case '>': 1486179404Sobrien case '[': 1487179404Sobrien case ']': 1488179404Sobrien case '4': 1489179404Sobrien case '5': 1490179404Sobrien case 'H': 1491179404Sobrien case 'W': 1492179404Sobrien case 'D': 1493179404Sobrien case 'j': 1494179404Sobrien case '6': 1495179404Sobrien case '8': 1496179404Sobrien case 'V': 1497179404Sobrien case 'C': 1498179404Sobrien case 'U': 1499179404Sobrien case 'k': 1500179404Sobrien case 'K': 1501179404Sobrien case 'p': 1502179404Sobrien case 'q': 1503179404Sobrien case 'A': 1504179404Sobrien case 'B': 1505179404Sobrien case 'E': 1506179404Sobrien { 1507179404Sobrien int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; 1508179404Sobrien 1509179404Sobrien shift = 0; 1510179404Sobrien signedp = 0; 1511179404Sobrien extbits = 16; 1512179404Sobrien pcrel = 0; 1513179404Sobrien extu = 0; 1514179404Sobrien branch = 0; 1515179404Sobrien switch (type) 1516179404Sobrien { 1517179404Sobrien case '<': 1518179404Sobrien nbits = 3; 1519179404Sobrien immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; 1520179404Sobrien extbits = 5; 1521179404Sobrien extu = 1; 1522179404Sobrien break; 1523179404Sobrien case '>': 1524179404Sobrien nbits = 3; 1525179404Sobrien immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; 1526179404Sobrien extbits = 5; 1527179404Sobrien extu = 1; 1528179404Sobrien break; 1529179404Sobrien case '[': 1530179404Sobrien nbits = 3; 1531179404Sobrien immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; 1532179404Sobrien extbits = 6; 1533179404Sobrien extu = 1; 1534179404Sobrien break; 1535179404Sobrien case ']': 1536179404Sobrien nbits = 3; 1537179404Sobrien immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; 1538179404Sobrien extbits = 6; 1539179404Sobrien extu = 1; 1540179404Sobrien break; 1541179404Sobrien case '4': 1542179404Sobrien nbits = 4; 1543179404Sobrien immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; 1544179404Sobrien signedp = 1; 1545179404Sobrien extbits = 15; 1546179404Sobrien break; 1547179404Sobrien case '5': 1548179404Sobrien nbits = 5; 1549179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1550179404Sobrien info->insn_type = dis_dref; 1551179404Sobrien info->data_size = 1; 1552179404Sobrien break; 1553179404Sobrien case 'H': 1554179404Sobrien nbits = 5; 1555179404Sobrien shift = 1; 1556179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1557179404Sobrien info->insn_type = dis_dref; 1558179404Sobrien info->data_size = 2; 1559179404Sobrien break; 1560179404Sobrien case 'W': 1561179404Sobrien nbits = 5; 1562179404Sobrien shift = 2; 1563179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1564179404Sobrien if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 1565179404Sobrien && (op->pinfo & MIPS16_INSN_READ_SP) == 0) 1566179404Sobrien { 1567179404Sobrien info->insn_type = dis_dref; 1568179404Sobrien info->data_size = 4; 1569179404Sobrien } 1570179404Sobrien break; 1571179404Sobrien case 'D': 1572179404Sobrien nbits = 5; 1573179404Sobrien shift = 3; 1574179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1575179404Sobrien info->insn_type = dis_dref; 1576179404Sobrien info->data_size = 8; 1577179404Sobrien break; 1578179404Sobrien case 'j': 1579179404Sobrien nbits = 5; 1580179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1581179404Sobrien signedp = 1; 1582179404Sobrien break; 1583179404Sobrien case '6': 1584179404Sobrien nbits = 6; 1585179404Sobrien immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; 1586179404Sobrien break; 1587179404Sobrien case '8': 1588179404Sobrien nbits = 8; 1589179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1590179404Sobrien break; 1591179404Sobrien case 'V': 1592179404Sobrien nbits = 8; 1593179404Sobrien shift = 2; 1594179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1595179404Sobrien /* FIXME: This might be lw, or it might be addiu to $sp or 1596179404Sobrien $pc. We assume it's load. */ 1597179404Sobrien info->insn_type = dis_dref; 1598179404Sobrien info->data_size = 4; 1599179404Sobrien break; 1600179404Sobrien case 'C': 1601179404Sobrien nbits = 8; 1602179404Sobrien shift = 3; 1603179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1604179404Sobrien info->insn_type = dis_dref; 1605179404Sobrien info->data_size = 8; 1606179404Sobrien break; 1607179404Sobrien case 'U': 1608179404Sobrien nbits = 8; 1609179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1610179404Sobrien extu = 1; 1611179404Sobrien break; 1612179404Sobrien case 'k': 1613179404Sobrien nbits = 8; 1614179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1615179404Sobrien signedp = 1; 1616179404Sobrien break; 1617179404Sobrien case 'K': 1618179404Sobrien nbits = 8; 1619179404Sobrien shift = 3; 1620179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1621179404Sobrien signedp = 1; 1622179404Sobrien break; 1623179404Sobrien case 'p': 1624179404Sobrien nbits = 8; 1625179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1626179404Sobrien signedp = 1; 1627179404Sobrien pcrel = 1; 1628179404Sobrien branch = 1; 1629179404Sobrien info->insn_type = dis_condbranch; 1630179404Sobrien break; 1631179404Sobrien case 'q': 1632179404Sobrien nbits = 11; 1633179404Sobrien immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; 1634179404Sobrien signedp = 1; 1635179404Sobrien pcrel = 1; 1636179404Sobrien branch = 1; 1637179404Sobrien info->insn_type = dis_branch; 1638179404Sobrien break; 1639179404Sobrien case 'A': 1640179404Sobrien nbits = 8; 1641179404Sobrien shift = 2; 1642179404Sobrien immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; 1643179404Sobrien pcrel = 1; 1644179404Sobrien /* FIXME: This can be lw or la. We assume it is lw. */ 1645179404Sobrien info->insn_type = dis_dref; 1646179404Sobrien info->data_size = 4; 1647179404Sobrien break; 1648179404Sobrien case 'B': 1649179404Sobrien nbits = 5; 1650179404Sobrien shift = 3; 1651179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1652179404Sobrien pcrel = 1; 1653179404Sobrien info->insn_type = dis_dref; 1654179404Sobrien info->data_size = 8; 1655179404Sobrien break; 1656179404Sobrien case 'E': 1657179404Sobrien nbits = 5; 1658179404Sobrien shift = 2; 1659179404Sobrien immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; 1660179404Sobrien pcrel = 1; 1661179404Sobrien break; 1662179404Sobrien default: 1663179404Sobrien abort (); 1664179404Sobrien } 1665179404Sobrien 1666179404Sobrien if (! use_extend) 1667179404Sobrien { 1668179404Sobrien if (signedp && immed >= (1 << (nbits - 1))) 1669179404Sobrien immed -= 1 << nbits; 1670179404Sobrien immed <<= shift; 1671179404Sobrien if ((type == '<' || type == '>' || type == '[' || type == ']') 1672179404Sobrien && immed == 0) 1673179404Sobrien immed = 8; 1674179404Sobrien } 1675179404Sobrien else 1676179404Sobrien { 1677179404Sobrien if (extbits == 16) 1678179404Sobrien immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); 1679179404Sobrien else if (extbits == 15) 1680179404Sobrien immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); 1681179404Sobrien else 1682179404Sobrien immed = ((extend >> 6) & 0x1f) | (extend & 0x20); 1683179404Sobrien immed &= (1 << extbits) - 1; 1684179404Sobrien if (! extu && immed >= (1 << (extbits - 1))) 1685179404Sobrien immed -= 1 << extbits; 1686179404Sobrien } 1687179404Sobrien 1688179404Sobrien if (! pcrel) 1689179404Sobrien (*info->fprintf_func) (info->stream, "%d", immed); 1690179404Sobrien else 1691179404Sobrien { 1692179404Sobrien bfd_vma baseaddr; 1693179404Sobrien 1694179404Sobrien if (branch) 1695179404Sobrien { 1696179404Sobrien immed *= 2; 1697179404Sobrien baseaddr = memaddr + 2; 1698179404Sobrien } 1699179404Sobrien else if (use_extend) 1700179404Sobrien baseaddr = memaddr - 2; 1701179404Sobrien else 1702179404Sobrien { 1703179404Sobrien int status; 1704179404Sobrien bfd_byte buffer[2]; 1705179404Sobrien 1706179404Sobrien baseaddr = memaddr; 1707179404Sobrien 1708179404Sobrien /* If this instruction is in the delay slot of a jr 1709179404Sobrien instruction, the base address is the address of the 1710179404Sobrien jr instruction. If it is in the delay slot of jalr 1711179404Sobrien instruction, the base address is the address of the 1712179404Sobrien jalr instruction. This test is unreliable: we have 1713179404Sobrien no way of knowing whether the previous word is 1714179404Sobrien instruction or data. */ 1715179404Sobrien status = (*info->read_memory_func) (memaddr - 4, buffer, 2, 1716179404Sobrien info); 1717179404Sobrien if (status == 0 1718179404Sobrien && (((info->endian == BFD_ENDIAN_BIG 1719179404Sobrien ? bfd_getb16 (buffer) 1720179404Sobrien : bfd_getl16 (buffer)) 1721179404Sobrien & 0xf800) == 0x1800)) 1722179404Sobrien baseaddr = memaddr - 4; 1723179404Sobrien else 1724179404Sobrien { 1725179404Sobrien status = (*info->read_memory_func) (memaddr - 2, buffer, 1726179404Sobrien 2, info); 1727179404Sobrien if (status == 0 1728179404Sobrien && (((info->endian == BFD_ENDIAN_BIG 1729179404Sobrien ? bfd_getb16 (buffer) 1730179404Sobrien : bfd_getl16 (buffer)) 1731179404Sobrien & 0xf81f) == 0xe800)) 1732179404Sobrien baseaddr = memaddr - 2; 1733179404Sobrien } 1734179404Sobrien } 1735179404Sobrien info->target = (baseaddr & ~((1 << shift) - 1)) + immed; 1736218822Sdim if (pcrel && branch 1737218822Sdim && info->flavour == bfd_target_unknown_flavour) 1738218822Sdim /* For gdb disassembler, maintain odd address. */ 1739218822Sdim info->target |= 1; 1740179404Sobrien (*info->print_address_func) (info->target, info); 1741179404Sobrien } 1742179404Sobrien } 1743179404Sobrien break; 1744179404Sobrien 1745179404Sobrien case 'a': 1746218822Sdim { 1747218822Sdim int jalx = l & 0x400; 1748218822Sdim 1749218822Sdim if (! use_extend) 1750218822Sdim extend = 0; 1751218822Sdim l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); 1752218822Sdim if (!jalx && info->flavour == bfd_target_unknown_flavour) 1753218822Sdim /* For gdb disassembler, maintain odd address. */ 1754218822Sdim l |= 1; 1755218822Sdim } 1756179404Sobrien info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l; 1757179404Sobrien (*info->print_address_func) (info->target, info); 1758179404Sobrien info->insn_type = dis_jsr; 1759179404Sobrien info->branch_delay_insns = 1; 1760179404Sobrien break; 1761179404Sobrien 1762179404Sobrien case 'l': 1763179404Sobrien case 'L': 1764179404Sobrien { 1765179404Sobrien int need_comma, amask, smask; 1766179404Sobrien 1767179404Sobrien need_comma = 0; 1768179404Sobrien 1769179404Sobrien l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; 1770179404Sobrien 1771179404Sobrien amask = (l >> 3) & 7; 1772179404Sobrien 1773179404Sobrien if (amask > 0 && amask < 5) 1774179404Sobrien { 1775179404Sobrien (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); 1776179404Sobrien if (amask > 1) 1777179404Sobrien (*info->fprintf_func) (info->stream, "-%s", 1778179404Sobrien mips_gpr_names[amask + 3]); 1779179404Sobrien need_comma = 1; 1780179404Sobrien } 1781179404Sobrien 1782179404Sobrien smask = (l >> 1) & 3; 1783179404Sobrien if (smask == 3) 1784179404Sobrien { 1785179404Sobrien (*info->fprintf_func) (info->stream, "%s??", 1786179404Sobrien need_comma ? "," : ""); 1787179404Sobrien need_comma = 1; 1788179404Sobrien } 1789179404Sobrien else if (smask > 0) 1790179404Sobrien { 1791179404Sobrien (*info->fprintf_func) (info->stream, "%s%s", 1792179404Sobrien need_comma ? "," : "", 1793179404Sobrien mips_gpr_names[16]); 1794179404Sobrien if (smask > 1) 1795179404Sobrien (*info->fprintf_func) (info->stream, "-%s", 1796179404Sobrien mips_gpr_names[smask + 15]); 1797179404Sobrien need_comma = 1; 1798179404Sobrien } 1799179404Sobrien 1800179404Sobrien if (l & 1) 1801179404Sobrien { 1802179404Sobrien (*info->fprintf_func) (info->stream, "%s%s", 1803179404Sobrien need_comma ? "," : "", 1804179404Sobrien mips_gpr_names[31]); 1805179404Sobrien need_comma = 1; 1806179404Sobrien } 1807179404Sobrien 1808179404Sobrien if (amask == 5 || amask == 6) 1809179404Sobrien { 1810179404Sobrien (*info->fprintf_func) (info->stream, "%s$f0", 1811179404Sobrien need_comma ? "," : ""); 1812179404Sobrien if (amask == 6) 1813179404Sobrien (*info->fprintf_func) (info->stream, "-$f1"); 1814179404Sobrien } 1815179404Sobrien } 1816179404Sobrien break; 1817179404Sobrien 1818208737Sjmallett case 'm': 1819208737Sjmallett case 'M': 1820208737Sjmallett /* MIPS16e save/restore. */ 1821208737Sjmallett { 1822208737Sjmallett int need_comma = 0; 1823208737Sjmallett int amask, args, statics; 1824208737Sjmallett int nsreg, smask; 1825208737Sjmallett int framesz; 1826208737Sjmallett int i, j; 1827208737Sjmallett 1828208737Sjmallett l = l & 0x7f; 1829208737Sjmallett if (use_extend) 1830208737Sjmallett l |= extend << 16; 1831208737Sjmallett 1832208737Sjmallett amask = (l >> 16) & 0xf; 1833208737Sjmallett if (amask == MIPS16_ALL_ARGS) 1834208737Sjmallett { 1835208737Sjmallett args = 4; 1836208737Sjmallett statics = 0; 1837208737Sjmallett } 1838208737Sjmallett else if (amask == MIPS16_ALL_STATICS) 1839208737Sjmallett { 1840208737Sjmallett args = 0; 1841208737Sjmallett statics = 4; 1842208737Sjmallett } 1843208737Sjmallett else 1844208737Sjmallett { 1845208737Sjmallett args = amask >> 2; 1846208737Sjmallett statics = amask & 3; 1847208737Sjmallett } 1848208737Sjmallett 1849208737Sjmallett if (args > 0) { 1850208737Sjmallett (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); 1851208737Sjmallett if (args > 1) 1852208737Sjmallett (*info->fprintf_func) (info->stream, "-%s", 1853208737Sjmallett mips_gpr_names[4 + args - 1]); 1854208737Sjmallett need_comma = 1; 1855208737Sjmallett } 1856208737Sjmallett 1857208737Sjmallett framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; 1858208737Sjmallett if (framesz == 0 && !use_extend) 1859208737Sjmallett framesz = 128; 1860208737Sjmallett 1861208737Sjmallett (*info->fprintf_func) (info->stream, "%s%d", 1862208737Sjmallett need_comma ? "," : "", 1863208737Sjmallett framesz); 1864208737Sjmallett 1865208737Sjmallett if (l & 0x40) /* $ra */ 1866208737Sjmallett (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]); 1867208737Sjmallett 1868208737Sjmallett nsreg = (l >> 24) & 0x7; 1869208737Sjmallett smask = 0; 1870208737Sjmallett if (l & 0x20) /* $s0 */ 1871208737Sjmallett smask |= 1 << 0; 1872208737Sjmallett if (l & 0x10) /* $s1 */ 1873208737Sjmallett smask |= 1 << 1; 1874208737Sjmallett if (nsreg > 0) /* $s2-$s8 */ 1875208737Sjmallett smask |= ((1 << nsreg) - 1) << 2; 1876208737Sjmallett 1877208737Sjmallett /* Find first set static reg bit. */ 1878208737Sjmallett for (i = 0; i < 9; i++) 1879208737Sjmallett { 1880208737Sjmallett if (smask & (1 << i)) 1881208737Sjmallett { 1882208737Sjmallett (*info->fprintf_func) (info->stream, ",%s", 1883208737Sjmallett mips_gpr_names[i == 8 ? 30 : (16 + i)]); 1884208737Sjmallett /* Skip over string of set bits. */ 1885208737Sjmallett for (j = i; smask & (2 << j); j++) 1886208737Sjmallett continue; 1887208737Sjmallett if (j > i) 1888208737Sjmallett (*info->fprintf_func) (info->stream, "-%s", 1889208737Sjmallett mips_gpr_names[j == 8 ? 30 : (16 + j)]); 1890208737Sjmallett i = j + 1; 1891208737Sjmallett } 1892208737Sjmallett } 1893208737Sjmallett 1894208737Sjmallett /* Statics $ax - $a3. */ 1895208737Sjmallett if (statics == 1) 1896208737Sjmallett (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]); 1897208737Sjmallett else if (statics > 0) 1898208737Sjmallett (*info->fprintf_func) (info->stream, ",%s-%s", 1899208737Sjmallett mips_gpr_names[7 - statics + 1], 1900208737Sjmallett mips_gpr_names[7]); 1901208737Sjmallett } 1902208737Sjmallett break; 1903208737Sjmallett 1904179404Sobrien default: 1905179404Sobrien /* xgettext:c-format */ 1906179404Sobrien (*info->fprintf_func) 1907179404Sobrien (info->stream, 1908179404Sobrien _("# internal disassembler error, unrecognised modifier (%c)"), 1909179404Sobrien type); 1910179404Sobrien abort (); 1911179404Sobrien } 1912179404Sobrien} 1913179404Sobrien 1914208737Sjmallett/* Disassemble mips16 instructions. */ 1915208737Sjmallett 1916208737Sjmallettstatic int 1917208737Sjmallettprint_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) 1918208737Sjmallett{ 1919208737Sjmallett int status; 1920208737Sjmallett bfd_byte buffer[2]; 1921208737Sjmallett int length; 1922208737Sjmallett int insn; 1923208737Sjmallett bfd_boolean use_extend; 1924208737Sjmallett int extend = 0; 1925208737Sjmallett const struct mips_opcode *op, *opend; 1926208737Sjmallett 1927208737Sjmallett info->bytes_per_chunk = 2; 1928208737Sjmallett info->display_endian = info->endian; 1929208737Sjmallett info->insn_info_valid = 1; 1930208737Sjmallett info->branch_delay_insns = 0; 1931208737Sjmallett info->data_size = 0; 1932208737Sjmallett info->insn_type = dis_nonbranch; 1933208737Sjmallett info->target = 0; 1934208737Sjmallett info->target2 = 0; 1935208737Sjmallett 1936208737Sjmallett status = (*info->read_memory_func) (memaddr, buffer, 2, info); 1937208737Sjmallett if (status != 0) 1938208737Sjmallett { 1939208737Sjmallett (*info->memory_error_func) (status, memaddr, info); 1940208737Sjmallett return -1; 1941208737Sjmallett } 1942208737Sjmallett 1943208737Sjmallett length = 2; 1944208737Sjmallett 1945208737Sjmallett if (info->endian == BFD_ENDIAN_BIG) 1946208737Sjmallett insn = bfd_getb16 (buffer); 1947208737Sjmallett else 1948208737Sjmallett insn = bfd_getl16 (buffer); 1949208737Sjmallett 1950208737Sjmallett /* Handle the extend opcode specially. */ 1951208737Sjmallett use_extend = FALSE; 1952208737Sjmallett if ((insn & 0xf800) == 0xf000) 1953208737Sjmallett { 1954208737Sjmallett use_extend = TRUE; 1955208737Sjmallett extend = insn & 0x7ff; 1956208737Sjmallett 1957208737Sjmallett memaddr += 2; 1958208737Sjmallett 1959208737Sjmallett status = (*info->read_memory_func) (memaddr, buffer, 2, info); 1960208737Sjmallett if (status != 0) 1961208737Sjmallett { 1962208737Sjmallett (*info->fprintf_func) (info->stream, "extend 0x%x", 1963208737Sjmallett (unsigned int) extend); 1964208737Sjmallett (*info->memory_error_func) (status, memaddr, info); 1965208737Sjmallett return -1; 1966208737Sjmallett } 1967208737Sjmallett 1968208737Sjmallett if (info->endian == BFD_ENDIAN_BIG) 1969208737Sjmallett insn = bfd_getb16 (buffer); 1970208737Sjmallett else 1971208737Sjmallett insn = bfd_getl16 (buffer); 1972208737Sjmallett 1973208737Sjmallett /* Check for an extend opcode followed by an extend opcode. */ 1974208737Sjmallett if ((insn & 0xf800) == 0xf000) 1975208737Sjmallett { 1976208737Sjmallett (*info->fprintf_func) (info->stream, "extend 0x%x", 1977208737Sjmallett (unsigned int) extend); 1978208737Sjmallett info->insn_type = dis_noninsn; 1979208737Sjmallett return length; 1980208737Sjmallett } 1981208737Sjmallett 1982208737Sjmallett length += 2; 1983208737Sjmallett } 1984208737Sjmallett 1985208737Sjmallett /* FIXME: Should probably use a hash table on the major opcode here. */ 1986208737Sjmallett 1987208737Sjmallett opend = mips16_opcodes + bfd_mips16_num_opcodes; 1988208737Sjmallett for (op = mips16_opcodes; op < opend; op++) 1989208737Sjmallett { 1990208737Sjmallett if (op->pinfo != INSN_MACRO 1991208737Sjmallett && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) 1992208737Sjmallett && (insn & op->mask) == op->match) 1993208737Sjmallett { 1994208737Sjmallett const char *s; 1995208737Sjmallett 1996208737Sjmallett if (strchr (op->args, 'a') != NULL) 1997208737Sjmallett { 1998208737Sjmallett if (use_extend) 1999208737Sjmallett { 2000208737Sjmallett (*info->fprintf_func) (info->stream, "extend 0x%x", 2001208737Sjmallett (unsigned int) extend); 2002208737Sjmallett info->insn_type = dis_noninsn; 2003208737Sjmallett return length - 2; 2004208737Sjmallett } 2005208737Sjmallett 2006208737Sjmallett use_extend = FALSE; 2007208737Sjmallett 2008208737Sjmallett memaddr += 2; 2009208737Sjmallett 2010208737Sjmallett status = (*info->read_memory_func) (memaddr, buffer, 2, 2011208737Sjmallett info); 2012208737Sjmallett if (status == 0) 2013208737Sjmallett { 2014208737Sjmallett use_extend = TRUE; 2015208737Sjmallett if (info->endian == BFD_ENDIAN_BIG) 2016208737Sjmallett extend = bfd_getb16 (buffer); 2017208737Sjmallett else 2018208737Sjmallett extend = bfd_getl16 (buffer); 2019208737Sjmallett length += 2; 2020208737Sjmallett } 2021208737Sjmallett } 2022208737Sjmallett 2023208737Sjmallett (*info->fprintf_func) (info->stream, "%s", op->name); 2024208737Sjmallett if (op->args[0] != '\0') 2025208737Sjmallett (*info->fprintf_func) (info->stream, "\t"); 2026208737Sjmallett 2027208737Sjmallett for (s = op->args; *s != '\0'; s++) 2028208737Sjmallett { 2029208737Sjmallett if (*s == ',' 2030208737Sjmallett && s[1] == 'w' 2031208737Sjmallett && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) 2032208737Sjmallett == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) 2033208737Sjmallett { 2034208737Sjmallett /* Skip the register and the comma. */ 2035208737Sjmallett ++s; 2036208737Sjmallett continue; 2037208737Sjmallett } 2038208737Sjmallett if (*s == ',' 2039208737Sjmallett && s[1] == 'v' 2040208737Sjmallett && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) 2041208737Sjmallett == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) 2042208737Sjmallett { 2043208737Sjmallett /* Skip the register and the comma. */ 2044208737Sjmallett ++s; 2045208737Sjmallett continue; 2046208737Sjmallett } 2047208737Sjmallett print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr, 2048208737Sjmallett info); 2049208737Sjmallett } 2050208737Sjmallett 2051208737Sjmallett if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) 2052208737Sjmallett { 2053208737Sjmallett info->branch_delay_insns = 1; 2054208737Sjmallett if (info->insn_type != dis_jsr) 2055208737Sjmallett info->insn_type = dis_branch; 2056208737Sjmallett } 2057208737Sjmallett 2058208737Sjmallett return length; 2059208737Sjmallett } 2060208737Sjmallett } 2061208737Sjmallett 2062208737Sjmallett if (use_extend) 2063208737Sjmallett (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000); 2064208737Sjmallett (*info->fprintf_func) (info->stream, "0x%x", insn); 2065208737Sjmallett info->insn_type = dis_noninsn; 2066208737Sjmallett 2067208737Sjmallett return length; 2068208737Sjmallett} 2069208737Sjmallett 2070208737Sjmallett/* In an environment where we do not know the symbol type of the 2071208737Sjmallett instruction we are forced to assume that the low order bit of the 2072208737Sjmallett instructions' address may mark it as a mips16 instruction. If we 2073208737Sjmallett are single stepping, or the pc is within the disassembled function, 2074208737Sjmallett this works. Otherwise, we need a clue. Sometimes. */ 2075208737Sjmallett 2076208737Sjmallettstatic int 2077208737Sjmallett_print_insn_mips (bfd_vma memaddr, 2078208737Sjmallett struct disassemble_info *info, 2079208737Sjmallett enum bfd_endian endianness) 2080208737Sjmallett{ 2081208737Sjmallett bfd_byte buffer[INSNLEN]; 2082208737Sjmallett int status; 2083208737Sjmallett 2084208737Sjmallett set_default_mips_dis_options (info); 2085208737Sjmallett parse_mips_dis_options (info->disassembler_options); 2086208737Sjmallett 2087208737Sjmallett#if 1 2088208737Sjmallett /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */ 2089208737Sjmallett /* Only a few tools will work this way. */ 2090208737Sjmallett if (memaddr & 0x01) 2091208737Sjmallett return print_insn_mips16 (memaddr, info); 2092208737Sjmallett#endif 2093208737Sjmallett 2094208737Sjmallett#if SYMTAB_AVAILABLE 2095208737Sjmallett if (info->mach == bfd_mach_mips16 2096208737Sjmallett || (info->flavour == bfd_target_elf_flavour 2097208737Sjmallett && info->symbols != NULL 2098208737Sjmallett && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other 2099208737Sjmallett == STO_MIPS16))) 2100208737Sjmallett return print_insn_mips16 (memaddr, info); 2101208737Sjmallett#endif 2102208737Sjmallett 2103208737Sjmallett status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info); 2104208737Sjmallett if (status == 0) 2105208737Sjmallett { 2106208737Sjmallett unsigned long insn; 2107208737Sjmallett 2108208737Sjmallett if (endianness == BFD_ENDIAN_BIG) 2109208737Sjmallett insn = (unsigned long) bfd_getb32 (buffer); 2110208737Sjmallett else 2111208737Sjmallett insn = (unsigned long) bfd_getl32 (buffer); 2112208737Sjmallett 2113208737Sjmallett return print_insn_mips (memaddr, insn, info); 2114208737Sjmallett } 2115208737Sjmallett else 2116208737Sjmallett { 2117208737Sjmallett (*info->memory_error_func) (status, memaddr, info); 2118208737Sjmallett return -1; 2119208737Sjmallett } 2120208737Sjmallett} 2121208737Sjmallett 2122208737Sjmallettint 2123208737Sjmallettprint_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info) 2124208737Sjmallett{ 2125208737Sjmallett return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG); 2126208737Sjmallett} 2127208737Sjmallett 2128208737Sjmallettint 2129208737Sjmallettprint_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info) 2130208737Sjmallett{ 2131208737Sjmallett return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); 2132208737Sjmallett} 2133208737Sjmallett 2134179404Sobrienvoid 2135208737Sjmallettprint_mips_disassembler_options (FILE *stream) 2136179404Sobrien{ 2137179404Sobrien unsigned int i; 2138179404Sobrien 2139179404Sobrien fprintf (stream, _("\n\ 2140179404SobrienThe following MIPS specific disassembler options are supported for use\n\ 2141179404Sobrienwith the -M switch (multiple options should be separated by commas):\n")); 2142179404Sobrien 2143179404Sobrien fprintf (stream, _("\n\ 2144208737Sjmallett octeon-useun Disassemble Octeon unaligned load/store instructions.\n")); 2145208737Sjmallett 2146208737Sjmallett fprintf (stream, _("\n\ 2147208737Sjmallett no-octeon-useun Disassemble mips unaligned load/store instructions.\n")); 2148208737Sjmallett 2149208737Sjmallett fprintf (stream, _("\n\ 2150179404Sobrien gpr-names=ABI Print GPR names according to specified ABI.\n\ 2151179404Sobrien Default: based on binary being disassembled.\n")); 2152179404Sobrien 2153179404Sobrien fprintf (stream, _("\n\ 2154179404Sobrien fpr-names=ABI Print FPR names according to specified ABI.\n\ 2155179404Sobrien Default: numeric.\n")); 2156179404Sobrien 2157179404Sobrien fprintf (stream, _("\n\ 2158179404Sobrien cp0-names=ARCH Print CP0 register names according to\n\ 2159179404Sobrien specified architecture.\n\ 2160179404Sobrien Default: based on binary being disassembled.\n")); 2161179404Sobrien 2162179404Sobrien fprintf (stream, _("\n\ 2163179404Sobrien hwr-names=ARCH Print HWR names according to specified \n\ 2164179404Sobrien architecture.\n\ 2165179404Sobrien Default: based on binary being disassembled.\n")); 2166179404Sobrien 2167179404Sobrien fprintf (stream, _("\n\ 2168179404Sobrien reg-names=ABI Print GPR and FPR names according to\n\ 2169179404Sobrien specified ABI.\n")); 2170179404Sobrien 2171179404Sobrien fprintf (stream, _("\n\ 2172179404Sobrien reg-names=ARCH Print CP0 register and HWR names according to\n\ 2173179404Sobrien specified architecture.\n")); 2174179404Sobrien 2175179404Sobrien fprintf (stream, _("\n\ 2176179404Sobrien For the options above, the following values are supported for \"ABI\":\n\ 2177179404Sobrien ")); 2178179404Sobrien for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) 2179179404Sobrien fprintf (stream, " %s", mips_abi_choices[i].name); 2180179404Sobrien fprintf (stream, _("\n")); 2181179404Sobrien 2182179404Sobrien fprintf (stream, _("\n\ 2183179404Sobrien For the options above, The following values are supported for \"ARCH\":\n\ 2184179404Sobrien ")); 2185179404Sobrien for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) 2186179404Sobrien if (*mips_arch_choices[i].name != '\0') 2187179404Sobrien fprintf (stream, " %s", mips_arch_choices[i].name); 2188179404Sobrien fprintf (stream, _("\n")); 2189179404Sobrien 2190179404Sobrien fprintf (stream, _("\n")); 2191179404Sobrien} 2192