1 /* $NetBSD: db_disasm.c,v 1.2 1997/08/17 16:58:53 mhitch Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Ralph Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 39 */ 40 41 42 #include <sys/types.h> 43 #include <sys/systm.h> 44 #include <sys/param.h> 45 46 #include <machine/reg.h> 47 #include <machine/cpu.h> 48 #include <mips/mips_opcode.h> 49 /*#include <machine/param.h>*/ 50 #include <mips/db_machdep.h> 51 52 #include <ddb/db_interface.h> 53 #include <ddb/db_output.h> 54 #include <ddb/db_sym.h> 55 56 static char *op_name[64] = { 57 /* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", 58 /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", 59 /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", 60 /*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", 61 /*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", 62 /*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", 63 /*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", 64 /*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" 65 }; 66 67 static char *spec_name[64] = { 68 /* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", 69 /* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", 70 /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", 71 /*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", 72 /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", 73 /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", 74 /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", 75 /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" 76 }; 77 78 static char *bcond_name[32] = { 79 /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", 80 /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", 81 /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", 82 /*24 */ "?", "?", "?", "?", "?", "?", "?", "?", 83 }; 84 85 static char *cop1_name[64] = { 86 /* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", 87 /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", 88 /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", 89 /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", 90 /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", 91 /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", 92 /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", 93 "fcmp.ole","fcmp.ule", 94 /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", 95 "fcmp.le","fcmp.ngt" 96 }; 97 98 static char *fmt_name[16] = { 99 "s", "d", "e", "fmt3", 100 "w", "fmt5", "fmt6", "fmt7", 101 "fmt8", "fmt9", "fmta", "fmtb", 102 "fmtc", "fmtd", "fmte", "fmtf" 103 }; 104 105 static char *reg_name[32] = { 106 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 107 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 108 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 109 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 110 }; 111 112 static char *c0_opname[64] = { 113 "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", 114 "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", 115 "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", 116 "eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", 117 "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", 118 "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", 119 "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", 120 "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", 121 }; 122 123 static char *c0_reg[32] = { 124 "index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7", 125 "badvaddr","count","tlbhi","c0r11","sr","cause","epc", "prid", 126 "config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23", 127 "c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31" 128 }; 129 130 void print_addr(long); 131 132 /* 133 * Disassemble instruction at 'loc'. 'altfmt' specifies an 134 * (optional) alternate format (altfmt for vax: don't assume 135 * that each external label is a procedure entry mask). 136 * Return address of start of next instruction. 137 * Since this function is used by 'examine' and by 'step' 138 * "next instruction" does NOT mean the next instruction to 139 * be executed but the 'linear' next instruction. 140 */ 141 db_addr_t 142 db_disasm(loc, altfmt) 143 db_addr_t loc; 144 boolean_t altfmt; 145 146 { 147 return (db_disasm_insn(*(int*)loc, loc, altfmt)); 148 } 149 150 151 /* 152 * Disassemble instruction 'insn' nominally at 'loc'. 153 * 'loc' may in fact contain a breakpoint instruction. 154 */ 155 db_addr_t 156 db_disasm_insn(insn, loc, altfmt) 157 int insn; 158 db_addr_t loc; 159 boolean_t altfmt; 160 { 161 InstFmt i; 162 163 i.word = insn; 164 165 switch (i.JType.op) { 166 case OP_SPECIAL: 167 if (i.word == 0) { 168 db_printf("nop"); 169 break; 170 } 171 if (i.RType.func == OP_ADDU && i.RType.rt == 0) { 172 db_printf("move\t%s,%s", 173 reg_name[i.RType.rd], 174 reg_name[i.RType.rs]); 175 break; 176 } 177 db_printf("%s", spec_name[i.RType.func]); 178 switch (i.RType.func) { 179 case OP_SLL: 180 case OP_SRL: 181 case OP_SRA: 182 case OP_DSLL: 183 184 case OP_DSRL: 185 case OP_DSRA: 186 case OP_DSLL32: 187 case OP_DSRL32: 188 case OP_DSRA32: 189 db_printf("\t%s,%s,%d", 190 reg_name[i.RType.rd], 191 reg_name[i.RType.rt], 192 i.RType.shamt); 193 break; 194 195 case OP_SLLV: 196 case OP_SRLV: 197 case OP_SRAV: 198 case OP_DSLLV: 199 case OP_DSRLV: 200 case OP_DSRAV: 201 db_printf("\t%s,%s,%s", 202 reg_name[i.RType.rd], 203 reg_name[i.RType.rt], 204 reg_name[i.RType.rs]); 205 break; 206 207 case OP_MFHI: 208 case OP_MFLO: 209 db_printf("\t%s", reg_name[i.RType.rd]); 210 break; 211 212 case OP_JR: 213 case OP_JALR: 214 /* FALLTHROUGH */ 215 case OP_MTLO: 216 case OP_MTHI: 217 db_printf("\t%s", reg_name[i.RType.rs]); 218 break; 219 220 case OP_MULT: 221 case OP_MULTU: 222 case OP_DMULT: 223 case OP_DMULTU: 224 case OP_DIV: 225 case OP_DIVU: 226 case OP_DDIV: 227 case OP_DDIVU: 228 db_printf("\t%s,%s", 229 reg_name[i.RType.rs], 230 reg_name[i.RType.rt]); 231 break; 232 233 234 case OP_SYSCALL: 235 case OP_SYNC: 236 break; 237 238 case OP_BREAK: 239 db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); 240 break; 241 242 default: 243 db_printf("\t%s,%s,%s", 244 reg_name[i.RType.rd], 245 reg_name[i.RType.rs], 246 reg_name[i.RType.rt]); 247 } 248 break; 249 250 case OP_BCOND: 251 db_printf("%s\t%s,", bcond_name[i.IType.rt], 252 reg_name[i.IType.rs]); 253 goto pr_displ; 254 255 case OP_BLEZ: 256 case OP_BLEZL: 257 case OP_BGTZ: 258 case OP_BGTZL: 259 db_printf("%s\t%s,", op_name[i.IType.op], 260 reg_name[i.IType.rs]); 261 goto pr_displ; 262 263 case OP_BEQ: 264 case OP_BEQL: 265 if (i.IType.rs == 0 && i.IType.rt == 0) { 266 db_printf("b\t"); 267 goto pr_displ; 268 } 269 /* FALLTHROUGH */ 270 case OP_BNE: 271 case OP_BNEL: 272 db_printf("%s\t%s,%s,", op_name[i.IType.op], 273 reg_name[i.IType.rs], 274 reg_name[i.IType.rt]); 275 pr_displ: 276 print_addr(loc + 4 + ((short)i.IType.imm << 2)); 277 break; 278 279 case OP_COP0: 280 switch (i.RType.rs) { 281 case OP_BCx: 282 case OP_BCy: 283 284 db_printf("bc0%c\t", 285 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 286 goto pr_displ; 287 288 case OP_MT: 289 db_printf("mtc0\t%s,%s", 290 reg_name[i.RType.rt], 291 c0_reg[i.RType.rd]); 292 break; 293 294 case OP_DMT: 295 db_printf("dmtc0\t%s,%s", 296 reg_name[i.RType.rt], 297 c0_reg[i.RType.rd]); 298 break; 299 300 case OP_MF: 301 db_printf("mfc0\t%s,%s", 302 reg_name[i.RType.rt], 303 c0_reg[i.RType.rd]); 304 break; 305 306 case OP_DMF: 307 db_printf("dmfc0\t%s,%s", 308 reg_name[i.RType.rt], 309 c0_reg[i.RType.rd]); 310 break; 311 312 default: 313 db_printf("%s", c0_opname[i.FRType.func]); 314 } 315 break; 316 317 case OP_COP1: 318 switch (i.RType.rs) { 319 case OP_BCx: 320 case OP_BCy: 321 db_printf("bc1%c\t", 322 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 323 goto pr_displ; 324 325 case OP_MT: 326 db_printf("mtc1\t%s,f%d", 327 reg_name[i.RType.rt], 328 i.RType.rd); 329 break; 330 331 case OP_MF: 332 db_printf("mfc1\t%s,f%d", 333 reg_name[i.RType.rt], 334 i.RType.rd); 335 break; 336 337 case OP_CT: 338 db_printf("ctc1\t%s,f%d", 339 reg_name[i.RType.rt], 340 i.RType.rd); 341 break; 342 343 case OP_CF: 344 db_printf("cfc1\t%s,f%d", 345 reg_name[i.RType.rt], 346 i.RType.rd); 347 break; 348 349 default: 350 db_printf("%s.%s\tf%d,f%d,f%d", 351 cop1_name[i.FRType.func], 352 fmt_name[i.FRType.fmt], 353 i.FRType.fd, i.FRType.fs, i.FRType.ft); 354 } 355 break; 356 357 case OP_J: 358 case OP_JAL: 359 db_printf("%s\t", op_name[i.JType.op]); 360 print_addr((loc & 0xF0000000) | (i.JType.target << 2)); 361 break; 362 363 case OP_LWC1: 364 case OP_SWC1: 365 db_printf("%s\tf%d,", op_name[i.IType.op], 366 i.IType.rt); 367 goto loadstore; 368 369 case OP_LB: 370 case OP_LH: 371 case OP_LW: 372 case OP_LD: 373 case OP_LBU: 374 case OP_LHU: 375 case OP_LWU: 376 case OP_SB: 377 case OP_SH: 378 case OP_SW: 379 case OP_SD: 380 db_printf("%s\t%s,", op_name[i.IType.op], 381 reg_name[i.IType.rt]); 382 loadstore: 383 db_printf("%d(%s)", (short)i.IType.imm, 384 reg_name[i.IType.rs]); 385 break; 386 387 case OP_ORI: 388 case OP_XORI: 389 if (i.IType.rs == 0) { 390 db_printf("li\t%s,0x%x", 391 reg_name[i.IType.rt], 392 i.IType.imm); 393 break; 394 } 395 /* FALLTHROUGH */ 396 case OP_ANDI: 397 db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], 398 reg_name[i.IType.rt], 399 reg_name[i.IType.rs], 400 i.IType.imm); 401 break; 402 403 case OP_LUI: 404 db_printf("%s\t%s,0x%x", op_name[i.IType.op], 405 reg_name[i.IType.rt], 406 i.IType.imm); 407 break; 408 409 case OP_ADDI: 410 case OP_DADDI: 411 case OP_ADDIU: 412 case OP_DADDIU: 413 if (i.IType.rs == 0) { 414 db_printf("li\t%s,%d", 415 reg_name[i.IType.rt], 416 (short)i.IType.imm); 417 break; 418 } 419 /* FALLTHROUGH */ 420 default: 421 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 422 reg_name[i.IType.rt], 423 reg_name[i.IType.rs], 424 (short)i.IType.imm); 425 } 426 db_printf("\n"); 427 return (loc + 4); 428 } 429 430 void 431 print_addr(loc) 432 long loc; 433 { 434 db_expr_t diff; 435 db_sym_t sym; 436 char *symname; 437 438 diff = INT_MAX; 439 symname = NULL; 440 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 441 db_symbol_values(sym, &symname, 0); 442 443 if (symname) { 444 if (diff == 0) 445 db_printf("%s", symname); 446 else 447 db_printf("<%s+%lx>", symname, diff); 448 db_printf("\t[addr:0x%08lx]", loc); 449 } else { 450 db_printf("0x%08lx", loc); 451 } 452 } 453