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
61static char *sprintf_buffer;
62static int sprintf_buf_len;
63
64
65typedef uint32_t db_addr_t;
66static void db_printf(const char* fmt, ...);
67
68static 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
79static 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
90static 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
101static 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
108static 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
121static 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)
129static 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
137static 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
144static 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
151static char ** reg_name =  &mips_reg_name[0];
152
153#endif /* __mips_n32 || __mips_n64 */
154
155static 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
166static 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
177static void print_addr(db_addr_t);
178db_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 */
185static db_addr_t
186db_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
545static void
546print_addr(db_addr_t loc)
547{
548    db_printf("0x%08x", loc);
549}
550
551
552
553static 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 */
575db_addr_t
576mips_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