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 <stdarg.h> 38 #include <stdbool.h> 39 #include <stdint.h> 40 #include <stdio.h> 41 #include <sys/cdefs.h> 42 #include <sys/types.h> 43 44 #include <android/log.h> 45 46 #include "mips_opcode.h" 47 48 static char *sprintf_buffer; 49 static int sprintf_buf_len; 50 51 typedef uint64_t db_addr_t; 52 static void db_printf(const char* fmt, ...); 53 54 static const char * const op_name[64] = { 55 /* 0 */ "spec", "bcond", "j", "jal", "beq", "bne", "blez", "bgtz", 56 /* 8 */ "pop10", "addiu", "slti", "sltiu", "andi", "ori", "xori", "aui", 57 /*16 */ "cop0", "cop1", "cop2", "?", "?", "?", "pop26", "pop27", 58 /*24 */ "pop30", "daddiu", "?", "?", "?", "daui", "msa", "op37", 59 /*32 */ "lb", "lh", "?", "lw", "lbu", "lhu", "?", "lwu", 60 /*40 */ "sb", "sh", "?", "sw", "?", "?", "?", "?", 61 /*48 */ "?", "lwc1", "bc", "?", "?", "ldc1", "pop66", "ld", 62 /*56 */ "?", "swc1", "balc", "pcrel", "?", "sdc1", "pop76", "sd" 63 }; 64 65 static const char * const spec_name[64] = { 66 /* 0 */ "sll", "?", "srl", "sra", "sllv", "?", "srlv", "srav", 67 /* 8 */ "?", "jalr", "?", "?", "syscall", "break", "sdbpp", "sync", 68 /*16 */ "clz", "clo", "dclz", "dclo", "dsllv", "dlsa", "dsrlv", "dsrav", 69 /*24 */ "sop30", "sop31", "sop32", "sop33", "sop34", "sop35", "sop36", "sop37", 70 /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", 71 /*40 */ "?", "?", "slt", "sltu", "dadd", "daddu", "dsub", "dsubu", 72 /*48 */ "tge", "tgeu", "tlt", "tltu", "teq", "seleqz", "tne", "selnez", 73 /*56 */ "dsll", "?", "dsrl", "dsra", "dsll32", "?", "dsrl32", "dsra32" 74 }; 75 76 static const char * const bcond_name[32] = { 77 /* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?", 78 /* 8 */ "?", "?", "?", "?", "?", "?", "?", "?", 79 /*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie", 80 /*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci", 81 }; 82 83 static const char * const cop1_name[64] = { 84 /* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", 85 /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", 86 /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", 87 /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", 88 /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", 89 /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", 90 /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", 91 "fcmp.ole","fcmp.ule", 92 /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", 93 "fcmp.le","fcmp.ngt" 94 }; 95 96 static const char * const fmt_name[16] = { 97 "s", "d", "e", "fmt3", 98 "w", "fmt5", "fmt6", "fmt7", 99 "fmt8", "fmt9", "fmta", "fmtb", 100 "fmtc", "fmtd", "fmte", "fmtf" 101 }; 102 103 static char * const mips_reg_name[32] = { 104 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", 105 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", 106 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 107 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 108 }; 109 110 static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code 111 "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5", 112 "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", 113 "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7", 114 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" 115 }; 116 117 static char ** reg_name = &mips_reg_name[0]; 118 119 static const char * const c0_opname[64] = { 120 "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", 121 "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", 122 "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", 123 "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", 124 "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", 125 "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", 126 "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", 127 "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", 128 }; 129 130 static const char * const c0_reg[32] = { 131 "index", "random", "tlblo0", "tlblo1", 132 "context", "pagemask", "wired", "cp0r7", 133 "badvaddr", "count", "tlbhi", "compare", 134 "status", "cause", "epc", "prid", 135 "config", "lladdr", "watchlo", "watchhi", 136 "xcontext", "cp0r21", "cp0r22", "debug", 137 "depc", "perfcnt", "ecc", "cacheerr", 138 "taglo", "taghi", "errepc", "desave" 139 }; 140 141 static void print_addr(db_addr_t); 142 db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format); 143 144 145 /* 146 * Disassemble instruction 'insn' nominally at 'loc'. 147 * 'loc' may in fact contain a breakpoint instruction. 148 */ 149 static db_addr_t 150 db_disasm_insn(int insn, db_addr_t loc, bool altfmt) 151 { 152 bool bdslot = false; 153 InstFmt i; 154 155 i.word = insn; 156 157 switch (i.JType.op) { 158 case OP_SPECIAL: 159 if (i.word == 0) { 160 db_printf("nop"); 161 break; 162 } 163 if (i.word == 0x0080) { 164 db_printf("NIY"); 165 break; 166 } 167 if (i.word == 0x00c0) { 168 db_printf("NOT IMPL"); 169 break; 170 } 171 /* Special cases -------------------------------------------------- 172 * "addu" is a "move" only in 32-bit mode. What's the correct 173 * answer - never decode addu/daddu as "move"? 174 */ 175 if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) || 176 (i.RType.func == OP_OR && i.RType.rt == 0) ) { 177 db_printf("move\t%s,%s", 178 reg_name[i.RType.rd], 179 reg_name[i.RType.rs]); 180 break; 181 } 182 183 if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) { 184 db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd], 185 reg_name[i.RType.rt], i.RType.shamt); 186 break; 187 } 188 if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) { 189 db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd], 190 reg_name[i.RType.rt], reg_name[i.RType.rs]); 191 break; 192 } 193 194 if (i.RType.func == OP_SOP30) { 195 if (i.RType.shamt == OP_MUL) { 196 db_printf("mul"); 197 } else if (i.RType.shamt == OP_MUH) { 198 db_printf("muh"); 199 } 200 db_printf("\t%s,%s,%s", reg_name[i.RType.rd], 201 reg_name[i.RType.rs], reg_name[i.RType.rt]); 202 break; 203 } 204 if (i.RType.func == OP_SOP31) { 205 if (i.RType.shamt == OP_MUL) { 206 db_printf("mulu"); 207 } else if (i.RType.shamt == OP_MUH) { 208 db_printf("muhu"); 209 } 210 db_printf("\t%s,%s,%s", reg_name[i.RType.rd], 211 reg_name[i.RType.rs], reg_name[i.RType.rt]); 212 break; 213 } 214 215 if (i.RType.func == OP_JALR && i.RType.rd == 0) { 216 db_printf("jr\t%s", reg_name[i.RType.rs]); 217 bdslot = true; 218 break; 219 } 220 221 db_printf("%s", spec_name[i.RType.func]); 222 switch (i.RType.func) { 223 case OP_SLL: 224 case OP_SRL: 225 case OP_SRA: 226 case OP_DSLL: 227 228 case OP_DSRL: 229 case OP_DSRA: 230 case OP_DSLL32: 231 case OP_DSRL32: 232 case OP_DSRA32: 233 db_printf("\t%s,%s,%d", 234 reg_name[i.RType.rd], 235 reg_name[i.RType.rt], 236 i.RType.shamt); 237 break; 238 239 case OP_SLLV: 240 case OP_SRLV: 241 case OP_SRAV: 242 case OP_DSLLV: 243 case OP_DSRLV: 244 case OP_DSRAV: 245 db_printf("\t%s,%s,%s", 246 reg_name[i.RType.rd], 247 reg_name[i.RType.rt], 248 reg_name[i.RType.rs]); 249 break; 250 251 case OP_CLZ: 252 case OP_CLO: 253 case OP_DCLZ: 254 case OP_DCLO: 255 db_printf("\t%s,%s", 256 reg_name[i.RType.rd], 257 reg_name[i.RType.rs]); 258 break; 259 260 case OP_JALR: 261 db_printf("\t"); 262 if (i.RType.rd != 31) { 263 db_printf("%s,", reg_name[i.RType.rd]); 264 } 265 db_printf("%s", reg_name[i.RType.rs]); 266 bdslot = true; 267 break; 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_SPECIAL3: 286 if (i.RType.func == OP_EXT) 287 db_printf("ext\t%s,%s,%d,%d", 288 reg_name[i.RType.rt], 289 reg_name[i.RType.rs], 290 i.RType.shamt, 291 i.RType.rd+1); 292 else if (i.RType.func == OP_DEXT) 293 db_printf("dext\t%s,%s,%d,%d", 294 reg_name[i.RType.rt], 295 reg_name[i.RType.rs], 296 i.RType.shamt, 297 i.RType.rd+1); 298 else if (i.RType.func == OP_DEXTM) 299 db_printf("dextm\t%s,%s,%d,%d", 300 reg_name[i.RType.rt], 301 reg_name[i.RType.rs], 302 i.RType.shamt, 303 i.RType.rd+33); 304 else if (i.RType.func == OP_DEXTU) 305 db_printf("dextu\t%s,%s,%d,%d", 306 reg_name[i.RType.rt], 307 reg_name[i.RType.rs], 308 i.RType.shamt+32, 309 i.RType.rd+1); 310 else if (i.RType.func == OP_INS) 311 db_printf("ins\t%s,%s,%d,%d", 312 reg_name[i.RType.rt], 313 reg_name[i.RType.rs], 314 i.RType.shamt, 315 i.RType.rd-i.RType.shamt+1); 316 else if (i.RType.func == OP_DINS) 317 db_printf("dins\t%s,%s,%d,%d", 318 reg_name[i.RType.rt], 319 reg_name[i.RType.rs], 320 i.RType.shamt, 321 i.RType.rd-i.RType.shamt+1); 322 else if (i.RType.func == OP_DINSM) 323 db_printf("dinsm\t%s,%s,%d,%d", 324 reg_name[i.RType.rt], 325 reg_name[i.RType.rs], 326 i.RType.shamt, 327 i.RType.rd-i.RType.shamt+33); 328 else if (i.RType.func == OP_DINSU) 329 db_printf("dinsu\t%s,%s,%d,%d", 330 reg_name[i.RType.rt], 331 reg_name[i.RType.rs], 332 i.RType.shamt+32, 333 i.RType.rd-i.RType.shamt+1); 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 if (i.RType.func == OP_RDHWR) 347 db_printf("rdhwr\t%s,%s", 348 reg_name[i.RType.rd], 349 reg_name[i.RType.rt]); 350 else 351 db_printf("Unknown"); 352 break; 353 354 case OP_BCOND: 355 db_printf("%s\t%s,", bcond_name[i.IType.rt], 356 reg_name[i.IType.rs]); 357 goto pr_displ; 358 359 case OP_BLEZ: 360 case OP_BGTZ: 361 db_printf("%s\t%s,", op_name[i.IType.op], 362 reg_name[i.IType.rs]); 363 goto pr_displ; 364 365 case OP_BEQ: 366 if (i.IType.rs == 0 && i.IType.rt == 0) { 367 db_printf("b\t"); 368 goto pr_displ; 369 } 370 /* FALLTHROUGH */ 371 case OP_BNE: 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 & 0xFFFFFFFFF0000000) | (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_AUI: 506 if (i.IType.rs == 0) { 507 db_printf("lui\t%s,0x%x", reg_name[i.IType.rt], 508 i.IType.imm); 509 } else { 510 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 511 reg_name[i.IType.rt], reg_name[i.IType.rs], 512 (short)i.IType.imm); 513 } 514 break; 515 516 case OP_ADDIU: 517 case OP_DADDIU: 518 if (i.IType.rs == 0) { 519 db_printf("li\t%s,%d", 520 reg_name[i.IType.rt], 521 (short)i.IType.imm); 522 break; 523 } 524 /* FALLTHROUGH */ 525 default: 526 db_printf("%s\t%s,%s,%d", op_name[i.IType.op], 527 reg_name[i.IType.rt], 528 reg_name[i.IType.rs], 529 (short)i.IType.imm); 530 } 531 // db_printf("\n"); 532 // if (bdslot) { 533 // db_printf(" bd: "); 534 // mips_disassem(loc+4); 535 // return (loc + 8); 536 // } 537 return (loc + 4); 538 } 539 540 static void 541 print_addr(db_addr_t loc) 542 { 543 db_printf("0x%08lx", loc); 544 } 545 546 static void db_printf(const char* fmt, ...) 547 { 548 int cnt; 549 va_list argp; 550 va_start(argp, fmt); 551 if (sprintf_buffer) { 552 cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp); 553 sprintf_buffer += cnt; 554 sprintf_buf_len -= cnt; 555 } else { 556 vprintf(fmt, argp); 557 } 558 } 559 560 /* 561 * Disassemble instruction at 'loc'. 562 * Return address of start of next instruction. 563 * Since this function is used by 'examine' and by 'step' 564 * "next instruction" does NOT mean the next instruction to 565 * be executed but the 'linear' next instruction. 566 */ 567 db_addr_t 568 mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format) 569 { 570 u_int32_t instr; 571 572 if (alt_dis_format) { // use ARM register names for disassembly 573 reg_name = &alt_arm_reg_name[0]; 574 } 575 576 sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf() 577 sprintf_buf_len = 39; // should be passed in 578 579 instr = *(u_int32_t *)loc; 580 return (db_disasm_insn(instr, loc, false)); 581 } 582