]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/arm-dis.c
2003-07-17 Michael Snyder <msnyder@redhat.com>
[thirdparty/binutils-gdb.git] / opcodes / arm-dis.c
CommitLineData
252b5132 1/* Instruction printing code for the ARM
e16bb312 2 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
060d22b0 3 Free Software Foundation, Inc.
252b5132
RH
4 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5 Modification by James G. Smith (jsmith@cygnus.co.uk)
6
e16bb312 7 This file is part of libopcodes.
252b5132 8
e16bb312
NC
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your option)
12 any later version.
252b5132 13
e16bb312
NC
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
252b5132 18
e16bb312
NC
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
252b5132 22
cb6a5892 23#include "sysdep.h"
252b5132
RH
24#include "dis-asm.h"
25#define DEFINE_TABLE
26#include "arm-opc.h"
27#include "coff/internal.h"
28#include "libcoff.h"
29#include "opintl.h"
30
baf0cc5e 31/* FIXME: This shouldn't be done here. */
252b5132
RH
32#include "elf-bfd.h"
33#include "elf/internal.h"
34#include "elf/arm.h"
35
01c7f630 36#ifndef streq
58efb6c0 37#define streq(a,b) (strcmp ((a), (b)) == 0)
01c7f630 38#endif
58efb6c0 39
01c7f630 40#ifndef strneq
58efb6c0
NC
41#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
42#endif
43
44#ifndef NUM_ELEM
45#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
01c7f630
NC
46#endif
47
5876e06d 48static char * arm_conditional[] =
252b5132
RH
49{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
50 "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
51
58efb6c0
NC
52typedef struct
53{
54 const char * name;
55 const char * description;
56 const char * reg_names[16];
57}
58arm_regname;
dd92f639 59
58efb6c0
NC
60static arm_regname regnames[] =
61{
62 { "raw" , "Select raw register names",
63 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
7c03c75e
SB
64 { "gcc", "Select register names used by GCC",
65 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
58efb6c0
NC
66 { "std", "Select register names used in ARM's ISA documentation",
67 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
68 { "apcs", "Select register names used in the APCS",
69 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
70 { "atpcs", "Select register names used in the ATPCS",
71 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
a7f8487e 72 { "special-atpcs", "Select special register names used in the ATPCS",
e16bb312 73 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }},
5a6c6817 74 { "iwmmxt_regnames", "Select register names used on the Intel Wireless MMX technology coprocessor",
e16bb312 75 { "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15"}},
5a6c6817 76 { "iwmmxt_Cregnames", "Select control register names used on the Intel Wireless MMX technology coprocessor",
e16bb312
NC
77 {"wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved"}}
78};
79
80static char * iwmmxt_wwnames[] =
81{"b", "h", "w", "d"};
82
83static char * iwmmxt_wwssnames[] =
84{"b", "bus", "b", "bss",
85 "h", "hus", "h", "hss",
86 "w", "wus", "w", "wss",
87 "d", "dus", "d", "dss"
58efb6c0
NC
88};
89
7c03c75e 90/* Default to GCC register name set. */
58efb6c0
NC
91static unsigned int regname_selected = 1;
92
93#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
94#define arm_regnames regnames[regname_selected].reg_names
252b5132 95
b34976b6 96static bfd_boolean force_thumb = FALSE;
01c7f630 97
5876e06d 98static char * arm_fp_const[] =
252b5132
RH
99{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
100
b34976b6 101static char * arm_shift[] =
252b5132 102{"lsl", "lsr", "asr", "ror"};
01c7f630
NC
103\f
104/* Forward declarations. */
b34976b6
AM
105static void arm_decode_shift
106 PARAMS ((long, fprintf_ftype, void *));
107static int print_insn_arm
108 PARAMS ((bfd_vma, struct disassemble_info *, long));
109static int print_insn_thumb
110 PARAMS ((bfd_vma, struct disassemble_info *, long));
111static void parse_disassembler_options
112 PARAMS ((char *));
113static int print_insn
114 PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean));
e16bb312
NC
115static int set_iwmmxt_regnames
116 PARAMS ((void));
117
118int get_arm_regname_num_options
119 PARAMS ((void));
120int set_arm_regname_option
121 PARAMS ((int));
122int get_arm_regnames
123 PARAMS ((int, const char **, const char **, const char ***));
01c7f630 124\f
baf0cc5e 125/* Functions. */
a7f8487e 126int
baf0cc5e 127get_arm_regname_num_options ()
a7f8487e
FN
128{
129 return NUM_ARM_REGNAMES;
130}
131
132int
baf0cc5e
NC
133set_arm_regname_option (option)
134 int option;
a7f8487e
FN
135{
136 int old = regname_selected;
137 regname_selected = option;
138 return old;
139}
140
141int
baf0cc5e
NC
142get_arm_regnames (option, setname, setdescription, register_names)
143 int option;
144 const char **setname;
145 const char **setdescription;
146 const char ***register_names;
a7f8487e
FN
147{
148 *setname = regnames[option].name;
149 *setdescription = regnames[option].description;
150 *register_names = regnames[option].reg_names;
151 return 16;
152}
153
252b5132
RH
154static void
155arm_decode_shift (given, func, stream)
156 long given;
157 fprintf_ftype func;
5876e06d 158 void * stream;
252b5132
RH
159{
160 func (stream, "%s", arm_regnames[given & 0xf]);
b34976b6 161
252b5132
RH
162 if ((given & 0xff0) != 0)
163 {
164 if ((given & 0x10) == 0)
165 {
166 int amount = (given & 0xf80) >> 7;
167 int shift = (given & 0x60) >> 5;
b34976b6 168
252b5132
RH
169 if (amount == 0)
170 {
171 if (shift == 3)
172 {
173 func (stream, ", rrx");
174 return;
175 }
b34976b6 176
252b5132
RH
177 amount = 32;
178 }
b34976b6 179
252b5132
RH
180 func (stream, ", %s #%d", arm_shift[shift], amount);
181 }
182 else
183 func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
184 arm_regnames[(given & 0xf00) >> 8]);
185 }
186}
187
e16bb312
NC
188static int
189set_iwmmxt_regnames ()
190{
191 const char * setname;
192 const char * setdesc;
193 const char ** regnames;
194 int iwmmxt_regnames = 0;
195 int num_regnames = get_arm_regname_num_options ();
196
197 get_arm_regnames (iwmmxt_regnames, &setname,
198 &setdesc, &regnames);
199 while ((strcmp ("iwmmxt_regnames", setname))
200 && (iwmmxt_regnames < num_regnames))
201 get_arm_regnames (++iwmmxt_regnames, &setname, &setdesc, &regnames);
202
203 return iwmmxt_regnames;
204}
205
252b5132
RH
206/* Print one instruction from PC on INFO->STREAM.
207 Return the size of the instruction (always 4 on ARM). */
baf0cc5e 208
252b5132
RH
209static int
210print_insn_arm (pc, info, given)
6a51a8a8
AM
211 bfd_vma pc;
212 struct disassemble_info *info;
213 long given;
252b5132 214{
6a51a8a8
AM
215 const struct arm_opcode *insn;
216 void *stream = info->stream;
217 fprintf_ftype func = info->fprintf_func;
e16bb312 218 static int iwmmxt_regnames = 0;
252b5132
RH
219
220 for (insn = arm_opcodes; insn->assembler; insn++)
221 {
e16bb312
NC
222 if (insn->value == FIRST_IWMMXT_INSN
223 && info->mach != bfd_mach_arm_XScale
224 && info->mach != bfd_mach_arm_iWMMXt)
225 insn = insn + IWMMXT_INSN_COUNT;
226
252b5132
RH
227 if ((given & insn->mask) == insn->value)
228 {
229 char * c;
b34976b6 230
252b5132
RH
231 for (c = insn->assembler; *c; c++)
232 {
233 if (*c == '%')
234 {
235 switch (*++c)
236 {
237 case '%':
238 func (stream, "%%");
239 break;
240
241 case 'a':
242 if (((given & 0x000f0000) == 0x000f0000)
243 && ((given & 0x02000000) == 0))
244 {
245 int offset = given & 0xfff;
b34976b6 246
252b5132 247 func (stream, "[pc");
b34976b6 248
252b5132
RH
249 if (given & 0x01000000)
250 {
251 if ((given & 0x00800000) == 0)
252 offset = - offset;
b34976b6 253
baf0cc5e 254 /* Pre-indexed. */
40536497 255 func (stream, ", #%d]", offset);
252b5132
RH
256
257 offset += pc + 8;
258
58efb6c0
NC
259 /* Cope with the possibility of write-back
260 being used. Probably a very dangerous thing
261 for the programmer to do, but who are we to
262 argue ? */
252b5132
RH
263 if (given & 0x00200000)
264 func (stream, "!");
265 }
266 else
267 {
58efb6c0 268 /* Post indexed. */
40536497 269 func (stream, "], #%d", offset);
252b5132 270
baf0cc5e
NC
271 /* ie ignore the offset. */
272 offset = pc + 8;
252b5132 273 }
b34976b6 274
252b5132
RH
275 func (stream, "\t; ");
276 info->print_address_func (offset, info);
277 }
278 else
279 {
b34976b6 280 func (stream, "[%s",
252b5132
RH
281 arm_regnames[(given >> 16) & 0xf]);
282 if ((given & 0x01000000) != 0)
283 {
284 if ((given & 0x02000000) == 0)
285 {
286 int offset = given & 0xfff;
287 if (offset)
288 func (stream, ", %s#%d",
289 (((given & 0x00800000) == 0)
290 ? "-" : ""), offset);
291 }
292 else
293 {
294 func (stream, ", %s",
295 (((given & 0x00800000) == 0)
296 ? "-" : ""));
297 arm_decode_shift (given, func, stream);
298 }
299
b34976b6 300 func (stream, "]%s",
252b5132
RH
301 ((given & 0x00200000) != 0) ? "!" : "");
302 }
303 else
304 {
305 if ((given & 0x02000000) == 0)
306 {
307 int offset = given & 0xfff;
308 if (offset)
309 func (stream, "], %s#%d",
310 (((given & 0x00800000) == 0)
311 ? "-" : ""), offset);
b34976b6 312 else
252b5132
RH
313 func (stream, "]");
314 }
315 else
316 {
317 func (stream, "], %s",
b34976b6 318 (((given & 0x00800000) == 0)
252b5132
RH
319 ? "-" : ""));
320 arm_decode_shift (given, func, stream);
321 }
322 }
323 }
324 break;
325
326 case 's':
327 if ((given & 0x004f0000) == 0x004f0000)
328 {
58efb6c0 329 /* PC relative with immediate offset. */
252b5132 330 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
b34976b6 331
252b5132
RH
332 if ((given & 0x00800000) == 0)
333 offset = -offset;
b34976b6 334
40536497 335 func (stream, "[pc, #%d]\t; ", offset);
b34976b6 336
252b5132
RH
337 (*info->print_address_func)
338 (offset + pc + 8, info);
339 }
340 else
341 {
b34976b6 342 func (stream, "[%s",
252b5132
RH
343 arm_regnames[(given >> 16) & 0xf]);
344 if ((given & 0x01000000) != 0)
345 {
58efb6c0 346 /* Pre-indexed. */
252b5132
RH
347 if ((given & 0x00400000) == 0x00400000)
348 {
58efb6c0 349 /* Immediate. */
252b5132
RH
350 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
351 if (offset)
352 func (stream, ", %s#%d",
353 (((given & 0x00800000) == 0)
354 ? "-" : ""), offset);
355 }
356 else
357 {
58efb6c0 358 /* Register. */
252b5132
RH
359 func (stream, ", %s%s",
360 (((given & 0x00800000) == 0)
361 ? "-" : ""),
362 arm_regnames[given & 0xf]);
363 }
364
b34976b6 365 func (stream, "]%s",
252b5132
RH
366 ((given & 0x00200000) != 0) ? "!" : "");
367 }
368 else
369 {
58efb6c0 370 /* Post-indexed. */
252b5132
RH
371 if ((given & 0x00400000) == 0x00400000)
372 {
58efb6c0 373 /* Immediate. */
252b5132
RH
374 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
375 if (offset)
376 func (stream, "], %s#%d",
377 (((given & 0x00800000) == 0)
378 ? "-" : ""), offset);
b34976b6 379 else
252b5132
RH
380 func (stream, "]");
381 }
382 else
383 {
58efb6c0 384 /* Register. */
252b5132
RH
385 func (stream, "], %s%s",
386 (((given & 0x00800000) == 0)
387 ? "-" : ""),
388 arm_regnames[given & 0xf]);
389 }
390 }
391 }
392 break;
b34976b6 393
252b5132
RH
394 case 'b':
395 (*info->print_address_func)
396 (BDISP (given) * 4 + pc + 8, info);
397 break;
398
399 case 'c':
400 func (stream, "%s",
401 arm_conditional [(given >> 28) & 0xf]);
402 break;
403
404 case 'm':
405 {
406 int started = 0;
407 int reg;
408
409 func (stream, "{");
410 for (reg = 0; reg < 16; reg++)
411 if ((given & (1 << reg)) != 0)
412 {
413 if (started)
414 func (stream, ", ");
415 started = 1;
416 func (stream, "%s", arm_regnames[reg]);
417 }
418 func (stream, "}");
419 }
420 break;
421
422 case 'o':
423 if ((given & 0x02000000) != 0)
424 {
425 int rotate = (given & 0xf00) >> 7;
426 int immed = (given & 0xff);
9f20bbfd
NC
427 immed = (((immed << (32 - rotate))
428 | (immed >> rotate)) & 0xffffffff);
429 func (stream, "#%d\t; 0x%x", immed, immed);
252b5132
RH
430 }
431 else
432 arm_decode_shift (given, func, stream);
433 break;
434
435 case 'p':
436 if ((given & 0x0000f000) == 0x0000f000)
437 func (stream, "p");
438 break;
439
440 case 't':
441 if ((given & 0x01200000) == 0x00200000)
442 func (stream, "t");
443 break;
444
252b5132
RH
445 case 'A':
446 func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
447 if ((given & 0x01000000) != 0)
448 {
449 int offset = given & 0xff;
450 if (offset)
451 func (stream, ", %s#%d]%s",
452 ((given & 0x00800000) == 0 ? "-" : ""),
453 offset * 4,
454 ((given & 0x00200000) != 0 ? "!" : ""));
455 else
456 func (stream, "]");
457 }
458 else
459 {
460 int offset = given & 0xff;
461 if (offset)
462 func (stream, "], %s#%d",
463 ((given & 0x00800000) == 0 ? "-" : ""),
464 offset * 4);
465 else
466 func (stream, "]");
467 }
468 break;
469
077b8428
NC
470 case 'B':
471 /* Print ARM V5 BLX(1) address: pc+25 bits. */
472 {
473 bfd_vma address;
474 bfd_vma offset = 0;
b34976b6 475
077b8428
NC
476 if (given & 0x00800000)
477 /* Is signed, hi bits should be ones. */
478 offset = (-1) ^ 0x00ffffff;
479
480 /* Offset is (SignExtend(offset field)<<2). */
481 offset += given & 0x00ffffff;
482 offset <<= 2;
483 address = offset + pc + 8;
b34976b6 484
077b8428
NC
485 if (given & 0x01000000)
486 /* H bit allows addressing to 2-byte boundaries. */
487 address += 2;
488
489 info->print_address_func (address, info);
490 }
491 break;
492
b1ee46c5
AH
493 case 'I':
494 /* Print a Cirrus/DSP shift immediate. */
495 /* Immediates are 7bit signed ints with bits 0..3 in
496 bits 0..3 of opcode and bits 4..6 in bits 5..7
497 of opcode. */
498 {
499 int imm;
500
501 imm = (given & 0xf) | ((given & 0xe0) >> 1);
502
503 /* Is ``imm'' a negative number? */
504 if (imm & 0x40)
505 imm |= (-1 << 7);
506
507 func (stream, "%d", imm);
508 }
509
510 break;
511
252b5132 512 case 'C':
6eeeb4b4
AO
513 func (stream, "_");
514 if (given & 0x80000)
515 func (stream, "f");
516 if (given & 0x40000)
517 func (stream, "s");
518 if (given & 0x20000)
519 func (stream, "x");
520 if (given & 0x10000)
521 func (stream, "c");
252b5132
RH
522 break;
523
524 case 'F':
525 switch (given & 0x00408000)
526 {
527 case 0:
528 func (stream, "4");
529 break;
530 case 0x8000:
531 func (stream, "1");
532 break;
533 case 0x00400000:
534 func (stream, "2");
535 break;
536 default:
537 func (stream, "3");
538 }
539 break;
b34976b6 540
252b5132
RH
541 case 'P':
542 switch (given & 0x00080080)
543 {
544 case 0:
545 func (stream, "s");
546 break;
547 case 0x80:
548 func (stream, "d");
549 break;
550 case 0x00080000:
551 func (stream, "e");
552 break;
553 default:
554 func (stream, _("<illegal precision>"));
555 break;
556 }
557 break;
558 case 'Q':
559 switch (given & 0x00408000)
560 {
561 case 0:
562 func (stream, "s");
563 break;
564 case 0x8000:
565 func (stream, "d");
566 break;
567 case 0x00400000:
568 func (stream, "e");
569 break;
570 default:
571 func (stream, "p");
572 break;
573 }
574 break;
575 case 'R':
576 switch (given & 0x60)
577 {
578 case 0:
579 break;
580 case 0x20:
581 func (stream, "p");
582 break;
583 case 0x40:
584 func (stream, "m");
585 break;
586 default:
587 func (stream, "z");
588 break;
589 }
590 break;
591
b34976b6 592 case '0': case '1': case '2': case '3': case '4':
252b5132
RH
593 case '5': case '6': case '7': case '8': case '9':
594 {
595 int bitstart = *c++ - '0';
596 int bitend = 0;
597 while (*c >= '0' && *c <= '9')
598 bitstart = (bitstart * 10) + *c++ - '0';
599
600 switch (*c)
601 {
602 case '-':
603 c++;
b34976b6 604
252b5132
RH
605 while (*c >= '0' && *c <= '9')
606 bitend = (bitend * 10) + *c++ - '0';
b34976b6 607
252b5132
RH
608 if (!bitend)
609 abort ();
b34976b6 610
252b5132
RH
611 switch (*c)
612 {
613 case 'r':
614 {
615 long reg;
b34976b6 616
252b5132
RH
617 reg = given >> bitstart;
618 reg &= (2 << (bitend - bitstart)) - 1;
b34976b6 619
252b5132
RH
620 func (stream, "%s", arm_regnames[reg]);
621 }
622 break;
623 case 'd':
624 {
625 long reg;
b34976b6 626
252b5132
RH
627 reg = given >> bitstart;
628 reg &= (2 << (bitend - bitstart)) - 1;
b34976b6 629
252b5132
RH
630 func (stream, "%d", reg);
631 }
632 break;
633 case 'x':
634 {
635 long reg;
b34976b6 636
252b5132
RH
637 reg = given >> bitstart;
638 reg &= (2 << (bitend - bitstart)) - 1;
b34976b6 639
252b5132 640 func (stream, "0x%08x", reg);
b34976b6 641
58efb6c0
NC
642 /* Some SWI instructions have special
643 meanings. */
5876e06d
NC
644 if ((given & 0x0fffffff) == 0x0FF00000)
645 func (stream, "\t; IMB");
646 else if ((given & 0x0fffffff) == 0x0FF00001)
647 func (stream, "\t; IMBRange");
252b5132
RH
648 }
649 break;
cfbd315c
DL
650 case 'X':
651 {
652 long reg;
b34976b6 653
cfbd315c
DL
654 reg = given >> bitstart;
655 reg &= (2 << (bitend - bitstart)) - 1;
b34976b6 656
cfbd315c
DL
657 func (stream, "%01x", reg & 0xf);
658 }
659 break;
252b5132
RH
660 case 'f':
661 {
662 long reg;
b34976b6 663
252b5132
RH
664 reg = given >> bitstart;
665 reg &= (2 << (bitend - bitstart)) - 1;
b34976b6 666
252b5132
RH
667 if (reg > 7)
668 func (stream, "#%s",
669 arm_fp_const[reg & 7]);
670 else
671 func (stream, "f%d", reg);
672 }
673 break;
e16bb312
NC
674
675 case 'w':
676 {
677 long reg;
678
679 if (bitstart != bitend)
680 {
681 reg = given >> bitstart;
682 reg &= (2 << (bitend - bitstart)) - 1;
683 if (bitend - bitstart == 1)
684 func (stream, "%s", iwmmxt_wwnames[reg]);
685 else
686 func (stream, "%s", iwmmxt_wwssnames[reg]);
687 }
688 else
689 {
690 reg = (((given >> 8) & 0x1) |
691 ((given >> 22) & 0x1));
692 func (stream, "%s", iwmmxt_wwnames[reg]);
693 }
694 }
695 break;
696
697 case 'g':
698 {
699 long reg;
700 int current_regnames;
701
702 if (! iwmmxt_regnames)
703 iwmmxt_regnames = set_iwmmxt_regnames ();
704 current_regnames = set_arm_regname_option
705 (iwmmxt_regnames);
706
707 reg = given >> bitstart;
708 reg &= (2 << (bitend - bitstart)) - 1;
709 func (stream, "%s", arm_regnames[reg]);
710 set_arm_regname_option (current_regnames);
711 }
712 break;
713
714 case 'G':
715 {
716 long reg;
717 int current_regnames;
718
719 if (! iwmmxt_regnames)
720 iwmmxt_regnames = set_iwmmxt_regnames ();
721 current_regnames = set_arm_regname_option
722 (iwmmxt_regnames + 1);
723
724 reg = given >> bitstart;
725 reg &= (2 << (bitend - bitstart)) - 1;
726 func (stream, "%s", arm_regnames[reg]);
727 set_arm_regname_option (current_regnames);
728 }
729 break;
730
252b5132
RH
731 default:
732 abort ();
733 }
734 break;
a660f11e
RE
735
736 case 'y':
737 case 'z':
738 {
739 int single = *c == 'y';
740 int regno;
741
742 switch (bitstart)
743 {
744 case 4: /* Sm pair */
745 func (stream, "{");
746 /* Fall through. */
747 case 0: /* Sm, Dm */
748 regno = given & 0x0000000f;
749 if (single)
750 {
751 regno <<= 1;
752 regno += (given >> 5) & 1;
753 }
754 break;
755
756 case 1: /* Sd, Dd */
757 regno = (given >> 12) & 0x0000000f;
758 if (single)
759 {
760 regno <<= 1;
761 regno += (given >> 22) & 1;
762 }
763 break;
764
765 case 2: /* Sn, Dn */
766 regno = (given >> 16) & 0x0000000f;
767 if (single)
768 {
769 regno <<= 1;
770 regno += (given >> 7) & 1;
771 }
772 break;
773
774 case 3: /* List */
775 func (stream, "{");
776 regno = (given >> 12) & 0x0000000f;
777 if (single)
778 {
779 regno <<= 1;
780 regno += (given >> 22) & 1;
781 }
782 break;
783
b34976b6 784
a660f11e
RE
785 default:
786 abort ();
787 }
788
789 func (stream, "%c%d", single ? 's' : 'd', regno);
790
791 if (bitstart == 3)
792 {
793 int count = given & 0xff;
794
795 if (single == 0)
796 count >>= 1;
797
798 if (--count)
799 {
800 func (stream, "-%c%d",
801 single ? 's' : 'd',
802 regno + count);
803 }
804
805 func (stream, "}");
806 }
807 else if (bitstart == 4)
808 func (stream, ", %c%d}", single ? 's' : 'd',
809 regno + 1);
810
811 break;
812 }
813
252b5132
RH
814 case '`':
815 c++;
816 if ((given & (1 << bitstart)) == 0)
817 func (stream, "%c", *c);
818 break;
819 case '\'':
820 c++;
821 if ((given & (1 << bitstart)) != 0)
822 func (stream, "%c", *c);
823 break;
824 case '?':
825 ++c;
826 if ((given & (1 << bitstart)) != 0)
827 func (stream, "%c", *c++);
828 else
829 func (stream, "%c", *++c);
830 break;
831 default:
832 abort ();
833 }
834 break;
835
e16bb312
NC
836 case 'L':
837 switch (given & 0x00400100)
838 {
839 case 0x00000000: func (stream, "b"); break;
840 case 0x00400000: func (stream, "h"); break;
841 case 0x00000100: func (stream, "w"); break;
842 case 0x00400100: func (stream, "d"); break;
843 default:
844 break;
845 }
846 break;
847
848 case 'Z':
849 {
850 int value;
851 /* given (20, 23) | given (0, 3) */
852 value = ((given >> 16) & 0xf0) | (given & 0xf);
853 func (stream, "%d", value);
854 }
855 break;
856
857 case 'l':
858 /* This is like the 'A' operator, except that if
859 the width field "M" is zero, then the offset is
860 *not* multiplied by four. */
861 {
862 int offset = given & 0xff;
863 int multiplier = (given & 0x00000100) ? 4 : 1;
864
865 func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
866
867 if (offset)
868 {
869 if ((given & 0x01000000) != 0)
870 func (stream, ", %s#%d]%s",
871 ((given & 0x00800000) == 0 ? "-" : ""),
872 offset * multiplier,
873 ((given & 0x00200000) != 0 ? "!" : ""));
874 else
875 func (stream, "], %s#%d",
876 ((given & 0x00800000) == 0 ? "-" : ""),
877 offset * multiplier);
878 }
879 else
880 func (stream, "]");
881 }
882 break;
883
252b5132
RH
884 default:
885 abort ();
886 }
887 }
888 }
889 else
890 func (stream, "%c", *c);
891 }
892 return 4;
893 }
894 }
895 abort ();
896}
897
898/* Print one instruction from PC on INFO->STREAM.
899 Return the size of the instruction. */
baf0cc5e 900
252b5132
RH
901static int
902print_insn_thumb (pc, info, given)
6a51a8a8
AM
903 bfd_vma pc;
904 struct disassemble_info *info;
905 long given;
252b5132 906{
6a51a8a8
AM
907 const struct thumb_opcode *insn;
908 void *stream = info->stream;
909 fprintf_ftype func = info->fprintf_func;
252b5132
RH
910
911 for (insn = thumb_opcodes; insn->assembler; insn++)
912 {
913 if ((given & insn->mask) == insn->value)
914 {
5876e06d 915 char * c = insn->assembler;
252b5132 916
58efb6c0
NC
917 /* Special processing for Thumb 2 instruction BL sequence: */
918 if (!*c) /* Check for empty (not NULL) assembler string. */
252b5132 919 {
4f3c3dbb 920 long offset;
b34976b6 921
252b5132
RH
922 info->bytes_per_chunk = 4;
923 info->bytes_per_line = 4;
4f3c3dbb
NC
924
925 offset = BDISP23 (given);
baf0cc5e
NC
926 offset = offset * 2 + pc + 4;
927
077b8428 928 if ((given & 0x10000000) == 0)
4f3c3dbb
NC
929 {
930 func (stream, "blx\t");
baf0cc5e 931 offset &= 0xfffffffc;
4f3c3dbb 932 }
077b8428 933 else
4f3c3dbb
NC
934 func (stream, "bl\t");
935
baf0cc5e 936 info->print_address_func (offset, info);
252b5132
RH
937 return 4;
938 }
939 else
940 {
941 info->bytes_per_chunk = 2;
942 info->bytes_per_line = 4;
b34976b6 943
252b5132 944 given &= 0xffff;
b34976b6 945
252b5132
RH
946 for (; *c; c++)
947 {
948 if (*c == '%')
949 {
950 int domaskpc = 0;
951 int domasklr = 0;
b34976b6 952
252b5132
RH
953 switch (*++c)
954 {
955 case '%':
956 func (stream, "%%");
957 break;
958
959 case 'S':
960 {
961 long reg;
b34976b6 962
252b5132
RH
963 reg = (given >> 3) & 0x7;
964 if (given & (1 << 6))
965 reg += 8;
b34976b6 966
252b5132
RH
967 func (stream, "%s", arm_regnames[reg]);
968 }
969 break;
970
971 case 'D':
972 {
973 long reg;
b34976b6 974
252b5132
RH
975 reg = given & 0x7;
976 if (given & (1 << 7))
977 reg += 8;
b34976b6 978
252b5132
RH
979 func (stream, "%s", arm_regnames[reg]);
980 }
981 break;
982
983 case 'T':
984 func (stream, "%s",
985 arm_conditional [(given >> 8) & 0xf]);
986 break;
987
988 case 'N':
989 if (given & (1 << 8))
990 domasklr = 1;
58efb6c0 991 /* Fall through. */
252b5132
RH
992 case 'O':
993 if (*c == 'O' && (given & (1 << 8)))
994 domaskpc = 1;
58efb6c0 995 /* Fall through. */
252b5132
RH
996 case 'M':
997 {
998 int started = 0;
999 int reg;
b34976b6 1000
252b5132 1001 func (stream, "{");
b34976b6 1002
252b5132
RH
1003 /* It would be nice if we could spot
1004 ranges, and generate the rS-rE format: */
1005 for (reg = 0; (reg < 8); reg++)
1006 if ((given & (1 << reg)) != 0)
1007 {
1008 if (started)
1009 func (stream, ", ");
1010 started = 1;
1011 func (stream, "%s", arm_regnames[reg]);
1012 }
1013
1014 if (domasklr)
1015 {
1016 if (started)
1017 func (stream, ", ");
1018 started = 1;
a7f8487e 1019 func (stream, arm_regnames[14] /* "lr" */);
252b5132
RH
1020 }
1021
1022 if (domaskpc)
1023 {
1024 if (started)
1025 func (stream, ", ");
a7f8487e 1026 func (stream, arm_regnames[15] /* "pc" */);
252b5132
RH
1027 }
1028
1029 func (stream, "}");
1030 }
1031 break;
1032
1033
b34976b6 1034 case '0': case '1': case '2': case '3': case '4':
252b5132
RH
1035 case '5': case '6': case '7': case '8': case '9':
1036 {
1037 int bitstart = *c++ - '0';
1038 int bitend = 0;
b34976b6 1039
252b5132
RH
1040 while (*c >= '0' && *c <= '9')
1041 bitstart = (bitstart * 10) + *c++ - '0';
1042
1043 switch (*c)
1044 {
1045 case '-':
1046 {
1047 long reg;
b34976b6 1048
252b5132
RH
1049 c++;
1050 while (*c >= '0' && *c <= '9')
1051 bitend = (bitend * 10) + *c++ - '0';
1052 if (!bitend)
1053 abort ();
1054 reg = given >> bitstart;
1055 reg &= (2 << (bitend - bitstart)) - 1;
1056 switch (*c)
1057 {
1058 case 'r':
1059 func (stream, "%s", arm_regnames[reg]);
1060 break;
1061
1062 case 'd':
1063 func (stream, "%d", reg);
1064 break;
1065
1066 case 'H':
1067 func (stream, "%d", reg << 1);
1068 break;
1069
1070 case 'W':
1071 func (stream, "%d", reg << 2);
1072 break;
1073
1074 case 'a':
1075 /* PC-relative address -- the bottom two
58efb6c0
NC
1076 bits of the address are dropped
1077 before the calculation. */
252b5132
RH
1078 info->print_address_func
1079 (((pc + 4) & ~3) + (reg << 2), info);
1080 break;
1081
1082 case 'x':
1083 func (stream, "0x%04x", reg);
1084 break;
1085
1086 case 'I':
1087 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
1088 func (stream, "%d", reg);
1089 break;
1090
1091 case 'B':
1092 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
1093 (*info->print_address_func)
1094 (reg * 2 + pc + 4, info);
1095 break;
1096
1097 default:
5876e06d 1098 abort ();
252b5132
RH
1099 }
1100 }
1101 break;
1102
1103 case '\'':
1104 c++;
1105 if ((given & (1 << bitstart)) != 0)
1106 func (stream, "%c", *c);
1107 break;
1108
1109 case '?':
1110 ++c;
1111 if ((given & (1 << bitstart)) != 0)
1112 func (stream, "%c", *c++);
1113 else
1114 func (stream, "%c", *++c);
1115 break;
1116
1117 default:
5876e06d 1118 abort ();
252b5132
RH
1119 }
1120 }
1121 break;
1122
1123 default:
1124 abort ();
1125 }
1126 }
1127 else
1128 func (stream, "%c", *c);
1129 }
1130 }
1131 return 2;
1132 }
1133 }
1134
58efb6c0 1135 /* No match. */
252b5132
RH
1136 abort ();
1137}
1138
58efb6c0 1139/* Parse an individual disassembler option. */
baf0cc5e 1140
a3d9c82d
NC
1141void
1142parse_arm_disassembler_option (option)
01c7f630 1143 char * option;
dd92f639 1144{
01c7f630 1145 if (option == NULL)
dd92f639 1146 return;
b34976b6 1147
01c7f630 1148 if (strneq (option, "reg-names-", 10))
dd92f639 1149 {
58efb6c0 1150 int i;
b34976b6 1151
01c7f630 1152 option += 10;
58efb6c0
NC
1153
1154 for (i = NUM_ARM_REGNAMES; i--;)
1155 if (streq (option, regnames[i].name))
1156 {
1157 regname_selected = i;
1158 break;
1159 }
b34976b6 1160
58efb6c0
NC
1161 if (i < 0)
1162 fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
dd92f639 1163 }
01c7f630
NC
1164 else if (streq (option, "force-thumb"))
1165 force_thumb = 1;
1166 else if (streq (option, "no-force-thumb"))
1167 force_thumb = 0;
dd92f639 1168 else
58efb6c0 1169 fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
b34976b6 1170
dd92f639
NC
1171 return;
1172}
1173
58efb6c0 1174/* Parse the string of disassembler options, spliting it at whitespaces. */
baf0cc5e 1175
01c7f630
NC
1176static void
1177parse_disassembler_options (options)
1178 char * options;
1179{
1180 char * space;
b34976b6 1181
01c7f630
NC
1182 if (options == NULL)
1183 return;
1184
1185 do
1186 {
1187 space = strchr (options, ' ');
1188
1189 if (space)
1190 {
1191 * space = '\0';
a3d9c82d 1192 parse_arm_disassembler_option (options);
01c7f630
NC
1193 * space = ' ';
1194 options = space + 1;
1195 }
1196 else
a3d9c82d 1197 parse_arm_disassembler_option (options);
01c7f630
NC
1198 }
1199 while (space);
1200}
1201
58efb6c0
NC
1202/* NOTE: There are no checks in these routines that
1203 the relevant number of data bytes exist. */
baf0cc5e 1204
58efb6c0
NC
1205static int
1206print_insn (pc, info, little)
252b5132 1207 bfd_vma pc;
5876e06d 1208 struct disassemble_info * info;
b34976b6 1209 bfd_boolean little;
252b5132
RH
1210{
1211 unsigned char b[4];
1212 long given;
1213 int status;
252b5132 1214 int is_thumb;
58efb6c0 1215
dd92f639
NC
1216 if (info->disassembler_options)
1217 {
1218 parse_disassembler_options (info->disassembler_options);
b34976b6 1219
58efb6c0 1220 /* To avoid repeated parsing of these options, we remove them here. */
dd92f639
NC
1221 info->disassembler_options = NULL;
1222 }
b34976b6 1223
01c7f630 1224 is_thumb = force_thumb;
b34976b6 1225
01c7f630 1226 if (!is_thumb && info->symbols != NULL)
252b5132 1227 {
5876e06d
NC
1228 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
1229 {
2f0ca46a 1230 coff_symbol_type * cs;
b34976b6 1231
5876e06d
NC
1232 cs = coffsymbol (*info->symbols);
1233 is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
1234 || cs->native->u.syment.n_sclass == C_THUMBSTAT
1235 || cs->native->u.syment.n_sclass == C_THUMBLABEL
1236 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
1237 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
1238 }
1239 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
1240 {
2f0ca46a 1241 elf_symbol_type * es;
58efb6c0 1242 unsigned int type;
b34976b6 1243
5876e06d 1244 es = *(elf_symbol_type **)(info->symbols);
58efb6c0 1245 type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
b34976b6 1246
58efb6c0 1247 is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
5876e06d
NC
1248 }
1249 }
b34976b6 1250
252b5132 1251 info->bytes_per_chunk = 4;
58efb6c0 1252 info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
252b5132 1253
58efb6c0 1254 if (little)
252b5132 1255 {
58efb6c0
NC
1256 status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
1257 if (status != 0 && is_thumb)
1258 {
1259 info->bytes_per_chunk = 2;
b34976b6 1260
58efb6c0
NC
1261 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1262 b[3] = b[2] = 0;
1263 }
b34976b6 1264
58efb6c0
NC
1265 if (status != 0)
1266 {
1267 info->memory_error_func (status, pc, info);
1268 return -1;
1269 }
b34976b6 1270
58efb6c0 1271 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
252b5132 1272 }
58efb6c0 1273 else
252b5132 1274 {
58efb6c0
NC
1275 status = info->read_memory_func
1276 (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
1277 if (status != 0)
252b5132 1278 {
58efb6c0
NC
1279 info->memory_error_func (status, pc, info);
1280 return -1;
1281 }
b34976b6 1282
58efb6c0
NC
1283 if (is_thumb)
1284 {
1285 if (pc & 0x2)
252b5132 1286 {
58efb6c0 1287 given = (b[2] << 8) | b[3];
b34976b6 1288
58efb6c0
NC
1289 status = info->read_memory_func
1290 ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
1291 if (status != 0)
1292 {
1293 info->memory_error_func (status, pc + 4, info);
1294 return -1;
1295 }
b34976b6 1296
58efb6c0 1297 given |= (b[0] << 24) | (b[1] << 16);
252b5132 1298 }
58efb6c0
NC
1299 else
1300 given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
252b5132
RH
1301 }
1302 else
58efb6c0 1303 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
252b5132 1304 }
b34976b6 1305
6a56ec7e
NC
1306 if (info->flags & INSN_HAS_RELOC)
1307 /* If the instruction has a reloc associated with it, then
1308 the offset field in the instruction will actually be the
1309 addend for the reloc. (We are using REL type relocs).
1310 In such cases, we can ignore the pc when computing
1311 addresses, since the addend is not currently pc-relative. */
1312 pc = 0;
b34976b6 1313
252b5132 1314 if (is_thumb)
5876e06d 1315 status = print_insn_thumb (pc, info, given);
252b5132 1316 else
5876e06d 1317 status = print_insn_arm (pc, info, given);
252b5132
RH
1318
1319 return status;
1320}
1321
1322int
58efb6c0 1323print_insn_big_arm (pc, info)
252b5132
RH
1324 bfd_vma pc;
1325 struct disassemble_info * info;
1326{
b34976b6 1327 return print_insn (pc, info, FALSE);
58efb6c0 1328}
01c7f630 1329
58efb6c0
NC
1330int
1331print_insn_little_arm (pc, info)
1332 bfd_vma pc;
1333 struct disassemble_info * info;
1334{
b34976b6 1335 return print_insn (pc, info, TRUE);
58efb6c0 1336}
252b5132 1337
58efb6c0
NC
1338void
1339print_arm_disassembler_options (FILE * stream)
1340{
1341 int i;
252b5132 1342
58efb6c0
NC
1343 fprintf (stream, _("\n\
1344The following ARM specific disassembler options are supported for use with\n\
1345the -M switch:\n"));
b34976b6 1346
58efb6c0
NC
1347 for (i = NUM_ARM_REGNAMES; i--;)
1348 fprintf (stream, " reg-names-%s %*c%s\n",
1349 regnames[i].name,
d5b2f4d6 1350 (int)(14 - strlen (regnames[i].name)), ' ',
58efb6c0
NC
1351 regnames[i].description);
1352
1353 fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
1354 fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
252b5132 1355}