cd8c0ba3d98e3b214f1b2d14b8f4ac5ff79890d9
[deliverable/binutils-gdb.git] / opcodes / arm-dis.c
1 /* Instruction printing code for the ARM
2 Copyright (C) 1994, 95, 96, 97, 1998 Free Software Foundation, Inc.
3 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
4 Modification by James G. Smith (jsmith@cygnus.co.uk)
5
6 This file is part of libopcodes.
7
8 This program is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2 of the License, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 #include "dis-asm.h"
23 #define DEFINE_TABLE
24 #include "arm-opc.h"
25 #include "coff/internal.h"
26 #include "libcoff.h"
27 #include "opintl.h"
28
29 /* start-sanitize-armelf */
30 /* FIXME: This shouldn't be done here */
31 #include "elf-bfd.h"
32 #include "elf/internal.h"
33 /* end-sanitize-armelf */
34
35 static char *arm_conditional[] =
36 {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
37 "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
38
39 static char *arm_regnames[] =
40 {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
41 "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc"};
42
43 static char *arm_fp_const[] =
44 {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
45
46 static char *arm_shift[] =
47 {"lsl", "lsr", "asr", "ror"};
48
49 static int print_insn_arm PARAMS ((bfd_vma, struct disassemble_info *,
50 long));
51
52 static void
53 arm_decode_shift (given, func, stream)
54 long given;
55 fprintf_ftype func;
56 void *stream;
57 {
58 func (stream, "%s", arm_regnames[given & 0xf]);
59 if ((given & 0xff0) != 0)
60 {
61 if ((given & 0x10) == 0)
62 {
63 int amount = (given & 0xf80) >> 7;
64 int shift = (given & 0x60) >> 5;
65 if (amount == 0)
66 {
67 if (shift == 3)
68 {
69 func (stream, ", rrx");
70 return;
71 }
72 amount = 32;
73 }
74 func (stream, ", %s #%d", arm_shift[shift], amount);
75 }
76 else
77 func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
78 arm_regnames[(given & 0xf00) >> 8]);
79 }
80 }
81
82 /* Print one instruction from PC on INFO->STREAM.
83 Return the size of the instruction (always 4 on ARM). */
84
85 static int
86 print_insn_arm (pc, info, given)
87 bfd_vma pc;
88 struct disassemble_info *info;
89 long given;
90 {
91 struct arm_opcode *insn;
92 void *stream = info->stream;
93 fprintf_ftype func = info->fprintf_func;
94
95 for (insn = arm_opcodes; insn->assembler; insn++)
96 {
97 if ((given & insn->mask) == insn->value)
98 {
99 char *c;
100 for (c = insn->assembler; *c; c++)
101 {
102 if (*c == '%')
103 {
104 switch (*++c)
105 {
106 case '%':
107 func (stream, "%%");
108 break;
109
110 case 'a':
111 if (((given & 0x000f0000) == 0x000f0000)
112 && ((given & 0x02000000) == 0))
113 {
114 int offset = given & 0xfff;
115 if ((given & 0x00800000) == 0)
116 offset = -offset;
117 (*info->print_address_func)
118 (offset + pc + 8, info);
119 }
120 else
121 {
122 func (stream, "[%s",
123 arm_regnames[(given >> 16) & 0xf]);
124 if ((given & 0x01000000) != 0)
125 {
126 if ((given & 0x02000000) == 0)
127 {
128 int offset = given & 0xfff;
129 if (offset)
130 func (stream, ", %s#%d",
131 (((given & 0x00800000) == 0)
132 ? "-" : ""), offset);
133 }
134 else
135 {
136 func (stream, ", %s",
137 (((given & 0x00800000) == 0)
138 ? "-" : ""));
139 arm_decode_shift (given, func, stream);
140 }
141
142 func (stream, "]%s",
143 ((given & 0x00200000) != 0) ? "!" : "");
144 }
145 else
146 {
147 if ((given & 0x02000000) == 0)
148 {
149 int offset = given & 0xfff;
150 if (offset)
151 func (stream, "], %s#%d",
152 (((given & 0x00800000) == 0)
153 ? "-" : ""), offset);
154 else
155 func (stream, "]");
156 }
157 else
158 {
159 func (stream, "], %s",
160 (((given & 0x00800000) == 0)
161 ? "-" : ""));
162 arm_decode_shift (given, func, stream);
163 }
164 }
165 }
166 break;
167
168 case 's':
169 if ((given & 0x004f0000) == 0x004f0000)
170 {
171 /* PC relative with immediate offset */
172 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
173 if ((given & 0x00800000) == 0)
174 offset = -offset;
175 (*info->print_address_func)
176 (offset + pc + 8, info);
177 }
178 else
179 {
180 func (stream, "[%s",
181 arm_regnames[(given >> 16) & 0xf]);
182 if ((given & 0x01000000) != 0)
183 {
184 /* pre-indexed */
185 if ((given & 0x00400000) == 0x00400000)
186 {
187 /* immediate */
188 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
189 if (offset)
190 func (stream, ", %s#%d",
191 (((given & 0x00800000) == 0)
192 ? "-" : ""), offset);
193 }
194 else
195 {
196 /* register */
197 func (stream, ", %s%s",
198 (((given & 0x00800000) == 0)
199 ? "-" : ""),
200 arm_regnames[given & 0xf]);
201 }
202
203 func (stream, "]%s",
204 ((given & 0x00200000) != 0) ? "!" : "");
205 }
206 else
207 {
208 /* post-indexed */
209 if ((given & 0x00400000) == 0x00400000)
210 {
211 /* immediate */
212 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
213 if (offset)
214 func (stream, "], %s#%d",
215 (((given & 0x00800000) == 0)
216 ? "-" : ""), offset);
217 else
218 func (stream, "]");
219 }
220 else
221 {
222 /* register */
223 func (stream, "], %s%s",
224 (((given & 0x00800000) == 0)
225 ? "-" : ""),
226 arm_regnames[given & 0xf]);
227 }
228 }
229 }
230 break;
231
232 case 'b':
233 (*info->print_address_func)
234 (BDISP (given) * 4 + pc + 8, info);
235 break;
236
237 case 'c':
238 func (stream, "%s",
239 arm_conditional [(given >> 28) & 0xf]);
240 break;
241
242 case 'm':
243 {
244 int started = 0;
245 int reg;
246
247 func (stream, "{");
248 for (reg = 0; reg < 16; reg++)
249 if ((given & (1 << reg)) != 0)
250 {
251 if (started)
252 func (stream, ", ");
253 started = 1;
254 func (stream, "%s", arm_regnames[reg]);
255 }
256 func (stream, "}");
257 }
258 break;
259
260 case 'o':
261 if ((given & 0x02000000) != 0)
262 {
263 int rotate = (given & 0xf00) >> 7;
264 int immed = (given & 0xff);
265 func (stream, "#%d",
266 ((immed << (32 - rotate))
267 | (immed >> rotate)) & 0xffffffff);
268 }
269 else
270 arm_decode_shift (given, func, stream);
271 break;
272
273 case 'p':
274 if ((given & 0x0000f000) == 0x0000f000)
275 func (stream, "p");
276 break;
277
278 case 't':
279 if ((given & 0x01200000) == 0x00200000)
280 func (stream, "t");
281 break;
282
283 case 'h':
284 if ((given & 0x00000020) == 0x00000020)
285 func (stream, "h");
286 else
287 func (stream, "b");
288 break;
289
290 case 'A':
291 func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
292 if ((given & 0x01000000) != 0)
293 {
294 int offset = given & 0xff;
295 if (offset)
296 func (stream, ", %s#%d]%s",
297 ((given & 0x00800000) == 0 ? "-" : ""),
298 offset * 4,
299 ((given & 0x00200000) != 0 ? "!" : ""));
300 else
301 func (stream, "]");
302 }
303 else
304 {
305 int offset = given & 0xff;
306 if (offset)
307 func (stream, "], %s#%d",
308 ((given & 0x00800000) == 0 ? "-" : ""),
309 offset * 4);
310 else
311 func (stream, "]");
312 }
313 break;
314
315 case 'C':
316 switch (given & 0x00090000)
317 {
318 default:
319 func (stream, "_???");
320 break;
321 case 0x90000:
322 func (stream, "_all");
323 break;
324 case 0x10000:
325 func (stream, "_ctl");
326 break;
327 case 0x80000:
328 func (stream, "_flg");
329 break;
330 }
331 break;
332
333 case 'F':
334 switch (given & 0x00408000)
335 {
336 case 0:
337 func (stream, "4");
338 break;
339 case 0x8000:
340 func (stream, "1");
341 break;
342 case 0x00400000:
343 func (stream, "2");
344 break;
345 default:
346 func (stream, "3");
347 }
348 break;
349
350 case 'P':
351 switch (given & 0x00080080)
352 {
353 case 0:
354 func (stream, "s");
355 break;
356 case 0x80:
357 func (stream, "d");
358 break;
359 case 0x00080000:
360 func (stream, "e");
361 break;
362 default:
363 func (stream, _("<illegal precision>"));
364 break;
365 }
366 break;
367 case 'Q':
368 switch (given & 0x00408000)
369 {
370 case 0:
371 func (stream, "s");
372 break;
373 case 0x8000:
374 func (stream, "d");
375 break;
376 case 0x00400000:
377 func (stream, "e");
378 break;
379 default:
380 func (stream, "p");
381 break;
382 }
383 break;
384 case 'R':
385 switch (given & 0x60)
386 {
387 case 0:
388 break;
389 case 0x20:
390 func (stream, "p");
391 break;
392 case 0x40:
393 func (stream, "m");
394 break;
395 default:
396 func (stream, "z");
397 break;
398 }
399 break;
400
401 case '0': case '1': case '2': case '3': case '4':
402 case '5': case '6': case '7': case '8': case '9':
403 {
404 int bitstart = *c++ - '0';
405 int bitend = 0;
406 while (*c >= '0' && *c <= '9')
407 bitstart = (bitstart * 10) + *c++ - '0';
408
409 switch (*c)
410 {
411 case '-':
412 c++;
413 while (*c >= '0' && *c <= '9')
414 bitend = (bitend * 10) + *c++ - '0';
415 if (!bitend)
416 abort ();
417 switch (*c)
418 {
419 case 'r':
420 {
421 long reg;
422 reg = given >> bitstart;
423 reg &= (2 << (bitend - bitstart)) - 1;
424 func (stream, "%s", arm_regnames[reg]);
425 }
426 break;
427 case 'd':
428 {
429 long reg;
430 reg = given >> bitstart;
431 reg &= (2 << (bitend - bitstart)) - 1;
432 func (stream, "%d", reg);
433 }
434 break;
435 case 'x':
436 {
437 long reg;
438 reg = given >> bitstart;
439 reg &= (2 << (bitend - bitstart)) - 1;
440 func (stream, "0x%08x", reg);
441 }
442 break;
443 case 'f':
444 {
445 long reg;
446 reg = given >> bitstart;
447 reg &= (2 << (bitend - bitstart)) - 1;
448 if (reg > 7)
449 func (stream, "#%s",
450 arm_fp_const[reg & 7]);
451 else
452 func (stream, "f%d", reg);
453 }
454 break;
455 default:
456 abort ();
457 }
458 break;
459 case '`':
460 c++;
461 if ((given & (1 << bitstart)) == 0)
462 func (stream, "%c", *c);
463 break;
464 case '\'':
465 c++;
466 if ((given & (1 << bitstart)) != 0)
467 func (stream, "%c", *c);
468 break;
469 case '?':
470 ++c;
471 if ((given & (1 << bitstart)) != 0)
472 func (stream, "%c", *c++);
473 else
474 func (stream, "%c", *++c);
475 break;
476 default:
477 abort ();
478 }
479 break;
480
481 default:
482 abort ();
483 }
484 }
485 }
486 else
487 func (stream, "%c", *c);
488 }
489 return 4;
490 }
491 }
492 abort ();
493 }
494
495 /* Print one instruction from PC on INFO->STREAM.
496 Return the size of the instruction. */
497
498 static int
499 print_insn_thumb (pc, info, given)
500 bfd_vma pc;
501 struct disassemble_info *info;
502 long given;
503 {
504 struct thumb_opcode *insn;
505 void *stream = info->stream;
506 fprintf_ftype func = info->fprintf_func;
507
508 for (insn = thumb_opcodes; insn->assembler; insn++)
509 {
510 if ((given & insn->mask) == insn->value)
511 {
512 char *c = insn->assembler;
513
514 /* Special processing for Thumb 2 instruction BL sequence: */
515 if (!*c) /* check for empty (not NULL) assembler string */
516 {
517 info->bytes_per_chunk = 4;
518 info->bytes_per_line = 4;
519
520 func (stream, "%04x\tbl\t", given & 0xffff);
521 (*info->print_address_func)
522 (BDISP23 (given) * 2 + pc + 4, info);
523 return 4;
524 }
525 else
526 {
527 info->bytes_per_chunk = 2;
528 info->bytes_per_line = 4;
529
530 given &= 0xffff;
531 func (stream, "%04x\t", given);
532 for (; *c; c++)
533 {
534 if (*c == '%')
535 {
536 int domaskpc = 0;
537 int domasklr = 0;
538 switch (*++c)
539 {
540 case '%':
541 func (stream, "%%");
542 break;
543
544 case 'S':
545 {
546 long reg;
547 reg = (given >> 3) & 0x7;
548 if (given & (1 << 6))
549 reg += 8;
550 func (stream, "%s", arm_regnames[reg]);
551 }
552 break;
553
554 case 'D':
555 {
556 long reg;
557 reg = given & 0x7;
558 if (given & (1 << 7))
559 reg += 8;
560 func (stream, "%s", arm_regnames[reg]);
561 }
562 break;
563
564 case 'T':
565 func (stream, "%s",
566 arm_conditional [(given >> 8) & 0xf]);
567 break;
568
569 case 'N':
570 if (given & (1 << 8))
571 domasklr = 1;
572 /* fall through */
573 case 'O':
574 if (*c == 'O' && (given & (1 << 8)))
575 domaskpc = 1;
576 /* fall through */
577 case 'M':
578 {
579 int started = 0;
580 int reg;
581 func (stream, "{");
582 /* It would be nice if we could spot
583 ranges, and generate the rS-rE format: */
584 for (reg = 0; (reg < 8); reg++)
585 if ((given & (1 << reg)) != 0)
586 {
587 if (started)
588 func (stream, ", ");
589 started = 1;
590 func (stream, "%s", arm_regnames[reg]);
591 }
592
593 if (domasklr)
594 {
595 if (started)
596 func (stream, ", ");
597 started = 1;
598 func (stream, "lr");
599 }
600
601 if (domaskpc)
602 {
603 if (started)
604 func (stream, ", ");
605 func (stream, "pc");
606 }
607
608 func (stream, "}");
609 }
610 break;
611
612
613 case '0': case '1': case '2': case '3': case '4':
614 case '5': case '6': case '7': case '8': case '9':
615 {
616 int bitstart = *c++ - '0';
617 int bitend = 0;
618 while (*c >= '0' && *c <= '9')
619 bitstart = (bitstart * 10) + *c++ - '0';
620
621 switch (*c)
622 {
623 case '-':
624 {
625 long reg;
626 c++;
627 while (*c >= '0' && *c <= '9')
628 bitend = (bitend * 10) + *c++ - '0';
629 if (!bitend)
630 abort ();
631 reg = given >> bitstart;
632 reg &= (2 << (bitend - bitstart)) - 1;
633 switch (*c)
634 {
635 case 'r':
636 func (stream, "%s", arm_regnames[reg]);
637 break;
638
639 case 'd':
640 func (stream, "%d", reg);
641 break;
642
643 case 'H':
644 func (stream, "%d", reg << 1);
645 break;
646
647 case 'W':
648 func (stream, "%d", reg << 2);
649 break;
650
651 case 'a':
652 /* PC-relative address -- the bottom two
653 bits of the address are dropped before
654 the calculation. */
655 info->print_address_func
656 (((pc + 4) & ~3) + (reg << 2), info);
657 break;
658
659 case 'x':
660 func (stream, "0x%04x", reg);
661 break;
662
663 case 'I':
664 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
665 func (stream, "%d", reg);
666 break;
667
668 case 'B':
669 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
670 (*info->print_address_func)
671 (reg * 2 + pc + 4, info);
672 break;
673
674 default:
675 abort();
676 }
677 }
678 break;
679
680 case '\'':
681 c++;
682 if ((given & (1 << bitstart)) != 0)
683 func (stream, "%c", *c);
684 break;
685
686 case '?':
687 ++c;
688 if ((given & (1 << bitstart)) != 0)
689 func (stream, "%c", *c++);
690 else
691 func (stream, "%c", *++c);
692 break;
693
694 default:
695 abort();
696 }
697 }
698 break;
699
700 default:
701 abort ();
702 }
703 }
704 else
705 func (stream, "%c", *c);
706 }
707 }
708 return 2;
709 }
710 }
711
712 /* no match */
713 abort ();
714 }
715
716 /* NOTE: There are no checks in these routines that the relevant number of data bytes exist */
717
718 int
719 print_insn_big_arm (pc, info)
720 bfd_vma pc;
721 struct disassemble_info *info;
722 {
723 unsigned char b[4];
724 long given;
725 int status;
726 coff_symbol_type *cs;
727 /* start-sanitize-armelf */
728 elf_symbol_type *es;
729 /* end-sanitize-armelf */
730 int is_thumb;
731
732 is_thumb = false;
733 if (info->symbols != NULL)
734 {
735 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
736 {
737 cs = coffsymbol (*info->symbols);
738 is_thumb = (cs->native->u.syment.n_sclass == C_THUMBEXT
739 || cs->native->u.syment.n_sclass == C_THUMBSTAT
740 || cs->native->u.syment.n_sclass == C_THUMBLABEL
741 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
742 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
743
744 }
745 /* start-sanitize-armelf */
746 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
747 {
748 es = *(elf_symbol_type **)(info->symbols);
749 is_thumb = (es->internal_elf_sym.st_other == C_THUMBEXT
750 || es->internal_elf_sym.st_other == C_THUMBSTAT
751 || es->internal_elf_sym.st_other == C_THUMBLABEL
752 || es->internal_elf_sym.st_other == C_THUMBEXTFUNC
753 || es->internal_elf_sym.st_other == C_THUMBSTATFUNC);
754 }
755 /* end-sanitize-armelf */
756 }
757
758 info->bytes_per_chunk = 4;
759 info->display_endian = BFD_ENDIAN_BIG;
760
761 /* Always fetch word aligned values. */
762
763 status = (*info->read_memory_func) (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
764 if (status != 0)
765 {
766 (*info->memory_error_func) (status, pc, info);
767 return -1;
768 }
769
770 if (is_thumb)
771 {
772 if (pc & 0x2)
773 {
774 given = (b[2] << 8) | b[3];
775
776 status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
777 if (status != 0)
778 {
779 info->memory_error_func (status, pc + 4, info);
780 return -1;
781 }
782
783 given |= (b[0] << 24) | (b[1] << 16);
784 }
785 else
786 {
787 given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
788 }
789 }
790 else
791 {
792 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
793 }
794
795 if (is_thumb)
796 {
797 status = print_insn_thumb (pc, info, given);
798 }
799 else
800 {
801 status = print_insn_arm (pc, info, given);
802 }
803
804 return status;
805 }
806
807 int
808 print_insn_little_arm (pc, info)
809 bfd_vma pc;
810 struct disassemble_info * info;
811 {
812 unsigned char b[4];
813 long given;
814 int status;
815 coff_symbol_type *cs;
816 /* start-sanitize-armelf */
817 elf_symbol_type *es;
818 /* end-sanitize-armelf */
819 int is_thumb;
820
821 is_thumb = false;
822 if (info->symbols != NULL)
823 {
824 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
825 {
826 cs = coffsymbol (*info->symbols);
827 is_thumb = (cs->native->u.syment.n_sclass == C_THUMBEXT
828 || cs->native->u.syment.n_sclass == C_THUMBSTAT
829 || cs->native->u.syment.n_sclass == C_THUMBLABEL
830 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
831 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
832
833 }
834 /* start-sanitize-armelf */
835 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
836 {
837 es = *(elf_symbol_type **)(info->symbols);
838 is_thumb = (es->internal_elf_sym.st_other == C_THUMBEXT
839 || es->internal_elf_sym.st_other == C_THUMBSTAT
840 || es->internal_elf_sym.st_other == C_THUMBLABEL
841 || es->internal_elf_sym.st_other == C_THUMBEXTFUNC
842 || es->internal_elf_sym.st_other == C_THUMBSTATFUNC);
843 }
844 /* end-sanitize-armelf */
845 }
846
847
848 info->bytes_per_chunk = 4;
849 info->display_endian = BFD_ENDIAN_LITTLE;
850
851 status = (*info->read_memory_func) (pc, (bfd_byte *) &b[0], 4, info);
852 if (status != 0 && is_thumb)
853 {
854 info->bytes_per_chunk = 2;
855
856 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
857 b[3] = b[2] = 0;
858 }
859 if (status != 0)
860 {
861 (*info->memory_error_func) (status, pc, info);
862 return -1;
863 }
864
865 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
866
867 if (is_thumb)
868 {
869 status = print_insn_thumb (pc, info, given);
870 }
871 else
872 {
873 status = print_insn_arm (pc, info, given);
874 }
875
876 return status;
877 }
This page took 0.047712 seconds and 3 git commands to generate.