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