959e023cd3658615b44b1b78068ba9e1bd89d0a1
[external/binutils.git] / opcodes / arm-dis.c
1 /* Instruction printing code for the ARM
2    Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 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 "sysdep.h"
23 #include "dis-asm.h"
24 #define DEFINE_TABLE
25 #include "arm-opc.h"
26 #include "coff/internal.h"
27 #include "libcoff.h"
28 #include "opintl.h"
29
30 /* FIXME: This shouldn't be done here */
31 #include "elf-bfd.h"
32 #include "elf/internal.h"
33 #include "elf/arm.h"
34
35 #ifndef streq
36 #define streq(a,b) (strcmp ((a), (b)) == 0)
37 #endif
38 #ifndef strneq
39 #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
40 #endif
41
42 static char * arm_conditional[] =
43 {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
44  "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
45
46 static char * arm_regnames_raw[] =
47 {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
48  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
49
50 static char * arm_regnames_standard[] =
51 {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
52  "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"};
53
54 static char * arm_regnames_apcs[] =
55 {"a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4",
56  "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc"};
57
58 /* Choose which register name set to use.  */
59 static char ** arm_regnames = arm_regnames_standard;
60
61 static boolean force_thumb = false;
62
63 static char * arm_fp_const[] =
64 {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
65
66 static char * arm_shift[] = 
67 {"lsl", "lsr", "asr", "ror"};
68 \f
69 /* Forward declarations.  */
70 static void arm_decode_shift PARAMS ((long, fprintf_ftype, void *));
71 static int  print_insn_arm   PARAMS ((bfd_vma, struct disassemble_info *, long));
72 static int  print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
73 static void parse_disassembler_option PARAMS ((char *));
74 static void parse_disassembler_options PARAMS ((char *));
75 \f
76 /* Functions. */
77 static void
78 arm_decode_shift (given, func, stream)
79      long given;
80      fprintf_ftype func;
81      void * stream;
82 {
83   func (stream, "%s", arm_regnames[given & 0xf]);
84   
85   if ((given & 0xff0) != 0)
86     {
87       if ((given & 0x10) == 0)
88         {
89           int amount = (given & 0xf80) >> 7;
90           int shift = (given & 0x60) >> 5;
91           
92           if (amount == 0)
93             {
94               if (shift == 3)
95                 {
96                   func (stream, ", rrx");
97                   return;
98                 }
99               
100               amount = 32;
101             }
102           
103           func (stream, ", %s #%d", arm_shift[shift], amount);
104         }
105       else
106         func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
107               arm_regnames[(given & 0xf00) >> 8]);
108     }
109 }
110
111 /* Print one instruction from PC on INFO->STREAM.
112    Return the size of the instruction (always 4 on ARM). */
113
114 static int
115 print_insn_arm (pc, info, given)
116      bfd_vma                   pc;
117      struct disassemble_info * info;
118      long                      given;
119 {
120   struct arm_opcode *  insn;
121   void *               stream = info->stream;
122   fprintf_ftype        func   = info->fprintf_func;
123
124   for (insn = arm_opcodes; insn->assembler; insn++)
125     {
126       if ((given & insn->mask) == insn->value)
127         {
128           char * c;
129           
130           for (c = insn->assembler; *c; c++)
131             {
132               if (*c == '%')
133                 {
134                   switch (*++c)
135                     {
136                     case '%':
137                       func (stream, "%%");
138                       break;
139
140                     case 'a':
141                       if (((given & 0x000f0000) == 0x000f0000)
142                           && ((given & 0x02000000) == 0))
143                         {
144                           int offset = given & 0xfff;
145                           
146                           func (stream, "[pc");
147  
148                           if (given & 0x01000000)
149                             {
150                               if ((given & 0x00800000) == 0)
151                                 offset = - offset;
152                           
153                               /* pre-indexed */
154                               func (stream, ", #%x]", offset);
155
156                               offset += pc + 8;
157
158                               /* Cope with the possibility of write-back being used.
159                                  Probably a very dangerous thing for the programmer
160                                  to do, but who are we to argue ?  */
161                               if (given & 0x00200000)
162                                 func (stream, "!");
163                             }
164                           else
165                             {
166                               /* post indexed */
167                               func (stream, "], #%x", offset);
168
169                               offset = pc + 8;  /* ie ignore the offset */
170                             }
171                           
172                           func (stream, "\t; ");
173                           info->print_address_func (offset, info);
174                         }
175                       else
176                         {
177                           func (stream, "[%s", 
178                                 arm_regnames[(given >> 16) & 0xf]);
179                           if ((given & 0x01000000) != 0)
180                             {
181                               if ((given & 0x02000000) == 0)
182                                 {
183                                   int offset = given & 0xfff;
184                                   if (offset)
185                                     func (stream, ", %s#%d",
186                                           (((given & 0x00800000) == 0)
187                                            ? "-" : ""), offset);
188                                 }
189                               else
190                                 {
191                                   func (stream, ", %s",
192                                         (((given & 0x00800000) == 0)
193                                          ? "-" : ""));
194                                   arm_decode_shift (given, func, stream);
195                                 }
196
197                               func (stream, "]%s", 
198                                     ((given & 0x00200000) != 0) ? "!" : "");
199                             }
200                           else
201                             {
202                               if ((given & 0x02000000) == 0)
203                                 {
204                                   int offset = given & 0xfff;
205                                   if (offset)
206                                     func (stream, "], %s#%d",
207                                           (((given & 0x00800000) == 0)
208                                            ? "-" : ""), offset);
209                                   else 
210                                     func (stream, "]");
211                                 }
212                               else
213                                 {
214                                   func (stream, "], %s",
215                                         (((given & 0x00800000) == 0) 
216                                          ? "-" : ""));
217                                   arm_decode_shift (given, func, stream);
218                                 }
219                             }
220                         }
221                       break;
222
223                     case 's':
224                       if ((given & 0x004f0000) == 0x004f0000)
225                         {
226                           /* PC relative with immediate offset */
227                           int offset = ((given & 0xf00) >> 4) | (given & 0xf);
228                           
229                           if ((given & 0x00800000) == 0)
230                             offset = -offset;
231                           
232                           func (stream, "[pc, #%x]\t; ", offset);
233                           
234                           (*info->print_address_func)
235                             (offset + pc + 8, info);
236                         }
237                       else
238                         {
239                           func (stream, "[%s", 
240                                 arm_regnames[(given >> 16) & 0xf]);
241                           if ((given & 0x01000000) != 0)
242                             {
243                               /* pre-indexed */
244                               if ((given & 0x00400000) == 0x00400000)
245                                 {
246                                   /* immediate */
247                                   int offset = ((given & 0xf00) >> 4) | (given & 0xf);
248                                   if (offset)
249                                     func (stream, ", %s#%d",
250                                           (((given & 0x00800000) == 0)
251                                            ? "-" : ""), offset);
252                                 }
253                               else
254                                 {
255                                   /* register */
256                                   func (stream, ", %s%s",
257                                         (((given & 0x00800000) == 0)
258                                          ? "-" : ""),
259                                         arm_regnames[given & 0xf]);
260                                 }
261
262                               func (stream, "]%s", 
263                                     ((given & 0x00200000) != 0) ? "!" : "");
264                             }
265                           else
266                             {
267                               /* post-indexed */
268                               if ((given & 0x00400000) == 0x00400000)
269                                 {
270                                   /* immediate */
271                                   int offset = ((given & 0xf00) >> 4) | (given & 0xf);
272                                   if (offset)
273                                     func (stream, "], %s#%d",
274                                           (((given & 0x00800000) == 0)
275                                            ? "-" : ""), offset);
276                                   else 
277                                     func (stream, "]");
278                                 }
279                               else
280                                 {
281                                   /* register */
282                                   func (stream, "], %s%s",
283                                         (((given & 0x00800000) == 0)
284                                          ? "-" : ""),
285                                         arm_regnames[given & 0xf]);
286                                 }
287                             }
288                         }
289                       break;
290                           
291                     case 'b':
292                       (*info->print_address_func)
293                         (BDISP (given) * 4 + pc + 8, info);
294                       break;
295
296                     case 'c':
297                       func (stream, "%s",
298                             arm_conditional [(given >> 28) & 0xf]);
299                       break;
300
301                     case 'm':
302                       {
303                         int started = 0;
304                         int reg;
305
306                         func (stream, "{");
307                         for (reg = 0; reg < 16; reg++)
308                           if ((given & (1 << reg)) != 0)
309                             {
310                               if (started)
311                                 func (stream, ", ");
312                               started = 1;
313                               func (stream, "%s", arm_regnames[reg]);
314                             }
315                         func (stream, "}");
316                       }
317                       break;
318
319                     case 'o':
320                       if ((given & 0x02000000) != 0)
321                         {
322                           int rotate = (given & 0xf00) >> 7;
323                           int immed = (given & 0xff);
324                           immed = (((immed << (32 - rotate))
325                                     | (immed >> rotate)) & 0xffffffff);
326                           func (stream, "#%d\t; 0x%x", immed, immed);
327                         }
328                       else
329                         arm_decode_shift (given, func, stream);
330                       break;
331
332                     case 'p':
333                       if ((given & 0x0000f000) == 0x0000f000)
334                         func (stream, "p");
335                       break;
336
337                     case 't':
338                       if ((given & 0x01200000) == 0x00200000)
339                         func (stream, "t");
340                       break;
341
342                     case 'h':
343                       if ((given & 0x00000020) == 0x00000020)
344                         func (stream, "h");
345                       else
346                         func (stream, "b");
347                       break;
348
349                     case 'A':
350                       func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
351                       if ((given & 0x01000000) != 0)
352                         {
353                           int offset = given & 0xff;
354                           if (offset)
355                             func (stream, ", %s#%d]%s",
356                                   ((given & 0x00800000) == 0 ? "-" : ""),
357                                   offset * 4,
358                                   ((given & 0x00200000) != 0 ? "!" : ""));
359                           else
360                             func (stream, "]");
361                         }
362                       else
363                         {
364                           int offset = given & 0xff;
365                           if (offset)
366                             func (stream, "], %s#%d",
367                                   ((given & 0x00800000) == 0 ? "-" : ""),
368                                   offset * 4);
369                           else
370                             func (stream, "]");
371                         }
372                       break;
373
374                     case 'C':
375                       switch (given & 0x00090000)
376                         {
377                         default:
378                           func (stream, "_???");
379                           break;
380                         case 0x90000:
381                           func (stream, "_all");
382                           break;
383                         case 0x10000:
384                           func (stream, "_ctl");
385                           break;
386                         case 0x80000:
387                           func (stream, "_flg");
388                           break;
389                         }
390                       break;
391
392                     case 'F':
393                       switch (given & 0x00408000)
394                         {
395                         case 0:
396                           func (stream, "4");
397                           break;
398                         case 0x8000:
399                           func (stream, "1");
400                           break;
401                         case 0x00400000:
402                           func (stream, "2");
403                           break;
404                         default:
405                           func (stream, "3");
406                         }
407                       break;
408                         
409                     case 'P':
410                       switch (given & 0x00080080)
411                         {
412                         case 0:
413                           func (stream, "s");
414                           break;
415                         case 0x80:
416                           func (stream, "d");
417                           break;
418                         case 0x00080000:
419                           func (stream, "e");
420                           break;
421                         default:
422                           func (stream, _("<illegal precision>"));
423                           break;
424                         }
425                       break;
426                     case 'Q':
427                       switch (given & 0x00408000)
428                         {
429                         case 0:
430                           func (stream, "s");
431                           break;
432                         case 0x8000:
433                           func (stream, "d");
434                           break;
435                         case 0x00400000:
436                           func (stream, "e");
437                           break;
438                         default:
439                           func (stream, "p");
440                           break;
441                         }
442                       break;
443                     case 'R':
444                       switch (given & 0x60)
445                         {
446                         case 0:
447                           break;
448                         case 0x20:
449                           func (stream, "p");
450                           break;
451                         case 0x40:
452                           func (stream, "m");
453                           break;
454                         default:
455                           func (stream, "z");
456                           break;
457                         }
458                       break;
459
460                     case '0': case '1': case '2': case '3': case '4': 
461                     case '5': case '6': case '7': case '8': case '9':
462                       {
463                         int bitstart = *c++ - '0';
464                         int bitend = 0;
465                         while (*c >= '0' && *c <= '9')
466                           bitstart = (bitstart * 10) + *c++ - '0';
467
468                         switch (*c)
469                           {
470                           case '-':
471                             c++;
472                             while (*c >= '0' && *c <= '9')
473                               bitend = (bitend * 10) + *c++ - '0';
474                             if (!bitend)
475                               abort ();
476                             switch (*c)
477                               {
478                               case 'r':
479                                 {
480                                   long reg;
481                                   reg = given >> bitstart;
482                                   reg &= (2 << (bitend - bitstart)) - 1;
483                                   func (stream, "%s", arm_regnames[reg]);
484                                 }
485                                 break;
486                               case 'd':
487                                 {
488                                   long reg;
489                                   reg = given >> bitstart;
490                                   reg &= (2 << (bitend - bitstart)) - 1;
491                                   func (stream, "%d", reg);
492                                 }
493                                 break;
494                               case 'x':
495                                 {
496                                   long reg;
497                                   reg = given >> bitstart;
498                                   reg &= (2 << (bitend - bitstart)) - 1;
499                                   func (stream, "0x%08x", reg);
500                                   
501                                   /* Some SWI instructions have special meanings.  */
502                                   if ((given & 0x0fffffff) == 0x0FF00000)
503                                     func (stream, "\t; IMB");
504                                   else if ((given & 0x0fffffff) == 0x0FF00001)
505                                     func (stream, "\t; IMBRange");
506                                 }
507                                 break;
508                               case 'X':
509                                 {
510                                   long reg;
511                                   reg = given >> bitstart;
512                                   reg &= (2 << (bitend - bitstart)) - 1;
513                                   func (stream, "%01x", reg & 0xf);
514                                 }
515                                 break;
516                               case 'f':
517                                 {
518                                   long reg;
519                                   reg = given >> bitstart;
520                                   reg &= (2 << (bitend - bitstart)) - 1;
521                                   if (reg > 7)
522                                     func (stream, "#%s",
523                                           arm_fp_const[reg & 7]);
524                                   else
525                                     func (stream, "f%d", reg);
526                                 }
527                                 break;
528                               default:
529                                 abort ();
530                               }
531                             break;
532                           case '`':
533                             c++;
534                             if ((given & (1 << bitstart)) == 0)
535                               func (stream, "%c", *c);
536                             break;
537                           case '\'':
538                             c++;
539                             if ((given & (1 << bitstart)) != 0)
540                               func (stream, "%c", *c);
541                             break;
542                           case '?':
543                             ++c;
544                             if ((given & (1 << bitstart)) != 0)
545                               func (stream, "%c", *c++);
546                             else
547                               func (stream, "%c", *++c);
548                             break;
549                           default:
550                             abort ();
551                           }
552                         break;
553
554                       default:
555                         abort ();
556                       }
557                     }
558                 }
559               else
560                 func (stream, "%c", *c);
561             }
562           return 4;
563         }
564     }
565   abort ();
566 }
567
568 /* Print one instruction from PC on INFO->STREAM.
569    Return the size of the instruction. */
570
571 static int
572 print_insn_thumb (pc, info, given)
573      bfd_vma                   pc;
574      struct disassemble_info * info;
575      long                      given;
576 {
577   struct thumb_opcode * insn;
578   void *                stream = info->stream;
579   fprintf_ftype         func = info->fprintf_func;
580
581   for (insn = thumb_opcodes; insn->assembler; insn++)
582     {
583       if ((given & insn->mask) == insn->value)
584         {
585           char * c = insn->assembler;
586
587           /* Special processing for Thumb 2 instruction BL sequence: */
588           if (!*c) /* check for empty (not NULL) assembler string */
589             {
590               info->bytes_per_chunk = 4;
591               info->bytes_per_line  = 4;
592               
593               func (stream, "bl\t");
594               (*info->print_address_func)
595                 (BDISP23 (given) * 2 + pc + 4, info);
596               return 4;
597             }
598           else
599             {
600               info->bytes_per_chunk = 2;
601               info->bytes_per_line  = 4;
602                       
603               given &= 0xffff;
604
605               for (; *c; c++)
606                 {
607                   if (*c == '%')
608                     {
609                       int domaskpc = 0;
610                       int domasklr = 0;
611                       
612                       switch (*++c)
613                         {
614                         case '%':
615                           func (stream, "%%");
616                           break;
617
618                         case 'S':
619                           {
620                             long reg;
621                             reg = (given >> 3) & 0x7;
622                             if (given & (1 << 6))
623                               reg += 8;
624                             func (stream, "%s", arm_regnames[reg]);
625                           }
626                           break;
627
628                         case 'D':
629                           {
630                             long reg;
631                             
632                             reg = given & 0x7;
633                             if (given & (1 << 7))
634                              reg += 8;
635                             func (stream, "%s", arm_regnames[reg]);
636                           }
637                           break;
638
639                         case 'T':
640                           func (stream, "%s",
641                                 arm_conditional [(given >> 8) & 0xf]);
642                           break;
643
644                         case 'N':
645                           if (given & (1 << 8))
646                             domasklr = 1;
647                           /* fall through */
648                         case 'O':
649                           if (*c == 'O' && (given & (1 << 8)))
650                             domaskpc = 1;
651                           /* fall through */
652                         case 'M':
653                           {
654                             int started = 0;
655                             int reg;
656                             
657                             func (stream, "{");
658                             /* It would be nice if we could spot
659                                ranges, and generate the rS-rE format: */
660                             for (reg = 0; (reg < 8); reg++)
661                               if ((given & (1 << reg)) != 0)
662                                 {
663                                   if (started)
664                                     func (stream, ", ");
665                                   started = 1;
666                                   func (stream, "%s", arm_regnames[reg]);
667                                 }
668
669                             if (domasklr)
670                               {
671                                 if (started)
672                                   func (stream, ", ");
673                                 started = 1;
674                                 func (stream, "lr");
675                               }
676
677                             if (domaskpc)
678                               {
679                                 if (started)
680                                   func (stream, ", ");
681                                 func (stream, "pc");
682                               }
683
684                             func (stream, "}");
685                           }
686                           break;
687
688
689                         case '0': case '1': case '2': case '3': case '4': 
690                         case '5': case '6': case '7': case '8': case '9':
691                           {
692                             int bitstart = *c++ - '0';
693                             int bitend = 0;
694                             
695                             while (*c >= '0' && *c <= '9')
696                               bitstart = (bitstart * 10) + *c++ - '0';
697
698                             switch (*c)
699                               {
700                               case '-':
701                                 {
702                                   long reg;
703                                   
704                                   c++;
705                                   while (*c >= '0' && *c <= '9')
706                                     bitend = (bitend * 10) + *c++ - '0';
707                                   if (!bitend)
708                                     abort ();
709                                   reg = given >> bitstart;
710                                   reg &= (2 << (bitend - bitstart)) - 1;
711                                   switch (*c)
712                                     {
713                                     case 'r':
714                                       func (stream, "%s", arm_regnames[reg]);
715                                       break;
716
717                                     case 'd':
718                                       func (stream, "%d", reg);
719                                       break;
720
721                                     case 'H':
722                                       func (stream, "%d", reg << 1);
723                                       break;
724
725                                     case 'W':
726                                       func (stream, "%d", reg << 2);
727                                       break;
728
729                                     case 'a':
730                                       /* PC-relative address -- the bottom two
731                                          bits of the address are dropped before
732                                          the calculation.  */
733                                       info->print_address_func
734                                         (((pc + 4) & ~3) + (reg << 2), info);
735                                       break;
736
737                                     case 'x':
738                                       func (stream, "0x%04x", reg);
739                                       break;
740
741                                     case 'I':
742                                       reg = ((reg ^ (1 << bitend)) - (1 << bitend));
743                                       func (stream, "%d", reg);
744                                       break;
745
746                                     case 'B':
747                                       reg = ((reg ^ (1 << bitend)) - (1 << bitend));
748                                       (*info->print_address_func)
749                                         (reg * 2 + pc + 4, info);
750                                       break;
751
752                                     default:
753                                       abort ();
754                                     }
755                                 }
756                                 break;
757
758                               case '\'':
759                                 c++;
760                                 if ((given & (1 << bitstart)) != 0)
761                                   func (stream, "%c", *c);
762                                 break;
763
764                               case '?':
765                                 ++c;
766                                 if ((given & (1 << bitstart)) != 0)
767                                   func (stream, "%c", *c++);
768                                 else
769                                   func (stream, "%c", *++c);
770                                 break;
771
772                               default:
773                                  abort ();
774                               }
775                           }
776                           break;
777
778                         default:
779                           abort ();
780                         }
781                     }
782                   else
783                     func (stream, "%c", *c);
784                 }
785              }
786           return 2;
787        }
788     }
789
790   /* no match */
791   abort ();
792 }
793
794 /* Select a different register name set.
795    Returns true if the name set selected is the APCS name set.  */
796 int
797 arm_toggle_regnames ()
798 {
799   if (arm_regnames == arm_regnames_standard)
800     arm_regnames = arm_regnames_apcs;
801   else
802     arm_regnames = arm_regnames_standard;
803
804   return arm_regnames == arm_regnames_apcs;
805 }
806
807 static void
808 parse_disassembler_option (option)
809      char * option;
810 {
811   if (option == NULL)
812     return;
813       
814   if (strneq (option, "reg-names-", 10))
815     {
816       option += 10;
817       
818       if (streq (option, "std"))
819         arm_regnames = arm_regnames_standard;
820       else if (streq (option, "apcs"))
821         arm_regnames = arm_regnames_apcs;
822       else if (streq (option, "raw"))
823         arm_regnames = arm_regnames_raw;
824       else
825         fprintf (stderr, "Unrecognised register name set: %s\n", option);
826     }
827   else if (streq (option, "force-thumb"))
828     force_thumb = 1;
829   else if (streq (option, "no-force-thumb"))
830     force_thumb = 0;
831   else
832     fprintf (stderr, "Unrecognised disassembler option: %s\n", option);
833   
834   return;
835 }
836
837 static void
838 parse_disassembler_options (options)
839      char * options;
840 {
841   char * space;
842   
843   if (options == NULL)
844     return;
845
846   do
847     {
848       space = strchr (options, ' ');
849
850       if (space)
851         {
852           * space = '\0';
853           parse_disassembler_option (options);
854           * space = ' ';
855           options = space + 1;
856         }
857       else
858         parse_disassembler_option (options);
859     }
860   while (space);
861 }
862
863 /* NOTE: There are no checks in these routines that the relevant number of
864    data bytes exist.  */
865
866 int
867 print_insn_big_arm (pc, info)
868      bfd_vma pc;
869      struct disassemble_info * info;
870 {
871   unsigned char      b[4];
872   long               given;
873   int                status;
874   int                is_thumb;
875   
876   if (info->disassembler_options)
877     {
878       parse_disassembler_options (info->disassembler_options);
879       
880       /* To avoid repeated parsing of the options, we remove it here.  */
881       info->disassembler_options = NULL;
882     }
883   
884   is_thumb = force_thumb;
885   
886   if (!is_thumb && info->symbols != NULL)
887     {
888       if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
889         {
890           coff_symbol_type * cs;
891           
892           cs = coffsymbol (*info->symbols);
893           is_thumb = (   cs->native->u.syment.n_sclass == C_THUMBEXT
894                       || cs->native->u.syment.n_sclass == C_THUMBSTAT
895                       || cs->native->u.syment.n_sclass == C_THUMBLABEL
896                       || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
897                       || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
898         }
899       else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
900         {
901           elf_symbol_type *  es;
902           
903           es = *(elf_symbol_type **)(info->symbols);
904           is_thumb = (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_TFUNC)
905                   || (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_16BIT);
906         }
907     }
908
909   info->bytes_per_chunk = 4;
910   info->display_endian = BFD_ENDIAN_BIG;
911
912   /* Always fetch word aligned values.  */
913   
914   status = (*info->read_memory_func) (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
915   if (status != 0)
916     {
917       (*info->memory_error_func) (status, pc, info);
918       return -1;
919     }
920
921   if (is_thumb)
922     {
923       if (pc & 0x2)
924         {
925           given = (b[2] << 8) | b[3];
926
927           status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
928           if (status != 0)
929             {
930               info->memory_error_func (status, pc + 4, info);
931               return -1;
932             }
933           
934           given |= (b[0] << 24) | (b[1] << 16);
935         }
936       else
937         given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
938     }
939   else
940     given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
941
942   if (is_thumb)
943     status = print_insn_thumb (pc, info, given);
944   else
945     status = print_insn_arm (pc, info, given);
946
947   return status;
948 }
949
950 int
951 print_insn_little_arm (pc, info)
952      bfd_vma pc;
953      struct disassemble_info * info;
954 {
955   unsigned char      b[4];
956   long               given;
957   int                status;
958   int                is_thumb;
959
960   if (info->disassembler_options)
961     {
962       parse_disassembler_options (info->disassembler_options);
963       
964       /* To avoid repeated parsing of the options, we remove it here.  */
965       info->disassembler_options = NULL;
966     }
967
968   is_thumb = force_thumb;
969   
970   if (!is_thumb && info->symbols != NULL)
971     {
972       if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
973         {
974           coff_symbol_type * cs;
975           
976           cs = coffsymbol (*info->symbols);
977           is_thumb = (   cs->native->u.syment.n_sclass == C_THUMBEXT
978                       || cs->native->u.syment.n_sclass == C_THUMBSTAT
979                       || cs->native->u.syment.n_sclass == C_THUMBLABEL
980                       || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
981                       || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
982         }
983       else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
984         {
985           elf_symbol_type *  es;
986           
987           es = *(elf_symbol_type **)(info->symbols);
988           is_thumb = (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_TFUNC)
989                   || (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_16BIT);
990         }
991     }
992   
993   info->bytes_per_chunk = 4;
994   info->display_endian = BFD_ENDIAN_LITTLE;
995
996   status = (*info->read_memory_func) (pc, (bfd_byte *) &b[0], 4, info);
997   if (status != 0 && is_thumb)
998     {
999       info->bytes_per_chunk = 2;
1000
1001       status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1002       b[3] = b[2] = 0;
1003     }
1004   
1005   if (status != 0)
1006     {
1007       info->memory_error_func (status, pc, info);
1008       return -1;
1009     }
1010
1011   given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
1012
1013   if (is_thumb)
1014     status = print_insn_thumb (pc, info, given);
1015   else
1016     status = print_insn_arm (pc, info, given);
1017
1018   return status;
1019 }