1 /* $NetBSD: db_disasm.c,v 1.10 2002/02/22 16:18:36 simonb 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 static char *reg_name[32] = { 111 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 112 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 113 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 114 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 115 }; 116 117 static char *c0_opname[64] = { 118 "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", 119 "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", 120 "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", 121 "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", 122 "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", 123 "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", 124 "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", 125 "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", 126 }; 127 128 static char *c0_reg[32] = { 129 "index", "random", "tlblo0", "tlblo1", 130 "context", "pagemask", "wired", "cp0r7", 131 "badvaddr", "count", "tlbhi", "compare", 132 "status", "cause", "epc", "prid", 133 "config", "lladdr", "watchlo", "watchhi", 134 "xcontext", "cp0r21", "cp0r22", "debug", 135 "depc", "perfcnt", "ecc", "cacheerr", 136 "taglo", "taghi", "errepc", "desave" 137 }; 138 139 static void print_addr(db_addr_t); 140 141 /* 142 * Disassemble instruction at 'loc'. 'altfmt' specifies an 143 * (optional) alternate format (altfmt for vax: don't assume 144 * that each external label is a procedure entry mask). 145 * Return address of start of next instruction. 146 * Since this function is used by 'examine' and by 'step' 147 * "next instruction" does NOT mean the next instruction to 148 * be executed but the 'linear' next instruction. 149 */ 150 db_addr_t 151 db_disasm(db_addr_t loc, boolean_t altfmt) 152 { 153 u_int32_t instr; 154 155 /* 156 * Take some care with addresses to not UTLB here as it 157 * loses the current debugging context. KSEG2 not checked. 158 */ 159 if (loc < MIPS_KSEG0_START) { 160 instr = fuword((void *)loc); 161 if (instr == 0xffffffff) { 162 /* "sd ra, -1(ra)" is unlikely */ 163 db_printf("invalid address.\n"); 164 return loc; 165 } 166 } 167 else { 168 instr = *(u_int32_t *)loc; 169 } 170 171 return (db_disasm_insn(instr, loc, altfmt)); 172 } 173 174 175 /* 176 * Disassemble instruction 'insn' nominally at 'loc'. 177 * 'loc' may in fact contain a breakpoint instruction. 178 */ 179 db_addr_t 180 db_disasm_insn(int insn, db_addr_t loc, boolean_t altfmt) 181 { 182 boolean_t bdslot = FALSE; 183 InstFmt i; 184 185 i.word = insn; 186 187 switch (i.JType.op) { 188 case OP_SPECIAL: 189 if (i.word == 0) { 190 db_printf("nop"); 191 break; 192 } 193 /* XXX 194 * "addu" is a "move" only in 32-bit mode. What's the correct 195 * answer - never decode addu/daddu as "move"? 196 */ 197 if (i.RType.func == OP_ADDU && i.RType.rt == 0) { 198 db_printf("move\t%s,%s", 199 reg_name[i.RType.rd], 200 reg_name[i.RType.rs]); 201 break; 202 } 203 db_printf("%s", spec_name[i.RType.func]); 204 switch (i.RType.func) { 205 case OP_SLL: 206 case OP_SRL: 207 case OP_SRA: 208 case OP_DSLL: 209 210 case OP_DSRL: 211 case OP_DSRA: 212 case OP_DSLL32: 213 case OP_DSRL32: 214 case OP_DSRA32: 215 db_printf("\t%s,%s,%d", 216 reg_name[i.RType.rd], 217 reg_name[i.RType.rt], 218 i.RType.shamt); 219 break; 220 221 case OP_SLLV: 222 case OP_SRLV: 223 case OP_SRAV: 224 case OP_DSLLV: 225 case OP_DSRLV: 226 case OP_DSRAV: 227 db_printf("\t%s,%s,%s", 228 reg_name[i.RType.rd], 229 reg_name[i.RType.rt], 230 reg_name[i.RType.rs]); 231 break; 232 233 case OP_MFHI: 234 case OP_MFLO: 235 db_printf("\t%s", reg_name[i.RType.rd]); 236 break; 237 238 case OP_JR: 239 case OP_JALR: 240 db_printf("\t%s", reg_name[i.RType.rs]); 241 bdslot = TRUE; 242 break; 243 case OP_MTLO: 244 case OP_MTHI: 245 db_printf("\t%s", reg_name[i.RType.rs]); 246 break; 247 248 case OP_MULT: 249 case OP_MULTU: 250 case OP_DMULT: 251 case OP_DMULTU: 252 case OP_DIV: 253 case OP_DIVU: 254 case OP_DDIV: 255 case OP_DDIVU: 256 db_printf("\t%s,%s", 257 reg_name[i.RType.rs], 258 reg_name[i.RType.rt]); 259 break; 260 261 262 case OP_SYSCALL: 263 case OP_SYNC: 264 break; 265 266 case OP_BREAK: 267 db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); 268 break; 269 270 default: 271 db_printf("\t%s,%s,%s", 272 reg_name[i.RType.rd], 273 reg_name[i.RType.rs], 274 reg_name[i.RType.rt]); 275 } 276 break; 277 278 case OP_SPECIAL2: 279 if (i.RType.func == OP_MUL) 280 db_printf("%s\t%s,%s,%s", 281 spec2_name[i.RType.func & 0x3], 282 reg_name[i.RType.rd], 283 reg_name[i.RType.rs], 284 reg_name[i.RType.rt]); 285 else 286 db_printf("%s\t%s,%s", 287 spec2_name[i.RType.func & 0x3], 288 reg_name[i.RType.rs], 289 reg_name[i.RType.rt]); 290 291 break; 292 293 case OP_BCOND: 294 db_printf("%s\t%s,", bcond_name[i.IType.rt], 295 reg_name[i.IType.rs]); 296 goto pr_displ; 297 298 case OP_BLEZ: 299 case OP_BLEZL: 300 case OP_BGTZ: 301 case OP_BGTZL: 302 db_printf("%s\t%s,", op_name[i.IType.op], 303 reg_name[i.IType.rs]); 304 goto pr_displ; 305 306 case OP_BEQ: 307 case OP_BEQL: 308 if (i.IType.rs == 0 && i.IType.rt == 0) { 309 db_printf("b\t"); 310 goto pr_displ; 311 } 312 /* FALLTHROUGH */ 313 case OP_BNE: 314 case OP_BNEL: 315 db_printf("%s\t%s,%s,", op_name[i.IType.op], 316 reg_name[i.IType.rs], 317 reg_name[i.IType.rt]); 318 pr_displ: 319 print_addr(loc + 4 + ((short)i.IType.imm << 2)); 320 bdslot = TRUE; 321 break; 322 323 case OP_COP0: 324 switch (i.RType.rs) { 325 case OP_BCx: 326 case OP_BCy: 327 328 db_printf("bc0%c\t", 329 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 330 goto pr_displ; 331 332 case OP_MT: 333 db_printf("mtc0\t%s,%s", 334 reg_name[i.RType.rt], 335 c0_reg[i.RType.rd]); 336 break; 337 338 case OP_DMT: 339 db_printf("dmtc0\t%s,%s", 340 reg_name[i.RType.rt], 341 c0_reg[i.RType.rd]); 342 break; 343 344 case OP_MF: 345 db_printf("mfc0\t%s,%s", 346 reg_name[i.RType.rt], 347 c0_reg[i.RType.rd]); 348 break; 349 350 case OP_DMF: 351 db_printf("dmfc0\t%s,%s", 352 reg_name[i.RType.rt], 353 c0_reg[i.RType.rd]); 354 break; 355 356 default: 357 db_printf("%s", c0_opname[i.FRType.func]); 358 } 359 break; 360 361 case OP_COP1: 362 switch (i.RType.rs) { 363 case OP_BCx: 364 case OP_BCy: 365 db_printf("bc1%c\t", 366 "ft"[i.RType.rt & COPz_BC_TF_MASK]); 367 goto pr_displ; 368 369 case OP_MT: 370 db_printf("mtc1\t%s,f%d", 371 reg_name[i.RType.rt], 372 i.RType.rd); 373 break; 374 375 case OP_MF: 376 db_printf("mfc1\t%s,f%d", 377 reg_name[i.RType.rt], 378 i.RType.rd); 379 break; 380 381 case OP_CT: 382 db_printf("ctc1\t%s,f%d", 383 reg_name[i.RType.rt], 384 i.RType.rd); 385 break; 386 387 case OP_CF: 388 db_printf("cfc1\t%s,f%d", 389 reg_name[i.RType.rt], 390 i.RType.rd); 391 break; 392 393 default: 394 db_printf("%s.%s\tf%d,f%d,f%d", 395 cop1_name[i.FRType.func], 396 fmt_name[i.FRType.fmt], 397 i.FRType.fd, i.FRType.fs, i.FRType.ft); 398 } 399 break; 400 401 case OP_J: 402 case OP_JAL: 403 db_printf("%s\t", op_name[i.JType.op]); 404 print_addr((loc & 0xF0000000) | (i.JType.target << 2)); 405 bdslot = TRUE; 406 break; 407 408 case OP_LWC1: 409 case OP_SWC1: 410 db_printf("%s\tf%d,", op_name[i.IType.op], 411 i.IType.rt); 412 goto loadstore; 413 414 case OP_LB: 415 case OP_LH: 416 case OP_LW: 417 case OP_LD: 418 case OP_LBU: 419 case OP_LHU: 420 case OP_LWU: 421 case OP_SB: 422 case OP_SH: 423 case OP_SW: 424 case OP_SD: 425 db_printf("%s\t%s,", op_name[i.IType.op], 426 reg_name[i.IType.rt]); 427 loadstore: 428 db_printf("%d(%s)", (short)i.IType.imm, 429 reg_name[i.IType.rs]); 430 break; 431 432 case OP_ORI: 433 case OP_XORI: 434 if (i.IType.rs == 0) { 435 db_printf("li\t%s,0x%x", 436 reg_name[i.IType.rt], 437 i.IType.imm); 438 break; 439 } 440 /* FALLTHROUGH */ 441 case OP_ANDI: 442 db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], 443 reg_name[i.IType.rt], 444 reg_name[i.IType.rs], 445 i.IType.imm); 446 break; 447 448 case OP_LUI: 449 db_printf("%s\t%s,0x%x", op_name[i.IType.op], 450 reg_name[i.IType.rt], 451 i.IType.imm); 452 break; 453 454 case OP_CACHE: 455 db_printf("%s\t0x%x,0x%x(%s)", 456 op_name[i.IType.op], 457 i.IType.rt, 458 i.IType.imm, 459 reg_name[i.IType.rs]); 460 break; 461 462 case OP_ADDI: 463 case OP_DADDI: 464 case OP_ADDIU: 465 case OP_DADDIU: 466 if (i.IType.rs == 0) { 467 db_printf("li\t%s,%d", 468 reg_name[i.IType.rt], 469 (short)i.IType.imm); 470 break; 471 } 472 /* FALLTHROUGH */ 473 default: 474 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 475 reg_name[i.IType.rt], 476 reg_name[i.IType.rs], 477 (short)i.IType.imm); 478 } 479 db_printf("\n"); 480 if (bdslot) { 481 db_printf("\t\tbdslot:\t"); 482 db_disasm(loc+4, FALSE); 483 return (loc + 8); 484 } 485 return (loc + 4); 486 } 487 488 static void 489 print_addr(db_addr_t loc) 490 { 491 db_expr_t diff; 492 db_sym_t sym; 493 char *symname; 494 495 diff = INT_MAX; 496 symname = NULL; 497 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 498 db_symbol_values(sym, &symname, 0); 499 500 if (symname) { 501 if (diff == 0) 502 db_printf("%s", symname); 503 else 504 db_printf("<%s+%lx>", symname, diff); 505 db_printf("\t[addr:0x%08lx]", loc); 506 } else { 507 db_printf("0x%08lx", loc); 508 } 509 } 510