1 /* $NetBSD: db_disasm.c,v 1.21 2009/12/14 00:46:06 matt 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.21 2009/12/14 00:46:06 matt 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 = ufetch_uint32((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 case OP_DMT: 401 db_printf("dmtc1\t%s,f%d", 402 reg_name[i.RType.rt], 403 i.RType.rd); 404 break; 405 406 case OP_DMF: 407 db_printf("dmfc1\t%s,f%d", 408 reg_name[i.RType.rt], 409 i.RType.rd); 410 break; 411 412 case OP_MTH: 413 db_printf("mthc1\t%s,f%d", 414 reg_name[i.RType.rt], 415 i.RType.rd); 416 break; 417 418 case OP_MFH: 419 db_printf("mfhc1\t%s,f%d", 420 reg_name[i.RType.rt], 421 i.RType.rd); 422 break; 423 424 default: 425 db_printf("%s.%s\tf%d,f%d,f%d", 426 cop1_name[i.FRType.func], 427 fmt_name[i.FRType.fmt], 428 i.FRType.fd, i.FRType.fs, i.FRType.ft); 429 } 430 break; 431 432 case OP_J: 433 case OP_JAL: 434 db_printf("%s\t", op_name[i.JType.op]); 435 print_addr((loc & 0xF0000000) | (i.JType.target << 2)); 436 bdslot = true; 437 break; 438 439 case OP_LWC1: 440 case OP_SWC1: 441 db_printf("%s\tf%d,", op_name[i.IType.op], 442 i.IType.rt); 443 goto loadstore; 444 445 case OP_LB: 446 case OP_LH: 447 case OP_LW: 448 case OP_LD: 449 case OP_LBU: 450 case OP_LHU: 451 case OP_LWU: 452 case OP_SB: 453 case OP_SH: 454 case OP_SW: 455 case OP_SD: 456 db_printf("%s\t%s,", op_name[i.IType.op], 457 reg_name[i.IType.rt]); 458 loadstore: 459 db_printf("%d(%s)", (short)i.IType.imm, 460 reg_name[i.IType.rs]); 461 break; 462 463 case OP_ORI: 464 case OP_XORI: 465 if (i.IType.rs == 0) { 466 db_printf("li\t%s,0x%x", 467 reg_name[i.IType.rt], 468 i.IType.imm); 469 break; 470 } 471 /* FALLTHROUGH */ 472 case OP_ANDI: 473 db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], 474 reg_name[i.IType.rt], 475 reg_name[i.IType.rs], 476 i.IType.imm); 477 break; 478 479 case OP_LUI: 480 db_printf("%s\t%s,0x%x", op_name[i.IType.op], 481 reg_name[i.IType.rt], 482 i.IType.imm); 483 break; 484 485 case OP_CACHE: 486 db_printf("%s\t0x%x,0x%x(%s)", 487 op_name[i.IType.op], 488 i.IType.rt, 489 i.IType.imm, 490 reg_name[i.IType.rs]); 491 break; 492 493 case OP_ADDI: 494 case OP_DADDI: 495 case OP_ADDIU: 496 case OP_DADDIU: 497 if (i.IType.rs == 0) { 498 db_printf("li\t%s,%d", 499 reg_name[i.IType.rt], 500 (short)i.IType.imm); 501 break; 502 } 503 /* FALLTHROUGH */ 504 default: 505 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 506 reg_name[i.IType.rt], 507 reg_name[i.IType.rs], 508 (short)i.IType.imm); 509 } 510 db_printf("\n"); 511 if (bdslot) { 512 db_printf("\t\tbdslot:\t"); 513 db_disasm(loc+4, false); 514 return (loc + 8); 515 } 516 return (loc + 4); 517 } 518 519 static void 520 print_addr(db_addr_t loc) 521 { 522 db_expr_t diff; 523 db_sym_t sym; 524 const char *symname; 525 526 diff = INT_MAX; 527 symname = NULL; 528 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 529 db_symbol_values(sym, &symname, 0); 530 531 if (symname) { 532 if (diff == 0) 533 db_printf("%s", symname); 534 else 535 db_printf("<%s+%lx>", symname, diff); 536 db_printf("\t[addr:%#"PRIxVADDR"]", loc); 537 } else { 538 db_printf("%#"PRIxVADDR, loc); 539 } 540 } 541