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