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