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
db_disasm_insn(int insn,db_addr_t loc,bool altfmt)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
print_addr(db_addr_t loc)541 print_addr(db_addr_t loc)
542 {
543 db_printf("0x%08lx", loc);
544 }
545
db_printf(const char * fmt,...)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
mips_disassem(db_addr_t loc,char * di_buffer,int alt_dis_format)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