xref: /netbsd/sys/arch/mips/mips/db_disasm.c (revision 6550d01e)
1 /*	$NetBSD: db_disasm.c,v 1.21 2009/12/14 00:46:06 matt 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 <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.21 2009/12/14 00:46:06 matt Exp $");
39 
40 #include <sys/types.h>
41 #include <sys/systm.h>
42 #include <sys/param.h>
43 
44 #include <machine/reg.h>
45 #include <machine/cpu.h>
46 #include <mips/mips_opcode.h>
47 /*#include <machine/param.h>*/
48 #include <machine/db_machdep.h>
49 
50 #include <ddb/db_interface.h>
51 #include <ddb/db_output.h>
52 #include <ddb/db_extern.h>
53 #include <ddb/db_sym.h>
54 
55 static const char * const op_name[64] = {
56 /* 0 */ "spec", "bcond","j",	"jal",	"beq",	"bne",	"blez", "bgtz",
57 /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori",	"xori", "lui",
58 /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
59 /*24 */ "daddi","daddiu","ldl", "ldr",	"op34", "op35", "op36", "op37",
60 /*32 */ "lb",	"lh",	"lwl",	"lw",	"lbu",	"lhu",	"lwr",	"lwu",
61 /*40 */ "sb",	"sh",	"swl",	"sw",	"sdl",	"sdr",	"swr",	"cache",
62 /*48 */ "ll",	"lwc1", "lwc2", "lwc3", "lld",	"ldc1", "ldc2", "ld",
63 /*56 */ "sc",	"swc1", "swc2", "swc3", "scd",	"sdc1", "sdc2", "sd"
64 };
65 
66 static const char * const spec_name[64] = {
67 /* 0 */ "sll",	"spec01","srl", "sra",	"sllv", "spec05","srlv","srav",
68 /* 8 */ "jr",	"jalr", "spec12","spec13","syscall","break","spec16","sync",
69 /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
70 /*24 */ "mult", "multu","div",	"divu", "dmult","dmultu","ddiv","ddivu",
71 /*32 */ "add",	"addu", "sub",	"subu", "and",	"or",	"xor",	"nor",
72 /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
73 /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
74 /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
75 };
76 
77 static const char * const spec2_name[4] = {		/* QED RM4650, R5000, etc. */
78 /* 0 */ "mad", "madu", "mul", "spec3"
79 };
80 
81 static const char * const bcond_name[32] = {
82 /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
83 /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
84 /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
85 /*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
86 };
87 
88 static const char * const cop1_name[64] = {
89 /* 0 */ "fadd",  "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
90 /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
91 /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
92 /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
93 /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
94 /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
95 /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
96 	"fcmp.ole","fcmp.ule",
97 /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
98 	"fcmp.le","fcmp.ngt"
99 };
100 
101 static const char * const fmt_name[16] = {
102 	"s",	"d",	"e",	"fmt3",
103 	"w",	"fmt5", "fmt6", "fmt7",
104 	"fmt8", "fmt9", "fmta", "fmtb",
105 	"fmtc", "fmtd", "fmte", "fmtf"
106 };
107 
108 #if defined(__mips_n32) || defined(__mips_n64)
109 static const char * const reg_name[32] = {
110 	"zero", "at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
111 	"a4",	"a5",	"a6",	"a7",	"t0",	"t1",	"t2",	"t3",
112 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
113 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
114 };
115 #else
116 static const char * const reg_name[32] = {
117 	"zero", "at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
118 	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7",
119 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
120 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
121 };
122 #endif /* __mips_n32 || __mips_n64 */
123 
124 static const char * const c0_opname[64] = {
125 	"c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
126 	"tlbp",	 "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
127 	"rfe",	 "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
128 	"eret",  "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
129 	"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
130 	"c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
131 	"c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
132 	"c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
133 };
134 
135 static const char * const c0_reg[32] = {
136 	"index",    "random",   "tlblo0",  "tlblo1",
137 	"context",  "pagemask", "wired",   "cp0r7",
138 	"badvaddr", "count",    "tlbhi",   "compare",
139 	"status",   "cause",    "epc",     "prid",
140 	"config",   "lladdr",   "watchlo", "watchhi",
141 	"xcontext", "cp0r21",   "cp0r22",  "debug",
142 	"depc",     "perfcnt",  "ecc",     "cacheerr",
143 	"taglo",    "taghi",    "errepc",  "desave"
144 };
145 
146 static void print_addr(db_addr_t);
147 
148 /*
149  * Disassemble instruction at 'loc'.  'altfmt' specifies an
150  * (optional) alternate format (altfmt for vax: don't assume
151  * that each external label is a procedure entry mask).
152  * Return address of start of next instruction.
153  * Since this function is used by 'examine' and by 'step'
154  * "next instruction" does NOT mean the next instruction to
155  * be executed but the 'linear' next instruction.
156  */
157 db_addr_t
158 db_disasm(db_addr_t loc, bool altfmt)
159 {
160 	u_int32_t instr;
161 
162 	/*
163 	 * Take some care with addresses to not UTLB here as it
164 	 * loses the current debugging context.  KSEG2 not checked.
165 	 */
166 	if (loc < MIPS_KSEG0_START) {
167 		instr = ufetch_uint32((void *)loc);
168 		if (instr == 0xffffffff) {
169 			/* "sd ra, -1(ra)" is unlikely */
170 			db_printf("invalid address.\n");
171 			return loc;
172 		}
173 	}
174 	else {
175 		instr =  *(u_int32_t *)loc;
176 	}
177 
178 	return (db_disasm_insn(instr, loc, altfmt));
179 }
180 
181 
182 /*
183  * Disassemble instruction 'insn' nominally at 'loc'.
184  * 'loc' may in fact contain a breakpoint instruction.
185  */
186 db_addr_t
187 db_disasm_insn(int insn, db_addr_t loc, bool altfmt)
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 		/* XXX
201 		 * "addu" is a "move" only in 32-bit mode.  What's the correct
202 		 * answer - never decode addu/daddu as "move"?
203 		 */
204 		if (i.RType.func == OP_ADDU && i.RType.rt == 0) {
205 			db_printf("move\t%s,%s",
206 			    reg_name[i.RType.rd],
207 			    reg_name[i.RType.rs]);
208 			break;
209 		}
210 		db_printf("%s", spec_name[i.RType.func]);
211 		switch (i.RType.func) {
212 		case OP_SLL:
213 		case OP_SRL:
214 		case OP_SRA:
215 		case OP_DSLL:
216 
217 		case OP_DSRL:
218 		case OP_DSRA:
219 		case OP_DSLL32:
220 		case OP_DSRL32:
221 		case OP_DSRA32:
222 			db_printf("\t%s,%s,%d",
223 			    reg_name[i.RType.rd],
224 			    reg_name[i.RType.rt],
225 			    i.RType.shamt);
226 			break;
227 
228 		case OP_SLLV:
229 		case OP_SRLV:
230 		case OP_SRAV:
231 		case OP_DSLLV:
232 		case OP_DSRLV:
233 		case OP_DSRAV:
234 			db_printf("\t%s,%s,%s",
235 			    reg_name[i.RType.rd],
236 			    reg_name[i.RType.rt],
237 			    reg_name[i.RType.rs]);
238 			break;
239 
240 		case OP_MFHI:
241 		case OP_MFLO:
242 			db_printf("\t%s", reg_name[i.RType.rd]);
243 			break;
244 
245 		case OP_JR:
246 		case OP_JALR:
247 			db_printf("\t%s", reg_name[i.RType.rs]);
248 			bdslot = true;
249 			break;
250 		case OP_MTLO:
251 		case OP_MTHI:
252 			db_printf("\t%s", reg_name[i.RType.rs]);
253 			break;
254 
255 		case OP_MULT:
256 		case OP_MULTU:
257 		case OP_DMULT:
258 		case OP_DMULTU:
259 		case OP_DIV:
260 		case OP_DIVU:
261 		case OP_DDIV:
262 		case OP_DDIVU:
263 			db_printf("\t%s,%s",
264 			    reg_name[i.RType.rs],
265 			    reg_name[i.RType.rt]);
266 			break;
267 
268 
269 		case OP_SYSCALL:
270 		case OP_SYNC:
271 			break;
272 
273 		case OP_BREAK:
274 			db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
275 			break;
276 
277 		default:
278 			db_printf("\t%s,%s,%s",
279 			    reg_name[i.RType.rd],
280 			    reg_name[i.RType.rs],
281 			    reg_name[i.RType.rt]);
282 		}
283 		break;
284 
285 	case OP_SPECIAL2:
286 		if (i.RType.func == OP_MUL)
287 			db_printf("%s\t%s,%s,%s",
288 				spec2_name[i.RType.func & 0x3],
289 		    		reg_name[i.RType.rd],
290 		    		reg_name[i.RType.rs],
291 		    		reg_name[i.RType.rt]);
292 		else
293 			db_printf("%s\t%s,%s",
294 				spec2_name[i.RType.func & 0x3],
295 		    		reg_name[i.RType.rs],
296 		    		reg_name[i.RType.rt]);
297 
298 		break;
299 
300 	case OP_BCOND:
301 		db_printf("%s\t%s,", bcond_name[i.IType.rt],
302 		    reg_name[i.IType.rs]);
303 		goto pr_displ;
304 
305 	case OP_BLEZ:
306 	case OP_BLEZL:
307 	case OP_BGTZ:
308 	case OP_BGTZL:
309 		db_printf("%s\t%s,", op_name[i.IType.op],
310 		    reg_name[i.IType.rs]);
311 		goto pr_displ;
312 
313 	case OP_BEQ:
314 	case OP_BEQL:
315 		if (i.IType.rs == 0 && i.IType.rt == 0) {
316 			db_printf("b\t");
317 			goto pr_displ;
318 		}
319 		/* FALLTHROUGH */
320 	case OP_BNE:
321 	case OP_BNEL:
322 		db_printf("%s\t%s,%s,", op_name[i.IType.op],
323 		    reg_name[i.IType.rs],
324 		    reg_name[i.IType.rt]);
325 	pr_displ:
326 		print_addr(loc + 4 + ((short)i.IType.imm << 2));
327 		bdslot = true;
328 		break;
329 
330 	case OP_COP0:
331 		switch (i.RType.rs) {
332 		case OP_BCx:
333 		case OP_BCy:
334 
335 			db_printf("bc0%c\t",
336 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
337 			goto pr_displ;
338 
339 		case OP_MT:
340 			db_printf("mtc0\t%s,%s",
341 			    reg_name[i.RType.rt],
342 			    c0_reg[i.RType.rd]);
343 			break;
344 
345 		case OP_DMT:
346 			db_printf("dmtc0\t%s,%s",
347 			    reg_name[i.RType.rt],
348 			    c0_reg[i.RType.rd]);
349 			break;
350 
351 		case OP_MF:
352 			db_printf("mfc0\t%s,%s",
353 			    reg_name[i.RType.rt],
354 			    c0_reg[i.RType.rd]);
355 			break;
356 
357 		case OP_DMF:
358 			db_printf("dmfc0\t%s,%s",
359 			    reg_name[i.RType.rt],
360 			    c0_reg[i.RType.rd]);
361 			break;
362 
363 		default:
364 			db_printf("%s", c0_opname[i.FRType.func]);
365 		}
366 		break;
367 
368 	case OP_COP1:
369 		switch (i.RType.rs) {
370 		case OP_BCx:
371 		case OP_BCy:
372 			db_printf("bc1%c\t",
373 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
374 			goto pr_displ;
375 
376 		case OP_MT:
377 			db_printf("mtc1\t%s,f%d",
378 			    reg_name[i.RType.rt],
379 			    i.RType.rd);
380 			break;
381 
382 		case OP_MF:
383 			db_printf("mfc1\t%s,f%d",
384 			    reg_name[i.RType.rt],
385 			    i.RType.rd);
386 			break;
387 
388 		case OP_CT:
389 			db_printf("ctc1\t%s,f%d",
390 			    reg_name[i.RType.rt],
391 			    i.RType.rd);
392 			break;
393 
394 		case OP_CF:
395 			db_printf("cfc1\t%s,f%d",
396 			    reg_name[i.RType.rt],
397 			    i.RType.rd);
398 			break;
399 
400 		case OP_DMT:
401 			db_printf("dmtc1\t%s,f%d",
402 			    reg_name[i.RType.rt],
403 			    i.RType.rd);
404 			break;
405 
406 		case OP_DMF:
407 			db_printf("dmfc1\t%s,f%d",
408 			    reg_name[i.RType.rt],
409 			    i.RType.rd);
410 			break;
411 
412 		case OP_MTH:
413 			db_printf("mthc1\t%s,f%d",
414 			    reg_name[i.RType.rt],
415 			    i.RType.rd);
416 			break;
417 
418 		case OP_MFH:
419 			db_printf("mfhc1\t%s,f%d",
420 			    reg_name[i.RType.rt],
421 			    i.RType.rd);
422 			break;
423 
424 		default:
425 			db_printf("%s.%s\tf%d,f%d,f%d",
426 			    cop1_name[i.FRType.func],
427 			    fmt_name[i.FRType.fmt],
428 			    i.FRType.fd, i.FRType.fs, i.FRType.ft);
429 		}
430 		break;
431 
432 	case OP_J:
433 	case OP_JAL:
434 		db_printf("%s\t", op_name[i.JType.op]);
435 		print_addr((loc & 0xF0000000) | (i.JType.target << 2));
436 		bdslot = true;
437 		break;
438 
439 	case OP_LWC1:
440 	case OP_SWC1:
441 		db_printf("%s\tf%d,", op_name[i.IType.op],
442 		    i.IType.rt);
443 		goto loadstore;
444 
445 	case OP_LB:
446 	case OP_LH:
447 	case OP_LW:
448 	case OP_LD:
449 	case OP_LBU:
450 	case OP_LHU:
451 	case OP_LWU:
452 	case OP_SB:
453 	case OP_SH:
454 	case OP_SW:
455 	case OP_SD:
456 		db_printf("%s\t%s,", op_name[i.IType.op],
457 		    reg_name[i.IType.rt]);
458 	loadstore:
459 		db_printf("%d(%s)", (short)i.IType.imm,
460 		    reg_name[i.IType.rs]);
461 		break;
462 
463 	case OP_ORI:
464 	case OP_XORI:
465 		if (i.IType.rs == 0) {
466 			db_printf("li\t%s,0x%x",
467 			    reg_name[i.IType.rt],
468 			    i.IType.imm);
469 			break;
470 		}
471 		/* FALLTHROUGH */
472 	case OP_ANDI:
473 		db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
474 		    reg_name[i.IType.rt],
475 		    reg_name[i.IType.rs],
476 		    i.IType.imm);
477 		break;
478 
479 	case OP_LUI:
480 		db_printf("%s\t%s,0x%x", op_name[i.IType.op],
481 		    reg_name[i.IType.rt],
482 		    i.IType.imm);
483 		break;
484 
485 	case OP_CACHE:
486 		db_printf("%s\t0x%x,0x%x(%s)",
487 		    op_name[i.IType.op],
488 		    i.IType.rt,
489 		    i.IType.imm,
490 		    reg_name[i.IType.rs]);
491 		break;
492 
493 	case OP_ADDI:
494 	case OP_DADDI:
495 	case OP_ADDIU:
496 	case OP_DADDIU:
497 		if (i.IType.rs == 0) {
498 			db_printf("li\t%s,%d",
499 			    reg_name[i.IType.rt],
500 			    (short)i.IType.imm);
501 			break;
502 		}
503 		/* FALLTHROUGH */
504 	default:
505 		db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
506 		    reg_name[i.IType.rt],
507 		    reg_name[i.IType.rs],
508 		    (short)i.IType.imm);
509 	}
510 	db_printf("\n");
511 	if (bdslot) {
512 		db_printf("\t\tbdslot:\t");
513 		db_disasm(loc+4, false);
514 		return (loc + 8);
515 	}
516 	return (loc + 4);
517 }
518 
519 static void
520 print_addr(db_addr_t loc)
521 {
522 	db_expr_t diff;
523 	db_sym_t sym;
524 	const char *symname;
525 
526 	diff = INT_MAX;
527 	symname = NULL;
528 	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
529 	db_symbol_values(sym, &symname, 0);
530 
531 	if (symname) {
532 		if (diff == 0)
533 			db_printf("%s", symname);
534 		else
535 			db_printf("<%s+%lx>", symname, diff);
536 		db_printf("\t[addr:%#"PRIxVADDR"]", loc);
537 	} else {
538 		db_printf("%#"PRIxVADDR, loc);
539 	}
540 }
541