* config.guess: More accurate determination of HP processor types.
[external/binutils.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   asymbol *          saved_symbol;
713   coff_symbol_type * cs;
714   int                is_thumb;
715   
716   cs = coffsymbol (info->symbol);
717   is_thumb = 
718      (   cs->native->u.syment.n_sclass == C_THUMBEXT
719       || cs->native->u.syment.n_sclass == C_THUMBSTAT
720       || cs->native->u.syment.n_sclass == C_THUMBLABEL
721       || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
722       || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
723
724   info->bytes_per_chunk = 4;
725   info->display_endian = BFD_ENDIAN_BIG;
726
727   /* Always fetch word aligned values.  */
728   
729   status = (*info->read_memory_func) (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
730   if (status != 0)
731     {
732       (*info->memory_error_func) (status, pc, info);
733       return -1;
734     }
735
736   if (is_thumb)
737     {
738       if (pc & 0x2)
739         {
740           given = (b[2] << 8) | b[3];
741
742           status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
743           if (status != 0)
744             {
745               info->memory_error_func (status, pc + 4, info);
746               return -1;
747             }
748           
749           given |= (b[0] << 24) | (b[1] << 16);
750         }
751       else
752         {
753           given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
754         }
755     }
756   else
757     {
758       given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
759     }
760
761   if (is_thumb)
762     {
763       status = print_insn_thumb (pc, info, given);
764     }
765   else
766     {
767       status = print_insn_arm (pc, info, given);
768     }
769
770   info->symbol = saved_symbol; /* Stop displayed symbols from resetting the stored symbol */
771   
772   return status;
773 }
774
775 int
776 print_insn_little_arm (pc, info)
777      bfd_vma pc;
778      struct disassemble_info * info;
779 {
780   unsigned char      b[4];
781   long               given;
782   int                status;
783   asymbol *          saved_symbol;
784   coff_symbol_type * cs;
785   int                is_thumb;
786   
787   cs = coffsymbol (info->symbol);
788   is_thumb = 
789      (   cs->native->u.syment.n_sclass == C_THUMBEXT
790       || cs->native->u.syment.n_sclass == C_THUMBSTAT
791       || cs->native->u.syment.n_sclass == C_THUMBLABEL
792       || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
793       || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
794
795   info->bytes_per_chunk = 4;
796   info->display_endian = BFD_ENDIAN_LITTLE;
797
798   status = (*info->read_memory_func) (pc, (bfd_byte *) &b[0], 4, info);
799   if (status != 0 && is_thumb)
800     {
801       info->bytes_per_chunk = 2;
802
803       status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
804       b[3] = b[2] = 0;
805     }
806   if (status != 0)
807     {
808       (*info->memory_error_func) (status, pc, info);
809       return -1;
810     }
811
812   given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
813
814   saved_symbol = info->symbol;
815   
816   if (is_thumb)
817     {
818       status = print_insn_thumb (pc, info, given);
819     }
820   else
821     {
822       status = print_insn_arm (pc, info, given);
823     }
824
825   info->symbol = saved_symbol; /* Stop displayed symbols from resetting the stored symbol */
826
827   return status;
828 }