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