1 /* $NetBSD: db_disasm.c,v 1.11 2002/11/04 03:30:32 thorpej 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 <machine/db_machdep.h> 51 52 #include <ddb/db_interface.h> 53 #include <ddb/db_output.h> 54 #include <ddb/db_extern.h> 55 #include <ddb/db_sym.h> 56 57 static char *op_name[64] = { 58 /* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", 59 /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", 60 /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", 61 /*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", 62 /*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", 63 /*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", 64 /*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", 65 /*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" 66 }; 67 68 static char *spec_name[64] = { 69 /* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", 70 /* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", 71 /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", 72 /*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", 73 /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", 74 /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", 75 /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", 76 /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" 77 }; 78 79 static char *spec2_name[4] = { /* QED RM4650, R5000, etc. */ 80 /* 0 */ "mad", "madu", "mul", "spec3" 81 }; 82 83 static char *bcond_name[32] = { 84 /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", 85 /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", 86 /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", 87 /*24 */ "?", "?", "?", "?", "?", "?", "?", "?", 88 }; 89 90 static char *cop1_name[64] = { 91 /* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", 92 /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", 93 /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", 94 /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", 95 /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", 96 /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", 97 /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", 98 "fcmp.ole","fcmp.ule", 99 /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", 100 "fcmp.le","fcmp.ngt" 101 }; 102 103 static char *fmt_name[16] = { 104 "s", "d", "e", "fmt3", 105 "w", "fmt5", "fmt6", "fmt7", 106 "fmt8", "fmt9", "fmta", "fmtb", 107 "fmtc", "fmtd", "fmte", "fmtf" 108 }; 109 110 #if defined(__mips_n32) || defined(__mips_n64) 111 static char *reg_name[32] = { 112 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 113 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", 114 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 115 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 116 }; 117 #else 118 static char *reg_name[32] = { 119 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 120 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 121 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 122 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 123 }; 124 #endif /* __mips_n32 || __mips_n64 */ 125 126 static char *c0_opname[64] = { 127 "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", 128 "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", 129 "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", 130 "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", 131 "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", 132 "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", 133 "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", 134 "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", 135 }; 136 137 static char *c0_reg[32] = { 138 "index", "random", "tlblo0", "tlblo1", 139 "context", "pagemask", "wired", "cp0r7", 140 "badvaddr", "count", "tlbhi", "compare", 141 "status", "cause", "epc", "prid", 142 "config", "lladdr", "watchlo", "watchhi", 143 "xcontext", "cp0r21", "cp0r22", "debug", 144 "depc", "perfcnt", "ecc", "cacheerr", 145 "taglo", "taghi", "errepc", "desave" 146 }; 147 148 static void print_addr(db_addr_t); 149 150 /* 151 * Disassemble instruction at 'loc'. 'altfmt' specifies an 152 * (optional) alternate format (altfmt for vax: don't assume 153 * that each external label is a procedure entry mask). 154 * Return address of start of next instruction. 155 * Since this function is used by 'examine' and by 'step' 156 * "next instruction" does NOT mean the next instruction to 157 * be executed but the 'linear' next instruction. 158 */ 159 db_addr_t 160 db_disasm(db_addr_t loc, boolean_t altfmt) 161 { 162 u_int32_t instr; 163 164 /* 165 * Take some care with addresses to not UTLB here as it 166 * loses the current debugging context. KSEG2 not checked. 167 */ 168 if (loc < MIPS_KSEG0_START) { 169 instr = fuword((void *)loc); 170 if (instr == 0xffffffff) { 171 /* "sd ra, -1(ra)" is unlikely */ 172 db_printf("invalid address.\n"); 173 return loc; 174 } 175 } 176 else { 177 instr = *(u_int32_t *)loc; 178 } 179 180 return (db_disasm_insn(instr, loc, altfmt)); 181 } 182 183 184 /* 185 * Disassemble instruction 'insn' nominally at 'loc'. 186 * 'loc' may in fact contain a breakpoint instruction. 187 */ 188 db_addr_t 189 db_disasm_insn(int insn, db_addr_t loc, boolean_t altfmt) 190 { 191 boolean_t bdslot = FALSE; 192 InstFmt i; 193 194 i.word = insn; 195 196 switch (i.JType.op) { 197 case OP_SPECIAL: 198 if (i.word == 0) { 199 db_printf("nop"); 200 break; 201 } 202 /* XXX 203 * "addu" is a "move" only in 32-bit mode. What's the correct 204 * answer - never decode addu/daddu as "move"? 205 */ 206 if (i.RType.func == OP_ADDU && i.RType.rt == 0) { 207 db_printf("move\t%s,%s", 208 reg_name[i.RType.rd], 209 reg_name[i.RType.rs]); 210 break; 211 } 212 db_printf("%s", spec_name[i.RType.func]); 213 switch (i.RType.func) { 214 case OP_SLL: 215 case OP_SRL: 216 case OP_SRA: 217 case OP_DSLL: 218 219 case OP_DSRL: 220 case OP_DSRA: 221 case OP_DSLL32: 222 case OP_DSRL32: 223 case OP_DSRA32: 224 db_printf("\t%s,%s,%d", 225 reg_name[i.RType.rd], 226 reg_name[i.RType.rt], 227 i.RType.shamt); 228 break; 229 230 case OP_SLLV: 231 case OP_SRLV: 232 case OP_SRAV: 233 case OP_DSLLV: 234 case OP_DSRLV: 235 case OP_DSRAV: 236 db_printf("\t%s,%s,%s", 237 reg_name[i.RType.rd], 238 reg_name[i.RType.rt], 239 reg_name[i.RType.rs]); 240 break; 241 242 case OP_MFHI: 243 case OP_MFLO: 244 db_printf("\t%s", reg_name[i.RType.rd]); 245 break; 246 247 case OP_JR: 248 case OP_JALR: 249 db_printf("\t%s", reg_name[i.RType.rs]); 250 bdslot = TRUE; 251 break; 252 case OP_MTLO: 253 case OP_MTHI: 254 db_printf("\t%s", reg_name[i.RType.rs]); 255 break; 256 257 case OP_MULT: 258 case OP_MULTU: 259 case OP_DMULT: 260 case OP_DMULTU: 261 case OP_DIV: 262 case OP_DIVU: 263 case OP_DDIV: 264 case OP_DDIVU: 265 db_printf("\t%s,%s", 266 reg_name[i.RType.rs], 267 reg_name[i.RType.rt]); 268 break; 269 270 271 case OP_SYSCALL: 272 case OP_SYNC: 273 break; 274 275 case OP_BREAK: 276 db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); 277 break; 278 279 default: 280 db_printf("\t%s,%s,%s", 281 reg_name[i.RType.rd], 282 reg_name[i.RType.rs], 283 reg_name[i.RType.rt]); 284 } 285 break; 286 287 case OP_SPECIAL2: 288 if (i.RType.func == OP_MUL) 289 db_printf("%s\t%s,%s,%s", 290 spec2_name[i.RType.func & 0x3], 291 reg_name[i.RType.rd], 292 reg_name[i.RType.rs], 293 reg_name[i.RType.rt]); 294 else 295 db_printf("%s\t%s,%s", 296 spec2_name[i.RType.func & 0x3], 297 reg_name[i.RType.rs], 298 reg_name[i.RType.rt]); 299 300 break; 301 302 case OP_BCOND: 303 db_printf("%s\t%s,", bcond_name[i.IType.rt], 304 reg_name[i.IType.rs]); 305 goto pr_displ; 306 307 case OP_BLEZ: 308 case OP_BLEZL: 309 case OP_BGTZ: 310 case OP_BGTZL: 311 db_printf("%s\t%s,", op_name[i.IType.op], 312 reg_name[i.IType.rs]); 313 goto pr_displ; 314 315 case OP_BEQ: 316 case OP_BEQL: 317 if (i.IType.rs == 0 && i.IType.rt == 0) { 318 db_printf("b\t"); 319 goto pr_displ; 320 } 321 /* FALLTHROUGH */ 322 case OP_BNE: 323 case OP_BNEL: 324 db_printf("%s\t%s,%s,", op_name[i.IType.op], 325 reg_name[i.IType.rs], 326 reg_name[i.IType.rt]); 327 pr_displ: 328 print_addr(loc + 4 + ((short)i.IType.imm << 2)); 329 bdslot = TRUE; 330 break; 331 332 case OP_COP0: 333 switch (i.RType.rs) { 334 case OP_BCx: 335 case OP_BCy: 336 337 db_printf("bc0%c\t", 338 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 339 goto pr_displ; 340 341 case OP_MT: 342 db_printf("mtc0\t%s,%s", 343 reg_name[i.RType.rt], 344 c0_reg[i.RType.rd]); 345 break; 346 347 case OP_DMT: 348 db_printf("dmtc0\t%s,%s", 349 reg_name[i.RType.rt], 350 c0_reg[i.RType.rd]); 351 break; 352 353 case OP_MF: 354 db_printf("mfc0\t%s,%s", 355 reg_name[i.RType.rt], 356 c0_reg[i.RType.rd]); 357 break; 358 359 case OP_DMF: 360 db_printf("dmfc0\t%s,%s", 361 reg_name[i.RType.rt], 362 c0_reg[i.RType.rd]); 363 break; 364 365 default: 366 db_printf("%s", c0_opname[i.FRType.func]); 367 } 368 break; 369 370 case OP_COP1: 371 switch (i.RType.rs) { 372 case OP_BCx: 373 case OP_BCy: 374 db_printf("bc1%c\t", 375 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 376 goto pr_displ; 377 378 case OP_MT: 379 db_printf("mtc1\t%s,f%d", 380 reg_name[i.RType.rt], 381 i.RType.rd); 382 break; 383 384 case OP_MF: 385 db_printf("mfc1\t%s,f%d", 386 reg_name[i.RType.rt], 387 i.RType.rd); 388 break; 389 390 case OP_CT: 391 db_printf("ctc1\t%s,f%d", 392 reg_name[i.RType.rt], 393 i.RType.rd); 394 break; 395 396 case OP_CF: 397 db_printf("cfc1\t%s,f%d", 398 reg_name[i.RType.rt], 399 i.RType.rd); 400 break; 401 402 default: 403 db_printf("%s.%s\tf%d,f%d,f%d", 404 cop1_name[i.FRType.func], 405 fmt_name[i.FRType.fmt], 406 i.FRType.fd, i.FRType.fs, i.FRType.ft); 407 } 408 break; 409 410 case OP_J: 411 case OP_JAL: 412 db_printf("%s\t", op_name[i.JType.op]); 413 print_addr((loc & 0xF0000000) | (i.JType.target << 2)); 414 bdslot = TRUE; 415 break; 416 417 case OP_LWC1: 418 case OP_SWC1: 419 db_printf("%s\tf%d,", op_name[i.IType.op], 420 i.IType.rt); 421 goto loadstore; 422 423 case OP_LB: 424 case OP_LH: 425 case OP_LW: 426 case OP_LD: 427 case OP_LBU: 428 case OP_LHU: 429 case OP_LWU: 430 case OP_SB: 431 case OP_SH: 432 case OP_SW: 433 case OP_SD: 434 db_printf("%s\t%s,", op_name[i.IType.op], 435 reg_name[i.IType.rt]); 436 loadstore: 437 db_printf("%d(%s)", (short)i.IType.imm, 438 reg_name[i.IType.rs]); 439 break; 440 441 case OP_ORI: 442 case OP_XORI: 443 if (i.IType.rs == 0) { 444 db_printf("li\t%s,0x%x", 445 reg_name[i.IType.rt], 446 i.IType.imm); 447 break; 448 } 449 /* FALLTHROUGH */ 450 case OP_ANDI: 451 db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], 452 reg_name[i.IType.rt], 453 reg_name[i.IType.rs], 454 i.IType.imm); 455 break; 456 457 case OP_LUI: 458 db_printf("%s\t%s,0x%x", op_name[i.IType.op], 459 reg_name[i.IType.rt], 460 i.IType.imm); 461 break; 462 463 case OP_CACHE: 464 db_printf("%s\t0x%x,0x%x(%s)", 465 op_name[i.IType.op], 466 i.IType.rt, 467 i.IType.imm, 468 reg_name[i.IType.rs]); 469 break; 470 471 case OP_ADDI: 472 case OP_DADDI: 473 case OP_ADDIU: 474 case OP_DADDIU: 475 if (i.IType.rs == 0) { 476 db_printf("li\t%s,%d", 477 reg_name[i.IType.rt], 478 (short)i.IType.imm); 479 break; 480 } 481 /* FALLTHROUGH */ 482 default: 483 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 484 reg_name[i.IType.rt], 485 reg_name[i.IType.rs], 486 (short)i.IType.imm); 487 } 488 db_printf("\n"); 489 if (bdslot) { 490 db_printf("\t\tbdslot:\t"); 491 db_disasm(loc+4, FALSE); 492 return (loc + 8); 493 } 494 return (loc + 4); 495 } 496 497 static void 498 print_addr(db_addr_t loc) 499 { 500 db_expr_t diff; 501 db_sym_t sym; 502 char *symname; 503 504 diff = INT_MAX; 505 symname = NULL; 506 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 507 db_symbol_values(sym, &symname, 0); 508 509 if (symname) { 510 if (diff == 0) 511 db_printf("%s", symname); 512 else 513 db_printf("<%s+%lx>", symname, diff); 514 db_printf("\t[addr:0x%08lx]", loc); 515 } else { 516 db_printf("0x%08lx", loc); 517 } 518 } 519