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