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