xref: /netbsd/sys/arch/alpha/alpha/db_disasm.c (revision b6d987a8)
1 /* $NetBSD: db_disasm.c,v 1.18 2021/06/21 02:10:46 thorpej Exp $ */
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie Mellon
26  * the rights to redistribute these changes.
27  */
28 
29 /*
30  *	File: db_disasm.c
31  * 	Author: Alessandro Forin, Carnegie Mellon University
32  *	Date:	11/91
33  *
34  *	Disassembler for Alpha
35  *
36  *	Modified for NetBSD/alpha by:
37  *
38  *	Christopher G. Demetriou, Carnegie Mellon University
39  *
40  *	Jason R. Thorpe, Numerical Aerospace Simulation Facility,
41  *	NASA Ames Research Center
42  *
43  *	This code was derived exclusively from information available in
44  *	"Alpha Architecture Reference Manual", Richard L. Sites ed.
45  *	Digital Press, Burlington, MA 01803
46  *	ISBN 1-55558-098-X, Order no. EY-L520E-DP
47  */
48 
49 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
50 
51 __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.18 2021/06/21 02:10:46 thorpej Exp $");
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/proc.h>
56 #include <machine/db_machdep.h>
57 #include <alpha/alpha/db_instruction.h>
58 
59 #include <machine/pal.h>
60 
61 #include <ddb/db_access.h>
62 #include <ddb/db_sym.h>
63 #include <ddb/db_output.h>
64 #include <ddb/db_interface.h>
65 
66 /*
67  * This would belong in a header file, except noone else needs it
68  *
69  * XXX THESE SHOULD BE CONVERTED TO ra, rb, rc FORMAT.
70  */
71 typedef union {
72 	/*
73 	 *	All instructions are 32 bits wide, PAL included
74 	 */
75 	unsigned int	bits;
76 
77 	/*
78 	 *	Internal processor register access instrs
79 	 *	specify the IPR index, doubly specify the
80 	 *	(same) GP register as src/dest, and qualifiers
81 	 *	for the IPR set involved (abox/ibox/tmp)
82 	 */
83 	struct {
84 		unsigned	index : 5,
85 				regset : 3, /* a,i,p */
86 				xxx : 8,
87 				rs : 5,
88 				rd : 5,
89 				opcode : 6;
90 	} mXpr_format;
91 
92 	/*
93 	 *	Load/store instructions have a 12 bit displacement,
94 	 *	and two register specifiers just as normal ld/st.
95 	 *	Four bits have special meanings:
96 	 *		phy: bypass the MMU (physical access)
97 	 *		alt: use mode in ALT register for checks,
98 	 *		     or if PHY is also on locked/linked access
99 	 *		rwc: read-with-write-check (probew)
100 	 *		qw:  quadword access
101 	 */
102 	struct {
103 		signed int	displacement : 12;
104 		unsigned	qw : 1,
105 				qualif : 3,
106 				rs : 5,
107 				rd : 5,
108 				opcode : 6;
109 	} mem_format;
110 
111 	/*
112 	 *	Return from exception or interrupt has
113 	 *	a branch-like encoding, but only one
114 	 *	instantiation is actually usable.
115 	 */
116 	struct {
117 		unsigned	xxx : 14,
118 				zero : 1,	/* branch prediction! */
119 				one : 1,
120 				rb : 5,		/* r31 or stall */
121 				ra : 5,		/* r31 or stall */
122 				opcode : 6;
123 	} rei_format;
124 
125 } pal_instruction;
126 
127 /*
128  * Major opcodes
129  */
130 static const char * const op_name[64] = {
131 /* 0 */	"call_pal", "op1", "op2", "op3", "op4",	"op5",	"op6",	"op7",
132 /* 8 */	"lda",	"ldah",	"ldbu",	"ldq_u","ldwu",	"stw",	"stb",	"stq_u",
133 /*16 */	"arit",	"logical","bit","mul",	"op20",	"vaxf",	"ieeef","anyf",
134 /*24 */	"spec",	"hw_mfpr","jump","hw_ld","intmisc","hw_mtpr","hw_rei","hw_st",
135 /*32 */	"ldf",	"ldg",	"lds",	"ldt",	"stf",	"stg",	"sts",	"stt",
136 /*40 */	"ldl",	"ldq",	"ldl_l","ldq_l","stl",	"stq",	"stl_c","stq_c",
137 /*48 */	"br",	"fbeq",	"fblt",	"fble",	"bsr",	"fbne",	"fbge",	"fbgt",
138 /*56 */	"blbc",	"beq",	"blt",	"ble",	"blbs",	"bne",	"bge",	"bgt"
139 };
140 
141 /*
142  * The function field is too big (7 or 11 bits), so the sub-tables
143  * are addressed in a somewhat complicated manner to save
144  * space.  After all, alu operations is what RISCs are good at.
145  */
146 
147 struct tbl {
148 	const char	*name;
149 	int		code;
150 };
151 
152 static const struct tbl pal_op_tbl[] = {
153 	/* Common PAL function codes. */
154 	{ "halt",		PAL_halt },
155 	{ "cflush",		PAL_cflush },
156 	{ "draina",		PAL_draina },
157 	{ "cserve",		PAL_cserve, },
158 	{ "swppal",		PAL_swppal },
159 	{ "ipir",		PAL_ipir },
160 	{ "bpt",		PAL_bpt },
161 	{ "bugchk",		PAL_bugchk },
162 	{ "imb",		PAL_imb },
163 	{ "rdunique",		PAL_rdunique },
164 	{ "wrunique",		PAL_wrunique },
165 	{ "gentrap",		PAL_gentrap },
166 
167 	/* OSF/1 PAL function codes. */
168 	{ "osf1_rdmces",	PAL_OSF1_rdmces },
169 	{ "osf1_wrmces",	PAL_OSF1_wrmces },
170 	{ "osf1_wrfen",		PAL_OSF1_wrfen },
171 	{ "osf1_wrvptptr",	PAL_OSF1_wrvptptr },
172 	{ "osf1_swpctx",	PAL_OSF1_swpctx },
173 	{ "osf1_wrval",		PAL_OSF1_wrval },
174 	{ "osf1_rdval",		PAL_OSF1_rdval },
175 	{ "osf1_tbi",		PAL_OSF1_tbi },
176 	{ "osf1_wrent",		PAL_OSF1_wrent },
177 	{ "osf1_swpipl",	PAL_OSF1_swpipl },
178 	{ "osf1_rdps",		PAL_OSF1_rdps },
179 	{ "osf1_wrkgp",		PAL_OSF1_wrkgp },
180 	{ "osf1_wrusp",		PAL_OSF1_wrusp },
181 	{ "osf1_wrperfmon",	PAL_OSF1_wrperfmon },
182 	{ "osf1_rdusp",		PAL_OSF1_rdusp },
183 	{ "osf1_whami",		PAL_OSF1_whami },
184 	{ "osf1_retsys",	PAL_OSF1_retsys },
185 	{ "osf1_rti",		PAL_OSF1_rti },
186 	{ "osf1_callsys",	PAL_OSF1_callsys },
187 
188 	{ NULL,			-1 },
189 };
190 
191 static const char *
pal_opname(int op)192 pal_opname(int op)
193 {
194 	static char unk[8];
195 	int i;
196 
197 	for (i = 0; pal_op_tbl[i].name != NULL; i++) {
198 		if (pal_op_tbl[i].code == op)
199 			return (pal_op_tbl[i].name);
200 	}
201 
202 	snprintf(unk, sizeof(unk), "0x%x", op);
203 	return (unk);
204 }
205 
206 /* HW (PAL) instruction qualifiers, stright tables */
207 static const char * const mXpr_name[8] = {
208 	"", "/i", "/a", "/ai", "/p", "/pi", "/pa", "/pai"
209 };
210 static const char * const hwlds_name[8] = {
211 	"", "/r", "/a", "/ar", "/p", "/p?r", "_l-c", "_l-c/?r"
212 };
213 
214 /*
215  * For this one we take the low nibble (valid values 0/2/9/b/d)
216  * and shift it down one to get the row index.  Within a row
217  * we can just take the high nibble deprived of the high bit
218  * (valid values 0/1/2/3/4/6).  We could have used a flat 64
219  * entry array, but in this way we use just 48 pointers.
220  * BUGFIX: the 'cmpbge 0x0f' opcode fits in here too
221  */
222 static const char * const arit_c0[8] = {
223 	"addl", 0, "addq", 0, "addl/v", 0, "addq/v",
224 };
225 static const char * const arit_c2[8] = {
226 	"s4addl", "s8addl", "s4addq", "s8addq",
227 };
228 static const char * const arit_c9[8] = {
229 	"subl", 0, "subq", 0, "subl/v", 0, "subq/v",
230 };
231 static const char * const arit_cB[8] = {
232 	"s4subl", "s8subl", "s4subq", "s8subq",
233 };
234 static const char * const arit_cD[8] = {
235 	0, "cmpult", "cmpeq", "cmpule", "cmplt", 0, "cmple",
236 };
237 static const char * const arit_cF[1] = {
238 	"cmpbge"
239 };
240 static const char * const * const arit_opname[8] = {
241 	arit_c0, arit_c2, 0, 0, arit_c9, arit_cB, arit_cD, arit_cF
242 };
243 
244 static const char *
arit_name(int op)245 arit_name(int op)
246 {
247 	static char unk[32];
248 	const char *name = NULL;
249 
250 	if (arit_opname[((op)&0xe)>>1])
251 		name = arit_opname[((op)&0xe)>>1][((op)&0x70)>>4];
252 
253 	if (name != NULL)
254 		return (name);
255 
256 	snprintf(unk, sizeof(unk), "?arit 0x%x?", op);
257 	return (unk);
258 }
259 
260 /*
261  * Something similar for this one, except there are only
262  * 16 entries so the row indexing is done by enumeration
263  * of the low nibble (valid values 0/4/6/8).  Then we can
264  * just shift the high nibble to index inside the row
265  * (valid values are 0/2/4 or 1/2/4/6)
266  *
267  * There are two functions that don't play by these simple rules,
268  * so we special-case them.
269  */
270 static const char * const logical_c0[4] = {
271 	"and", "or", "xor", 0
272 };
273 static const char * const logical_c4[4] = {
274 	"cmovlbs", "cmoveq", "cmovlt", "cmovle"
275 };
276 static const char * const logical_c6[4] = {
277 	"cmovlbc", "cmovne", "cmovge", "cmovgt"
278 };
279 static const char * const logical_c8[4] = {
280 	"andnot", "ornot", "xornot", 0
281 };
282 
283 static const char *
logical_name(int op)284 logical_name(int op)
285 {
286 	static char unk[32];
287 	const char *name = NULL;
288 
289 	if (op == op_amask)
290 		return ("amask");
291 	else if (op == op_implver)
292 		return ("implver");
293 
294 	switch (op & 0xf) {
295 	case 0: name = logical_c0[((op)>>5)&3]; break;
296 	case 4: name = logical_c4[((op)>>5)&3]; break;
297 	case 6: name = logical_c6[((op)>>5)&3]; break;
298 	case 8: name = logical_c8[((op)>>5)&3]; break;
299 	}
300 
301 	if (name != NULL)
302 		return (name);
303 
304 	snprintf(unk, sizeof(unk), "?logical 0x%x?", op);
305 	return (unk);
306 }
307 
308 /*
309  * This is the messy one. First, we single out the dense
310  * case of a 3 in the high nibble (valid values 0/1/2/4/6/9/b/c).
311  * Then the case of a 2 in the low nibble (valid values 0/1/2/5/6/7).
312  * For the remaining codes (6/7/a/b) we do as above: high
313  * nibble has valid values 0/1/2 or 5/6/7.  The low nibble
314  * can be used as row index picking bits 0 and 2, for the
315  * high one just the lower two bits.
316  */
317 static const char * const bitop_c3[8] = {
318 	"zapnot", "mskql", "srl", "extql", "sll", "insql", "sra", 0
319 };
320 static const char * const bitop_c2[8] = {
321 	"mskbl", "mskwl", "mskll", 0/*mskql*/, 0, "mskwh", "msklh", "mskqh"
322 };
323 static const char * const bitop_c67ab[4][4] = {
324 /* a */	{ 0, "extwh", "extlh", "extqh"},
325 /* b */	{ "insbl", "inswl", "insll", 0 },
326 /* 6 */	{ "extbl", "extwl", "extll", 0 },
327 /* 7 */	{ 0, "inswh", "inslh", "insqh" },
328 };
329 
330 static const char *
bitop_name(int op)331 bitop_name(int op)
332 {
333 	static char unk[32];
334 	const char *name = NULL;
335 
336 	if ((op & 0x70) == 0x30)
337 		name = (op == op_zap) ? "zap" : bitop_c3[((op)&0xe)>>1];
338 	else if ((op & 0xf) == 0x02)
339 		name = bitop_c2[(op)>>4];
340 	else
341 		name =
342 		    bitop_c67ab[(((op)&1)|(((op)&0x4)>>1))][(((op)&0x30)>>4)];
343 
344 	if (name != NULL)
345 		return (name);
346 
347 	snprintf(unk, sizeof(unk), "?bit 0x%x?", op);
348 	return (unk);
349 }
350 
351 /*
352  * Only 4 entries in this one
353  */
354 static const char * const mul_opname[4] = {
355 	"mull", "mulq", "mull/v", "mulq/v"
356 };
357 
358 static const char *
mul_name(int op)359 mul_name(int op)
360 {
361 	static char unk[32];
362 	const char *name = NULL;
363 
364 	name = (op == op_umulh) ? "umulh" : mul_opname[((op)>>5)&3];
365 
366 	if (name != NULL)
367 		return (name);
368 
369 	snprintf(unk, sizeof(unk), "?mul 0x%x?", op);
370 	return (unk);
371 }
372 
373 /*
374  * These are few, the high nibble is usually enough to dispatch.
375  * We single out the `f' case to halve the table size, as
376  * well as the cases in which the high nibble isn't enough.
377  */
378 static const char * const special_opname[8] = {
379 	"trapb", 0, "mb", 0, "fetch", "fetch_m", "rpcc", "rc"
380 };
381 
382 static const char *
special_name(int op)383 special_name(int op)
384 {
385 	static char unk[32];
386 	const char *name;
387 
388 	switch (op) {
389 	case op_excb:		name = "excb";		break;
390 	case op_wmb:		name = "wmb";		break;
391 	case op_ecb:		name = "ecb";		break;
392 	case op_rs:		name = "rs";		break;
393 	case op_wh64:		name = "wh64";		break;
394 	default:
395 		name = special_opname[(op)>>13];
396 	}
397 
398 	if (name != NULL)
399 		return (name);
400 
401 	snprintf(unk, sizeof(unk), "?special 0x%x?", op);
402 	return (unk);
403 }
404 
405 /*
406  * This is trivial
407  */
408 static const char * const jump_opname[4] = {
409 	"jmp", "jsr", "ret", "jcr"
410 };
411 #define jump_name(ix)	jump_opname[ix]
412 
413 /*
414  * For all but 4 of these, we can dispatch on the lower nibble of
415  * the "function".
416  */
417 static const char * const intmisc_opname_3x[16] = {
418 	"ctpop", "perr", "ctlz", "cttz", "unpkbw", "unpkbl", "pkwb",
419 	"pklb", "minsb8", "minsw4", "minub8", "minuw4", "maxub8",
420 	"maxuw4", "maxsb8", "maxsw4",
421 };
422 
423 static const char *
intmisc_name(int op)424 intmisc_name(int op)
425 {
426 	static char unk[32];
427 
428 	if ((op & 0xf0) == 0x30)
429 		return (intmisc_opname_3x[op & 0x0f]);
430 
431 	switch (op) {
432 	case op_sextb: return ("sextb");
433 	case op_sextw: return ("sextw");
434 	case op_ftoit: return ("ftoit");
435 	case op_ftois: return ("ftois");
436 	}
437 
438 	snprintf(unk, sizeof(unk), "?intmisc 0x%x?", op);
439 	return (unk);
440 }
441 
442 static const char *
float_name(const struct tbl * tbl,int op,const char * type)443 float_name(const struct tbl *tbl, int op, const char *type)
444 {
445 	static char unk[32];
446 	int i;
447 
448 	for (i = 0; tbl[i].name != NULL; i++) {
449 		if (tbl[i].code == op)
450 			return (tbl[i].name);
451 	}
452 
453 	snprintf(unk, sizeof(unk), "?%s 0x%x?", type, op);
454 	return (unk);
455 }
456 
457 #define vaxf_name(op)	float_name(vaxf_tbl, op, "vaxfl")
458 #define ieeef_name(op)	float_name(ieeef_tbl, op, "ieeefl")
459 #define anyf_name(op)	float_name(anyf_tbl, op, "anyfl")
460 
461 static const struct tbl anyf_tbl[] = {
462 	{ "cvtlq",	0x010},
463 	{ "cpys",	0x020},
464 	{ "cpysn",	0x021},
465 	{ "cpyse",	0x022},
466 	{ "mt_fpcr",	0x024},
467 	{ "mf_fpcr",	0x025},
468 	{ "fcmoveq",	0x02a},
469 	{ "fcmovne",	0x02b},
470 	{ "fcmovlt",	0x02c},
471 	{ "fcmovge",	0x02d},
472 	{ "fcmovle",	0x02e},
473 	{ "fcmovgt",	0x02f},
474 	{ "cvtql",	0x030},
475 	{ "cvtql/v",	0x130},
476 	{ "cvtql/sv",	0x330},
477 	{ 0, 0},
478 };
479 
480 static const struct tbl ieeef_tbl[] = {
481 	{ "adds/c",	0x000},
482 	{ "subs/c",	0x001},
483 	{ "muls/c",	0x002},
484 	{ "divs/c",	0x003},
485 	{ "addt/c",	0x020},
486 	{ "subt/c",	0x021},
487 	{ "mult/c",	0x022},
488 	{ "divt/c",	0x023},
489 	{ "cvtts/c",	0x02c},
490 	{ "cvttq/c",	0x02f},
491 	{ "cvtqs/c",	0x03c},
492 	{ "cvtqt/c",	0x03e},
493 	{ "adds/m",	0x040},
494 	{ "subs/m",	0x041},
495 	{ "muls/m",	0x042},
496 	{ "divs/m",	0x043},
497 	{ "addt/m",	0x060},
498 	{ "subt/m",	0x061},
499 	{ "mult/m",	0x062},
500 	{ "divt/m",	0x063},
501 	{ "cvtts/m",	0x06c},
502 	{ "cvtqs/m",	0x07c},
503 	{ "cvtqt/m",	0x07e},
504 	{ "adds",	0x080},
505 	{ "subs",	0x081},
506 	{ "muls",	0x082},
507 	{ "divs",	0x083},
508 	{ "addt",	0x0a0},
509 	{ "subt",	0x0a1},
510 	{ "mult",	0x0a2},
511 	{ "divt",	0x0a3},
512 	{ "cmptun",	0x0a4},
513 	{ "cmpteq",	0x0a5},
514 	{ "cmptlt",	0x0a6},
515 	{ "cmptle",	0x0a7},
516 	{ "cvtts",	0x0ac},
517 	{ "cvttq",	0x0af},
518 	{ "cvtqs",	0x0bc},
519 	{ "cvtqt",	0x0be},
520 	{ "adds/d",	0x0c0},
521 	{ "subs/d",	0x0c1},
522 	{ "muls/d",	0x0c2},
523 	{ "divs/d",	0x0c3},
524 	{ "addt/d",	0x0e0},
525 	{ "subt/d",	0x0e1},
526 	{ "mult/d",	0x0e2},
527 	{ "divt/d",	0x0e3},
528 	{ "cvtts/d",	0x0ec},
529 	{ "cvtqs/d",	0x0fc},
530 	{ "cvtqt/d",	0x0fe},
531 	{ "adds/uc",	0x100},
532 	{ "subs/uc",	0x101},
533 	{ "muls/uc",	0x102},
534 	{ "divs/uc",	0x103},
535 	{ "addt/uc",	0x120},
536 	{ "subt/uc",	0x121},
537 	{ "mult/uc",	0x122},
538 	{ "divt/uc",	0x123},
539 	{ "cvtts/uc",	0x12c},
540 	{ "cvttq/vc",	0x12f},
541 	{ "adds/um",	0x140},
542 	{ "subs/um",	0x141},
543 	{ "muls/um",	0x142},
544 	{ "divs/um",	0x143},
545 	{ "addt/um",	0x160},
546 	{ "subt/um",	0x161},
547 	{ "mult/um",	0x162},
548 	{ "divt/um",	0x163},
549 	{ "cvtts/um",	0x16c},
550 	{ "adds/u",	0x180},
551 	{ "subs/u",	0x181},
552 	{ "muls/u",	0x182},
553 	{ "divs/u",	0x183},
554 	{ "addt/u",	0x1a0},
555 	{ "subt/u",	0x1a1},
556 	{ "mult/u",	0x1a2},
557 	{ "divt/u",	0x1a3},
558 	{ "cvtts/u",	0x1ac},
559 	{ "cvttq/v",	0x1af},
560 	{ "adds/ud",	0x1c0},
561 	{ "subs/ud",	0x1c1},
562 	{ "muls/ud",	0x1c2},
563 	{ "divs/ud",	0x1c3},
564 	{ "addt/ud",	0x1e0},
565 	{ "subt/ud",	0x1e1},
566 	{ "mult/ud",	0x1e2},
567 	{ "divt/ud",	0x1e3},
568 	{ "cvtts/ud",	0x1ec},
569 	{ "adds/suc",	0x500},
570 	{ "subs/suc",	0x501},
571 	{ "muls/suc",	0x502},
572 	{ "divs/suc",	0x503},
573 	{ "addt/suc",	0x520},
574 	{ "subt/suc",	0x521},
575 	{ "mult/suc",	0x522},
576 	{ "divt/suc",	0x523},
577 	{ "cvtts/suc",	0x52c},
578 	{ "cvttq/svc",	0x52f},
579 	{ "adds/sum",	0x540},
580 	{ "subs/sum",	0x541},
581 	{ "muls/sum",	0x542},
582 	{ "divs/sum",	0x543},
583 	{ "addt/sum",	0x560},
584 	{ "subt/sum",	0x561},
585 	{ "mult/sum",	0x562},
586 	{ "divt/sum",	0x563},
587 	{ "cvtts/sum",	0x56c},
588 	{ "adds/su",	0x580},
589 	{ "subs/su",	0x581},
590 	{ "muls/su",	0x582},
591 	{ "divs/su",	0x583},
592 	{ "addt/su",	0x5a0},
593 	{ "subt/su",	0x5a1},
594 	{ "mult/su",	0x5a2},
595 	{ "divt/su",	0x5a3},
596 	{ "cmptun/su",	0x5a4},
597 	{ "cmpteq/su",	0x5a5},
598 	{ "cmptlt/su",	0x5a6},
599 	{ "cmptle/su",	0x5a7},
600 	{ "cvtts/su",	0x5ac},
601 	{ "cvttq/sv",	0x5af},
602 	{ "adds/sud",	0x5c0},
603 	{ "subs/sud",	0x5c1},
604 	{ "muls/sud",	0x5c2},
605 	{ "divs/sud",	0x5c3},
606 	{ "addt/sud",	0x5e0},
607 	{ "subt/sud",	0x5e1},
608 	{ "mult/sud",	0x5e2},
609 	{ "divt/sud",	0x5e3},
610 	{ "cvtts/sud",	0x5ec},
611 	{ "adds/suic",	0x700},
612 	{ "subs/suic",	0x701},
613 	{ "muls/suic",	0x702},
614 	{ "divs/suic",	0x703},
615 	{ "addt/suic",	0x720},
616 	{ "subt/suic",	0x721},
617 	{ "mult/suic",	0x722},
618 	{ "divt/suic",	0x723},
619 	{ "cvtts/suic",	0x72c},
620 	{ "cvttq/svic",	0x72f},
621 	{ "cvtqs/suic",	0x73c},
622 	{ "cvtqt/suic",	0x73e},
623 	{ "adds/suim",	0x740},
624 	{ "subs/suim",	0x741},
625 	{ "muls/suim",	0x742},
626 	{ "divs/suim",	0x743},
627 	{ "addt/suim",	0x760},
628 	{ "subt/suim",	0x761},
629 	{ "mult/suim",	0x762},
630 	{ "divt/suim",	0x763},
631 	{ "cvtts/suim",	0x76c},
632 	{ "cvtqs/suim",	0x77c},
633 	{ "cvtqt/suim",	0x77e},
634 	{ "adds/sui",	0x780},
635 	{ "subs/sui",	0x781},
636 	{ "muls/sui",	0x782},
637 	{ "divs/sui",	0x783},
638 	{ "addt/sui",	0x7a0},
639 	{ "subt/sui",	0x7a1},
640 	{ "mult/sui",	0x7a2},
641 	{ "divt/sui",	0x7a3},
642 	{ "cvtts/sui",	0x7ac},
643 	{ "cvttq/svi",	0x7af},
644 	{ "cvtqs/sui",	0x7bc},
645 	{ "cvtqt/sui",	0x7be},
646 	{ "adds/suid",	0x7c0},
647 	{ "subs/suid",	0x7c1},
648 	{ "muls/suid",	0x7c2},
649 	{ "divs/suid",	0x7c3},
650 	{ "addt/suid",	0x7e0},
651 	{ "subt/suid",	0x7e1},
652 	{ "mult/suid",	0x7e2},
653 	{ "divt/suid",	0x7e3},
654 	{ "cvtts/suid",	0x7ec},
655 	{ "cvtqs/suid",	0x7fc},
656 	{ "cvtqt/suid",	0x7fe},
657 	{ 0, 0}
658 };
659 
660 static const struct tbl vaxf_tbl[] = {
661 	{ "addf/c",	0x000},
662 	{ "subf/c",	0x001},
663 	{ "mulf/c",	0x002},
664 	{ "divf/c",	0x003},
665 	{ "cvtdg/c",	0x01e},
666 	{ "addg/c",	0x020},
667 	{ "subg/c",	0x021},
668 	{ "mulg/c",	0x022},
669 	{ "divg/c",	0x023},
670 	{ "cvtgf/c",	0x02c},
671 	{ "cvtgd/c",	0x02d},
672 	{ "cvtgq/c",	0x02f},
673 	{ "cvtqf/c",	0x03c},
674 	{ "cvtqg/c",	0x03e},
675 	{ "addf",	0x080},
676 	{ "subf",	0x081},
677 	{ "mulf",	0x082},
678 	{ "divf",	0x083},
679 	{ "cvtdg",	0x09e},
680 	{ "addg",	0x0a0},
681 	{ "subg",	0x0a1},
682 	{ "mulg",	0x0a2},
683 	{ "divg",	0x0a3},
684 	{ "cmpgeq",	0x0a5},
685 	{ "cmpglt",	0x0a6},
686 	{ "cmpgle",	0x0a7},
687 	{ "cvtgf",	0x0ac},
688 	{ "cvtgd",	0x0ad},
689 	{ "cvtgq",	0x0af},
690 	{ "cvtqf",	0x0bc},
691 	{ "cvtqg",	0x0be},
692 	{ "addf/uc",	0x100},
693 	{ "subf/uc",	0x101},
694 	{ "mulf/uc",	0x102},
695 	{ "divf/uc",	0x103},
696 	{ "cvtdg/uc",	0x11e},
697 	{ "addg/uc",	0x120},
698 	{ "subg/uc",	0x121},
699 	{ "mulg/uc",	0x122},
700 	{ "divg/uc",	0x123},
701 	{ "cvtgf/uc",	0x12c},
702 	{ "cvtgd/uc",	0x12d},
703 	{ "cvtgq/vc",	0x12f},
704 	{ "addf/u",	0x180},
705 	{ "subf/u",	0x181},
706 	{ "mulf/u",	0x182},
707 	{ "divf/u",	0x183},
708 	{ "cvtdg/u",	0x19e},
709 	{ "addg/u",	0x1a0},
710 	{ "subg/u",	0x1a1},
711 	{ "mulg/u",	0x1a2},
712 	{ "divg/u",	0x1a3},
713 	{ "cvtgf/u",	0x1ac},
714 	{ "cvtgd/u",	0x1ad},
715 	{ "cvtgq/v",	0x1af},
716 	{ "addf/sc",	0x400},
717 	{ "subf/sc",	0x401},
718 	{ "mulf/sc",	0x402},
719 	{ "divf/sc",	0x403},
720 	{ "cvtdg/sc",	0x41e},
721 	{ "addg/sc",	0x420},
722 	{ "subg/sc",	0x421},
723 	{ "mulg/sc",	0x422},
724 	{ "divg/sc",	0x423},
725 	{ "cvtgf/sc",	0x42c},
726 	{ "cvtgd/sc",	0x42d},
727 	{ "cvtgq/sc",	0x42f},
728 	{ "cvtqf/sc",	0x43c},
729 	{ "cvtqg/sc",	0x43e},
730 	{ "addf/s",	0x480},
731 	{ "subf/s",	0x481},
732 	{ "mulf/s",	0x482},
733 	{ "divf/s",	0x483},
734 	{ "cvtdg/s",	0x49e},
735 	{ "addg/s",	0x4a0},
736 	{ "subg/s",	0x4a1},
737 	{ "mulg/s",	0x4a2},
738 	{ "divg/s",	0x4a3},
739 	{ "cmpgeq/s",	0x4a5},
740 	{ "cmpglt/s",	0x4a6},
741 	{ "cmpgle/s",	0x4a7},
742 	{ "cvtgf/s",	0x4ac},
743 	{ "cvtgd/s",	0x4ad},
744 	{ "cvtgq/s",	0x4af},
745 	{ "cvtqf/s",	0x4bc},
746 	{ "cvtqg/s",	0x4be},
747 	{ "addf/suc",	0x500},
748 	{ "subf/suc",	0x501},
749 	{ "mulf/suc",	0x502},
750 	{ "divf/suc",	0x503},
751 	{ "cvtdg/suc",	0x51e},
752 	{ "addg/suc",	0x520},
753 	{ "subg/suc",	0x521},
754 	{ "mulg/suc",	0x522},
755 	{ "divg/suc",	0x523},
756 	{ "cvtgf/suc",	0x52c},
757 	{ "cvtgd/suc",	0x52d},
758 	{ "cvtgq/svc",	0x52f},
759 	{ "addf/su",	0x580},
760 	{ "subf/su",	0x581},
761 	{ "mulf/su",	0x582},
762 	{ "divf/su",	0x583},
763 	{ "cvtdg/su",	0x59e},
764 	{ "addg/su",	0x5a0},
765 	{ "subg/su",	0x5a1},
766 	{ "mulg/su",	0x5a2},
767 	{ "divg/su",	0x5a3},
768 	{ "cvtgf/su",	0x5ac},
769 	{ "cvtgd/su",	0x5ad},
770 	{ "cvtgq/sv",	0x5af},
771 	{ 0, 0}
772 };
773 
774 /*
775  * General purpose registers
776  */
777 static const char * const name_of_register[32] = {
778 	"v0",	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",
779 	"t7",	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",
780 	"a0",	"a1",	"a2",	"a3",	"a4",	"a5",	"t8",	"t9",
781 	"t10",	"t11",	"ra",	"pv",	"at",	"gp",	"sp",	"zero"
782 };
783 
784 static const char *
register_name(struct alpha_print_instruction_context * ctx,int ireg)785 register_name(struct alpha_print_instruction_context *ctx, int ireg)
786 {
787 	return (name_of_register[ireg]);
788 }
789 
790 static void
insn_printf(struct alpha_print_instruction_context * ctx,const char * fmt,...)791 insn_printf(struct alpha_print_instruction_context *ctx,
792     const char *fmt, ...)
793 {
794 	va_list ap;
795 
796 	va_start(ap, fmt);
797 
798 	if (ctx->buf != NULL) {
799 		if (ctx->cursor < ctx->bufsize) {
800 			ctx->cursor += vsnprintf(ctx->buf + ctx->cursor,
801 			    ctx->bufsize - ctx->cursor, fmt, ap);
802 		}
803 	} else {
804 		db_vprintf(fmt, ap);
805 	}
806 
807 	va_end(ap);
808 }
809 
810 /*
811  * Disassemble instruction at 'loc'.  'altfmt' specifies an
812  * (optional) alternate format.  Return address of start of
813  * next instruction.
814  */
815 
816 int
alpha_print_instruction(struct alpha_print_instruction_context * ctx)817 alpha_print_instruction(struct alpha_print_instruction_context *ctx)
818 {
819 	const char	*opcode;
820 	long		signed_immediate;
821 	bool		fstore;
822 	pal_instruction	p;
823 
824 	fstore = false;
825 	opcode = op_name[ctx->insn.mem_format.opcode];
826 
827 	/*
828 	 *	Dispatch directly on the opcode, save code
829 	 *	duplication sometimes via "harmless gotos".
830 	 */
831 	switch (ctx->insn.mem_format.opcode) {
832 	case op_pal:
833 		/* "call_pal" is a long string; just use a space. */
834 		insn_printf(ctx, "%s %s", opcode,
835 		    pal_opname(ctx->insn.pal_format.function));
836 		break;
837 	case op_lda:
838 	case op_ldah:
839 	case op_ldbu:
840 	case op_ldq_u:
841 	case op_ldwu:
842 	case op_stw:
843 	case op_stb:
844 	case op_stq_u:
845 		/*
846 		 * These loadstores are here to make compiling the
847 		 * switch a bit easier.  Could embellish the output
848 		 * someday, too.
849 		 */
850 		goto loadstore;
851 		break;
852 	case op_arit:
853 		/*
854 		 * For this and the following three groups we
855 		 * just need different opcode strings
856 		 */
857 		opcode = arit_name(ctx->insn.operate_lit_format.function);
858 		goto operate;
859 		break;
860 	case op_logical:
861 		opcode = logical_name(ctx->insn.operate_lit_format.function);
862 		goto operate;
863 		break;
864 	case op_bit:
865 		opcode = bitop_name(ctx->insn.operate_lit_format.function);
866 		goto operate;
867 		break;
868 	case op_mul:
869 		opcode = mul_name(ctx->insn.operate_lit_format.function);
870 operate:
871 		/*
872 		 * Nice and uniform, just check for literals
873 		 */
874 		insn_printf(ctx, "%s\t%s,", opcode,
875 		    register_name(ctx, ctx->insn.operate_lit_format.ra));
876 		if (ctx->insn.operate_lit_format.one) {
877 			insn_printf(ctx, "#0x%x",
878 			    ctx->insn.operate_lit_format.literal);
879 		} else {
880 			insn_printf(ctx, "%s",
881 			    register_name(ctx,
882 					  ctx->insn.operate_reg_format.rb));
883 		}
884 		insn_printf(ctx, ",%s",
885 		    register_name(ctx, ctx->insn.operate_lit_format.rc));
886 		break;
887 	case op_vax_float:
888 		/*
889 		 * The three floating point groups are even simpler
890 		 */
891 		opcode = vaxf_name(ctx->insn.float_format.function);
892 		goto foperate;
893 		break;
894 	case op_ieee_float:
895 		opcode = ieeef_name(ctx->insn.float_format.function);
896 		goto foperate;
897 		break;
898 	case op_any_float:
899 		opcode = anyf_name(ctx->insn.float_format.function);
900 foperate:
901 		insn_printf(ctx, "%s\tf%d,f%d,f%d", opcode,
902 			ctx->insn.float_format.fa,
903 			ctx->insn.float_format.fb,
904 			ctx->insn.float_format.fc);
905 		break;
906 	case op_special:
907 		/*
908 		 * Miscellaneous.
909 		 */
910 		{
911 			register unsigned int code;
912 
913 			code = (ctx->insn.mem_format.displacement)&0xffff;
914 			opcode = special_name(code);
915 
916 			switch (code) {
917 			case op_ecb:
918 				insn_printf(ctx, "%s\t(%s)", opcode,
919 				    register_name(ctx,
920 						  ctx->insn.mem_format.rb));
921 				break;
922 			case op_fetch:
923 			case op_fetch_m:
924 				insn_printf(ctx, "%s\t0(%s)", opcode,
925 				    register_name(ctx,
926 						  ctx->insn.mem_format.rb));
927 				break;
928 			case op_rpcc:
929 			case op_rc:
930 			case op_rs:
931 				insn_printf(ctx, "%s\t%s", opcode,
932 				    register_name(ctx,
933 						  ctx->insn.mem_format.ra));
934 				break;
935 			default:
936 				insn_printf(ctx, "%s", opcode);
937 			break;
938 			}
939 		}
940 		break;
941 	case op_j:
942 		/*
943 		 * Jump instructions really are of two sorts,
944 		 * depending on the use of the hint info.
945 		 */
946 		opcode = jump_name(ctx->insn.jump_format.action);
947 		switch (ctx->insn.jump_format.action) {
948 		case op_jmp:
949 		case op_jsr:
950 			insn_printf(ctx, "%s\t%s,(%s),", opcode,
951 			    register_name(ctx, ctx->insn.jump_format.ra),
952 			    register_name(ctx, ctx->insn.jump_format.rb));
953 			signed_immediate = ctx->insn.jump_format.hint;
954 			goto branch_displacement;
955 			break;
956 		case op_ret:
957 		case op_jcr:
958 			insn_printf(ctx, "%s\t%s,(%s)", opcode,
959 			    register_name(ctx, ctx->insn.jump_format.ra),
960 			    register_name(ctx, ctx->insn.jump_format.rb));
961 			break;
962 		}
963 		break;
964 	case op_intmisc:
965 		/*
966 		 * These are just in "operate" format.
967 		 */
968 		opcode = intmisc_name(ctx->insn.operate_lit_format.function);
969 		goto operate;
970 		break;
971 			/* HW instructions, possibly chip-specific XXXX */
972 	case op_pal19:	/* "hw_mfpr" */
973 	case op_pal1d:	/* "hw_mtpr" */
974 		p.bits = ctx->insn.bits;
975 		insn_printf(ctx, "\t%s%s\t%s, %d", opcode,
976 			mXpr_name[p.mXpr_format.regset],
977 			register_name(ctx, p.mXpr_format.rd),
978 			p.mXpr_format.index);
979 		break;
980 	case op_pal1b:	/* "hw_ld" */
981 	case op_pal1f:	/* "hw_st" */
982 		p.bits = ctx->insn.bits;
983 		insn_printf(ctx, "\t%s%c%s\t%s,", opcode,
984 			(p.mem_format.qw) ? 'q' : 'l',
985 			hwlds_name[p.mem_format.qualif],
986 			register_name(ctx, p.mem_format.rd));
987 		signed_immediate = (long)p.mem_format.displacement;
988 		goto loadstore_address;
989 
990 	case op_pal1e:	/* "hw_rei" */
991 		insn_printf(ctx, "\t%s", opcode);
992 		break;
993 
994 	case op_ldf:
995 	case op_ldg:
996 	case op_lds:
997 	case op_ldt:
998 	case op_stf:
999 	case op_stg:
1000 	case op_sts:
1001 	case op_stt:
1002 		fstore = true;
1003 		/* fall through */
1004 	case op_ldl:
1005 	case op_ldq:
1006 	case op_ldl_l:
1007 	case op_ldq_l:
1008 	case op_stl:
1009 	case op_stq:
1010 	case op_stl_c:
1011 	case op_stq_c:
1012 		/*
1013 		 * Memory operations, including floats
1014 		 */
1015 loadstore:
1016 		if (fstore) {
1017 			insn_printf(ctx, "%s\tf%d,", opcode,
1018 			    ctx->insn.mem_format.ra);
1019 		} else {
1020 			insn_printf(ctx, "%s\t%s,", opcode,
1021 			    register_name(ctx, ctx->insn.mem_format.ra));
1022 		}
1023 		signed_immediate = (long)ctx->insn.mem_format.displacement;
1024 loadstore_address:
1025 		{
1026 			char tbuf[24];
1027 
1028 			db_format_hex(tbuf, 24, signed_immediate, false);
1029 			insn_printf(ctx, "%s(%s)", tbuf,
1030 			    register_name(ctx, ctx->insn.mem_format.rb));
1031 		}
1032 		break;
1033 	case op_br:
1034 	case op_fbeq:
1035 	case op_fblt:
1036 	case op_fble:
1037 	case op_bsr:
1038 	case op_fbne:
1039 	case op_fbge:
1040 	case op_fbgt:
1041 	case op_blbc:
1042 	case op_beq:
1043 	case op_blt:
1044 	case op_ble:
1045 	case op_blbs:
1046 	case op_bne:
1047 	case op_bge:
1048 	case op_bgt:
1049 		/*
1050 		 * We want to know where we are branching to
1051 		 */
1052 		signed_immediate = (long)ctx->insn.branch_format.displacement;
1053 		insn_printf(ctx, "%s\t%s,", opcode,
1054 		    register_name(ctx, ctx->insn.branch_format.ra));
1055 branch_displacement:
1056 		if (ctx->buf == NULL) {
1057 			db_printsym(ctx->pc + sizeof(alpha_instruction) +
1058 			    (signed_immediate << 2), DB_STGY_PROC, db_printf);
1059 		}
1060 		break;
1061 	default:
1062 		/*
1063 		 * Shouldn't happen
1064 		 */
1065 		insn_printf(ctx, "? 0x%x ?", ctx->insn.bits);
1066 	}
1067 
1068 	/* If printing into a buffer, skip the newline. */
1069 	if (ctx->buf == NULL) {
1070 		insn_printf(ctx, "\n");
1071 	}
1072 
1073 	return (sizeof(alpha_instruction));
1074 }
1075 
1076 db_addr_t
db_disasm(db_addr_t loc,bool altfmt __unused)1077 db_disasm(db_addr_t loc, bool altfmt __unused)
1078 {
1079 	struct alpha_print_instruction_context ctx = {
1080 		.insn.bits = db_get_value(loc, 4, 0),
1081 		.pc = loc,
1082 	};
1083 
1084 	loc += alpha_print_instruction(&ctx);
1085 	return loc;
1086 }
1087