xref: /netbsd-src/sys/arch/mips/mips/db_disasm.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*	$NetBSD: db_disasm.c,v 1.2 1997/08/17 16:58:53 mhitch 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 <mips/db_machdep.h>
51 
52 #include <ddb/db_interface.h>
53 #include <ddb/db_output.h>
54 #include <ddb/db_sym.h>
55 
56 static char *op_name[64] = {
57 /* 0 */ "spec", "bcond","j",	"jal",	"beq",	"bne",	"blez", "bgtz",
58 /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori",	"xori", "lui",
59 /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
60 /*24 */ "daddi","daddiu","ldl", "ldr",	"op34", "op35", "op36", "op37",
61 /*32 */ "lb",	"lh",	"lwl",	"lw",	"lbu",	"lhu",	"lwr",	"lwu",
62 /*40 */ "sb",	"sh",	"swl",	"sw",	"sdl",	"sdr",	"swr",	"cache",
63 /*48 */ "ll",	"lwc1", "lwc2", "lwc3", "lld",	"ldc1", "ldc2", "ld",
64 /*56 */ "sc",	"swc1", "swc2", "swc3", "scd",	"sdc1", "sdc2", "sd"
65 };
66 
67 static char *spec_name[64] = {
68 /* 0 */ "sll",	"spec01","srl", "sra",	"sllv", "spec05","srlv","srav",
69 /* 8 */ "jr",	"jalr", "spec12","spec13","syscall","break","spec16","sync",
70 /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
71 /*24 */ "mult", "multu","div",	"divu", "dmult","dmultu","ddiv","ddivu",
72 /*32 */ "add",	"addu", "sub",	"subu", "and",	"or",	"xor",	"nor",
73 /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
74 /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
75 /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
76 };
77 
78 static char *bcond_name[32] = {
79 /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
80 /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
81 /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
82 /*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
83 };
84 
85 static char *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 
98 static char *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 
105 static char *reg_name[32] = {
106 	"zero", "at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
107 	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7",
108 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
109 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
110 };
111 
112 static char *c0_opname[64] = {
113 	"c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
114 	"tlbp",	 "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
115 	"rfe",	 "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
116 	"eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
117 	"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
118 	"c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
119 	"c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
120 	"c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
121 };
122 
123 static char *c0_reg[32] = {
124 	"index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7",
125 	"badvaddr","count","tlbhi","c0r11","sr","cause","epc",	"prid",
126 	"config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23",
127 	"c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31"
128 };
129 
130 void print_addr(long);
131 
132 /*
133  * Disassemble instruction at 'loc'.  'altfmt' specifies an
134  * (optional) alternate format (altfmt for vax: don't assume
135  * that each external label is a procedure entry mask).
136  * Return address of start of next instruction.
137  * Since this function is used by 'examine' and by 'step'
138  * "next instruction" does NOT mean the next instruction to
139  * be executed but the 'linear' next instruction.
140  */
141 db_addr_t
142 db_disasm(loc, altfmt)
143 	db_addr_t	loc;
144 	boolean_t	altfmt;
145 
146 {
147 	return (db_disasm_insn(*(int*)loc, loc, altfmt));
148 }
149 
150 
151 /*
152  * Disassemble instruction 'insn' nominally at 'loc'.
153  * 'loc' may in fact contain a breakpoint instruction.
154  */
155 db_addr_t
156 db_disasm_insn(insn, loc, altfmt)
157 	int		insn;
158 	db_addr_t	loc;
159 	boolean_t	altfmt;
160 {
161 	InstFmt i;
162 
163 	i.word = insn;
164 
165 	switch (i.JType.op) {
166 	case OP_SPECIAL:
167 		if (i.word == 0) {
168 			db_printf("nop");
169 			break;
170 		}
171 		if (i.RType.func == OP_ADDU && i.RType.rt == 0) {
172 			db_printf("move\t%s,%s",
173 			    reg_name[i.RType.rd],
174 			    reg_name[i.RType.rs]);
175 			break;
176 		}
177 		db_printf("%s", spec_name[i.RType.func]);
178 		switch (i.RType.func) {
179 		case OP_SLL:
180 		case OP_SRL:
181 		case OP_SRA:
182 		case OP_DSLL:
183 
184 		case OP_DSRL:
185 		case OP_DSRA:
186 		case OP_DSLL32:
187 		case OP_DSRL32:
188 		case OP_DSRA32:
189 			db_printf("\t%s,%s,%d",
190 			    reg_name[i.RType.rd],
191 			    reg_name[i.RType.rt],
192 			    i.RType.shamt);
193 			break;
194 
195 		case OP_SLLV:
196 		case OP_SRLV:
197 		case OP_SRAV:
198 		case OP_DSLLV:
199 		case OP_DSRLV:
200 		case OP_DSRAV:
201 			db_printf("\t%s,%s,%s",
202 			    reg_name[i.RType.rd],
203 			    reg_name[i.RType.rt],
204 			    reg_name[i.RType.rs]);
205 			break;
206 
207 		case OP_MFHI:
208 		case OP_MFLO:
209 			db_printf("\t%s", reg_name[i.RType.rd]);
210 			break;
211 
212 		case OP_JR:
213 		case OP_JALR:
214 			/* FALLTHROUGH */
215 		case OP_MTLO:
216 		case OP_MTHI:
217 			db_printf("\t%s", reg_name[i.RType.rs]);
218 			break;
219 
220 		case OP_MULT:
221 		case OP_MULTU:
222 		case OP_DMULT:
223 		case OP_DMULTU:
224 		case OP_DIV:
225 		case OP_DIVU:
226 		case OP_DDIV:
227 		case OP_DDIVU:
228 			db_printf("\t%s,%s",
229 			    reg_name[i.RType.rs],
230 			    reg_name[i.RType.rt]);
231 			break;
232 
233 
234 		case OP_SYSCALL:
235 		case OP_SYNC:
236 			break;
237 
238 		case OP_BREAK:
239 			db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
240 			break;
241 
242 		default:
243 			db_printf("\t%s,%s,%s",
244 			    reg_name[i.RType.rd],
245 			    reg_name[i.RType.rs],
246 			    reg_name[i.RType.rt]);
247 		}
248 		break;
249 
250 	case OP_BCOND:
251 		db_printf("%s\t%s,", bcond_name[i.IType.rt],
252 		    reg_name[i.IType.rs]);
253 		goto pr_displ;
254 
255 	case OP_BLEZ:
256 	case OP_BLEZL:
257 	case OP_BGTZ:
258 	case OP_BGTZL:
259 		db_printf("%s\t%s,", op_name[i.IType.op],
260 		    reg_name[i.IType.rs]);
261 		goto pr_displ;
262 
263 	case OP_BEQ:
264 	case OP_BEQL:
265 		if (i.IType.rs == 0 && i.IType.rt == 0) {
266 			db_printf("b\t");
267 			goto pr_displ;
268 		}
269 		/* FALLTHROUGH */
270 	case OP_BNE:
271 	case OP_BNEL:
272 		db_printf("%s\t%s,%s,", op_name[i.IType.op],
273 		    reg_name[i.IType.rs],
274 		    reg_name[i.IType.rt]);
275 	pr_displ:
276 		print_addr(loc + 4 + ((short)i.IType.imm << 2));
277 		break;
278 
279 	case OP_COP0:
280 		switch (i.RType.rs) {
281 		case OP_BCx:
282 		case OP_BCy:
283 
284 			db_printf("bc0%c\t",
285 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
286 			goto pr_displ;
287 
288 		case OP_MT:
289 			db_printf("mtc0\t%s,%s",
290 			    reg_name[i.RType.rt],
291 			    c0_reg[i.RType.rd]);
292 			break;
293 
294 		case OP_DMT:
295 			db_printf("dmtc0\t%s,%s",
296 			    reg_name[i.RType.rt],
297 			    c0_reg[i.RType.rd]);
298 			break;
299 
300 		case OP_MF:
301 			db_printf("mfc0\t%s,%s",
302 			    reg_name[i.RType.rt],
303 			    c0_reg[i.RType.rd]);
304 			break;
305 
306 		case OP_DMF:
307 			db_printf("dmfc0\t%s,%s",
308 			    reg_name[i.RType.rt],
309 			    c0_reg[i.RType.rd]);
310 			break;
311 
312 		default:
313 			db_printf("%s", c0_opname[i.FRType.func]);
314 		}
315 		break;
316 
317 	case OP_COP1:
318 		switch (i.RType.rs) {
319 		case OP_BCx:
320 		case OP_BCy:
321 			db_printf("bc1%c\t",
322 			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
323 			goto pr_displ;
324 
325 		case OP_MT:
326 			db_printf("mtc1\t%s,f%d",
327 			    reg_name[i.RType.rt],
328 			    i.RType.rd);
329 			break;
330 
331 		case OP_MF:
332 			db_printf("mfc1\t%s,f%d",
333 			    reg_name[i.RType.rt],
334 			    i.RType.rd);
335 			break;
336 
337 		case OP_CT:
338 			db_printf("ctc1\t%s,f%d",
339 			    reg_name[i.RType.rt],
340 			    i.RType.rd);
341 			break;
342 
343 		case OP_CF:
344 			db_printf("cfc1\t%s,f%d",
345 			    reg_name[i.RType.rt],
346 			    i.RType.rd);
347 			break;
348 
349 		default:
350 			db_printf("%s.%s\tf%d,f%d,f%d",
351 			    cop1_name[i.FRType.func],
352 			    fmt_name[i.FRType.fmt],
353 			    i.FRType.fd, i.FRType.fs, i.FRType.ft);
354 		}
355 		break;
356 
357 	case OP_J:
358 	case OP_JAL:
359 		db_printf("%s\t", op_name[i.JType.op]);
360 		print_addr((loc & 0xF0000000) | (i.JType.target << 2));
361 		break;
362 
363 	case OP_LWC1:
364 	case OP_SWC1:
365 		db_printf("%s\tf%d,", op_name[i.IType.op],
366 		    i.IType.rt);
367 		goto loadstore;
368 
369 	case OP_LB:
370 	case OP_LH:
371 	case OP_LW:
372 	case OP_LD:
373 	case OP_LBU:
374 	case OP_LHU:
375 	case OP_LWU:
376 	case OP_SB:
377 	case OP_SH:
378 	case OP_SW:
379 	case OP_SD:
380 		db_printf("%s\t%s,", op_name[i.IType.op],
381 		    reg_name[i.IType.rt]);
382 	loadstore:
383 		db_printf("%d(%s)", (short)i.IType.imm,
384 		    reg_name[i.IType.rs]);
385 		break;
386 
387 	case OP_ORI:
388 	case OP_XORI:
389 		if (i.IType.rs == 0) {
390 			db_printf("li\t%s,0x%x",
391 			    reg_name[i.IType.rt],
392 			    i.IType.imm);
393 			break;
394 		}
395 		/* FALLTHROUGH */
396 	case OP_ANDI:
397 		db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
398 		    reg_name[i.IType.rt],
399 		    reg_name[i.IType.rs],
400 		    i.IType.imm);
401 		break;
402 
403 	case OP_LUI:
404 		db_printf("%s\t%s,0x%x", op_name[i.IType.op],
405 		    reg_name[i.IType.rt],
406 		    i.IType.imm);
407 		break;
408 
409 	case OP_ADDI:
410 	case OP_DADDI:
411 	case OP_ADDIU:
412 	case OP_DADDIU:
413 		if (i.IType.rs == 0) {
414 			db_printf("li\t%s,%d",
415 			    reg_name[i.IType.rt],
416 			    (short)i.IType.imm);
417 			break;
418 		}
419 		/* FALLTHROUGH */
420 	default:
421 		db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
422 		    reg_name[i.IType.rt],
423 		    reg_name[i.IType.rs],
424 		    (short)i.IType.imm);
425 	}
426 	db_printf("\n");
427 	return (loc + 4);
428 }
429 
430 void
431 print_addr(loc)
432 	long loc;
433 {
434 	db_expr_t diff;
435 	db_sym_t sym;
436 	char *symname;
437 
438 	diff = INT_MAX;
439 	symname = NULL;
440 	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
441 	db_symbol_values(sym, &symname, 0);
442 
443 	if (symname) {
444 		if (diff == 0)
445 			db_printf("%s", symname);
446 		else
447 			db_printf("<%s+%lx>", symname, diff);
448 		db_printf("\t[addr:0x%08lx]", loc);
449 	} else {
450 		db_printf("0x%08lx", loc);
451 	}
452 }
453