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