7b4ac7e1 |
1 | /* Print vax instructions for GDB, the GNU debugger. |
4187119d |
2 | Copyright (C) 1986, 1989 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GDB. |
5 | |
6 | GDB is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 1, or (at your option) |
9 | any later version. |
10 | |
11 | GDB is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GDB; see the file COPYING. If not, write to |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
7b4ac7e1 |
19 | |
20 | #include <stdio.h> |
21 | |
22 | #include "defs.h" |
23 | #include "param.h" |
24 | #include "symtab.h" |
3bf57d21 |
25 | #include "opcode.h" |
7b4ac7e1 |
26 | |
27 | /* Vax instructions are never longer than this. */ |
28 | #define MAXLEN 62 |
29 | |
30 | /* Number of elements in the opcode table. */ |
31 | #define NOPCODES (sizeof votstrs / sizeof votstrs[0]) |
32 | |
33 | extern char *reg_names[]; |
34 | |
35 | static unsigned char *print_insn_arg (); |
36 | \f |
37 | /* Print the vax instruction at address MEMADDR in debugged memory, |
38 | on STREAM. Returns length of the instruction, in bytes. */ |
39 | |
40 | int |
41 | print_insn (memaddr, stream) |
42 | CORE_ADDR memaddr; |
43 | FILE *stream; |
44 | { |
45 | unsigned char buffer[MAXLEN]; |
46 | register int i; |
47 | register unsigned char *p; |
48 | register char *d; |
49 | |
50 | read_memory (memaddr, buffer, MAXLEN); |
51 | |
52 | for (i = 0; i < NOPCODES; i++) |
53 | if (votstrs[i].detail.code == buffer[0] |
54 | || votstrs[i].detail.code == *(unsigned short *)buffer) |
55 | break; |
56 | |
57 | /* Handle undefined instructions. */ |
58 | if (i == NOPCODES) |
59 | { |
60 | fprintf (stream, "0%o", buffer[0]); |
61 | return 1; |
62 | } |
63 | |
64 | fprintf (stream, "%s", votstrs[i].name); |
65 | |
66 | /* Point at first byte of argument data, |
67 | and at descriptor for first argument. */ |
68 | p = buffer + 1 + (votstrs[i].detail.code >= 0x100); |
69 | d = votstrs[i].detail.args; |
70 | |
71 | if (*d) |
72 | fputc (' ', stream); |
73 | |
74 | while (*d) |
75 | { |
76 | p = print_insn_arg (d, p, memaddr + (p - buffer), stream); |
77 | d += 2; |
78 | if (*d) |
79 | fprintf (stream, ","); |
80 | } |
81 | return p - buffer; |
82 | } |
83 | |
84 | static unsigned char * |
85 | print_insn_arg (d, p, addr, stream) |
86 | char *d; |
87 | register char *p; |
88 | CORE_ADDR addr; |
89 | FILE *stream; |
90 | { |
91 | register int regnum = *p & 0xf; |
92 | float floatlitbuf; |
93 | |
94 | if (*d == 'b') |
95 | { |
96 | if (d[1] == 'b') |
97 | fprintf (stream, "0x%x", addr + *p++ + 1); |
98 | else |
99 | { |
100 | fprintf (stream, "0x%x", addr + *(short *)p + 2); |
101 | p += 2; |
102 | } |
103 | } |
104 | else |
105 | switch ((*p++ >> 4) & 0xf) |
106 | { |
107 | case 0: |
108 | case 1: |
109 | case 2: |
110 | case 3: /* Literal mode */ |
111 | if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h') |
112 | { |
113 | *(int *)&floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4); |
114 | fprintf (stream, "$%f", floatlitbuf); |
115 | } |
116 | else |
117 | fprintf (stream, "$%d", p[-1] & 0x3f); |
118 | break; |
119 | |
120 | case 4: /* Indexed */ |
121 | p = (char *) print_insn_arg (d, p, addr + 1, stream); |
122 | fprintf (stream, "[%s]", reg_names[regnum]); |
123 | break; |
124 | |
125 | case 5: /* Register */ |
126 | fprintf (stream, reg_names[regnum]); |
127 | break; |
128 | |
129 | case 7: /* Autodecrement */ |
130 | fputc ('-', stream); |
131 | case 6: /* Register deferred */ |
132 | fprintf (stream, "(%s)", reg_names[regnum]); |
133 | break; |
134 | |
135 | case 9: /* Autoincrement deferred */ |
136 | fputc ('@', stream); |
137 | if (regnum == PC_REGNUM) |
138 | { |
139 | fputc ('#', stream); |
140 | print_address (*(long *)p, stream); |
141 | p += 4; |
142 | break; |
143 | } |
144 | case 8: /* Autoincrement */ |
145 | if (regnum == PC_REGNUM) |
146 | { |
147 | fputc ('#', stream); |
148 | switch (d[1]) |
149 | { |
150 | case 'b': |
151 | fprintf (stream, "%d", *p++); |
152 | break; |
153 | |
154 | case 'w': |
155 | fprintf (stream, "%d", *(short *)p); |
156 | p += 2; |
157 | break; |
158 | |
159 | case 'l': |
160 | fprintf (stream, "%d", *(long *)p); |
161 | p += 4; |
162 | break; |
163 | |
164 | case 'q': |
165 | fprintf (stream, "0x%x%08x", ((long *)p)[1], ((long *)p)[0]); |
166 | p += 8; |
167 | break; |
168 | |
169 | case 'o': |
170 | fprintf (stream, "0x%x%08x%08x%08x", |
171 | ((long *)p)[3], ((long *)p)[2], |
172 | ((long *)p)[1], ((long *)p)[0]); |
173 | p += 16; |
174 | break; |
175 | |
176 | case 'f': |
177 | if (INVALID_FLOAT (p, 4)) |
178 | fprintf (stream, "<<invalid float 0x%x>>", *(int *) p); |
179 | else |
180 | fprintf (stream, "%f", *(float *) p); |
181 | p += 4; |
182 | break; |
183 | |
184 | case 'd': |
185 | if (INVALID_FLOAT (p, 8)) |
186 | fprintf (stream, "<<invalid float 0x%x%08x>>", |
187 | ((long *)p)[1], ((long *)p)[0]); |
188 | else |
189 | fprintf (stream, "%f", *(double *) p); |
190 | p += 8; |
191 | break; |
192 | |
193 | case 'g': |
194 | fprintf (stream, "g-float"); |
195 | p += 8; |
196 | break; |
197 | |
198 | case 'h': |
199 | fprintf (stream, "h-float"); |
200 | p += 16; |
201 | break; |
202 | |
203 | } |
204 | } |
205 | else |
206 | fprintf (stream, "(%s)+", reg_names[regnum]); |
207 | break; |
208 | |
209 | case 11: /* Byte displacement deferred */ |
210 | fputc ('@', stream); |
211 | case 10: /* Byte displacement */ |
212 | if (regnum == PC_REGNUM) |
213 | print_address (addr + *p + 2, stream); |
214 | else |
215 | fprintf (stream, "%d(%s)", *p, reg_names[regnum]); |
216 | p += 1; |
217 | break; |
218 | |
219 | case 13: /* Word displacement deferred */ |
220 | fputc ('@', stream); |
221 | case 12: /* Word displacement */ |
222 | if (regnum == PC_REGNUM) |
223 | print_address (addr + *(short *)p + 3, stream); |
224 | else |
225 | fprintf (stream, "%d(%s)", *(short *)p, reg_names[regnum]); |
226 | p += 2; |
227 | break; |
228 | |
229 | case 15: /* Long displacement deferred */ |
230 | fputc ('@', stream); |
231 | case 14: /* Long displacement */ |
232 | if (regnum == PC_REGNUM) |
233 | print_address (addr + *(long *)p + 5, stream); |
234 | else |
235 | fprintf (stream, "%d(%s)", *(long *)p, reg_names[regnum]); |
236 | p += 4; |
237 | } |
238 | |
239 | return (unsigned char *) p; |
240 | } |