]> Git Repo - binutils.git/blob - gdb/sparc-pinsn.c
One step closer.
[binutils.git] / gdb / sparc-pinsn.c
1 /* Print SPARC instructions for GDB, the GNU Debugger.
2    Copyright 1989, 1991 Free Software Foundation, Inc.
3
4 This file is part of GDB, the GNU disassembler.
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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <stdio.h>
21
22 #include "defs.h"
23 #include "symtab.h"
24 #include "opcode/sparc.h"
25 #include "gdbcore.h"
26 #include "string.h"
27 #include "target.h"
28
29 extern char *reg_names[];
30 #define freg_names      (&reg_names[4 * 8])
31
32 union sparc_insn
33   {
34     unsigned long int code;
35     struct
36       {
37         unsigned int anop:2;
38 #define op      ldst.anop
39         unsigned int anrd:5;
40 #define rd      ldst.anrd
41         unsigned int op3:6;
42         unsigned int anrs1:5;
43 #define rs1     ldst.anrs1
44         unsigned int i:1;
45         unsigned int anasi:8;
46 #define asi     ldst.anasi
47         unsigned int anrs2:5;
48 #define rs2     ldst.anrs2
49 #define shcnt   rs2
50       } ldst;
51     struct
52       {
53         unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
54         unsigned int IMM13:13;
55 #define imm13   IMM13.IMM13
56       } IMM13;
57     struct
58       {
59         unsigned int anop:2;
60         unsigned int a:1;
61         unsigned int cond:4;
62         unsigned int op2:3;
63         unsigned int DISP22:22;
64 #define disp22  branch.DISP22
65       } branch;
66 #define imm22   disp22
67     struct
68       {
69         unsigned int anop:2;
70         unsigned int adisp30:30;
71 #define disp30  call.adisp30
72       } call;
73   };
74
75 /* Nonzero if INSN is the opcode for a delayed branch.  */
76 static int
77 is_delayed_branch (insn)
78      union sparc_insn insn;
79 {
80   unsigned int i;
81
82   for (i = 0; i < NUMOPCODES; ++i)
83     {
84       const struct sparc_opcode *opcode = &sparc_opcodes[i];
85       if ((opcode->match & insn.code) == opcode->match
86           && (opcode->lose & insn.code) == 0)
87         return (opcode->flags & F_DELAYED);
88     }
89   return 0;
90 }
91
92 /* Print one instruction from MEMADDR on STREAM.  */
93 int
94 print_insn (memaddr, stream)
95      CORE_ADDR memaddr;
96      FILE *stream;
97 {
98   union sparc_insn insn;
99
100   register unsigned int i;
101
102   read_memory (memaddr, &insn, sizeof (insn));
103
104   for (i = 0; i < NUMOPCODES; ++i)
105     {
106       const struct sparc_opcode *opcode = &sparc_opcodes[i];
107       if ((opcode->match & insn.code) == opcode->match
108           && (opcode->lose & insn.code) == 0)
109         {
110           /* Nonzero means that we have found an instruction which has
111              the effect of adding or or'ing the imm13 field to rs1.  */
112           int imm_added_to_rs1 = 0;
113
114           /* Nonzero means that we have found a plus sign in the args
115              field of the opcode table.  */
116           int found_plus = 0;
117           
118           /* Do we have an 'or' instruction where rs1 is the same
119              as rsd, and which has the i bit set?  */
120           if (opcode->match == 0x80102000
121               && insn.rs1 == insn.rd)
122             imm_added_to_rs1 = 1;
123
124           if (insn.rs1 != insn.rd
125               && strchr (opcode->args, 'r') != 0)
126               /* Can't do simple format if source and dest are different.  */
127               continue;
128
129           fputs_filtered (opcode->name, stream);
130
131           {
132             register const char *s;
133
134             if (opcode->args[0] != ',')
135               fputs_filtered (" ", stream);
136             for (s = opcode->args; *s != '\0'; ++s)
137               {
138                 if (*s == ',')
139                   {
140                     fputs_filtered (",", stream);
141                     ++s;
142                     if (*s == 'a')
143                       {
144                         fputs_filtered ("a", stream);
145                         ++s;
146                       }
147                     fputs_filtered (" ", stream);
148                   }
149
150                 switch (*s)
151                   {
152                   case '+':
153                     found_plus = 1;
154
155                     /* note fall-through */
156                   default:
157                     fprintf_filtered (stream, "%c", *s);
158                     break;
159
160                   case '#':
161                     fputs_filtered ("0", stream);
162                     break;
163
164 #define reg(n)  fprintf_filtered (stream, "%%%s", reg_names[n])
165                   case '1':
166                   case 'r':
167                     reg (insn.rs1);
168                     break;
169
170                   case '2':
171                     reg (insn.rs2);
172                     break;
173
174                   case 'd':
175                     reg (insn.rd);
176                     break;
177 #undef  reg
178
179 #define freg(n) fprintf_filtered (stream, "%%%s", freg_names[n])
180                   case 'e':
181                     freg (insn.rs1);
182                     break;
183
184                   case 'f':
185                     freg (insn.rs2);
186                     break;
187
188                   case 'g':
189                     freg (insn.rd);
190                     break;
191 #undef  freg
192
193 #define creg(n) fprintf_filtered (stream, "%%c%u", (unsigned int) (n))
194                   case 'b':
195                     creg (insn.rs1);
196                     break;
197
198                   case 'c':
199                     creg (insn.rs2);
200                     break;
201
202                   case 'D':
203                     creg (insn.rd);
204                     break;
205 #undef  creg
206
207                   case 'h':
208                     fprintf_filtered (stream, "%%hi(%#x)",
209                                       (int) insn.imm22 << 10);
210                     break;
211
212                   case 'i':
213                     {
214                       /* We cannot trust the compiler to sign-extend
215                          when extracting the bitfield, hence the shifts.  */
216                       int imm = ((int) insn.imm13 << 19) >> 19;
217
218                       /* Check to see whether we have a 1+i, and take
219                          note of that fact.
220
221                          FIXME: No longer true/relavant ???
222                          Note: because of the way we sort the table,
223                          we will be matching 1+i rather than i+1,
224                          so it is OK to assume that i is after +,
225                          not before it.  */
226                       if (found_plus)
227                         imm_added_to_rs1 = 1;
228                       
229                       if (imm <= 9)
230                         fprintf_filtered (stream, "%d", imm);
231                       else
232                         fprintf_filtered (stream, "%#x", imm);
233                     }
234                     break;
235
236                   case 'L':
237                     print_address ((CORE_ADDR) memaddr + insn.disp30 * 4,
238                                    stream);
239                     break;
240
241                   case 'l':
242                     if ((insn.code >> 22) == 0)
243                       /* Special case for `unimp'.  Don't try to turn
244                          it's operand into a function offset.  */
245                       fprintf_filtered (stream, "%#x",
246                                         (int) (((int) insn.disp22 << 10) >> 10));
247                     else
248                       /* We cannot trust the compiler to sign-extend
249                          when extracting the bitfield, hence the shifts.  */
250                       print_address ((CORE_ADDR)
251                                      (memaddr
252                                       + (((int) insn.disp22 << 10) >> 10) * 4),
253                                      stream);
254                     break;
255
256                   case 'A':
257                     fprintf_filtered (stream, "(%d)", (int) insn.asi);
258                     break;
259
260                   case 'C':
261                     fputs_filtered ("%csr", stream);
262                     break;
263
264                   case 'F':
265                     fputs_filtered ("%fsr", stream);
266                     break;
267
268                   case 'p':
269                     fputs_filtered ("%psr", stream);
270                     break;
271
272                   case 'q':
273                     fputs_filtered ("%fq", stream);
274                     break;
275
276                   case 'Q':
277                     fputs_filtered ("%cq", stream);
278                     break;
279
280                   case 't':
281                     fputs_filtered ("%tbr", stream);
282                     break;
283
284                   case 'w':
285                     fputs_filtered ("%wim", stream);
286                     break;
287
288                   case 'y':
289                     fputs_filtered ("%y", stream);
290                     break;
291                   }
292               }
293           }
294
295           /* If we are adding or or'ing something to rs1, then
296              check to see whether the previous instruction was
297              a sethi to the same register as in the sethi.
298              If so, attempt to print the result of the add or
299              or (in this context add and or do the same thing)
300              and its symbolic value.  */
301           if (imm_added_to_rs1)
302             {
303               union sparc_insn prev_insn;
304               int errcode;
305
306               errcode = target_read_memory (memaddr - 4,
307                                      (char *)&prev_insn, sizeof (prev_insn));
308
309               if (errcode == 0)
310                 {
311                   /* If it is a delayed branch, we need to look at the
312                      instruction before the delayed branch.  This handles
313                      sequences such as
314
315                      sethi %o1, %hi(_foo), %o1
316                      call _printf
317                      or %o1, %lo(_foo), %o1
318                      */
319
320                   if (is_delayed_branch (prev_insn))
321                     errcode = target_read_memory
322                       (memaddr - 8, (char *)&prev_insn, sizeof (prev_insn));
323                 }
324
325               /* If there was a problem reading memory, then assume
326                  the previous instruction was not sethi.  */
327               if (errcode == 0)
328                 {
329                   /* Is it sethi to the same register?  */
330                   if ((prev_insn.code & 0xc1c00000) == 0x01000000
331                       && prev_insn.rd == insn.rs1)
332                     {
333                       fprintf_filtered (stream, "\t! ");
334                       /* We cannot trust the compiler to sign-extend
335                          when extracting the bitfield, hence the shifts.  */
336                       print_address (((int) prev_insn.imm22 << 10)
337                                      | (insn.imm13 << 19) >> 19, stream);
338                     }
339                 }
340             }
341
342           return sizeof (insn);
343         }
344     }
345
346   printf_filtered ("%#8x", insn.code);
347   return sizeof (insn);
348 }
This page took 0.045332 seconds and 4 git commands to generate.