Protoization.
[platform/upstream/binutils.git] / gdb / vax-tdep.c
1 /* Print VAX instructions for GDB, the GNU debugger.
2    Copyright 1986, 1989, 1991, 1992, 1996 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program 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 2 of the License, or
9    (at your option) any later version.
10
11    This program 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 this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include "defs.h"
22 #include "symtab.h"
23 #include "opcode/vax.h"
24
25 /* Vax instructions are never longer than this.  */
26 #define MAXLEN 62
27
28 /* Number of elements in the opcode table.  */
29 #define NOPCODES (sizeof votstrs / sizeof votstrs[0])
30
31 static unsigned char *print_insn_arg ();
32 \f
33 /* Advance PC across any function entry prologue instructions
34    to reach some "real" code.  */
35
36 CORE_ADDR
37 vax_skip_prologue (CORE_ADDR pc)
38 {
39   register int op = (unsigned char) read_memory_integer (pc, 1);
40   if (op == 0x11)
41     pc += 2;                    /* skip brb */
42   if (op == 0x31)
43     pc += 3;                    /* skip brw */
44   if (op == 0xC2
45       && ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
46     pc += 3;                    /* skip subl2 */
47   if (op == 0x9E
48       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
49       && ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
50     pc += 4;                    /* skip movab */
51   if (op == 0x9E
52       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
53       && ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
54     pc += 5;                    /* skip movab */
55   if (op == 0x9E
56       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
57       && ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
58     pc += 7;                    /* skip movab */
59   return pc;
60 }
61
62 /* Return number of args passed to a frame.
63    Can return -1, meaning no way to tell.  */
64
65 int
66 vax_frame_num_args (struct frame_info *fi)
67 {
68   return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
69 }
70
71
72
73 /* Print the vax instruction at address MEMADDR in debugged memory,
74    from disassembler info INFO.
75    Returns length of the instruction, in bytes.  */
76
77 static int
78 vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
79 {
80   unsigned char buffer[MAXLEN];
81   register int i;
82   register unsigned char *p;
83   register char *d;
84
85   int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
86   if (status != 0)
87     {
88       (*info->memory_error_func) (status, memaddr, info);
89       return -1;
90     }
91
92   for (i = 0; i < NOPCODES; i++)
93     if (votstrs[i].detail.code == buffer[0]
94         || votstrs[i].detail.code == *(unsigned short *) buffer)
95       break;
96
97   /* Handle undefined instructions.  */
98   if (i == NOPCODES)
99     {
100       (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
101       return 1;
102     }
103
104   (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
105
106   /* Point at first byte of argument data,
107      and at descriptor for first argument.  */
108   p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
109   d = votstrs[i].detail.args;
110
111   if (*d)
112     (*info->fprintf_func) (info->stream, " ");
113
114   while (*d)
115     {
116       p = print_insn_arg (d, p, memaddr + (p - buffer), info);
117       d += 2;
118       if (*d)
119         (*info->fprintf_func) (info->stream, ",");
120     }
121   return p - buffer;
122 }
123
124 static unsigned char *
125 print_insn_arg (char *d, register char *p, CORE_ADDR addr,
126                 disassemble_info *info)
127 {
128   register int regnum = *p & 0xf;
129   float floatlitbuf;
130
131   if (*d == 'b')
132     {
133       if (d[1] == 'b')
134         (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
135       else
136         {
137           (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *) p + 2);
138           p += 2;
139         }
140     }
141   else
142     switch ((*p++ >> 4) & 0xf)
143       {
144       case 0:
145       case 1:
146       case 2:
147       case 3:                   /* Literal mode */
148         if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
149           {
150             *(int *) &floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
151             (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
152           }
153         else
154           (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
155         break;
156
157       case 4:                   /* Indexed */
158         p = (char *) print_insn_arg (d, p, addr + 1, info);
159         (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
160         break;
161
162       case 5:                   /* Register */
163         (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
164         break;
165
166       case 7:                   /* Autodecrement */
167         (*info->fprintf_func) (info->stream, "-");
168       case 6:                   /* Register deferred */
169         (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
170         break;
171
172       case 9:                   /* Autoincrement deferred */
173         (*info->fprintf_func) (info->stream, "@");
174         if (regnum == PC_REGNUM)
175           {
176             (*info->fprintf_func) (info->stream, "#");
177             info->target = *(long *) p;
178             (*info->print_address_func) (info->target, info);
179             p += 4;
180             break;
181           }
182       case 8:                   /* Autoincrement */
183         if (regnum == PC_REGNUM)
184           {
185             (*info->fprintf_func) (info->stream, "#");
186             switch (d[1])
187               {
188               case 'b':
189                 (*info->fprintf_func) (info->stream, "%d", *p++);
190                 break;
191
192               case 'w':
193                 (*info->fprintf_func) (info->stream, "%d", *(short *) p);
194                 p += 2;
195                 break;
196
197               case 'l':
198                 (*info->fprintf_func) (info->stream, "%d", *(long *) p);
199                 p += 4;
200                 break;
201
202               case 'q':
203                 (*info->fprintf_func) (info->stream, "0x%x%08x",
204                                        ((long *) p)[1], ((long *) p)[0]);
205                 p += 8;
206                 break;
207
208               case 'o':
209                 (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
210                                        ((long *) p)[3], ((long *) p)[2],
211                                        ((long *) p)[1], ((long *) p)[0]);
212                 p += 16;
213                 break;
214
215               case 'f':
216                 if (INVALID_FLOAT (p, 4))
217                   (*info->fprintf_func) (info->stream,
218                                          "<<invalid float 0x%x>>",
219                                          *(int *) p);
220                 else
221                   (*info->fprintf_func) (info->stream, "%f", *(float *) p);
222                 p += 4;
223                 break;
224
225               case 'd':
226                 if (INVALID_FLOAT (p, 8))
227                   (*info->fprintf_func) (info->stream,
228                                          "<<invalid float 0x%x%08x>>",
229                                          ((long *) p)[1], ((long *) p)[0]);
230                 else
231                   (*info->fprintf_func) (info->stream, "%f", *(double *) p);
232                 p += 8;
233                 break;
234
235               case 'g':
236                 (*info->fprintf_func) (info->stream, "g-float");
237                 p += 8;
238                 break;
239
240               case 'h':
241                 (*info->fprintf_func) (info->stream, "h-float");
242                 p += 16;
243                 break;
244
245               }
246           }
247         else
248           (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
249         break;
250
251       case 11:                  /* Byte displacement deferred */
252         (*info->fprintf_func) (info->stream, "@");
253       case 10:                  /* Byte displacement */
254         if (regnum == PC_REGNUM)
255           {
256             info->target = addr + *p + 2;
257             (*info->print_address_func) (info->target, info);
258           }
259         else
260           (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
261         p += 1;
262         break;
263
264       case 13:                  /* Word displacement deferred */
265         (*info->fprintf_func) (info->stream, "@");
266       case 12:                  /* Word displacement */
267         if (regnum == PC_REGNUM)
268           {
269             info->target = addr + *(short *) p + 3;
270             (*info->print_address_func) (info->target, info);
271           }
272         else
273           (*info->fprintf_func) (info->stream, "%d(%s)",
274                                  *(short *) p, REGISTER_NAME (regnum));
275         p += 2;
276         break;
277
278       case 15:                  /* Long displacement deferred */
279         (*info->fprintf_func) (info->stream, "@");
280       case 14:                  /* Long displacement */
281         if (regnum == PC_REGNUM)
282           {
283             info->target = addr + *(short *) p + 5;
284             (*info->print_address_func) (info->target, info);
285           }
286         else
287           (*info->fprintf_func) (info->stream, "%d(%s)",
288                                  *(long *) p, REGISTER_NAME (regnum));
289         p += 4;
290       }
291
292   return (unsigned char *) p;
293 }
294
295 void
296 _initialize_vax_tdep (void)
297 {
298   tm_print_insn = vax_print_insn;
299 }