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