Document new --unwind option to readelf.
[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
RH
670 {
671 info->bytes_per_chunk = 4;
672 info->bytes_per_line = 4;
673
077b8428
NC
674 if ((given & 0x10000000) == 0)
675 func (stream, "blx\t");
676 else
a3d9c82d
NC
677 func (stream, "bl\t");
678
58efb6c0 679 info->print_address_func (BDISP23 (given) * 2 + pc + 4, info);
252b5132
RH
680 return 4;
681 }
682 else
683 {
684 info->bytes_per_chunk = 2;
685 info->bytes_per_line = 4;
686
687 given &= 0xffff;
58efb6c0 688
252b5132
RH
689 for (; *c; c++)
690 {
691 if (*c == '%')
692 {
693 int domaskpc = 0;
694 int domasklr = 0;
5876e06d 695
252b5132
RH
696 switch (*++c)
697 {
698 case '%':
699 func (stream, "%%");
700 break;
701
702 case 'S':
703 {
704 long reg;
58efb6c0 705
252b5132
RH
706 reg = (given >> 3) & 0x7;
707 if (given & (1 << 6))
708 reg += 8;
58efb6c0 709
252b5132
RH
710 func (stream, "%s", arm_regnames[reg]);
711 }
712 break;
713
714 case 'D':
715 {
716 long reg;
5876e06d 717
252b5132
RH
718 reg = given & 0x7;
719 if (given & (1 << 7))
720 reg += 8;
58efb6c0 721
252b5132
RH
722 func (stream, "%s", arm_regnames[reg]);
723 }
724 break;
725
726 case 'T':
727 func (stream, "%s",
728 arm_conditional [(given >> 8) & 0xf]);
729 break;
730
731 case 'N':
732 if (given & (1 << 8))
733 domasklr = 1;
58efb6c0 734 /* Fall through. */
252b5132
RH
735 case 'O':
736 if (*c == 'O' && (given & (1 << 8)))
737 domaskpc = 1;
58efb6c0 738 /* Fall through. */
252b5132
RH
739 case 'M':
740 {
741 int started = 0;
742 int reg;
5876e06d 743
252b5132 744 func (stream, "{");
58efb6c0 745
252b5132
RH
746 /* It would be nice if we could spot
747 ranges, and generate the rS-rE format: */
748 for (reg = 0; (reg < 8); reg++)
749 if ((given & (1 << reg)) != 0)
750 {
751 if (started)
752 func (stream, ", ");
753 started = 1;
754 func (stream, "%s", arm_regnames[reg]);
755 }
756
757 if (domasklr)
758 {
759 if (started)
760 func (stream, ", ");
761 started = 1;
a7f8487e 762 func (stream, arm_regnames[14] /* "lr" */);
252b5132
RH
763 }
764
765 if (domaskpc)
766 {
767 if (started)
768 func (stream, ", ");
a7f8487e 769 func (stream, arm_regnames[15] /* "pc" */);
252b5132
RH
770 }
771
772 func (stream, "}");
773 }
774 break;
775
776
777 case '0': case '1': case '2': case '3': case '4':
778 case '5': case '6': case '7': case '8': case '9':
779 {
780 int bitstart = *c++ - '0';
781 int bitend = 0;
5876e06d 782
252b5132
RH
783 while (*c >= '0' && *c <= '9')
784 bitstart = (bitstart * 10) + *c++ - '0';
785
786 switch (*c)
787 {
788 case '-':
789 {
790 long reg;
5876e06d 791
252b5132
RH
792 c++;
793 while (*c >= '0' && *c <= '9')
794 bitend = (bitend * 10) + *c++ - '0';
795 if (!bitend)
796 abort ();
797 reg = given >> bitstart;
798 reg &= (2 << (bitend - bitstart)) - 1;
799 switch (*c)
800 {
801 case 'r':
802 func (stream, "%s", arm_regnames[reg]);
803 break;
804
805 case 'd':
806 func (stream, "%d", reg);
807 break;
808
809 case 'H':
810 func (stream, "%d", reg << 1);
811 break;
812
813 case 'W':
814 func (stream, "%d", reg << 2);
815 break;
816
817 case 'a':
818 /* PC-relative address -- the bottom two
58efb6c0
NC
819 bits of the address are dropped
820 before the calculation. */
252b5132
RH
821 info->print_address_func
822 (((pc + 4) & ~3) + (reg << 2), info);
823 break;
824
825 case 'x':
826 func (stream, "0x%04x", reg);
827 break;
828
829 case 'I':
830 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
831 func (stream, "%d", reg);
832 break;
833
834 case 'B':
835 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
836 (*info->print_address_func)
837 (reg * 2 + pc + 4, info);
838 break;
839
840 default:
5876e06d 841 abort ();
252b5132
RH
842 }
843 }
844 break;
845
846 case '\'':
847 c++;
848 if ((given & (1 << bitstart)) != 0)
849 func (stream, "%c", *c);
850 break;
851
852 case '?':
853 ++c;
854 if ((given & (1 << bitstart)) != 0)
855 func (stream, "%c", *c++);
856 else
857 func (stream, "%c", *++c);
858 break;
859
860 default:
5876e06d 861 abort ();
252b5132
RH
862 }
863 }
864 break;
865
866 default:
867 abort ();
868 }
869 }
870 else
871 func (stream, "%c", *c);
872 }
873 }
874 return 2;
875 }
876 }
877
58efb6c0 878 /* No match. */
252b5132
RH
879 abort ();
880}
881
58efb6c0 882/* Parse an individual disassembler option. */
a3d9c82d
NC
883void
884parse_arm_disassembler_option (option)
01c7f630 885 char * option;
dd92f639 886{
01c7f630 887 if (option == NULL)
dd92f639
NC
888 return;
889
01c7f630 890 if (strneq (option, "reg-names-", 10))
dd92f639 891 {
58efb6c0
NC
892 int i;
893
01c7f630 894 option += 10;
58efb6c0
NC
895
896 for (i = NUM_ARM_REGNAMES; i--;)
897 if (streq (option, regnames[i].name))
898 {
899 regname_selected = i;
900 break;
901 }
dd92f639 902
58efb6c0
NC
903 if (i < 0)
904 fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
dd92f639 905 }
01c7f630
NC
906 else if (streq (option, "force-thumb"))
907 force_thumb = 1;
908 else if (streq (option, "no-force-thumb"))
909 force_thumb = 0;
dd92f639 910 else
58efb6c0 911 fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
dd92f639
NC
912
913 return;
914}
915
58efb6c0 916/* Parse the string of disassembler options, spliting it at whitespaces. */
01c7f630
NC
917static void
918parse_disassembler_options (options)
919 char * options;
920{
921 char * space;
922
923 if (options == NULL)
924 return;
925
926 do
927 {
928 space = strchr (options, ' ');
929
930 if (space)
931 {
932 * space = '\0';
a3d9c82d 933 parse_arm_disassembler_option (options);
01c7f630
NC
934 * space = ' ';
935 options = space + 1;
936 }
937 else
a3d9c82d 938 parse_arm_disassembler_option (options);
01c7f630
NC
939 }
940 while (space);
941}
942
58efb6c0
NC
943/* NOTE: There are no checks in these routines that
944 the relevant number of data bytes exist. */
945static int
946print_insn (pc, info, little)
252b5132 947 bfd_vma pc;
5876e06d 948 struct disassemble_info * info;
58efb6c0 949 boolean little;
252b5132
RH
950{
951 unsigned char b[4];
952 long given;
953 int status;
252b5132 954 int is_thumb;
58efb6c0 955
dd92f639
NC
956 if (info->disassembler_options)
957 {
958 parse_disassembler_options (info->disassembler_options);
959
58efb6c0 960 /* To avoid repeated parsing of these options, we remove them here. */
dd92f639
NC
961 info->disassembler_options = NULL;
962 }
963
01c7f630
NC
964 is_thumb = force_thumb;
965
966 if (!is_thumb && info->symbols != NULL)
252b5132 967 {
5876e06d
NC
968 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
969 {
2f0ca46a
NC
970 coff_symbol_type * cs;
971
5876e06d
NC
972 cs = coffsymbol (*info->symbols);
973 is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
974 || cs->native->u.syment.n_sclass == C_THUMBSTAT
975 || cs->native->u.syment.n_sclass == C_THUMBLABEL
976 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
977 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
978 }
979 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
980 {
2f0ca46a 981 elf_symbol_type * es;
58efb6c0 982 unsigned int type;
2f0ca46a 983
5876e06d 984 es = *(elf_symbol_type **)(info->symbols);
58efb6c0
NC
985 type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
986
987 is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
5876e06d
NC
988 }
989 }
58efb6c0 990
252b5132 991 info->bytes_per_chunk = 4;
58efb6c0 992 info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
252b5132 993
58efb6c0 994 if (little)
252b5132 995 {
58efb6c0
NC
996 status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
997 if (status != 0 && is_thumb)
998 {
999 info->bytes_per_chunk = 2;
1000
1001 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1002 b[3] = b[2] = 0;
1003 }
1004
1005 if (status != 0)
1006 {
1007 info->memory_error_func (status, pc, info);
1008 return -1;
1009 }
1010
1011 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
252b5132 1012 }
58efb6c0 1013 else
252b5132 1014 {
58efb6c0
NC
1015 status = info->read_memory_func
1016 (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
1017 if (status != 0)
252b5132 1018 {
58efb6c0
NC
1019 info->memory_error_func (status, pc, info);
1020 return -1;
1021 }
1022
1023 if (is_thumb)
1024 {
1025 if (pc & 0x2)
252b5132 1026 {
58efb6c0
NC
1027 given = (b[2] << 8) | b[3];
1028
1029 status = info->read_memory_func
1030 ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
1031 if (status != 0)
1032 {
1033 info->memory_error_func (status, pc + 4, info);
1034 return -1;
1035 }
1036
1037 given |= (b[0] << 24) | (b[1] << 16);
252b5132 1038 }
58efb6c0
NC
1039 else
1040 given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
252b5132
RH
1041 }
1042 else
58efb6c0 1043 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
252b5132 1044 }
58efb6c0 1045
6a56ec7e
NC
1046 if (info->flags & INSN_HAS_RELOC)
1047 /* If the instruction has a reloc associated with it, then
1048 the offset field in the instruction will actually be the
1049 addend for the reloc. (We are using REL type relocs).
1050 In such cases, we can ignore the pc when computing
1051 addresses, since the addend is not currently pc-relative. */
1052 pc = 0;
1053
252b5132 1054 if (is_thumb)
5876e06d 1055 status = print_insn_thumb (pc, info, given);
252b5132 1056 else
5876e06d 1057 status = print_insn_arm (pc, info, given);
252b5132
RH
1058
1059 return status;
1060}
1061
1062int
58efb6c0 1063print_insn_big_arm (pc, info)
252b5132
RH
1064 bfd_vma pc;
1065 struct disassemble_info * info;
1066{
58efb6c0
NC
1067 return print_insn (pc, info, false);
1068}
01c7f630 1069
58efb6c0
NC
1070int
1071print_insn_little_arm (pc, info)
1072 bfd_vma pc;
1073 struct disassemble_info * info;
1074{
1075 return print_insn (pc, info, true);
1076}
252b5132 1077
58efb6c0
NC
1078void
1079print_arm_disassembler_options (FILE * stream)
1080{
1081 int i;
252b5132 1082
58efb6c0
NC
1083 fprintf (stream, _("\n\
1084The following ARM specific disassembler options are supported for use with\n\
1085the -M switch:\n"));
01c7f630 1086
58efb6c0
NC
1087 for (i = NUM_ARM_REGNAMES; i--;)
1088 fprintf (stream, " reg-names-%s %*c%s\n",
1089 regnames[i].name,
1090 14 - strlen (regnames[i].name), ' ',
1091 regnames[i].description);
1092
1093 fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
1094 fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
252b5132 1095}
This page took 0.116606 seconds and 4 git commands to generate.