db_disasm.c revision 1.4 1 /* $NetBSD: db_disasm.c,v 1.4 1996/02/02 18:08:50 mycroft Exp $ */
2 /*
3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Ludd by
7 * Bertram Barth.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed at Ludd, University of
20 * Lule}, Sweden and its contributors.
21 * 4. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36
37 #include <sys/param.h>
38 #include <sys/proc.h>
39 #include <sys/reboot.h>
40
41 #include <ddb/db_variables.h>
42 #include <machine/db_machdep.h>
43 #include <ddb/db_sym.h>
44
45 #include <vax/vax/db_disasm.h>
46
47 #ifdef VMS_MODE
48 #define DEFERRED '@'
49 #define LITERAL '#'
50 #else
51 #define DEFERRED '*'
52 #define LITERAL '$'
53 #endif
54 /*
55 * disassembling vax instructions works as follows:
56 *
57 * - get first byte as opcode (check for two-byte opcodes!)
58 * - evaluate (variable length) argument list
59 * - for each argument get type (byte, long, address etc.)
60 * - evaluate addressing mode for this argument
61 * - db_printf the opcode and the (value of the) arguments
62 * - return the start of the next instruction
63 *
64 * - if jump/branch calculate (and display) the target-address
65 */
66
67 /*
68 #define BROKEN_DB_REGS
69 */
70 #ifdef BROKEN_DB_REGS
71 struct { /* Due to order and contents of db_regs[], we can't */
72 char *name; /* use this array to extract register-names. */
73 void *valuep; /* eg. "psl" vs "pc", "pc" vs "sp" */
74 } my_db_regs[16] = {
75 { "r0", NULL },
76 { "r1", NULL },
77 { "r2", NULL },
78 { "r3", NULL },
79 { "r4", NULL },
80 { "r5", NULL },
81 { "r6", NULL },
82 { "r7", NULL },
83 { "r8", NULL },
84 { "r9", NULL },
85 { "r10", NULL },
86 { "r11", NULL },
87 { "ap", NULL }, /* aka "r12" */
88 { "fp", NULL }, /* aka "r13" */
89 { "sp", NULL }, /* aka "r14" */
90 { "pc", NULL }, /* aka "r15" */
91 };
92 #else
93 #define my_db_regs db_regs
94 #endif
95
96 typedef struct {
97 char dasm[256]; /* disassebled instruction as text */
98 char *curp; /* pointer into result */
99 char *ppc; /* pseudo PC */
100 int opc; /* op-code */
101 char *argp; /* pointer into argument-list */
102 int itype; /* instruction-type, eg. branch, call, unspec */
103 int atype; /* argument-type, eg. byte, long, address */
104 int off; /* offset specified by last argument */
105 int addr; /* address specified by last argument */
106 } inst_buffer;
107
108 #define ITYPE_INVALID -1
109 #define ITYPE_UNSPEC 0
110 #define ITYPE_BRANCH 1
111 #define ITYPE_CALL 2
112
113 int get_byte __P((inst_buffer * ib));
114 int get_word __P((inst_buffer * ib));
115 int get_long __P((inst_buffer * ib));
116
117 int get_opcode __P((inst_buffer * ib));
118 int get_operands __P((inst_buffer * ib));
119 int get_operand __P((inst_buffer * ib, int size));
120
121 void add_char __P((inst_buffer * ib, int c));
122 void add_str __P((inst_buffer * ib, char *s));
123 void add_int __P((inst_buffer * ib, int i));
124 void add_xint __P((inst_buffer * ib, int i));
125 void add_sym __P((inst_buffer * ib, int i));
126 void add_off __P((inst_buffer * ib, int i));
127
128 #define err_print printf
129
130 /*
131 * Disassemble instruction at 'loc'. 'altfmt' specifies an
132 * (optional) alternate format (altfmt for vax: don't assume
133 * that each external label is a procedure entry mask).
134 * Return address of start of next instruction.
135 * Since this function is used by 'examine' and by 'step'
136 * "next instruction" does NOT mean the next instruction to
137 * be executed but the 'linear' next instruction.
138 */
139 db_addr_t
140 db_disasm(loc, altfmt)
141 db_addr_t loc;
142 boolean_t altfmt;
143 {
144 db_expr_t diff;
145 db_sym_t sym;
146 char *symname;
147
148 inst_buffer ib;
149
150 bzero(&ib, sizeof(ib));
151 ib.ppc = (void *) loc;
152 ib.curp = ib.dasm;
153
154 if (!altfmt) { /* ignore potential entry masks in altfmt */
155 diff = INT_MAX;
156 symname = NULL;
157 sym = db_search_symbol(loc, DB_STGY_PROC, &diff);
158 db_symbol_values(sym, &symname, 0);
159
160 if (symname && !diff) { /* symbol at loc */
161 db_printf("function \"%s()\", entry-mask 0x%x\n\t\t",
162 symname, (unsigned short) get_word(&ib));
163 ib.ppc += 2;
164 }
165 }
166 get_opcode(&ib);
167 get_operands(&ib);
168 db_printf("%s\n", ib.dasm);
169
170 return ((u_int) ib.ppc);
171 }
172
173 int
174 get_opcode(ib)
175 inst_buffer *ib;
176 {
177 ib->opc = get_byte(ib);
178 if (ib->opc >> 2 == 0x3F) { /* two byte op-code */
179 ib->opc = ib->opc << 8;
180 ib->opc += get_byte(ib);
181 }
182 switch (ib->opc) {
183 case 0xFA: /* CALLG */
184 case 0xFB: /* CALLS */
185 case 0xFC: /* XFC */
186 ib->itype = ITYPE_CALL;
187 break;
188 case 0x16: /* JSB */
189 case 0x17: /* JMP */
190 ib->itype = ITYPE_BRANCH;
191 break;
192 default:
193 ib->itype = ITYPE_UNSPEC;
194 }
195 if (ib->opc < 0 || ib->opc > 0xFF) {
196 add_str(ib, "invalid or two-byte opcode ");
197 add_xint(ib, ib->opc);
198 ib->itype = ITYPE_INVALID;
199 } else {
200 add_str(ib, vax_inst[ib->opc].mnemonic);
201 add_char(ib, '\t');
202 }
203 return (ib->opc);
204 }
205
206 int
207 get_operands(ib)
208 inst_buffer *ib;
209 {
210 int aa = 0; /* absolute address mode ? */
211 int size;
212
213 if (ib->opc < 0 || ib->opc > 0xFF) {
214 /* invalid or two-byte opcode */
215 ib->argp = NULL;
216 return (-1);
217 }
218 ib->argp = vax_inst[ib->opc].argdesc;
219
220 while (*ib->argp) {
221 switch (*ib->argp) {
222
223 case 'b': /* branch displacement */
224 switch (*(++ib->argp)) {
225 case 'b':
226 ib->off = (signed char) get_byte(ib);
227 break;
228 case 'w':
229 ib->off = (short) get_word(ib);
230 break;
231 case 'l':
232 ib->off = get_long(ib);
233 break;
234 default:
235 err_print("XXX eror\n");
236 }
237 /* add_int(ib, ib->off); */
238 ib->addr = (u_int) ib->ppc + ib->off;
239 add_off(ib, ib->addr);
240 break;
241
242 case 'a': /* absolute adressing mode */
243 aa = 1; /* do not break here ! */
244
245 default:
246 switch (*(++ib->argp)) {
247 case 'b': /* Byte */
248 size = SIZE_BYTE;
249 break;
250 case 'w': /* Word */
251 size = SIZE_WORD;
252 break;
253 case 'l': /* Long-Word */
254 case 'f': /* F_Floating */
255 size = SIZE_LONG;
256 break;
257 case 'q': /* Quad-Word */
258 case 'd': /* D_Floating */
259 case 'g': /* G_Floating */
260 size = SIZE_QWORD;
261 break;
262 case 'o': /* Octa-Word */
263 case 'h': /* H_Floating */
264 size = SIZE_OWORD;
265 break;
266 default:
267 err_print("invalid op-type %X (%c) found.\n",
268 *ib->argp, *ib->argp);
269 size = 0;
270 }
271 if (aa) {
272 /* get the address */
273 ib->addr = get_operand(ib, size);
274 add_sym(ib, ib->addr);
275 } else {
276 /* get the operand */
277 ib->addr = get_operand(ib, size);
278 add_off(ib, ib->addr);
279 }
280 }
281
282 if (!*ib->argp || !*++ib->argp)
283 break;
284 if (*ib->argp++ == ',') {
285 add_char(ib, ',');
286 add_char(ib, ' ');
287 } else {
288 err_print("XXX error\n");
289 add_char(ib, '\0');
290 return (-1);
291 }
292 }
293
294 add_char(ib, '\0');
295 return (0);
296 }
297
298 int
299 get_operand(ib, size)
300 inst_buffer *ib;
301 int size;
302 {
303 int c = get_byte(ib);
304 int mode = c >> 4;
305 int reg = c & 0x0F;
306 int lit = c & 0x3F;
307 int tmp = 0;
308 char buf[16];
309
310 switch (mode) {
311 case 0: /* literal */
312 case 1: /* literal */
313 case 2: /* literal */
314 case 3: /* literal */
315 add_char(ib, LITERAL);
316 add_int(ib, lit);
317 tmp = lit;
318 break;
319
320 case 4: /* indexed */
321 sprintf(buf, "[%s]", my_db_regs[reg].name);
322 get_operand(ib, 0);
323 add_str(ib, buf);
324 break;
325
326 case 5: /* register */
327 add_str(ib, my_db_regs[reg].name);
328 break;
329
330 case 6: /* register deferred */
331 add_char(ib, '(');
332 add_str(ib, my_db_regs[reg].name);
333 add_char(ib, ')');
334 break;
335
336 case 7: /* autodecrement */
337 add_char(ib, '-');
338 add_char(ib, '(');
339 add_str(ib, my_db_regs[reg].name);
340 add_char(ib, ')');
341 if (reg == 0x0F) { /* pc is not allowed in this mode */
342 err_print("autodecrement not allowd for PC.\n");
343 }
344 break;
345
346 case 9: /* autoincrement deferred */
347 add_char(ib, DEFERRED);
348 case 8: /* autoincrement */
349 if (reg == 0x0F) { /* pc: immediate ==> special syntax */
350 switch (size) {
351 case SIZE_BYTE:
352 tmp = (signed char) get_byte(ib);
353 break;
354 case SIZE_WORD:
355 tmp = (signed short) get_word(ib);
356 break;
357 case SIZE_LONG:
358 tmp = get_long(ib);
359 break;
360 default:
361 err_print("illegal op-type %d\n", size);
362 tmp = -1;
363 }
364 if (mode == 8)
365 add_char(ib, LITERAL);
366 add_int(ib, tmp);
367 break;
368 }
369 add_char(ib, '(');
370 add_str(ib, my_db_regs[reg].name);
371 add_char(ib, ')');
372 add_char(ib, '+');
373 break;
374
375 case 11: /* byte displacement deferred/ relative deferred */
376 add_char(ib, DEFERRED);
377 case 10: /* byte displacement / relative mode */
378 tmp = (signed char) get_byte(ib);
379 if (reg == 0x0F) {
380 add_off(ib, (u_int) ib->ppc + tmp);
381 break;
382 }
383 /* add_str (ib, "b^"); */
384 add_int(ib, tmp);
385 add_char(ib, '(');
386 add_str(ib, my_db_regs[reg].name);
387 add_char(ib, ')');
388 break;
389
390 case 13: /* word displacement deferred */
391 add_char(ib, DEFERRED);
392 case 12: /* word displacement */
393 tmp = (signed short) get_word(ib);
394 if (reg == 0x0F) {
395 add_off(ib, (u_int) ib->ppc + tmp);
396 break;
397 }
398 /* add_str (ib, "w^"); */
399 add_int(ib, tmp);
400 add_char(ib, '(');
401 add_str(ib, my_db_regs[reg].name);
402 add_char(ib, ')');
403 break;
404
405 case 15: /* long displacement referred */
406 add_char(ib, DEFERRED);
407 case 14: /* long displacement */
408 tmp = get_long(ib);
409 if (reg == 0x0F) {
410 add_off(ib, (u_int) ib->ppc + tmp);
411 break;
412 }
413 /* add_str (ib, "l^"); */
414 add_int(ib, tmp);
415 add_char(ib, '(');
416 add_str(ib, my_db_regs[reg].name);
417 add_char(ib, ')');
418 break;
419
420 default:
421 err_print("can\'t evaluate operand (%02X).\n", lit);
422 break;
423 }
424
425 return (0);
426 }
427
428 int
429 get_byte(ib)
430 inst_buffer *ib;
431 {
432 return ((unsigned char) *(ib->ppc++));
433 }
434
435 int
436 get_word(ib)
437 inst_buffer *ib;
438 {
439 int tmp;
440 char *p = (void *) &tmp;
441 *p++ = get_byte(ib);
442 *p++ = get_byte(ib);
443 return (tmp);
444 }
445
446 int
447 get_long(ib)
448 inst_buffer *ib;
449 {
450 int tmp;
451 char *p = (void *) &tmp;
452 *p++ = get_byte(ib);
453 *p++ = get_byte(ib);
454 *p++ = get_byte(ib);
455 *p++ = get_byte(ib);
456 return (tmp);
457 }
458
459 void
460 add_char(ib, c)
461 inst_buffer *ib;
462 int c;
463 {
464 *ib->curp++ = c;
465 }
466
467 void
468 add_str(ib, s)
469 inst_buffer *ib;
470 char *s;
471 {
472 while (*ib->curp++ = *s++);
473 *--ib->curp = '\0';
474 }
475
476 void
477 add_int(ib, i)
478 inst_buffer *ib;
479 int i;
480 {
481 char buf[32];
482 if (i < 100 && i > -100)
483 sprintf(buf, "%d", i);
484 else
485 sprintf(buf, "0x%x", i);
486 add_str(ib, buf);
487 }
488
489 void
490 add_xint(ib, val)
491 inst_buffer *ib;
492 int val;
493 {
494 char buf[32];
495 sprintf(buf, "0x%x", val);
496 add_str(ib, buf);
497 }
498
499 void
500 add_sym(ib, loc)
501 inst_buffer *ib;
502 int loc;
503 {
504 db_expr_t diff;
505 db_sym_t sym;
506 char *symname;
507
508 if (! loc)
509 return;
510
511 diff = INT_MAX;
512 symname = NULL;
513 sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
514 db_symbol_values(sym, &symname, 0);
515
516 if (symname && !diff) {
517 /* add_char(ib, '<'); */
518 add_str(ib, symname);
519 /* add_char(ib, '>'); */
520 }
521 else
522 add_xint(ib, loc);
523 }
524
525 void
526 add_off(ib, loc)
527 inst_buffer *ib;
528 int loc;
529 {
530 db_expr_t diff;
531 db_sym_t sym;
532 char *symname;
533
534 if (!loc)
535 return;
536
537 diff = INT_MAX;
538 symname = NULL;
539 sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
540 db_symbol_values(sym, &symname, 0);
541
542 if (symname) {
543 /* add_char(ib, '<'); */
544 add_str(ib, symname);
545 if (diff) {
546 add_char(ib, '+');
547 add_xint(ib, diff);
548 }
549 /* add_char(ib, '>'); */
550 }
551 else
552 add_xint(ib, loc);
553 }
554