3bf57d21 |
1 | /* Print GOULD RISC instructions for GDB, the GNU debugger. |
4187119d |
2 | Copyright (C) 1986, 1987, 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. */ |
3bf57d21 |
19 | |
20 | #include <stdio.h> |
21 | #include <a.out.h> |
22 | |
23 | #include "defs.h" |
24 | #include "param.h" |
25 | #include "symtab.h" |
26 | #include "frame.h" |
27 | #include "opcode.h" |
28 | |
29 | /* GOULD RISC instructions are never longer than this many bytes. */ |
30 | #define MAXLEN 4 |
31 | |
32 | /* Number of elements in the opcode table. */ |
33 | #define NOPCODES (sizeof gld_opcodes / sizeof gld_opcodes[0]) |
34 | |
35 | \f |
36 | /* Print the GOULD instruction at address MEMADDR in debugged memory, |
37 | on STREAM. Returns length of the instruction, in bytes. */ |
38 | |
39 | int |
40 | print_insn (memaddr, stream) |
41 | CORE_ADDR memaddr; |
42 | FILE *stream; |
43 | { |
44 | unsigned char buffer[MAXLEN]; |
45 | register int i; |
46 | register char *d; |
47 | register int bestmask; |
48 | unsigned best; |
49 | int temp, index, bestlen; |
50 | |
51 | read_memory (memaddr, buffer, MAXLEN); |
52 | |
53 | bestmask = 0; |
54 | index = -1; |
55 | best = 0xffffffff; |
56 | for (i = 0; i < NOPCODES; i++) |
57 | { |
58 | register unsigned int opcode = gld_opcodes[i].opcode; |
59 | register unsigned int mask = gld_opcodes[i].mask; |
60 | register unsigned int len = gld_opcodes[i].length; |
61 | register unsigned int test; |
62 | |
63 | /* Get possible opcode bytes into integer */ |
64 | test = buffer[0] << 24; |
65 | test |= buffer[1] << 16; |
66 | test |= buffer[2] << 8; |
67 | test |= buffer[3]; |
68 | |
69 | /* Mask with opcode and see if match */ |
70 | if ((opcode & mask) == (test & mask)) |
71 | { |
72 | /* See if second or third match */ |
73 | if (index >= 0) |
74 | { |
75 | /* Take new one if it looks good */ |
76 | if (bestlen == MAXLEN && len == MAXLEN) |
77 | { |
78 | /* See if lower bits matched */ |
79 | if (((bestmask & 3) == 0) && |
80 | ((mask & 3) != 0)) |
81 | { |
82 | bestmask = mask; |
83 | bestlen = len; |
84 | best = test; |
85 | index = i; |
86 | } |
87 | } |
88 | } |
89 | else |
90 | { |
91 | /* First match, save it */ |
92 | bestmask = mask; |
93 | bestlen = len; |
94 | best = test; |
95 | index = i; |
96 | } |
97 | } |
98 | } |
99 | |
100 | /* Handle undefined instructions. */ |
101 | if (index < 0) |
102 | { |
103 | fprintf (stream, "undefined 0%o",(buffer[0]<<8)+buffer[1]); |
104 | return 2; |
105 | } |
106 | |
107 | /* Print instruction name */ |
108 | fprintf (stream, "%-12s", gld_opcodes[index].name); |
109 | |
110 | /* Adjust if short instruction */ |
111 | if (gld_opcodes[index].length < 4) |
112 | { |
113 | best >>= 16; |
114 | i = 0; |
115 | } |
116 | else |
117 | { |
118 | i = 16; |
119 | } |
120 | |
121 | /* Dump out instruction arguments */ |
122 | for (d = gld_opcodes[index].args; *d; ++d) |
123 | { |
124 | switch (*d) |
125 | { |
126 | case 'f': |
127 | fprintf (stream, "%d", (best >> (7 + i)) & 7); |
128 | break; |
129 | case 'r': |
130 | fprintf (stream, "r%d", (best >> (7 + i)) & 7); |
131 | break; |
132 | case 'R': |
133 | fprintf (stream, "r%d", (best >> (4 + i)) & 7); |
134 | break; |
135 | case 'b': |
136 | fprintf (stream, "b%d", (best >> (7 + i)) & 7); |
137 | break; |
138 | case 'B': |
139 | fprintf (stream, "b%d", (best >> (4 + i)) & 7); |
140 | break; |
141 | case 'v': |
142 | fprintf (stream, "b%d", (best >> (7 + i)) & 7); |
143 | break; |
144 | case 'V': |
145 | fprintf (stream, "b%d", (best >> (4 + i)) & 7); |
146 | break; |
147 | case 'X': |
148 | temp = (best >> 20) & 7; |
149 | if (temp) |
150 | fprintf (stream, "r%d", temp); |
151 | else |
152 | putc ('0', stream); |
153 | break; |
154 | case 'A': |
155 | temp = (best >> 16) & 7; |
156 | if (temp) |
157 | fprintf (stream, "(b%d)", temp); |
158 | break; |
159 | case 'S': |
160 | fprintf (stream, "#%d", best & 0x1f); |
161 | break; |
162 | case 'I': |
163 | fprintf (stream, "#%x", best & 0xffff); |
164 | break; |
165 | case 'O': |
166 | fprintf (stream, "%x", best & 0xffff); |
167 | break; |
168 | case 'h': |
169 | fprintf (stream, "%d", best & 0xfffe); |
170 | break; |
171 | case 'd': |
172 | fprintf (stream, "%d", best & 0xfffc); |
173 | break; |
174 | case 'T': |
175 | fprintf (stream, "%d", (best >> 8) & 0xff); |
176 | break; |
177 | case 'N': |
178 | fprintf (stream, "%d", best & 0xff); |
179 | break; |
180 | default: |
181 | putc (*d, stream); |
182 | break; |
183 | } |
184 | } |
185 | |
186 | /* Return length of instruction */ |
187 | return (gld_opcodes[index].length); |
188 | } |
189 | |
190 | /* |
191 | * Find the number of arguments to a function. |
192 | */ |
193 | findarg(frame) |
e91b87a3 |
194 | struct frame_info *frame; |
3bf57d21 |
195 | { |
196 | register struct symbol *func; |
197 | register unsigned pc; |
198 | |
199 | #ifdef notdef |
200 | /* find starting address of frame function */ |
e91b87a3 |
201 | pc = get_pc_function_start (frame->pc); |
3bf57d21 |
202 | |
203 | /* find function symbol info */ |
204 | func = find_pc_function (pc); |
205 | |
206 | /* call blockframe code to look for match */ |
207 | if (func != NULL) |
208 | return (func->value.block->nsyms / sizeof(int)); |
209 | #endif |
210 | |
211 | return (-1); |
212 | } |
213 | |
214 | /* |
215 | * In the case of the NPL, the frame's norminal address is Br2 and the |
216 | * previous routines frame is up the stack X bytes. Finding out what |
217 | * 'X' is can be tricky. |
218 | * |
219 | * 1.) stored in the code function header xA(Br1). |
220 | * 2.) must be careful of recurssion. |
221 | */ |
e91b87a3 |
222 | FRAME_ADDR |
3bf57d21 |
223 | findframe(thisframe) |
224 | FRAME thisframe; |
225 | { |
e91b87a3 |
226 | register FRAME_ADDR pointer; |
227 | #if 0 |
228 | struct frame_info *frame; |
229 | FRAME_ADDR framechain(); |
3bf57d21 |
230 | |
231 | /* Setup toplevel frame structure */ |
e91b87a3 |
232 | frame->pc = read_pc(); |
233 | frame->next_frame = 0; |
234 | frame->frame = read_register (SP_REGNUM); /* Br2 */ |
3bf57d21 |
235 | |
236 | /* Search for this frame (start at current Br2) */ |
237 | do |
238 | { |
239 | pointer = framechain(frame); |
e91b87a3 |
240 | frame->next_frame = frame->frame; |
241 | frame->frame = pointer; |
242 | frame->pc = FRAME_SAVED_PC(frame); |
3bf57d21 |
243 | } |
e91b87a3 |
244 | while (frame->next_frame != thisframe); |
245 | #endif |
246 | |
247 | pointer = framechain (thisframe); |
3bf57d21 |
248 | |
249 | /* stop gap for now, end at __base3 */ |
e91b87a3 |
250 | if (thisframe->pc == 0) |
3bf57d21 |
251 | return 0; |
252 | |
253 | return pointer; |
254 | } |
255 | |
256 | /* |
257 | * Gdb front-end and internal framechain routine. |
258 | * Go back up stack one level. Tricky... |
259 | */ |
e91b87a3 |
260 | FRAME_ADDR |
3bf57d21 |
261 | framechain(frame) |
e91b87a3 |
262 | register struct frame_info *frame; |
3bf57d21 |
263 | { |
264 | register CORE_ADDR func, prevsp; |
265 | register unsigned value; |
266 | |
267 | /* Get real function start address from internal frame address */ |
e91b87a3 |
268 | func = get_pc_function_start(frame->pc); |
3bf57d21 |
269 | |
270 | /* If no stack given, read register Br1 "(sp)" */ |
e91b87a3 |
271 | if (!frame->frame) |
3bf57d21 |
272 | prevsp = read_register (SP_REGNUM); |
273 | else |
e91b87a3 |
274 | prevsp = frame->frame; |
3bf57d21 |
275 | |
276 | /* Check function header, case #2 */ |
277 | value = read_memory_integer (func, 4); |
278 | if (value) |
279 | { |
280 | /* 32bit call push value stored in function header */ |
281 | prevsp += value; |
282 | } |
283 | else |
284 | { |
285 | /* read half-word from suabr at start of function */ |
286 | prevsp += read_memory_integer (func + 10, 2); |
287 | } |
288 | |
289 | return (prevsp); |
290 | } |