xref: /netbsd/sys/arch/mips/mips/db_disasm.c (revision bf9ec67e)
1 /*	$NetBSD: db_disasm.c,v 1.10 2002/02/22 16:18:36 simonb 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 static char *reg_name[32] = {
111 	"zero", "at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
112 	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7",
113 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
114 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
115 };
116 
117 static char *c0_opname[64] = {
118 	"c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
119 	"tlbp",	 "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
120 	"rfe",	 "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
121 	"eret",  "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
122 	"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
123 	"c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
124 	"c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
125 	"c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
126 };
127 
128 static char *c0_reg[32] = {
129 	"index",    "random",   "tlblo0",  "tlblo1",
130 	"context",  "pagemask", "wired",   "cp0r7",
131 	"badvaddr", "count",    "tlbhi",   "compare",
132 	"status",   "cause",    "epc",     "prid",
133 	"config",   "lladdr",   "watchlo", "watchhi",
134 	"xcontext", "cp0r21",   "cp0r22",  "debug",
135 	"depc",     "perfcnt",  "ecc",     "cacheerr",
136 	"taglo",    "taghi",    "errepc",  "desave"
137 };
138 
139 static void print_addr(db_addr_t);
140 
141 /*
142  * Disassemble instruction at 'loc'.  'altfmt' specifies an
143  * (optional) alternate format (altfmt for vax: don't assume
144  * that each external label is a procedure entry mask).
145  * Return address of start of next instruction.
146  * Since this function is used by 'examine' and by 'step'
147  * "next instruction" does NOT mean the next instruction to
148  * be executed but the 'linear' next instruction.
149  */
150 db_addr_t
151 db_disasm(db_addr_t loc, boolean_t altfmt)
152 {
153 	u_int32_t instr;
154 
155 	/*
156 	 * Take some care with addresses to not UTLB here as it
157 	 * loses the current debugging context.  KSEG2 not checked.
158 	 */
159 	if (loc < MIPS_KSEG0_START) {
160 		instr = fuword((void *)loc);
161 		if (instr == 0xffffffff) {
162 			/* "sd ra, -1(ra)" is unlikely */
163 			db_printf("invalid address.\n");
164 			return loc;
165 		}
166 	}
167 	else {
168 		instr =  *(u_int32_t *)loc;
169 	}
170 
171 	return (db_disasm_insn(instr, loc, altfmt));
172 }
173 
174 
175 /*
176  * Disassemble instruction 'insn' nominally at 'loc'.
177  * 'loc' may in fact contain a breakpoint instruction.
178  */
179 db_addr_t
180 db_disasm_insn(int insn, db_addr_t loc, boolean_t altfmt)
181 {
182 	boolean_t bdslot = FALSE;
183 	InstFmt i;
184 
185 	i.word = insn;
186 
187 	switch (i.JType.op) {
188 	case OP_SPECIAL:
189 		if (i.word == 0) {
190 			db_printf("nop");
191 			break;
192 		}
193 		/* XXX
194 		 * "addu" is a "move" only in 32-bit mode.  What's the correct
195 		 * answer - never decode addu/daddu as "move"?
196 		 */
197 		if (i.RType.func == OP_ADDU && i.RType.rt == 0) {
198 			db_printf("move\t%s,%s",
199 			    reg_name[i.RType.rd],
200 			    reg_name[i.RType.rs]);
201 			break;
202 		}
203 		db_printf("%s", spec_name[i.RType.func]);
204 		switch (i.RType.func) {
205 		case OP_SLL:
206 		case OP_SRL:
207 		case OP_SRA:
208 		case OP_DSLL:
209 
210 		case OP_DSRL:
211 		case OP_DSRA:
212 		case OP_DSLL32:
213 		case OP_DSRL32:
214 		case OP_DSRA32:
215 			db_printf("\t%s,%s,%d",
216 			    reg_name[i.RType.rd],
217 			    reg_name[i.RType.rt],
218 			    i.RType.shamt);
219 			break;
220 
221 		case OP_SLLV:
222 		case OP_SRLV:
223 		case OP_SRAV:
224 		case OP_DSLLV:
225 		case OP_DSRLV:
226 		case OP_DSRAV:
227 			db_printf("\t%s,%s,%s",
228 			    reg_name[i.RType.rd],
229 			    reg_name[i.RType.rt],
230 			    reg_name[i.RType.rs]);
231 			break;
232 
233 		case OP_MFHI:
234 		case OP_MFLO:
235 			db_printf("\t%s", reg_name[i.RType.rd]);
236 			break;
237 
238 		case OP_JR:
239 		case OP_JALR:
240 			db_printf("\t%s", reg_name[i.RType.rs]);
241 			bdslot = TRUE;
242 			break;
243 		case OP_MTLO:
244 		case OP_MTHI:
245 			db_printf("\t%s", reg_name[i.RType.rs]);
246 			break;
247 
248 		case OP_MULT:
249 		case OP_MULTU:
250 		case OP_DMULT:
251 		case OP_DMULTU:
252 		case OP_DIV:
253 		case OP_DIVU:
254 		case OP_DDIV:
255 		case OP_DDIVU:
256 			db_printf("\t%s,%s",
257 			    reg_name[i.RType.rs],
258 			    reg_name[i.RType.rt]);
259 			break;
260 
261 
262 		case OP_SYSCALL:
263 		case OP_SYNC:
264 			break;
265 
266 		case OP_BREAK:
267 			db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
268 			break;
269 
270 		default:
271 			db_printf("\t%s,%s,%s",
272 			    reg_name[i.RType.rd],
273 			    reg_name[i.RType.rs],
274 			    reg_name[i.RType.rt]);
275 		}
276 		break;
277 
278 	case OP_SPECIAL2:
279 		if (i.RType.func == OP_MUL)
280 			db_printf("%s\t%s,%s,%s",
281 				spec2_name[i.RType.func & 0x3],
282 		    		reg_name[i.RType.rd],
283 		    		reg_name[i.RType.rs],
284 		    		reg_name[i.RType.rt]);
285 		else
286 			db_printf("%s\t%s,%s",
287 				spec2_name[i.RType.func & 0x3],
288 		    		reg_name[i.RType.rs],
289 		    		reg_name[i.RType.rt]);
290 
291 		break;
292 
293 	case OP_BCOND:
294 		db_printf("%s\t%s,", bcond_name[i.IType.rt],
295 		    reg_name[i.IType.rs]);
296 		goto pr_displ;
297 
298 	case OP_BLEZ:
299 	case OP_BLEZL:
300 	case OP_BGTZ:
301 	case OP_BGTZL:
302 		db_printf("%s\t%s,", op_name[i.IType.op],
303 		    reg_name[i.IType.rs]);
304 		goto pr_displ;
305 
306 	case OP_BEQ:
307 	case OP_BEQL:
308 		if (i.IType.rs == 0 && i.IType.rt == 0) {
309 			db_printf("b\t");
310 			goto pr_displ;
311 		}
312 		/* FALLTHROUGH */
313 	case OP_BNE:
314 	case OP_BNEL:
315 		db_printf("%s\t%s,%s,", op_name[i.IType.op],
316 		    reg_name[i.IType.rs],
317 		    reg_name[i.IType.rt]);
318 	pr_displ:
319 		print_addr(loc + 4 + ((short)i.IType.imm << 2));
320 		bdslot = TRUE;
321 		break;
322 
323 	case OP_COP0:
324 		switch (i.RType.rs) {
325 		case OP_BCx:
326 		case OP_BCy:
327 
328 			db_printf("bc0%c\t",
329 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
330 			goto pr_displ;
331 
332 		case OP_MT:
333 			db_printf("mtc0\t%s,%s",
334 			    reg_name[i.RType.rt],
335 			    c0_reg[i.RType.rd]);
336 			break;
337 
338 		case OP_DMT:
339 			db_printf("dmtc0\t%s,%s",
340 			    reg_name[i.RType.rt],
341 			    c0_reg[i.RType.rd]);
342 			break;
343 
344 		case OP_MF:
345 			db_printf("mfc0\t%s,%s",
346 			    reg_name[i.RType.rt],
347 			    c0_reg[i.RType.rd]);
348 			break;
349 
350 		case OP_DMF:
351 			db_printf("dmfc0\t%s,%s",
352 			    reg_name[i.RType.rt],
353 			    c0_reg[i.RType.rd]);
354 			break;
355 
356 		default:
357 			db_printf("%s", c0_opname[i.FRType.func]);
358 		}
359 		break;
360 
361 	case OP_COP1:
362 		switch (i.RType.rs) {
363 		case OP_BCx:
364 		case OP_BCy:
365 			db_printf("bc1%c\t",
366 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
367 			goto pr_displ;
368 
369 		case OP_MT:
370 			db_printf("mtc1\t%s,f%d",
371 			    reg_name[i.RType.rt],
372 			    i.RType.rd);
373 			break;
374 
375 		case OP_MF:
376 			db_printf("mfc1\t%s,f%d",
377 			    reg_name[i.RType.rt],
378 			    i.RType.rd);
379 			break;
380 
381 		case OP_CT:
382 			db_printf("ctc1\t%s,f%d",
383 			    reg_name[i.RType.rt],
384 			    i.RType.rd);
385 			break;
386 
387 		case OP_CF:
388 			db_printf("cfc1\t%s,f%d",
389 			    reg_name[i.RType.rt],
390 			    i.RType.rd);
391 			break;
392 
393 		default:
394 			db_printf("%s.%s\tf%d,f%d,f%d",
395 			    cop1_name[i.FRType.func],
396 			    fmt_name[i.FRType.fmt],
397 			    i.FRType.fd, i.FRType.fs, i.FRType.ft);
398 		}
399 		break;
400 
401 	case OP_J:
402 	case OP_JAL:
403 		db_printf("%s\t", op_name[i.JType.op]);
404 		print_addr((loc & 0xF0000000) | (i.JType.target << 2));
405 		bdslot = TRUE;
406 		break;
407 
408 	case OP_LWC1:
409 	case OP_SWC1:
410 		db_printf("%s\tf%d,", op_name[i.IType.op],
411 		    i.IType.rt);
412 		goto loadstore;
413 
414 	case OP_LB:
415 	case OP_LH:
416 	case OP_LW:
417 	case OP_LD:
418 	case OP_LBU:
419 	case OP_LHU:
420 	case OP_LWU:
421 	case OP_SB:
422 	case OP_SH:
423 	case OP_SW:
424 	case OP_SD:
425 		db_printf("%s\t%s,", op_name[i.IType.op],
426 		    reg_name[i.IType.rt]);
427 	loadstore:
428 		db_printf("%d(%s)", (short)i.IType.imm,
429 		    reg_name[i.IType.rs]);
430 		break;
431 
432 	case OP_ORI:
433 	case OP_XORI:
434 		if (i.IType.rs == 0) {
435 			db_printf("li\t%s,0x%x",
436 			    reg_name[i.IType.rt],
437 			    i.IType.imm);
438 			break;
439 		}
440 		/* FALLTHROUGH */
441 	case OP_ANDI:
442 		db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
443 		    reg_name[i.IType.rt],
444 		    reg_name[i.IType.rs],
445 		    i.IType.imm);
446 		break;
447 
448 	case OP_LUI:
449 		db_printf("%s\t%s,0x%x", op_name[i.IType.op],
450 		    reg_name[i.IType.rt],
451 		    i.IType.imm);
452 		break;
453 
454 	case OP_CACHE:
455 		db_printf("%s\t0x%x,0x%x(%s)",
456 		    op_name[i.IType.op],
457 		    i.IType.rt,
458 		    i.IType.imm,
459 		    reg_name[i.IType.rs]);
460 		break;
461 
462 	case OP_ADDI:
463 	case OP_DADDI:
464 	case OP_ADDIU:
465 	case OP_DADDIU:
466 		if (i.IType.rs == 0) {
467 			db_printf("li\t%s,%d",
468 			    reg_name[i.IType.rt],
469 			    (short)i.IType.imm);
470 			break;
471 		}
472 		/* FALLTHROUGH */
473 	default:
474 		db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
475 		    reg_name[i.IType.rt],
476 		    reg_name[i.IType.rs],
477 		    (short)i.IType.imm);
478 	}
479 	db_printf("\n");
480 	if (bdslot) {
481 		db_printf("\t\tbdslot:\t");
482 		db_disasm(loc+4, FALSE);
483 		return (loc + 8);
484 	}
485 	return (loc + 4);
486 }
487 
488 static void
489 print_addr(db_addr_t loc)
490 {
491 	db_expr_t diff;
492 	db_sym_t sym;
493 	char *symname;
494 
495 	diff = INT_MAX;
496 	symname = NULL;
497 	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
498 	db_symbol_values(sym, &symname, 0);
499 
500 	if (symname) {
501 		if (diff == 0)
502 			db_printf("%s", symname);
503 		else
504 			db_printf("<%s+%lx>", symname, diff);
505 		db_printf("\t[addr:0x%08lx]", loc);
506 	} else {
507 		db_printf("0x%08lx", loc);
508 	}
509 }
510