blob: 8528299840682faff8d45269bfbfcef260b46d12 [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 <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
50static char *sprintf_buffer;
51static int sprintf_buf_len;
52
53typedef uint64_t db_addr_t;
54static void db_printf(const char* fmt, ...);
55
56static 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
67static 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
78static const char * const bcond_name[32] = {
79/* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?",
80/* 8 */ "?", "?", "?", "?", "?", "?", "?", "?",
81/*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie",
82/*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci",
83};
84
85static 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
98static 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
105static 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
112static 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
119static char * const * reg_name = &mips_reg_name[0];
120
121static 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
132static 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
143static void print_addr(db_addr_t);
144db_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 */
151static db_addr_t
152db_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
542static void
543print_addr(db_addr_t loc)
544{
545 db_printf("0x%08lx", loc);
546}
547
548static 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 */
570db_addr_t
571mips_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}