2000-09-19 H.J. Lu <hjl@gnu.org>
[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
252b5132 448 case 'C':
6eeeb4b4
AO
449 func (stream, "_");
450 if (given & 0x80000)
451 func (stream, "f");
452 if (given & 0x40000)
453 func (stream, "s");
454 if (given & 0x20000)
455 func (stream, "x");
456 if (given & 0x10000)
457 func (stream, "c");
252b5132
RH
458 break;
459
460 case 'F':
461 switch (given & 0x00408000)
462 {
463 case 0:
464 func (stream, "4");
465 break;
466 case 0x8000:
467 func (stream, "1");
468 break;
469 case 0x00400000:
470 func (stream, "2");
471 break;
472 default:
473 func (stream, "3");
474 }
475 break;
476
477 case 'P':
478 switch (given & 0x00080080)
479 {
480 case 0:
481 func (stream, "s");
482 break;
483 case 0x80:
484 func (stream, "d");
485 break;
486 case 0x00080000:
487 func (stream, "e");
488 break;
489 default:
490 func (stream, _("<illegal precision>"));
491 break;
492 }
493 break;
494 case 'Q':
495 switch (given & 0x00408000)
496 {
497 case 0:
498 func (stream, "s");
499 break;
500 case 0x8000:
501 func (stream, "d");
502 break;
503 case 0x00400000:
504 func (stream, "e");
505 break;
506 default:
507 func (stream, "p");
508 break;
509 }
510 break;
511 case 'R':
512 switch (given & 0x60)
513 {
514 case 0:
515 break;
516 case 0x20:
517 func (stream, "p");
518 break;
519 case 0x40:
520 func (stream, "m");
521 break;
522 default:
523 func (stream, "z");
524 break;
525 }
526 break;
527
528 case '0': case '1': case '2': case '3': case '4':
529 case '5': case '6': case '7': case '8': case '9':
530 {
531 int bitstart = *c++ - '0';
532 int bitend = 0;
533 while (*c >= '0' && *c <= '9')
534 bitstart = (bitstart * 10) + *c++ - '0';
535
536 switch (*c)
537 {
538 case '-':
539 c++;
58efb6c0 540
252b5132
RH
541 while (*c >= '0' && *c <= '9')
542 bitend = (bitend * 10) + *c++ - '0';
58efb6c0 543
252b5132
RH
544 if (!bitend)
545 abort ();
58efb6c0 546
252b5132
RH
547 switch (*c)
548 {
549 case 'r':
550 {
551 long reg;
58efb6c0 552
252b5132
RH
553 reg = given >> bitstart;
554 reg &= (2 << (bitend - bitstart)) - 1;
58efb6c0 555
252b5132
RH
556 func (stream, "%s", arm_regnames[reg]);
557 }
558 break;
559 case 'd':
560 {
561 long reg;
58efb6c0 562
252b5132
RH
563 reg = given >> bitstart;
564 reg &= (2 << (bitend - bitstart)) - 1;
58efb6c0 565
252b5132
RH
566 func (stream, "%d", reg);
567 }
568 break;
569 case 'x':
570 {
571 long reg;
58efb6c0 572
252b5132
RH
573 reg = given >> bitstart;
574 reg &= (2 << (bitend - bitstart)) - 1;
58efb6c0 575
252b5132 576 func (stream, "0x%08x", reg);
5876e06d 577
58efb6c0
NC
578 /* Some SWI instructions have special
579 meanings. */
5876e06d
NC
580 if ((given & 0x0fffffff) == 0x0FF00000)
581 func (stream, "\t; IMB");
582 else if ((given & 0x0fffffff) == 0x0FF00001)
583 func (stream, "\t; IMBRange");
252b5132
RH
584 }
585 break;
cfbd315c
DL
586 case 'X':
587 {
588 long reg;
58efb6c0 589
cfbd315c
DL
590 reg = given >> bitstart;
591 reg &= (2 << (bitend - bitstart)) - 1;
58efb6c0 592
cfbd315c
DL
593 func (stream, "%01x", reg & 0xf);
594 }
595 break;
252b5132
RH
596 case 'f':
597 {
598 long reg;
58efb6c0 599
252b5132
RH
600 reg = given >> bitstart;
601 reg &= (2 << (bitend - bitstart)) - 1;
58efb6c0 602
252b5132
RH
603 if (reg > 7)
604 func (stream, "#%s",
605 arm_fp_const[reg & 7]);
606 else
607 func (stream, "f%d", reg);
608 }
609 break;
610 default:
611 abort ();
612 }
613 break;
58efb6c0 614
252b5132
RH
615 case '`':
616 c++;
617 if ((given & (1 << bitstart)) == 0)
618 func (stream, "%c", *c);
619 break;
620 case '\'':
621 c++;
622 if ((given & (1 << bitstart)) != 0)
623 func (stream, "%c", *c);
624 break;
625 case '?':
626 ++c;
627 if ((given & (1 << bitstart)) != 0)
628 func (stream, "%c", *c++);
629 else
630 func (stream, "%c", *++c);
631 break;
632 default:
633 abort ();
634 }
635 break;
636
637 default:
638 abort ();
639 }
640 }
641 }
642 else
643 func (stream, "%c", *c);
644 }
645 return 4;
646 }
647 }
648 abort ();
649}
650
651/* Print one instruction from PC on INFO->STREAM.
652 Return the size of the instruction. */
252b5132
RH
653static int
654print_insn_thumb (pc, info, given)
5876e06d
NC
655 bfd_vma pc;
656 struct disassemble_info * info;
657 long given;
252b5132 658{
5876e06d
NC
659 struct thumb_opcode * insn;
660 void * stream = info->stream;
661 fprintf_ftype func = info->fprintf_func;
252b5132
RH
662
663 for (insn = thumb_opcodes; insn->assembler; insn++)
664 {
665 if ((given & insn->mask) == insn->value)
666 {
5876e06d 667 char * c = insn->assembler;
252b5132 668
58efb6c0
NC
669 /* Special processing for Thumb 2 instruction BL sequence: */
670 if (!*c) /* Check for empty (not NULL) assembler string. */
252b5132 671 {
4f3c3dbb
NC
672 long offset;
673
252b5132
RH
674 info->bytes_per_chunk = 4;
675 info->bytes_per_line = 4;
4f3c3dbb
NC
676
677 offset = BDISP23 (given);
252b5132 678
077b8428 679 if ((given & 0x10000000) == 0)
4f3c3dbb
NC
680 {
681 func (stream, "blx\t");
682
683 /* The spec says that bit 1 of the branch's destination
684 address comes from bit 1 of the instruction's
685 address and not from the offset in the instruction. */
686 if (offset & 0x1)
687 {
688 /* func (stream, "*malformed!* "); */
689 offset &= ~ 0x1;
690 }
691
692 offset |= ((pc & 0x2) >> 1);
693 }
077b8428 694 else
4f3c3dbb
NC
695 func (stream, "bl\t");
696
697 info->print_address_func (offset * 2 + pc + 4, info);
252b5132
RH
698 return 4;
699 }
700 else
701 {
702 info->bytes_per_chunk = 2;
703 info->bytes_per_line = 4;
704
705 given &= 0xffff;
58efb6c0 706
252b5132
RH
707 for (; *c; c++)
708 {
709 if (*c == '%')
710 {
711 int domaskpc = 0;
712 int domasklr = 0;
5876e06d 713
252b5132
RH
714 switch (*++c)
715 {
716 case '%':
717 func (stream, "%%");
718 break;
719
720 case 'S':
721 {
722 long reg;
58efb6c0 723
252b5132
RH
724 reg = (given >> 3) & 0x7;
725 if (given & (1 << 6))
726 reg += 8;
58efb6c0 727
252b5132
RH
728 func (stream, "%s", arm_regnames[reg]);
729 }
730 break;
731
732 case 'D':
733 {
734 long reg;
5876e06d 735
252b5132
RH
736 reg = given & 0x7;
737 if (given & (1 << 7))
738 reg += 8;
58efb6c0 739
252b5132
RH
740 func (stream, "%s", arm_regnames[reg]);
741 }
742 break;
743
744 case 'T':
745 func (stream, "%s",
746 arm_conditional [(given >> 8) & 0xf]);
747 break;
748
749 case 'N':
750 if (given & (1 << 8))
751 domasklr = 1;
58efb6c0 752 /* Fall through. */
252b5132
RH
753 case 'O':
754 if (*c == 'O' && (given & (1 << 8)))
755 domaskpc = 1;
58efb6c0 756 /* Fall through. */
252b5132
RH
757 case 'M':
758 {
759 int started = 0;
760 int reg;
5876e06d 761
252b5132 762 func (stream, "{");
58efb6c0 763
252b5132
RH
764 /* It would be nice if we could spot
765 ranges, and generate the rS-rE format: */
766 for (reg = 0; (reg < 8); reg++)
767 if ((given & (1 << reg)) != 0)
768 {
769 if (started)
770 func (stream, ", ");
771 started = 1;
772 func (stream, "%s", arm_regnames[reg]);
773 }
774
775 if (domasklr)
776 {
777 if (started)
778 func (stream, ", ");
779 started = 1;
a7f8487e 780 func (stream, arm_regnames[14] /* "lr" */);
252b5132
RH
781 }
782
783 if (domaskpc)
784 {
785 if (started)
786 func (stream, ", ");
a7f8487e 787 func (stream, arm_regnames[15] /* "pc" */);
252b5132
RH
788 }
789
790 func (stream, "}");
791 }
792 break;
793
794
795 case '0': case '1': case '2': case '3': case '4':
796 case '5': case '6': case '7': case '8': case '9':
797 {
798 int bitstart = *c++ - '0';
799 int bitend = 0;
5876e06d 800
252b5132
RH
801 while (*c >= '0' && *c <= '9')
802 bitstart = (bitstart * 10) + *c++ - '0';
803
804 switch (*c)
805 {
806 case '-':
807 {
808 long reg;
5876e06d 809
252b5132
RH
810 c++;
811 while (*c >= '0' && *c <= '9')
812 bitend = (bitend * 10) + *c++ - '0';
813 if (!bitend)
814 abort ();
815 reg = given >> bitstart;
816 reg &= (2 << (bitend - bitstart)) - 1;
817 switch (*c)
818 {
819 case 'r':
820 func (stream, "%s", arm_regnames[reg]);
821 break;
822
823 case 'd':
824 func (stream, "%d", reg);
825 break;
826
827 case 'H':
828 func (stream, "%d", reg << 1);
829 break;
830
831 case 'W':
832 func (stream, "%d", reg << 2);
833 break;
834
835 case 'a':
836 /* PC-relative address -- the bottom two
58efb6c0
NC
837 bits of the address are dropped
838 before the calculation. */
252b5132
RH
839 info->print_address_func
840 (((pc + 4) & ~3) + (reg << 2), info);
841 break;
842
843 case 'x':
844 func (stream, "0x%04x", reg);
845 break;
846
847 case 'I':
848 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
849 func (stream, "%d", reg);
850 break;
851
852 case 'B':
853 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
854 (*info->print_address_func)
855 (reg * 2 + pc + 4, info);
856 break;
857
858 default:
5876e06d 859 abort ();
252b5132
RH
860 }
861 }
862 break;
863
864 case '\'':
865 c++;
866 if ((given & (1 << bitstart)) != 0)
867 func (stream, "%c", *c);
868 break;
869
870 case '?':
871 ++c;
872 if ((given & (1 << bitstart)) != 0)
873 func (stream, "%c", *c++);
874 else
875 func (stream, "%c", *++c);
876 break;
877
878 default:
5876e06d 879 abort ();
252b5132
RH
880 }
881 }
882 break;
883
884 default:
885 abort ();
886 }
887 }
888 else
889 func (stream, "%c", *c);
890 }
891 }
892 return 2;
893 }
894 }
895
58efb6c0 896 /* No match. */
252b5132
RH
897 abort ();
898}
899
58efb6c0 900/* Parse an individual disassembler option. */
a3d9c82d
NC
901void
902parse_arm_disassembler_option (option)
01c7f630 903 char * option;
dd92f639 904{
01c7f630 905 if (option == NULL)
dd92f639
NC
906 return;
907
01c7f630 908 if (strneq (option, "reg-names-", 10))
dd92f639 909 {
58efb6c0
NC
910 int i;
911
01c7f630 912 option += 10;
58efb6c0
NC
913
914 for (i = NUM_ARM_REGNAMES; i--;)
915 if (streq (option, regnames[i].name))
916 {
917 regname_selected = i;
918 break;
919 }
dd92f639 920
58efb6c0
NC
921 if (i < 0)
922 fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
dd92f639 923 }
01c7f630
NC
924 else if (streq (option, "force-thumb"))
925 force_thumb = 1;
926 else if (streq (option, "no-force-thumb"))
927 force_thumb = 0;
dd92f639 928 else
58efb6c0 929 fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
dd92f639
NC
930
931 return;
932}
933
58efb6c0 934/* Parse the string of disassembler options, spliting it at whitespaces. */
01c7f630
NC
935static void
936parse_disassembler_options (options)
937 char * options;
938{
939 char * space;
940
941 if (options == NULL)
942 return;
943
944 do
945 {
946 space = strchr (options, ' ');
947
948 if (space)
949 {
950 * space = '\0';
a3d9c82d 951 parse_arm_disassembler_option (options);
01c7f630
NC
952 * space = ' ';
953 options = space + 1;
954 }
955 else
a3d9c82d 956 parse_arm_disassembler_option (options);
01c7f630
NC
957 }
958 while (space);
959}
960
58efb6c0
NC
961/* NOTE: There are no checks in these routines that
962 the relevant number of data bytes exist. */
963static int
964print_insn (pc, info, little)
252b5132 965 bfd_vma pc;
5876e06d 966 struct disassemble_info * info;
58efb6c0 967 boolean little;
252b5132
RH
968{
969 unsigned char b[4];
970 long given;
971 int status;
252b5132 972 int is_thumb;
58efb6c0 973
dd92f639
NC
974 if (info->disassembler_options)
975 {
976 parse_disassembler_options (info->disassembler_options);
977
58efb6c0 978 /* To avoid repeated parsing of these options, we remove them here. */
dd92f639
NC
979 info->disassembler_options = NULL;
980 }
981
01c7f630
NC
982 is_thumb = force_thumb;
983
984 if (!is_thumb && info->symbols != NULL)
252b5132 985 {
5876e06d
NC
986 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
987 {
2f0ca46a
NC
988 coff_symbol_type * cs;
989
5876e06d
NC
990 cs = coffsymbol (*info->symbols);
991 is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
992 || cs->native->u.syment.n_sclass == C_THUMBSTAT
993 || cs->native->u.syment.n_sclass == C_THUMBLABEL
994 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
995 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
996 }
997 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
998 {
2f0ca46a 999 elf_symbol_type * es;
58efb6c0 1000 unsigned int type;
2f0ca46a 1001
5876e06d 1002 es = *(elf_symbol_type **)(info->symbols);
58efb6c0
NC
1003 type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
1004
1005 is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
5876e06d
NC
1006 }
1007 }
58efb6c0 1008
252b5132 1009 info->bytes_per_chunk = 4;
58efb6c0 1010 info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
252b5132 1011
58efb6c0 1012 if (little)
252b5132 1013 {
58efb6c0
NC
1014 status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
1015 if (status != 0 && is_thumb)
1016 {
1017 info->bytes_per_chunk = 2;
1018
1019 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1020 b[3] = b[2] = 0;
1021 }
1022
1023 if (status != 0)
1024 {
1025 info->memory_error_func (status, pc, info);
1026 return -1;
1027 }
1028
1029 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
252b5132 1030 }
58efb6c0 1031 else
252b5132 1032 {
58efb6c0
NC
1033 status = info->read_memory_func
1034 (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
1035 if (status != 0)
252b5132 1036 {
58efb6c0
NC
1037 info->memory_error_func (status, pc, info);
1038 return -1;
1039 }
1040
1041 if (is_thumb)
1042 {
1043 if (pc & 0x2)
252b5132 1044 {
58efb6c0
NC
1045 given = (b[2] << 8) | b[3];
1046
1047 status = info->read_memory_func
1048 ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
1049 if (status != 0)
1050 {
1051 info->memory_error_func (status, pc + 4, info);
1052 return -1;
1053 }
1054
1055 given |= (b[0] << 24) | (b[1] << 16);
252b5132 1056 }
58efb6c0
NC
1057 else
1058 given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
252b5132
RH
1059 }
1060 else
58efb6c0 1061 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
252b5132 1062 }
58efb6c0 1063
6a56ec7e
NC
1064 if (info->flags & INSN_HAS_RELOC)
1065 /* If the instruction has a reloc associated with it, then
1066 the offset field in the instruction will actually be the
1067 addend for the reloc. (We are using REL type relocs).
1068 In such cases, we can ignore the pc when computing
1069 addresses, since the addend is not currently pc-relative. */
1070 pc = 0;
1071
252b5132 1072 if (is_thumb)
5876e06d 1073 status = print_insn_thumb (pc, info, given);
252b5132 1074 else
5876e06d 1075 status = print_insn_arm (pc, info, given);
252b5132
RH
1076
1077 return status;
1078}
1079
1080int
58efb6c0 1081print_insn_big_arm (pc, info)
252b5132
RH
1082 bfd_vma pc;
1083 struct disassemble_info * info;
1084{
58efb6c0
NC
1085 return print_insn (pc, info, false);
1086}
01c7f630 1087
58efb6c0
NC
1088int
1089print_insn_little_arm (pc, info)
1090 bfd_vma pc;
1091 struct disassemble_info * info;
1092{
1093 return print_insn (pc, info, true);
1094}
252b5132 1095
58efb6c0
NC
1096void
1097print_arm_disassembler_options (FILE * stream)
1098{
1099 int i;
252b5132 1100
58efb6c0
NC
1101 fprintf (stream, _("\n\
1102The following ARM specific disassembler options are supported for use with\n\
1103the -M switch:\n"));
01c7f630 1104
58efb6c0
NC
1105 for (i = NUM_ARM_REGNAMES; i--;)
1106 fprintf (stream, " reg-names-%s %*c%s\n",
1107 regnames[i].name,
1108 14 - strlen (regnames[i].name), ' ',
1109 regnames[i].description);
1110
1111 fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
1112 fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
252b5132 1113}
This page took 0.140911 seconds and 4 git commands to generate.