blob: 1fe680675d332eb58afe2b0c9cd970fa35e77305 [file] [log] [blame]
bigbiff673c7ae2020-12-02 19:44:56 -05001/* $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#define __unused __attribute__((__unused__))
61
62static char *sprintf_buffer;
63static int sprintf_buf_len;
64
65
66typedef uint32_t db_addr_t;
67static void db_printf(const char* fmt, ...);
68
69static const char * const op_name[64] = {
70/* 0 */ "spec", "bcond","j ", "jal", "beq", "bne", "blez", "bgtz",
71/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui",
72/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
73/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37",
74/*32 */ "lb ", "lh ", "lwl", "lw ", "lbu", "lhu", "lwr", "lwu",
75/*40 */ "sb ", "sh ", "swl", "sw ", "sdl", "sdr", "swr", "cache",
76/*48 */ "ll ", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld ",
77/*56 */ "sc ", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd "
78};
79
80static const char * const spec_name[64] = {
81/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav",
82/* 8 */ "jr", "jalr", "movz","movn","syscall","break","spec16","sync",
83/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
84/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu",
85/*32 */ "add", "addu", "sub", "subu", "and", "or ", "xor", "nor",
86/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
87/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
88/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
89};
90
91static const char * const spec2_name[64] = { /* QED RM4650, R5000, etc. */
92/* 0x00 */ "madd", "maddu", "mul", "spec3", "msub", "msubu", "rsrv6", "rsrv7",
93/* 0x08 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
94/* 0x10 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
95/* 0x18 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
96/* 0x20 */ "clz", "clo", "rsrv", "rsrv", "dclz", "dclo", "rsrv", "rsrv",
97/* 0x28 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
98/* 0x30 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
99/* 0x38 */ "rsrv", "rsrv", "rsrv", "resv", "rsrv", "rsrv", "rsrv", "sdbbp"
100};
101
102static const char * const bcond_name[32] = {
103/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
104/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
105/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
106/*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
107};
108
109static const char * const cop1_name[64] = {
110/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
111/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
112/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
113/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
114/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
115/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
116/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
117 "fcmp.ole","fcmp.ule",
118/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
119 "fcmp.le","fcmp.ngt"
120};
121
122static const char * const fmt_name[16] = {
123 "s", "d", "e", "fmt3",
124 "w", "fmt5", "fmt6", "fmt7",
125 "fmt8", "fmt9", "fmta", "fmtb",
126 "fmtc", "fmtd", "fmte", "fmtf"
127};
128
129#if defined(__mips_n32) || defined(__mips_n64)
130static char * const reg_name[32] = {
131 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
132 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
133 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
134 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
135};
136#else
137
138static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code
139 "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5",
140 "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13",
141 "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7",
142 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
143};
144
145static char * mips_reg_name[32] = {
146 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
147 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
148 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
149 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
150};
151
152static char ** reg_name = &mips_reg_name[0];
153
154#endif /* __mips_n32 || __mips_n64 */
155
156static const char * const c0_opname[64] = {
157 "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
158 "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
159 "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
160 "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
161 "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
162 "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
163 "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
164 "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
165};
166
167static const char * const c0_reg[32] = {
168 "index", "random", "tlblo0", "tlblo1",
169 "context", "pagemask", "wired", "cp0r7",
170 "badvaddr", "count", "tlbhi", "compare",
171 "status", "cause", "epc", "prid",
172 "config", "lladdr", "watchlo", "watchhi",
173 "xcontext", "cp0r21", "cp0r22", "debug",
174 "depc", "perfcnt", "ecc", "cacheerr",
175 "taglo", "taghi", "errepc", "desave"
176};
177
178static void print_addr(db_addr_t);
179db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format);
180
181
182/*
183 * Disassemble instruction 'insn' nominally at 'loc'.
184 * 'loc' may in fact contain a breakpoint instruction.
185 */
186static db_addr_t
187db_disasm_insn(int insn, db_addr_t loc, bool altfmt __unused)
188{
189 bool bdslot = false;
190 InstFmt i;
191
192 i.word = insn;
193
194 switch (i.JType.op) {
195 case OP_SPECIAL:
196 if (i.word == 0) {
197 db_printf("nop");
198 break;
199 }
200 if (i.word == 0x0080) {
201 db_printf("NIY");
202 break;
203 }
204 if (i.word == 0x00c0) {
205 db_printf("NOT IMPL");
206 break;
207 }
208 /* Special cases --------------------------------------------------
209 * "addu" is a "move" only in 32-bit mode. What's the correct
210 * answer - never decode addu/daddu as "move"?
211 */
212 if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) ||
213 (i.RType.func == OP_OR && i.RType.rt == 0) ) {
214 db_printf("move\t%s,%s",
215 reg_name[i.RType.rd],
216 reg_name[i.RType.rs]);
217 break;
218 }
219 // mips32r2, rotr & rotrv
220 if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) {
221 db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd],
222 reg_name[i.RType.rt], i.RType.shamt);
223 break;
224 }
225 if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) {
226 db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd],
227 reg_name[i.RType.rt], reg_name[i.RType.rs]);
228 break;
229 }
230
231
232 db_printf("%s", spec_name[i.RType.func]);
233 switch (i.RType.func) {
234 case OP_SLL:
235 case OP_SRL:
236 case OP_SRA:
237 case OP_DSLL:
238
239 case OP_DSRL:
240 case OP_DSRA:
241 case OP_DSLL32:
242 case OP_DSRL32:
243 case OP_DSRA32:
244 db_printf("\t%s,%s,%d",
245 reg_name[i.RType.rd],
246 reg_name[i.RType.rt],
247 i.RType.shamt);
248 break;
249
250 case OP_SLLV:
251 case OP_SRLV:
252 case OP_SRAV:
253 case OP_DSLLV:
254 case OP_DSRLV:
255 case OP_DSRAV:
256 db_printf("\t%s,%s,%s",
257 reg_name[i.RType.rd],
258 reg_name[i.RType.rt],
259 reg_name[i.RType.rs]);
260 break;
261
262 case OP_MFHI:
263 case OP_MFLO:
264 db_printf("\t%s", reg_name[i.RType.rd]);
265 break;
266
267 case OP_JR:
268 case OP_JALR:
269 db_printf("\t%s", reg_name[i.RType.rs]);
270 bdslot = true;
271 break;
272 case OP_MTLO:
273 case OP_MTHI:
274 db_printf("\t%s", reg_name[i.RType.rs]);
275 break;
276
277 case OP_MULT:
278 case OP_MULTU:
279 case OP_DMULT:
280 case OP_DMULTU:
281 case OP_DIV:
282 case OP_DIVU:
283 case OP_DDIV:
284 case OP_DDIVU:
285 db_printf("\t%s,%s",
286 reg_name[i.RType.rs],
287 reg_name[i.RType.rt]);
288 break;
289
290
291 case OP_SYSCALL:
292 case OP_SYNC:
293 break;
294
295 case OP_BREAK:
296 db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
297 break;
298
299 default:
300 db_printf("\t%s,%s,%s",
301 reg_name[i.RType.rd],
302 reg_name[i.RType.rs],
303 reg_name[i.RType.rt]);
304 }
305 break;
306
307 case OP_SPECIAL2:
308 if (i.RType.func == OP_MUL)
309 db_printf("%s\t%s,%s,%s",
310 spec2_name[i.RType.func & 0x3f],
311 reg_name[i.RType.rd],
312 reg_name[i.RType.rs],
313 reg_name[i.RType.rt]);
314 else
315 db_printf("%s\t%s,%s",
316 spec2_name[i.RType.func & 0x3f],
317 reg_name[i.RType.rs],
318 reg_name[i.RType.rt]);
319
320 break;
321
322 case OP_SPECIAL3:
323 if (i.RType.func == OP_EXT)
324 db_printf("ext\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+1);
329 else if (i.RType.func == OP_INS)
330 db_printf("ins\t%s,%s,%d,%d",
331 reg_name[i.RType.rt],
332 reg_name[i.RType.rs],
333 i.RType.shamt,
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
348 db_printf("Unknown");
349 break;
350
351 case OP_BCOND:
352 db_printf("%s\t%s,", bcond_name[i.IType.rt],
353 reg_name[i.IType.rs]);
354 goto pr_displ;
355
356 case OP_BLEZ:
357 case OP_BLEZL:
358 case OP_BGTZ:
359 case OP_BGTZL:
360 db_printf("%s\t%s,", op_name[i.IType.op],
361 reg_name[i.IType.rs]);
362 goto pr_displ;
363
364 case OP_BEQ:
365 case OP_BEQL:
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 case OP_BNEL:
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 & 0xF0000000) | (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_LUI:
507 db_printf("%s\t%s,0x%x", op_name[i.IType.op],
508 reg_name[i.IType.rt],
509 i.IType.imm);
510 break;
511
512 case OP_CACHE:
513 db_printf("%s\t0x%x,0x%x(%s)",
514 op_name[i.IType.op],
515 i.IType.rt,
516 i.IType.imm,
517 reg_name[i.IType.rs]);
518 break;
519
520 case OP_ADDI:
521 case OP_DADDI:
522 case OP_ADDIU:
523 case OP_DADDIU:
524 if (i.IType.rs == 0) {
525 db_printf("li\t%s,%d",
526 reg_name[i.IType.rt],
527 (short)i.IType.imm);
528 break;
529 }
530 /* FALLTHROUGH */
531 default:
532 db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
533 reg_name[i.IType.rt],
534 reg_name[i.IType.rs],
535 (short)i.IType.imm);
536 }
537 // db_printf("\n");
538 // if (bdslot) {
539 // db_printf(" bd: ");
540 // mips_disassem(loc+4);
541 // return (loc + 8);
542 // }
543 return (loc + 4);
544}
545
546static void
547print_addr(db_addr_t loc)
548{
549 db_printf("0x%08x", loc);
550}
551
552
553
554static void db_printf(const char* fmt, ...)
555{
556 int cnt;
557 va_list argp;
558 va_start(argp, fmt);
559 if (sprintf_buffer) {
560 cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp);
561 sprintf_buffer += cnt;
562 sprintf_buf_len -= cnt;
563 } else {
564 vprintf(fmt, argp);
565 }
566 va_end(argp);
567}
568
569
570/*
571 * Disassemble instruction at 'loc'.
572 * Return address of start of next instruction.
573 * Since this function is used by 'examine' and by 'step'
574 * "next instruction" does NOT mean the next instruction to
575 * be executed but the 'linear' next instruction.
576 */
577db_addr_t
578mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format)
579{
580 u_int32_t instr;
581
582 if (alt_dis_format) { // use ARM register names for disassembly
583 reg_name = &alt_arm_reg_name[0];
584 }
585
586 sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf()
587 sprintf_buf_len = 39; // should be passed in
588
589 instr = *(u_int32_t *)loc;
590 return (db_disasm_insn(instr, loc, false));
591}
592