]> Git Repo - binutils.git/blob - gdb/arm-pinsn.c
ansi name abuse changes
[binutils.git] / gdb / arm-pinsn.c
1 /* Print ARM instructions for GDB, the GNU debugger.
2    Copyright (C) 1986, 1989 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <assert.h>
23
24 #include "defs.h"
25 #include "param.h"
26 #include "symtab.h"
27 #include "arm-opcode.h"
28
29 extern char *reg_names[];
30
31 static char *shift_names[] = {
32     "lsl", "lsr", "asr", "ror",
33 };
34
35 static char *cond_names[] = {
36         "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
37         "hi", "ls", "ge", "lt", "gt", "le", "", "nv"
38 };
39
40 static char float_precision[] = "sdep";
41 static char float_rounding[] = " pmz";
42 static float float_immed[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0.5, 10.0 };
43
44 static void print_ldr_str_offset();
45 static void print_ldc_stc_offset();
46 static long immediate_value();
47 \f
48 /* Print the ARM instruction at address MEMADDR in debugged memory,
49    on STREAM.  Returns length of the instruction, in bytes.  */
50
51 int
52 print_insn (memaddr, stream)
53      CORE_ADDR memaddr;
54      FILE *stream;
55 {
56     unsigned long ins;
57     register struct opcode *op;
58     register char *p;
59     register int i, c;
60     int s, e, val;
61
62     ins = read_memory_integer(memaddr, 4);
63     for (i = 0, op = opcodes; i < N_OPCODES; i++, op++)
64         if ((ins & op->mask) == op->value) break;
65     assert(i != N_OPCODES);
66     
67     for (p = op->assembler; *p;) {
68         c = *p++;
69         if (c == '%') {
70             s = e = 0;
71             while (isdigit(*p))
72                 s = s*10 + (*p++ - '0');
73             if (*p == '-') {
74                 p++;
75                 while (isdigit(*p))
76                     e = e*10 + (*p++ - '0');
77             } else
78                 e = s;
79             assert(s >= 0 && s <= 31 && e >= 0 && e <= 31);
80             val = (ins >> s) & ((1 << (e + 1 - s)) - 1);
81             switch (*p++) {
82             case '%' :
83                 putc('%', stream);
84                 break;
85             case 'd' :
86                 fprintf(stream, "%d", val);
87                 break;
88             case 'x' :
89                 fprintf(stream, "%x", val);
90                 break;
91             case 'r' :
92                 assert(val >= 0 && val <= 15);
93                 fprintf(stream, "%s", reg_names[val]);
94                 break;
95             case 'c' :
96                 fprintf(stream, "%s", cond_names[ins >> 28]);
97                 break;
98             case '\'' :
99                 assert(*p);
100                 c = *p++;
101                 if (val)
102                     putc(c, stream);
103                 break;
104             case '`' :
105                 assert(*p);
106                 c = *p++;
107                 if (!val)
108                     putc(c, stream);
109                 break;
110             case '?' :
111                 assert(*p);
112                 c = *p++;
113                 assert(*p);
114                 if (val)
115                     p++;
116                 else
117                     c = *p++;
118                 putc(c, stream);
119                 break;
120             case 'p' :
121                 if (((ins >> 12) & 0xf) == 0xf)
122                     putc('p', stream);
123                 break;
124             case 'o' :
125                 if (ins & (1<<25)) {
126                     int immed = immediate_value(ins & 0xfff);
127                     fprintf (stream, "#%d (0x%x)", immed, immed);
128                 } else {
129                     int operand2 = ins & 0xfff;
130                     /* in operand2 :
131                        bits 0-3 are the base register
132                        bits 5-6 are the shift (0=lsl, 1=lsr, 2=asr, 3=ror)
133                        if bit 4 is zero then bits 7-11 are an immediate shift count
134                        else bit 7 must be zero and bits 8-11 are the register
135                        to be used as a shift count.
136                        Note: no shift at all is encoded as "reg lsl #0" */
137                     fprintf (stream, "%s", reg_names[operand2 & 0xf]);
138                     if (operand2 & 0xff0) {
139                         /* ror #0 is really rrx (rotate right extend) */
140                         if ((operand2 & 0xff0) == 0x060)
141                             fprintf (stream, ", rrx");
142                         else {
143                             fprintf (stream, ", %s ",
144                                      shift_names[(operand2 >> 5) & 3]);
145                             if (operand2 & (1<<4)) /* register shift */
146                                 fprintf (stream, "%s",
147                                          reg_names[operand2 >> 8]);
148                             else        /* immediate shift */
149                                 fprintf (stream, "#%d",
150                                          operand2 >> 7);
151                         }
152                     }
153                 }
154                 break;
155             case 'a' :
156                 fprintf (stream, "[%s", reg_names[(ins >> 16) & 0xf]);
157                 if (ins & (1<<24)) {
158                     fprintf (stream, ", ");
159                     print_ldr_str_offset (ins, stream);
160                     putc (']', stream);
161                     if (ins & (1<<21)) putc('!', stream);
162                     /* If it is a pc relative load, then it is probably
163                        a constant so print it */
164                     if (((ins >> 16) & 0xf) == 15 &&
165                         (ins & (1<<25)) == 0 &&
166                         (ins & (1<<20))) {
167                         int addr = memaddr + 8 +
168                             (ins & 0xfff) * ((ins & (1<<23)) ? 1 : -1);
169                         fprintf (stream, " (contents=");
170                         print_address (read_memory_integer(addr, 4), stream);
171                         fprintf (stream, ")");
172                     }
173                 } else {
174                     fprintf (stream, "]," );
175                     print_ldr_str_offset (ins, stream);
176                 }
177                 break;
178             case 'b' :
179                 print_address (memaddr + 8 + (((int)ins << 8) >> 6), stream);
180                 break;
181             case 'A' :
182                 fprintf (stream, "[%s", reg_names[(ins >> 16) & 0xf]);
183                 if (ins & (1<<24)) {
184                     fprintf (stream, ", ");
185                     print_ldc_stc_offset (ins, stream);
186                     putc(']', stream);
187                     if (ins & (1<<21))
188                         putc('!', stream);
189                 } else {
190                     fprintf (stream, "], ");
191                     print_ldc_stc_offset (ins, stream);
192                 }
193                 break;
194             case 'm' :
195                 {
196                     int regnum, first = 1;
197                     putc('{', stream);
198                     for (regnum = 0; regnum < 16; regnum++)
199                         if (ins & (1<<regnum)) {
200                             if (!first)
201                                 putc (',', stream);
202                             first = 0;
203                             fprintf (stream, "%s", reg_names[regnum]);
204                         }
205                     putc('}', stream);
206                 }
207                 break;
208             case 'P' :
209                 val = ((ins >> 18) & 2) | ((ins >> 7) & 1);
210                 putc(float_precision[val], stream);
211                 break;
212             case 'Q' :
213                 val = ((ins >> 21) & 2) | ((ins >> 15) & 1);
214                 putc(float_precision[val], stream);
215                 break;
216             case 'R' :
217                 val = ((ins >> 5) & 3);
218                 if (val) putc(float_rounding[val], stream);
219                 break;
220             case 'f' :
221                 assert(val >= 0 && val <= 15);
222                 if (val > 7)
223                     fprintf (stream, "#%3.1f", float_immed[val - 8]);
224                 else
225                     fprintf (stream, "f%d", val);
226                 break;
227             default:
228                 abort();
229             }
230         } else
231             putc(c, stream);
232     }
233     return 4;
234 }
235
236 static long
237 immediate_value(operand)
238 int operand;
239 {
240     int val = operand & 0xff;
241     int shift = 2*(operand >> 8);
242     /* immediate value is (val ror shift) */
243     return (val >> shift) | (val << (32 - shift));
244 }
245
246 static void
247 print_ldr_str_offset(ins, stream)
248 unsigned long ins;
249 FILE *stream;
250 {
251     if ((ins & (1<<25)) == 0)
252         fprintf (stream, "#%d",
253                  (ins & 0xfff) * ((ins & (1<<23)) ? 1 : -1));
254     else {
255         fprintf (stream, "%s%s", reg_names[ins & 0xf],
256                  (ins & (1<<23)) ? "" : "-");
257         if (ins & 0xff0)
258             fprintf (stream, ", %s #%d",
259                      shift_names[(ins >> 5) & 3],
260                      (ins >> 7) & 0x1f);
261     }
262 }
263
264 static void
265 print_ldc_stc_offset(ins, stream)
266 unsigned long ins;
267 FILE *stream;
268 {
269     fprintf (stream, "#%d",
270              4 * (ins & 0xff) * ((ins & (1<<23)) ? 1 : -1));
271 }
This page took 0.037418 seconds and 4 git commands to generate.