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