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