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