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