* config/vax/tm-vax.h (INVALID_FLOAT): Move macro from here...
[platform/upstream/binutils.git] / gdb / vax-tdep.c
1 /* Print VAX instructions for GDB, the GNU debugger.
2    Copyright 1986, 1989, 1991, 1992, 1995, 1996, 1998, 1999, 2000
3    Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include "defs.h"
23 #include "symtab.h"
24 #include "opcode/vax.h"
25 #include "gdbcore.h"
26 #include "frame.h"
27 #include "value.h"
28
29 /* Return 1 if P points to an invalid floating point value.
30    LEN is the length in bytes -- not relevant on the Vax.  */
31
32 /* FIXME: cagney/2002-01-19: The macro below was originally defined in
33    tm-vax.h and used in values.c.  Two problems.  Firstly this is a
34    very non-portable and secondly it is wrong.  The VAX should be
35    using floatformat and associated methods to identify and handle
36    invalid floating-point values.  Adding to the poor target's woes
37    there is no floatformat_vax_{f,d} and no TARGET_FLOAT_FORMAT
38    et.al..  */
39
40 /* FIXME: cagney/2002-01-19: It turns out that the only thing that
41    uses this macro is the vax disassembler code (so how old is this
42    target?).  This target should instead be using the opcodes
43    disassembler.  That allowing the macro to be eliminated.  */
44
45 #define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
46
47 /* Vax instructions are never longer than this.  */
48 #define MAXLEN 62
49
50 /* Number of elements in the opcode table.  */
51 #define NOPCODES (sizeof votstrs / sizeof votstrs[0])
52
53 static unsigned char *print_insn_arg ();
54 \f
55 /* Advance PC across any function entry prologue instructions
56    to reach some "real" code.  */
57
58 CORE_ADDR
59 vax_skip_prologue (CORE_ADDR pc)
60 {
61   register int op = (unsigned char) read_memory_integer (pc, 1);
62   if (op == 0x11)
63     pc += 2;                    /* skip brb */
64   if (op == 0x31)
65     pc += 3;                    /* skip brw */
66   if (op == 0xC2
67       && ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
68     pc += 3;                    /* skip subl2 */
69   if (op == 0x9E
70       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
71       && ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
72     pc += 4;                    /* skip movab */
73   if (op == 0x9E
74       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
75       && ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
76     pc += 5;                    /* skip movab */
77   if (op == 0x9E
78       && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
79       && ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
80     pc += 7;                    /* skip movab */
81   return pc;
82 }
83
84 /* Return number of args passed to a frame.
85    Can return -1, meaning no way to tell.  */
86
87 int
88 vax_frame_num_args (struct frame_info *fi)
89 {
90   return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
91 }
92
93
94
95 /* Print the vax instruction at address MEMADDR in debugged memory,
96    from disassembler info INFO.
97    Returns length of the instruction, in bytes.  */
98
99 static int
100 vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
101 {
102   unsigned char buffer[MAXLEN];
103   register int i;
104   register unsigned char *p;
105   const char *d;
106
107   int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
108   if (status != 0)
109     {
110       (*info->memory_error_func) (status, memaddr, info);
111       return -1;
112     }
113
114   for (i = 0; i < NOPCODES; i++)
115     if (votstrs[i].detail.code == buffer[0]
116         || votstrs[i].detail.code == *(unsigned short *) buffer)
117       break;
118
119   /* Handle undefined instructions.  */
120   if (i == NOPCODES)
121     {
122       (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
123       return 1;
124     }
125
126   (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
127
128   /* Point at first byte of argument data,
129      and at descriptor for first argument.  */
130   p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
131   d = votstrs[i].detail.args;
132
133   if (*d)
134     (*info->fprintf_func) (info->stream, " ");
135
136   while (*d)
137     {
138       p = print_insn_arg (d, p, memaddr + (p - buffer), info);
139       d += 2;
140       if (*d)
141         (*info->fprintf_func) (info->stream, ",");
142     }
143   return p - buffer;
144 }
145
146 static unsigned char *
147 print_insn_arg (char *d, register char *p, CORE_ADDR addr,
148                 disassemble_info *info)
149 {
150   register int regnum = *p & 0xf;
151   float floatlitbuf;
152
153   if (*d == 'b')
154     {
155       if (d[1] == 'b')
156         (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
157       else
158         {
159           (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *) p + 2);
160           p += 2;
161         }
162     }
163   else
164     switch ((*p++ >> 4) & 0xf)
165       {
166       case 0:
167       case 1:
168       case 2:
169       case 3:                   /* Literal mode */
170         if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
171           {
172             *(int *) &floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
173             (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
174           }
175         else
176           (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
177         break;
178
179       case 4:                   /* Indexed */
180         p = (char *) print_insn_arg (d, p, addr + 1, info);
181         (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
182         break;
183
184       case 5:                   /* Register */
185         (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
186         break;
187
188       case 7:                   /* Autodecrement */
189         (*info->fprintf_func) (info->stream, "-");
190       case 6:                   /* Register deferred */
191         (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
192         break;
193
194       case 9:                   /* Autoincrement deferred */
195         (*info->fprintf_func) (info->stream, "@");
196         if (regnum == PC_REGNUM)
197           {
198             (*info->fprintf_func) (info->stream, "#");
199             info->target = *(long *) p;
200             (*info->print_address_func) (info->target, info);
201             p += 4;
202             break;
203           }
204       case 8:                   /* Autoincrement */
205         if (regnum == PC_REGNUM)
206           {
207             (*info->fprintf_func) (info->stream, "#");
208             switch (d[1])
209               {
210               case 'b':
211                 (*info->fprintf_func) (info->stream, "%d", *p++);
212                 break;
213
214               case 'w':
215                 (*info->fprintf_func) (info->stream, "%d", *(short *) p);
216                 p += 2;
217                 break;
218
219               case 'l':
220                 (*info->fprintf_func) (info->stream, "%d", *(long *) p);
221                 p += 4;
222                 break;
223
224               case 'q':
225                 (*info->fprintf_func) (info->stream, "0x%x%08x",
226                                        ((long *) p)[1], ((long *) p)[0]);
227                 p += 8;
228                 break;
229
230               case 'o':
231                 (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
232                                        ((long *) p)[3], ((long *) p)[2],
233                                        ((long *) p)[1], ((long *) p)[0]);
234                 p += 16;
235                 break;
236
237               case 'f':
238                 if (INVALID_FLOAT (p, 4))
239                   (*info->fprintf_func) (info->stream,
240                                          "<<invalid float 0x%x>>",
241                                          *(int *) p);
242                 else
243                   (*info->fprintf_func) (info->stream, "%f", *(float *) p);
244                 p += 4;
245                 break;
246
247               case 'd':
248                 if (INVALID_FLOAT (p, 8))
249                   (*info->fprintf_func) (info->stream,
250                                          "<<invalid float 0x%x%08x>>",
251                                          ((long *) p)[1], ((long *) p)[0]);
252                 else
253                   (*info->fprintf_func) (info->stream, "%f", *(double *) p);
254                 p += 8;
255                 break;
256
257               case 'g':
258                 (*info->fprintf_func) (info->stream, "g-float");
259                 p += 8;
260                 break;
261
262               case 'h':
263                 (*info->fprintf_func) (info->stream, "h-float");
264                 p += 16;
265                 break;
266
267               }
268           }
269         else
270           (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
271         break;
272
273       case 11:                  /* Byte displacement deferred */
274         (*info->fprintf_func) (info->stream, "@");
275       case 10:                  /* Byte displacement */
276         if (regnum == PC_REGNUM)
277           {
278             info->target = addr + *p + 2;
279             (*info->print_address_func) (info->target, info);
280           }
281         else
282           (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
283         p += 1;
284         break;
285
286       case 13:                  /* Word displacement deferred */
287         (*info->fprintf_func) (info->stream, "@");
288       case 12:                  /* Word displacement */
289         if (regnum == PC_REGNUM)
290           {
291             info->target = addr + *(short *) p + 3;
292             (*info->print_address_func) (info->target, info);
293           }
294         else
295           (*info->fprintf_func) (info->stream, "%d(%s)",
296                                  *(short *) p, REGISTER_NAME (regnum));
297         p += 2;
298         break;
299
300       case 15:                  /* Long displacement deferred */
301         (*info->fprintf_func) (info->stream, "@");
302       case 14:                  /* Long displacement */
303         if (regnum == PC_REGNUM)
304           {
305             info->target = addr + *(short *) p + 5;
306             (*info->print_address_func) (info->target, info);
307           }
308         else
309           (*info->fprintf_func) (info->stream, "%d(%s)",
310                                  *(long *) p, REGISTER_NAME (regnum));
311         p += 4;
312       }
313
314   return (unsigned char *) p;
315 }
316
317 void
318 _initialize_vax_tdep (void)
319 {
320   tm_print_insn = vax_print_insn;
321 }