xref: /netbsd-src/sys/arch/alpha/alpha/db_disasm.c (revision bb5982f8bbaa662af03808c5b01ec4272494a494)
1 /* $NetBSD: db_disasm.c,v 1.20 2023/11/21 22:25:16 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.20 2023/11/21 22:25:16 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 <machine/alpha_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[11];
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%08x", 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 #ifndef _KERNEL
817 static
818 #endif
819 int
alpha_print_instruction(struct alpha_print_instruction_context * ctx)820 alpha_print_instruction(struct alpha_print_instruction_context *ctx)
821 {
822 	const char	*opcode;
823 	long		signed_immediate;
824 	bool		fstore;
825 	pal_instruction	p;
826 
827 	fstore = false;
828 	opcode = op_name[ctx->insn.mem_format.opcode];
829 
830 	/*
831 	 *	Dispatch directly on the opcode, save code
832 	 *	duplication sometimes via "harmless gotos".
833 	 */
834 	switch (ctx->insn.mem_format.opcode) {
835 	case op_pal:
836 		/* "call_pal" is a long string; just use a space. */
837 		insn_printf(ctx, "%s %s", opcode,
838 		    pal_opname(ctx->insn.pal_format.function));
839 		break;
840 	case op_lda:
841 	case op_ldah:
842 	case op_ldbu:
843 	case op_ldq_u:
844 	case op_ldwu:
845 	case op_stw:
846 	case op_stb:
847 	case op_stq_u:
848 		/*
849 		 * These loadstores are here to make compiling the
850 		 * switch a bit easier.  Could embellish the output
851 		 * someday, too.
852 		 */
853 		goto loadstore;
854 		break;
855 	case op_arit:
856 		/*
857 		 * For this and the following three groups we
858 		 * just need different opcode strings
859 		 */
860 		opcode = arit_name(ctx->insn.operate_lit_format.function);
861 		goto operate;
862 		break;
863 	case op_logical:
864 		opcode = logical_name(ctx->insn.operate_lit_format.function);
865 		goto operate;
866 		break;
867 	case op_bit:
868 		opcode = bitop_name(ctx->insn.operate_lit_format.function);
869 		goto operate;
870 		break;
871 	case op_mul:
872 		opcode = mul_name(ctx->insn.operate_lit_format.function);
873 operate:
874 		/*
875 		 * Nice and uniform, just check for literals
876 		 */
877 		insn_printf(ctx, "%s\t%s,", opcode,
878 		    register_name(ctx, ctx->insn.operate_lit_format.ra));
879 		if (ctx->insn.operate_lit_format.one) {
880 			insn_printf(ctx, "#0x%x",
881 			    ctx->insn.operate_lit_format.literal);
882 		} else {
883 			insn_printf(ctx, "%s",
884 			    register_name(ctx,
885 					  ctx->insn.operate_reg_format.rb));
886 		}
887 		insn_printf(ctx, ",%s",
888 		    register_name(ctx, ctx->insn.operate_lit_format.rc));
889 		break;
890 	case op_vax_float:
891 		/*
892 		 * The three floating point groups are even simpler
893 		 */
894 		opcode = vaxf_name(ctx->insn.float_format.function);
895 		goto foperate;
896 		break;
897 	case op_ieee_float:
898 		opcode = ieeef_name(ctx->insn.float_format.function);
899 		goto foperate;
900 		break;
901 	case op_any_float:
902 		opcode = anyf_name(ctx->insn.float_format.function);
903 foperate:
904 		insn_printf(ctx, "%s\tf%d,f%d,f%d", opcode,
905 			ctx->insn.float_format.fa,
906 			ctx->insn.float_format.fb,
907 			ctx->insn.float_format.fc);
908 		break;
909 	case op_special:
910 		/*
911 		 * Miscellaneous.
912 		 */
913 		{
914 			register unsigned int code;
915 
916 			code = (ctx->insn.mem_format.displacement)&0xffff;
917 			opcode = special_name(code);
918 
919 			switch (code) {
920 			case op_ecb:
921 				insn_printf(ctx, "%s\t(%s)", opcode,
922 				    register_name(ctx,
923 						  ctx->insn.mem_format.rb));
924 				break;
925 			case op_fetch:
926 			case op_fetch_m:
927 				insn_printf(ctx, "%s\t0(%s)", opcode,
928 				    register_name(ctx,
929 						  ctx->insn.mem_format.rb));
930 				break;
931 			case op_rpcc:
932 			case op_rc:
933 			case op_rs:
934 				insn_printf(ctx, "%s\t%s", opcode,
935 				    register_name(ctx,
936 						  ctx->insn.mem_format.ra));
937 				break;
938 			default:
939 				insn_printf(ctx, "%s", opcode);
940 			break;
941 			}
942 		}
943 		break;
944 	case op_j:
945 		/*
946 		 * Jump instructions really are of two sorts,
947 		 * depending on the use of the hint info.
948 		 */
949 		opcode = jump_name(ctx->insn.jump_format.action);
950 		switch (ctx->insn.jump_format.action) {
951 		case op_jmp:
952 		case op_jsr:
953 			insn_printf(ctx, "%s\t%s,(%s),", opcode,
954 			    register_name(ctx, ctx->insn.jump_format.ra),
955 			    register_name(ctx, ctx->insn.jump_format.rb));
956 			signed_immediate = ctx->insn.jump_format.hint;
957 			goto branch_displacement;
958 			break;
959 		case op_ret:
960 		case op_jcr:
961 			insn_printf(ctx, "%s\t%s,(%s)", opcode,
962 			    register_name(ctx, ctx->insn.jump_format.ra),
963 			    register_name(ctx, ctx->insn.jump_format.rb));
964 			break;
965 		}
966 		break;
967 	case op_intmisc:
968 		/*
969 		 * These are just in "operate" format.
970 		 */
971 		opcode = intmisc_name(ctx->insn.operate_lit_format.function);
972 		goto operate;
973 		break;
974 			/* HW instructions, possibly chip-specific XXXX */
975 	case op_pal19:	/* "hw_mfpr" */
976 	case op_pal1d:	/* "hw_mtpr" */
977 		p.bits = ctx->insn.bits;
978 		insn_printf(ctx, "\t%s%s\t%s, %d", opcode,
979 			mXpr_name[p.mXpr_format.regset],
980 			register_name(ctx, p.mXpr_format.rd),
981 			p.mXpr_format.index);
982 		break;
983 	case op_pal1b:	/* "hw_ld" */
984 	case op_pal1f:	/* "hw_st" */
985 		p.bits = ctx->insn.bits;
986 		insn_printf(ctx, "\t%s%c%s\t%s,", opcode,
987 			(p.mem_format.qw) ? 'q' : 'l',
988 			hwlds_name[p.mem_format.qualif],
989 			register_name(ctx, p.mem_format.rd));
990 		signed_immediate = (long)p.mem_format.displacement;
991 		goto loadstore_address;
992 
993 	case op_pal1e:	/* "hw_rei" */
994 		insn_printf(ctx, "\t%s", opcode);
995 		break;
996 
997 	case op_ldf:
998 	case op_ldg:
999 	case op_lds:
1000 	case op_ldt:
1001 	case op_stf:
1002 	case op_stg:
1003 	case op_sts:
1004 	case op_stt:
1005 		fstore = true;
1006 		/* fall through */
1007 	case op_ldl:
1008 	case op_ldq:
1009 	case op_ldl_l:
1010 	case op_ldq_l:
1011 	case op_stl:
1012 	case op_stq:
1013 	case op_stl_c:
1014 	case op_stq_c:
1015 		/*
1016 		 * Memory operations, including floats
1017 		 */
1018 loadstore:
1019 		if (fstore) {
1020 			insn_printf(ctx, "%s\tf%d,", opcode,
1021 			    ctx->insn.mem_format.ra);
1022 		} else {
1023 			insn_printf(ctx, "%s\t%s,", opcode,
1024 			    register_name(ctx, ctx->insn.mem_format.ra));
1025 		}
1026 		signed_immediate = (long)ctx->insn.mem_format.displacement;
1027 loadstore_address:
1028 		{
1029 			char tbuf[24];
1030 
1031 			db_format_hex(tbuf, 24, signed_immediate, false);
1032 			insn_printf(ctx, "%s(%s)", tbuf,
1033 			    register_name(ctx, ctx->insn.mem_format.rb));
1034 		}
1035 		break;
1036 	case op_br:
1037 	case op_fbeq:
1038 	case op_fblt:
1039 	case op_fble:
1040 	case op_bsr:
1041 	case op_fbne:
1042 	case op_fbge:
1043 	case op_fbgt:
1044 	case op_blbc:
1045 	case op_beq:
1046 	case op_blt:
1047 	case op_ble:
1048 	case op_blbs:
1049 	case op_bne:
1050 	case op_bge:
1051 	case op_bgt:
1052 		/*
1053 		 * We want to know where we are branching to
1054 		 */
1055 		signed_immediate = (long)ctx->insn.branch_format.displacement;
1056 		insn_printf(ctx, "%s\t%s,", opcode,
1057 		    register_name(ctx, ctx->insn.branch_format.ra));
1058 branch_displacement:
1059 		if (ctx->buf == NULL) {
1060 			db_printsym(ctx->pc + sizeof(alpha_instruction) +
1061 			    (signed_immediate << 2), DB_STGY_PROC, db_printf);
1062 		}
1063 		break;
1064 	default:
1065 		/*
1066 		 * Shouldn't happen
1067 		 */
1068 		insn_printf(ctx, "? 0x%x ?", ctx->insn.bits);
1069 	}
1070 
1071 	/* If printing into a buffer, skip the newline. */
1072 	if (ctx->buf == NULL) {
1073 		insn_printf(ctx, "\n");
1074 	}
1075 
1076 	return (sizeof(alpha_instruction));
1077 }
1078 
1079 db_addr_t
db_disasm(db_addr_t loc,bool altfmt __unused)1080 db_disasm(db_addr_t loc, bool altfmt __unused)
1081 {
1082 	struct alpha_print_instruction_context ctx = {
1083 		.insn.bits = db_get_value(loc, 4, 0),
1084 		.pc = loc,
1085 	};
1086 
1087 	loc += alpha_print_instruction(&ctx);
1088 	return loc;
1089 }
1090