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