blob: 4ab9bd35d2fbe58f5ef92f331631d288932a3566 [file] [log] [blame]
Paul Lind2bc2b792012-02-01 10:54:19 -08001/* $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