12159047fSniklas /* Instruction printing code for the ARM
2c074d1c9Sdrahn Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3b55d4692Sfgsch Free Software Foundation, Inc.
42159047fSniklas Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5b305b0f1Sespie Modification by James G. Smith (jsmith@cygnus.co.uk)
62159047fSniklas
72159047fSniklas This file is part of libopcodes.
82159047fSniklas
92159047fSniklas This program is free software; you can redistribute it and/or modify it under
102159047fSniklas the terms of the GNU General Public License as published by the Free
112159047fSniklas Software Foundation; either version 2 of the License, or (at your option)
122159047fSniklas any later version.
132159047fSniklas
142159047fSniklas This program is distributed in the hope that it will be useful, but WITHOUT
152159047fSniklas ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
162159047fSniklas FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
172159047fSniklas more details.
182159047fSniklas
19b305b0f1Sespie You should have received a copy of the GNU General Public License
20b305b0f1Sespie along with this program; if not, write to the Free Software
21b305b0f1Sespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
222159047fSniklas
23b305b0f1Sespie #include "sysdep.h"
242159047fSniklas #include "dis-asm.h"
252159047fSniklas #define DEFINE_TABLE
262159047fSniklas #include "arm-opc.h"
27b305b0f1Sespie #include "coff/internal.h"
28b305b0f1Sespie #include "libcoff.h"
29b305b0f1Sespie #include "opintl.h"
30*007c2a45Smiod #include "safe-ctype.h"
312159047fSniklas
32c074d1c9Sdrahn /* FIXME: This shouldn't be done here. */
33b305b0f1Sespie #include "elf-bfd.h"
34b305b0f1Sespie #include "elf/internal.h"
35b305b0f1Sespie #include "elf/arm.h"
36b305b0f1Sespie
37b305b0f1Sespie #ifndef streq
38b305b0f1Sespie #define streq(a,b) (strcmp ((a), (b)) == 0)
39b305b0f1Sespie #endif
40b305b0f1Sespie
41b305b0f1Sespie #ifndef strneq
42b305b0f1Sespie #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
43b305b0f1Sespie #endif
44b305b0f1Sespie
45b305b0f1Sespie #ifndef NUM_ELEM
46b305b0f1Sespie #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
47b305b0f1Sespie #endif
482159047fSniklas
492159047fSniklas static char * arm_conditional[] =
502159047fSniklas {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
512159047fSniklas "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
522159047fSniklas
53b305b0f1Sespie typedef struct
54b305b0f1Sespie {
55b305b0f1Sespie const char * name;
56b305b0f1Sespie const char * description;
57b305b0f1Sespie const char * reg_names[16];
58b305b0f1Sespie }
59b305b0f1Sespie arm_regname;
60b305b0f1Sespie
61b305b0f1Sespie static arm_regname regnames[] =
62b305b0f1Sespie {
63b305b0f1Sespie { "raw" , "Select raw register names",
64b305b0f1Sespie { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
65b55d4692Sfgsch { "gcc", "Select register names used by GCC",
66b55d4692Sfgsch { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
67b305b0f1Sespie { "std", "Select register names used in ARM's ISA documentation",
68b305b0f1Sespie { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
69b305b0f1Sespie { "apcs", "Select register names used in the APCS",
70b305b0f1Sespie { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
71b305b0f1Sespie { "atpcs", "Select register names used in the ATPCS",
72b305b0f1Sespie { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
73b305b0f1Sespie { "special-atpcs", "Select special register names used in the ATPCS",
74c074d1c9Sdrahn { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }},
75c074d1c9Sdrahn { "iwmmxt_regnames", "Select register names used on the Intel Wireless MMX technology coprocessor",
76c074d1c9Sdrahn { "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15"}},
77c074d1c9Sdrahn { "iwmmxt_Cregnames", "Select control register names used on the Intel Wireless MMX technology coprocessor",
78c074d1c9Sdrahn {"wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved"}}
79c074d1c9Sdrahn };
80c074d1c9Sdrahn
81c074d1c9Sdrahn static char * iwmmxt_wwnames[] =
82c074d1c9Sdrahn {"b", "h", "w", "d"};
83c074d1c9Sdrahn
84c074d1c9Sdrahn static char * iwmmxt_wwssnames[] =
85c074d1c9Sdrahn {"b", "bus", "b", "bss",
86c074d1c9Sdrahn "h", "hus", "h", "hss",
87c074d1c9Sdrahn "w", "wus", "w", "wss",
88c074d1c9Sdrahn "d", "dus", "d", "dss"
89b305b0f1Sespie };
90b305b0f1Sespie
91b55d4692Sfgsch /* Default to GCC register name set. */
92b305b0f1Sespie static unsigned int regname_selected = 1;
93b305b0f1Sespie
94b305b0f1Sespie #define NUM_ARM_REGNAMES NUM_ELEM (regnames)
95b305b0f1Sespie #define arm_regnames regnames[regname_selected].reg_names
96b305b0f1Sespie
97c074d1c9Sdrahn static bfd_boolean force_thumb = FALSE;
982159047fSniklas
992159047fSniklas static char * arm_fp_const[] =
1002159047fSniklas {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
1012159047fSniklas
1022159047fSniklas static char * arm_shift[] =
1032159047fSniklas {"lsl", "lsr", "asr", "ror"};
104b305b0f1Sespie
105b305b0f1Sespie /* Forward declarations. */
106c074d1c9Sdrahn static void arm_decode_shift
107c074d1c9Sdrahn PARAMS ((long, fprintf_ftype, void *));
108c074d1c9Sdrahn static int print_insn_arm
109c074d1c9Sdrahn PARAMS ((bfd_vma, struct disassemble_info *, long));
110c074d1c9Sdrahn static int print_insn_thumb
111c074d1c9Sdrahn PARAMS ((bfd_vma, struct disassemble_info *, long));
112c074d1c9Sdrahn static void parse_disassembler_options
113c074d1c9Sdrahn PARAMS ((char *));
114c074d1c9Sdrahn static int print_insn
115c074d1c9Sdrahn PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean));
116c074d1c9Sdrahn static int set_iwmmxt_regnames
117c074d1c9Sdrahn PARAMS ((void));
118c074d1c9Sdrahn
119c074d1c9Sdrahn int get_arm_regname_num_options
120c074d1c9Sdrahn PARAMS ((void));
121c074d1c9Sdrahn int set_arm_regname_option
122c074d1c9Sdrahn PARAMS ((int));
123c074d1c9Sdrahn int get_arm_regnames
124c074d1c9Sdrahn PARAMS ((int, const char **, const char **, const char ***));
125b305b0f1Sespie
126b305b0f1Sespie /* Functions. */
127b305b0f1Sespie int
get_arm_regname_num_options()128c074d1c9Sdrahn get_arm_regname_num_options ()
129b305b0f1Sespie {
130b305b0f1Sespie return NUM_ARM_REGNAMES;
131b305b0f1Sespie }
132b305b0f1Sespie
133b305b0f1Sespie int
set_arm_regname_option(option)134c074d1c9Sdrahn set_arm_regname_option (option)
135c074d1c9Sdrahn int option;
136b305b0f1Sespie {
137b305b0f1Sespie int old = regname_selected;
138b305b0f1Sespie regname_selected = option;
139b305b0f1Sespie return old;
140b305b0f1Sespie }
141b305b0f1Sespie
142b305b0f1Sespie int
get_arm_regnames(option,setname,setdescription,register_names)143c074d1c9Sdrahn get_arm_regnames (option, setname, setdescription, register_names)
144c074d1c9Sdrahn int option;
145c074d1c9Sdrahn const char **setname;
146c074d1c9Sdrahn const char **setdescription;
147c074d1c9Sdrahn const char ***register_names;
148b305b0f1Sespie {
149b305b0f1Sespie *setname = regnames[option].name;
150b305b0f1Sespie *setdescription = regnames[option].description;
151b305b0f1Sespie *register_names = regnames[option].reg_names;
152b305b0f1Sespie return 16;
153b305b0f1Sespie }
1542159047fSniklas
1552159047fSniklas static void
arm_decode_shift(given,func,stream)1562159047fSniklas arm_decode_shift (given, func, stream)
1572159047fSniklas long given;
1582159047fSniklas fprintf_ftype func;
1592159047fSniklas void * stream;
1602159047fSniklas {
1612159047fSniklas func (stream, "%s", arm_regnames[given & 0xf]);
162b305b0f1Sespie
1632159047fSniklas if ((given & 0xff0) != 0)
1642159047fSniklas {
1652159047fSniklas if ((given & 0x10) == 0)
1662159047fSniklas {
1672159047fSniklas int amount = (given & 0xf80) >> 7;
1682159047fSniklas int shift = (given & 0x60) >> 5;
169b305b0f1Sespie
1702159047fSniklas if (amount == 0)
1712159047fSniklas {
1722159047fSniklas if (shift == 3)
1732159047fSniklas {
1742159047fSniklas func (stream, ", rrx");
1752159047fSniklas return;
1762159047fSniklas }
177b305b0f1Sespie
1782159047fSniklas amount = 32;
1792159047fSniklas }
180b305b0f1Sespie
181b305b0f1Sespie func (stream, ", %s #%d", arm_shift[shift], amount);
1822159047fSniklas }
1832159047fSniklas else
1842159047fSniklas func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
1852159047fSniklas arm_regnames[(given & 0xf00) >> 8]);
1862159047fSniklas }
1872159047fSniklas }
1882159047fSniklas
189c074d1c9Sdrahn static int
set_iwmmxt_regnames()190c074d1c9Sdrahn set_iwmmxt_regnames ()
191c074d1c9Sdrahn {
192c074d1c9Sdrahn const char * setname;
193c074d1c9Sdrahn const char * setdesc;
194c074d1c9Sdrahn const char ** regnames;
195c074d1c9Sdrahn int iwmmxt_regnames = 0;
196c074d1c9Sdrahn int num_regnames = get_arm_regname_num_options ();
197c074d1c9Sdrahn
198c074d1c9Sdrahn get_arm_regnames (iwmmxt_regnames, &setname,
199c074d1c9Sdrahn &setdesc, ®names);
200c074d1c9Sdrahn while ((strcmp ("iwmmxt_regnames", setname))
201c074d1c9Sdrahn && (iwmmxt_regnames < num_regnames))
202c074d1c9Sdrahn get_arm_regnames (++iwmmxt_regnames, &setname, &setdesc, ®names);
203c074d1c9Sdrahn
204c074d1c9Sdrahn return iwmmxt_regnames;
205c074d1c9Sdrahn }
206c074d1c9Sdrahn
2072159047fSniklas /* Print one instruction from PC on INFO->STREAM.
2082159047fSniklas Return the size of the instruction (always 4 on ARM). */
209c074d1c9Sdrahn
2102159047fSniklas static int
print_insn_arm(pc,info,given)2112159047fSniklas print_insn_arm (pc, info, given)
2122159047fSniklas bfd_vma pc;
2132159047fSniklas struct disassemble_info *info;
2142159047fSniklas long given;
2152159047fSniklas {
216c074d1c9Sdrahn const struct arm_opcode *insn;
2172159047fSniklas void *stream = info->stream;
2182159047fSniklas fprintf_ftype func = info->fprintf_func;
219c074d1c9Sdrahn static int iwmmxt_regnames = 0;
2202159047fSniklas
2212159047fSniklas for (insn = arm_opcodes; insn->assembler; insn++)
2222159047fSniklas {
223c074d1c9Sdrahn if (insn->value == FIRST_IWMMXT_INSN
224c074d1c9Sdrahn && info->mach != bfd_mach_arm_XScale
225c074d1c9Sdrahn && info->mach != bfd_mach_arm_iWMMXt)
226c074d1c9Sdrahn insn = insn + IWMMXT_INSN_COUNT;
227c074d1c9Sdrahn
2282159047fSniklas if ((given & insn->mask) == insn->value)
2292159047fSniklas {
2302159047fSniklas char * c;
231b305b0f1Sespie
2322159047fSniklas for (c = insn->assembler; *c; c++)
2332159047fSniklas {
2342159047fSniklas if (*c == '%')
2352159047fSniklas {
2362159047fSniklas switch (*++c)
2372159047fSniklas {
2382159047fSniklas case '%':
2392159047fSniklas func (stream, "%%");
2402159047fSniklas break;
2412159047fSniklas
2422159047fSniklas case 'a':
2432159047fSniklas if (((given & 0x000f0000) == 0x000f0000)
2442159047fSniklas && ((given & 0x02000000) == 0))
2452159047fSniklas {
2462159047fSniklas int offset = given & 0xfff;
247b305b0f1Sespie
248b305b0f1Sespie func (stream, "[pc");
249b305b0f1Sespie
250b305b0f1Sespie if (given & 0x01000000)
251b305b0f1Sespie {
2522159047fSniklas if ((given & 0x00800000) == 0)
2532159047fSniklas offset = - offset;
254b305b0f1Sespie
255c074d1c9Sdrahn /* Pre-indexed. */
256c074d1c9Sdrahn func (stream, ", #%d]", offset);
257b305b0f1Sespie
258b305b0f1Sespie offset += pc + 8;
259b305b0f1Sespie
260b305b0f1Sespie /* Cope with the possibility of write-back
261b305b0f1Sespie being used. Probably a very dangerous thing
262b305b0f1Sespie for the programmer to do, but who are we to
263b305b0f1Sespie argue ? */
264b305b0f1Sespie if (given & 0x00200000)
265b305b0f1Sespie func (stream, "!");
266b305b0f1Sespie }
267b305b0f1Sespie else
268b305b0f1Sespie {
269b305b0f1Sespie /* Post indexed. */
270c074d1c9Sdrahn func (stream, "], #%d", offset);
271b305b0f1Sespie
272c074d1c9Sdrahn /* ie ignore the offset. */
273c074d1c9Sdrahn offset = pc + 8;
274b305b0f1Sespie }
275b305b0f1Sespie
276b305b0f1Sespie func (stream, "\t; ");
277b305b0f1Sespie info->print_address_func (offset, info);
2782159047fSniklas }
2792159047fSniklas else
2802159047fSniklas {
2812159047fSniklas func (stream, "[%s",
2822159047fSniklas arm_regnames[(given >> 16) & 0xf]);
2832159047fSniklas if ((given & 0x01000000) != 0)
2842159047fSniklas {
2852159047fSniklas if ((given & 0x02000000) == 0)
2862159047fSniklas {
2872159047fSniklas int offset = given & 0xfff;
2882159047fSniklas if (offset)
289*007c2a45Smiod func (stream, ", #%s%d",
2902159047fSniklas (((given & 0x00800000) == 0)
2912159047fSniklas ? "-" : ""), offset);
2922159047fSniklas }
2932159047fSniklas else
2942159047fSniklas {
2952159047fSniklas func (stream, ", %s",
2962159047fSniklas (((given & 0x00800000) == 0)
2972159047fSniklas ? "-" : ""));
2982159047fSniklas arm_decode_shift (given, func, stream);
2992159047fSniklas }
3002159047fSniklas
3012159047fSniklas func (stream, "]%s",
3022159047fSniklas ((given & 0x00200000) != 0) ? "!" : "");
3032159047fSniklas }
3042159047fSniklas else
3052159047fSniklas {
3062159047fSniklas if ((given & 0x02000000) == 0)
3072159047fSniklas {
3082159047fSniklas int offset = given & 0xfff;
3092159047fSniklas if (offset)
310*007c2a45Smiod func (stream, "], #%s%d",
3112159047fSniklas (((given & 0x00800000) == 0)
3122159047fSniklas ? "-" : ""), offset);
3132159047fSniklas else
3142159047fSniklas func (stream, "]");
3152159047fSniklas }
3162159047fSniklas else
3172159047fSniklas {
3182159047fSniklas func (stream, "], %s",
3192159047fSniklas (((given & 0x00800000) == 0)
3202159047fSniklas ? "-" : ""));
3212159047fSniklas arm_decode_shift (given, func, stream);
3222159047fSniklas }
3232159047fSniklas }
3242159047fSniklas }
3252159047fSniklas break;
3262159047fSniklas
3274361b62eSniklas case 's':
3284361b62eSniklas if ((given & 0x004f0000) == 0x004f0000)
3294361b62eSniklas {
330b305b0f1Sespie /* PC relative with immediate offset. */
3314361b62eSniklas int offset = ((given & 0xf00) >> 4) | (given & 0xf);
332b305b0f1Sespie
3334361b62eSniklas if ((given & 0x00800000) == 0)
3344361b62eSniklas offset = -offset;
335b305b0f1Sespie
336c074d1c9Sdrahn func (stream, "[pc, #%d]\t; ", offset);
337b305b0f1Sespie
3384361b62eSniklas (*info->print_address_func)
3394361b62eSniklas (offset + pc + 8, info);
3404361b62eSniklas }
3414361b62eSniklas else
3424361b62eSniklas {
3434361b62eSniklas func (stream, "[%s",
3444361b62eSniklas arm_regnames[(given >> 16) & 0xf]);
3454361b62eSniklas if ((given & 0x01000000) != 0)
3464361b62eSniklas {
347b305b0f1Sespie /* Pre-indexed. */
3484361b62eSniklas if ((given & 0x00400000) == 0x00400000)
3494361b62eSniklas {
350b305b0f1Sespie /* Immediate. */
3514361b62eSniklas int offset = ((given & 0xf00) >> 4) | (given & 0xf);
3524361b62eSniklas if (offset)
353*007c2a45Smiod func (stream, ", #%s%d",
3544361b62eSniklas (((given & 0x00800000) == 0)
3554361b62eSniklas ? "-" : ""), offset);
3564361b62eSniklas }
3574361b62eSniklas else
3584361b62eSniklas {
359b305b0f1Sespie /* Register. */
3604361b62eSniklas func (stream, ", %s%s",
3614361b62eSniklas (((given & 0x00800000) == 0)
3624361b62eSniklas ? "-" : ""),
3634361b62eSniklas arm_regnames[given & 0xf]);
3644361b62eSniklas }
3654361b62eSniklas
3664361b62eSniklas func (stream, "]%s",
3674361b62eSniklas ((given & 0x00200000) != 0) ? "!" : "");
3684361b62eSniklas }
3694361b62eSniklas else
3704361b62eSniklas {
371b305b0f1Sespie /* Post-indexed. */
3724361b62eSniklas if ((given & 0x00400000) == 0x00400000)
3734361b62eSniklas {
374b305b0f1Sespie /* Immediate. */
3754361b62eSniklas int offset = ((given & 0xf00) >> 4) | (given & 0xf);
3764361b62eSniklas if (offset)
377*007c2a45Smiod func (stream, "], #%s%d",
3784361b62eSniklas (((given & 0x00800000) == 0)
3794361b62eSniklas ? "-" : ""), offset);
3804361b62eSniklas else
3814361b62eSniklas func (stream, "]");
3824361b62eSniklas }
3834361b62eSniklas else
3844361b62eSniklas {
385b305b0f1Sespie /* Register. */
3864361b62eSniklas func (stream, "], %s%s",
3874361b62eSniklas (((given & 0x00800000) == 0)
3884361b62eSniklas ? "-" : ""),
3894361b62eSniklas arm_regnames[given & 0xf]);
3904361b62eSniklas }
3914361b62eSniklas }
3924361b62eSniklas }
3934361b62eSniklas break;
3944361b62eSniklas
3952159047fSniklas case 'b':
3962159047fSniklas (*info->print_address_func)
3972159047fSniklas (BDISP (given) * 4 + pc + 8, info);
3982159047fSniklas break;
3992159047fSniklas
4002159047fSniklas case 'c':
4012159047fSniklas func (stream, "%s",
4022159047fSniklas arm_conditional [(given >> 28) & 0xf]);
4032159047fSniklas break;
4042159047fSniklas
4052159047fSniklas case 'm':
4062159047fSniklas {
4072159047fSniklas int started = 0;
4082159047fSniklas int reg;
4092159047fSniklas
4102159047fSniklas func (stream, "{");
4112159047fSniklas for (reg = 0; reg < 16; reg++)
4122159047fSniklas if ((given & (1 << reg)) != 0)
4132159047fSniklas {
4142159047fSniklas if (started)
4152159047fSniklas func (stream, ", ");
4162159047fSniklas started = 1;
4172159047fSniklas func (stream, "%s", arm_regnames[reg]);
4182159047fSniklas }
4192159047fSniklas func (stream, "}");
4202159047fSniklas }
4212159047fSniklas break;
4222159047fSniklas
4232159047fSniklas case 'o':
4242159047fSniklas if ((given & 0x02000000) != 0)
4252159047fSniklas {
4262159047fSniklas int rotate = (given & 0xf00) >> 7;
4272159047fSniklas int immed = (given & 0xff);
428b305b0f1Sespie immed = (((immed << (32 - rotate))
4292159047fSniklas | (immed >> rotate)) & 0xffffffff);
430b305b0f1Sespie func (stream, "#%d\t; 0x%x", immed, immed);
4312159047fSniklas }
4322159047fSniklas else
4332159047fSniklas arm_decode_shift (given, func, stream);
4342159047fSniklas break;
4352159047fSniklas
4362159047fSniklas case 'p':
4372159047fSniklas if ((given & 0x0000f000) == 0x0000f000)
4382159047fSniklas func (stream, "p");
4392159047fSniklas break;
4402159047fSniklas
4412159047fSniklas case 't':
4422159047fSniklas if ((given & 0x01200000) == 0x00200000)
4432159047fSniklas func (stream, "t");
4442159047fSniklas break;
4452159047fSniklas
4462159047fSniklas case 'A':
4472159047fSniklas func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
448*007c2a45Smiod
449*007c2a45Smiod if ((given & (1 << 24)) != 0)
4502159047fSniklas {
4512159047fSniklas int offset = given & 0xff;
452*007c2a45Smiod
4532159047fSniklas if (offset)
454*007c2a45Smiod func (stream, ", #%s%d]%s",
4552159047fSniklas ((given & 0x00800000) == 0 ? "-" : ""),
4562159047fSniklas offset * 4,
4572159047fSniklas ((given & 0x00200000) != 0 ? "!" : ""));
4582159047fSniklas else
4592159047fSniklas func (stream, "]");
4602159047fSniklas }
4612159047fSniklas else
4622159047fSniklas {
4632159047fSniklas int offset = given & 0xff;
464*007c2a45Smiod
465*007c2a45Smiod func (stream, "]");
466*007c2a45Smiod
467*007c2a45Smiod if (given & (1 << 21))
468*007c2a45Smiod {
4692159047fSniklas if (offset)
470*007c2a45Smiod func (stream, ", #%s%d",
4712159047fSniklas ((given & 0x00800000) == 0 ? "-" : ""),
4722159047fSniklas offset * 4);
473*007c2a45Smiod }
4742159047fSniklas else
475*007c2a45Smiod func (stream, ", {%d}", offset);
4762159047fSniklas }
4772159047fSniklas break;
4782159047fSniklas
479b55d4692Sfgsch case 'B':
480b55d4692Sfgsch /* Print ARM V5 BLX(1) address: pc+25 bits. */
4812159047fSniklas {
482b55d4692Sfgsch bfd_vma address;
483b55d4692Sfgsch bfd_vma offset = 0;
484b55d4692Sfgsch
485b55d4692Sfgsch if (given & 0x00800000)
486b55d4692Sfgsch /* Is signed, hi bits should be ones. */
487b55d4692Sfgsch offset = (-1) ^ 0x00ffffff;
488b55d4692Sfgsch
489b55d4692Sfgsch /* Offset is (SignExtend(offset field)<<2). */
490b55d4692Sfgsch offset += given & 0x00ffffff;
491b55d4692Sfgsch offset <<= 2;
492b55d4692Sfgsch address = offset + pc + 8;
493b55d4692Sfgsch
494b55d4692Sfgsch if (given & 0x01000000)
495b55d4692Sfgsch /* H bit allows addressing to 2-byte boundaries. */
496b55d4692Sfgsch address += 2;
497b55d4692Sfgsch
498b55d4692Sfgsch info->print_address_func (address, info);
4992159047fSniklas }
5002159047fSniklas break;
5012159047fSniklas
502c074d1c9Sdrahn case 'I':
503c074d1c9Sdrahn /* Print a Cirrus/DSP shift immediate. */
504c074d1c9Sdrahn /* Immediates are 7bit signed ints with bits 0..3 in
505c074d1c9Sdrahn bits 0..3 of opcode and bits 4..6 in bits 5..7
506c074d1c9Sdrahn of opcode. */
507c074d1c9Sdrahn {
508c074d1c9Sdrahn int imm;
509c074d1c9Sdrahn
510c074d1c9Sdrahn imm = (given & 0xf) | ((given & 0xe0) >> 1);
511c074d1c9Sdrahn
512c074d1c9Sdrahn /* Is ``imm'' a negative number? */
513c074d1c9Sdrahn if (imm & 0x40)
514c074d1c9Sdrahn imm |= (-1 << 7);
515c074d1c9Sdrahn
516c074d1c9Sdrahn func (stream, "%d", imm);
517c074d1c9Sdrahn }
518c074d1c9Sdrahn
519c074d1c9Sdrahn break;
520c074d1c9Sdrahn
521b55d4692Sfgsch case 'C':
522b55d4692Sfgsch func (stream, "_");
523b55d4692Sfgsch if (given & 0x80000)
524b55d4692Sfgsch func (stream, "f");
525b55d4692Sfgsch if (given & 0x40000)
526b55d4692Sfgsch func (stream, "s");
527b55d4692Sfgsch if (given & 0x20000)
528b55d4692Sfgsch func (stream, "x");
529b55d4692Sfgsch if (given & 0x10000)
530b55d4692Sfgsch func (stream, "c");
531b55d4692Sfgsch break;
532b55d4692Sfgsch
5332159047fSniklas case 'F':
5342159047fSniklas switch (given & 0x00408000)
5352159047fSniklas {
5362159047fSniklas case 0:
5372159047fSniklas func (stream, "4");
5382159047fSniklas break;
5392159047fSniklas case 0x8000:
5402159047fSniklas func (stream, "1");
5412159047fSniklas break;
5422159047fSniklas case 0x00400000:
5432159047fSniklas func (stream, "2");
5442159047fSniklas break;
5452159047fSniklas default:
5462159047fSniklas func (stream, "3");
5472159047fSniklas }
5482159047fSniklas break;
5492159047fSniklas
5502159047fSniklas case 'P':
5512159047fSniklas switch (given & 0x00080080)
5522159047fSniklas {
5532159047fSniklas case 0:
5542159047fSniklas func (stream, "s");
5552159047fSniklas break;
5562159047fSniklas case 0x80:
5572159047fSniklas func (stream, "d");
5582159047fSniklas break;
5592159047fSniklas case 0x00080000:
5602159047fSniklas func (stream, "e");
5612159047fSniklas break;
5622159047fSniklas default:
563b305b0f1Sespie func (stream, _("<illegal precision>"));
5642159047fSniklas break;
5652159047fSniklas }
5662159047fSniklas break;
5672159047fSniklas case 'Q':
5682159047fSniklas switch (given & 0x00408000)
5692159047fSniklas {
5702159047fSniklas case 0:
5712159047fSniklas func (stream, "s");
5722159047fSniklas break;
5732159047fSniklas case 0x8000:
5742159047fSniklas func (stream, "d");
5752159047fSniklas break;
5762159047fSniklas case 0x00400000:
5772159047fSniklas func (stream, "e");
5782159047fSniklas break;
5792159047fSniklas default:
5802159047fSniklas func (stream, "p");
5812159047fSniklas break;
5822159047fSniklas }
5832159047fSniklas break;
5842159047fSniklas case 'R':
5852159047fSniklas switch (given & 0x60)
5862159047fSniklas {
5872159047fSniklas case 0:
5882159047fSniklas break;
5892159047fSniklas case 0x20:
5902159047fSniklas func (stream, "p");
5912159047fSniklas break;
5922159047fSniklas case 0x40:
5932159047fSniklas func (stream, "m");
5942159047fSniklas break;
5952159047fSniklas default:
5962159047fSniklas func (stream, "z");
5972159047fSniklas break;
5982159047fSniklas }
5992159047fSniklas break;
6002159047fSniklas
6012159047fSniklas case '0': case '1': case '2': case '3': case '4':
6022159047fSniklas case '5': case '6': case '7': case '8': case '9':
6032159047fSniklas {
6042159047fSniklas int bitstart = *c++ - '0';
6052159047fSniklas int bitend = 0;
6062159047fSniklas while (*c >= '0' && *c <= '9')
6072159047fSniklas bitstart = (bitstart * 10) + *c++ - '0';
6082159047fSniklas
6092159047fSniklas switch (*c)
6102159047fSniklas {
6112159047fSniklas case '-':
6122159047fSniklas c++;
613b305b0f1Sespie
6142159047fSniklas while (*c >= '0' && *c <= '9')
6152159047fSniklas bitend = (bitend * 10) + *c++ - '0';
616b305b0f1Sespie
6172159047fSniklas if (!bitend)
6182159047fSniklas abort ();
619b305b0f1Sespie
6202159047fSniklas switch (*c)
6212159047fSniklas {
6222159047fSniklas case 'r':
6232159047fSniklas {
6242159047fSniklas long reg;
625b305b0f1Sespie
6262159047fSniklas reg = given >> bitstart;
6272159047fSniklas reg &= (2 << (bitend - bitstart)) - 1;
628b305b0f1Sespie
6292159047fSniklas func (stream, "%s", arm_regnames[reg]);
6302159047fSniklas }
6312159047fSniklas break;
6322159047fSniklas case 'd':
6332159047fSniklas {
6342159047fSniklas long reg;
635b305b0f1Sespie
6362159047fSniklas reg = given >> bitstart;
6372159047fSniklas reg &= (2 << (bitend - bitstart)) - 1;
638b305b0f1Sespie
6392159047fSniklas func (stream, "%d", reg);
6402159047fSniklas }
6412159047fSniklas break;
642*007c2a45Smiod case 'W':
643*007c2a45Smiod {
644*007c2a45Smiod long reg;
645*007c2a45Smiod
646*007c2a45Smiod reg = given >> bitstart;
647*007c2a45Smiod reg &= (2 << (bitend - bitstart)) - 1;
648*007c2a45Smiod
649*007c2a45Smiod func (stream, "%d", reg + 1);
650*007c2a45Smiod }
651*007c2a45Smiod break;
6522159047fSniklas case 'x':
6532159047fSniklas {
6542159047fSniklas long reg;
655b305b0f1Sespie
6562159047fSniklas reg = given >> bitstart;
6572159047fSniklas reg &= (2 << (bitend - bitstart)) - 1;
658b305b0f1Sespie
6592159047fSniklas func (stream, "0x%08x", reg);
660b305b0f1Sespie
661b305b0f1Sespie /* Some SWI instructions have special
662b305b0f1Sespie meanings. */
663b305b0f1Sespie if ((given & 0x0fffffff) == 0x0FF00000)
664b305b0f1Sespie func (stream, "\t; IMB");
665b305b0f1Sespie else if ((given & 0x0fffffff) == 0x0FF00001)
666b305b0f1Sespie func (stream, "\t; IMBRange");
667b305b0f1Sespie }
668b305b0f1Sespie break;
669b305b0f1Sespie case 'X':
670b305b0f1Sespie {
671b305b0f1Sespie long reg;
672b305b0f1Sespie
673b305b0f1Sespie reg = given >> bitstart;
674b305b0f1Sespie reg &= (2 << (bitend - bitstart)) - 1;
675b305b0f1Sespie
676b305b0f1Sespie func (stream, "%01x", reg & 0xf);
6772159047fSniklas }
6782159047fSniklas break;
6792159047fSniklas case 'f':
6802159047fSniklas {
6812159047fSniklas long reg;
682b305b0f1Sespie
6832159047fSniklas reg = given >> bitstart;
6842159047fSniklas reg &= (2 << (bitend - bitstart)) - 1;
685b305b0f1Sespie
6862159047fSniklas if (reg > 7)
6872159047fSniklas func (stream, "#%s",
6882159047fSniklas arm_fp_const[reg & 7]);
6892159047fSniklas else
6902159047fSniklas func (stream, "f%d", reg);
6912159047fSniklas }
6922159047fSniklas break;
693c074d1c9Sdrahn
694c074d1c9Sdrahn case 'w':
695c074d1c9Sdrahn {
696c074d1c9Sdrahn long reg;
697c074d1c9Sdrahn
698c074d1c9Sdrahn if (bitstart != bitend)
699c074d1c9Sdrahn {
700c074d1c9Sdrahn reg = given >> bitstart;
701c074d1c9Sdrahn reg &= (2 << (bitend - bitstart)) - 1;
702c074d1c9Sdrahn if (bitend - bitstart == 1)
703c074d1c9Sdrahn func (stream, "%s", iwmmxt_wwnames[reg]);
704c074d1c9Sdrahn else
705c074d1c9Sdrahn func (stream, "%s", iwmmxt_wwssnames[reg]);
706c074d1c9Sdrahn }
707c074d1c9Sdrahn else
708c074d1c9Sdrahn {
709c074d1c9Sdrahn reg = (((given >> 8) & 0x1) |
710c074d1c9Sdrahn ((given >> 22) & 0x1));
711c074d1c9Sdrahn func (stream, "%s", iwmmxt_wwnames[reg]);
712c074d1c9Sdrahn }
713c074d1c9Sdrahn }
714c074d1c9Sdrahn break;
715c074d1c9Sdrahn
716c074d1c9Sdrahn case 'g':
717c074d1c9Sdrahn {
718c074d1c9Sdrahn long reg;
719c074d1c9Sdrahn int current_regnames;
720c074d1c9Sdrahn
721c074d1c9Sdrahn if (! iwmmxt_regnames)
722c074d1c9Sdrahn iwmmxt_regnames = set_iwmmxt_regnames ();
723c074d1c9Sdrahn current_regnames = set_arm_regname_option
724c074d1c9Sdrahn (iwmmxt_regnames);
725c074d1c9Sdrahn
726c074d1c9Sdrahn reg = given >> bitstart;
727c074d1c9Sdrahn reg &= (2 << (bitend - bitstart)) - 1;
728c074d1c9Sdrahn func (stream, "%s", arm_regnames[reg]);
729c074d1c9Sdrahn set_arm_regname_option (current_regnames);
730c074d1c9Sdrahn }
731c074d1c9Sdrahn break;
732c074d1c9Sdrahn
733c074d1c9Sdrahn case 'G':
734c074d1c9Sdrahn {
735c074d1c9Sdrahn long reg;
736c074d1c9Sdrahn int current_regnames;
737c074d1c9Sdrahn
738c074d1c9Sdrahn if (! iwmmxt_regnames)
739c074d1c9Sdrahn iwmmxt_regnames = set_iwmmxt_regnames ();
740c074d1c9Sdrahn current_regnames = set_arm_regname_option
741c074d1c9Sdrahn (iwmmxt_regnames + 1);
742c074d1c9Sdrahn
743c074d1c9Sdrahn reg = given >> bitstart;
744c074d1c9Sdrahn reg &= (2 << (bitend - bitstart)) - 1;
745c074d1c9Sdrahn func (stream, "%s", arm_regnames[reg]);
746c074d1c9Sdrahn set_arm_regname_option (current_regnames);
747c074d1c9Sdrahn }
748c074d1c9Sdrahn break;
749c074d1c9Sdrahn
7502159047fSniklas default:
7512159047fSniklas abort ();
7522159047fSniklas }
7532159047fSniklas break;
754b305b0f1Sespie
755c074d1c9Sdrahn case 'y':
756c074d1c9Sdrahn case 'z':
757c074d1c9Sdrahn {
758c074d1c9Sdrahn int single = *c == 'y';
759c074d1c9Sdrahn int regno;
760c074d1c9Sdrahn
761c074d1c9Sdrahn switch (bitstart)
762c074d1c9Sdrahn {
763c074d1c9Sdrahn case 4: /* Sm pair */
764c074d1c9Sdrahn func (stream, "{");
765c074d1c9Sdrahn /* Fall through. */
766c074d1c9Sdrahn case 0: /* Sm, Dm */
767c074d1c9Sdrahn regno = given & 0x0000000f;
768c074d1c9Sdrahn if (single)
769c074d1c9Sdrahn {
770c074d1c9Sdrahn regno <<= 1;
771c074d1c9Sdrahn regno += (given >> 5) & 1;
772c074d1c9Sdrahn }
773c074d1c9Sdrahn break;
774c074d1c9Sdrahn
775c074d1c9Sdrahn case 1: /* Sd, Dd */
776c074d1c9Sdrahn regno = (given >> 12) & 0x0000000f;
777c074d1c9Sdrahn if (single)
778c074d1c9Sdrahn {
779c074d1c9Sdrahn regno <<= 1;
780c074d1c9Sdrahn regno += (given >> 22) & 1;
781c074d1c9Sdrahn }
782c074d1c9Sdrahn break;
783c074d1c9Sdrahn
784c074d1c9Sdrahn case 2: /* Sn, Dn */
785c074d1c9Sdrahn regno = (given >> 16) & 0x0000000f;
786c074d1c9Sdrahn if (single)
787c074d1c9Sdrahn {
788c074d1c9Sdrahn regno <<= 1;
789c074d1c9Sdrahn regno += (given >> 7) & 1;
790c074d1c9Sdrahn }
791c074d1c9Sdrahn break;
792c074d1c9Sdrahn
793c074d1c9Sdrahn case 3: /* List */
794c074d1c9Sdrahn func (stream, "{");
795c074d1c9Sdrahn regno = (given >> 12) & 0x0000000f;
796c074d1c9Sdrahn if (single)
797c074d1c9Sdrahn {
798c074d1c9Sdrahn regno <<= 1;
799c074d1c9Sdrahn regno += (given >> 22) & 1;
800c074d1c9Sdrahn }
801c074d1c9Sdrahn break;
802c074d1c9Sdrahn
803c074d1c9Sdrahn
804c074d1c9Sdrahn default:
805c074d1c9Sdrahn abort ();
806c074d1c9Sdrahn }
807c074d1c9Sdrahn
808c074d1c9Sdrahn func (stream, "%c%d", single ? 's' : 'd', regno);
809c074d1c9Sdrahn
810c074d1c9Sdrahn if (bitstart == 3)
811c074d1c9Sdrahn {
812c074d1c9Sdrahn int count = given & 0xff;
813c074d1c9Sdrahn
814c074d1c9Sdrahn if (single == 0)
815c074d1c9Sdrahn count >>= 1;
816c074d1c9Sdrahn
817c074d1c9Sdrahn if (--count)
818c074d1c9Sdrahn {
819c074d1c9Sdrahn func (stream, "-%c%d",
820c074d1c9Sdrahn single ? 's' : 'd',
821c074d1c9Sdrahn regno + count);
822c074d1c9Sdrahn }
823c074d1c9Sdrahn
824c074d1c9Sdrahn func (stream, "}");
825c074d1c9Sdrahn }
826c074d1c9Sdrahn else if (bitstart == 4)
827c074d1c9Sdrahn func (stream, ", %c%d}", single ? 's' : 'd',
828c074d1c9Sdrahn regno + 1);
829c074d1c9Sdrahn
830c074d1c9Sdrahn break;
831c074d1c9Sdrahn }
832c074d1c9Sdrahn
8332159047fSniklas case '`':
8342159047fSniklas c++;
8352159047fSniklas if ((given & (1 << bitstart)) == 0)
8362159047fSniklas func (stream, "%c", *c);
8372159047fSniklas break;
8382159047fSniklas case '\'':
8392159047fSniklas c++;
8402159047fSniklas if ((given & (1 << bitstart)) != 0)
8412159047fSniklas func (stream, "%c", *c);
8422159047fSniklas break;
8432159047fSniklas case '?':
8442159047fSniklas ++c;
8452159047fSniklas if ((given & (1 << bitstart)) != 0)
8462159047fSniklas func (stream, "%c", *c++);
8472159047fSniklas else
8482159047fSniklas func (stream, "%c", *++c);
8492159047fSniklas break;
8502159047fSniklas default:
8512159047fSniklas abort ();
8522159047fSniklas }
8532159047fSniklas break;
8542159047fSniklas
855c074d1c9Sdrahn case 'L':
856c074d1c9Sdrahn switch (given & 0x00400100)
857c074d1c9Sdrahn {
858c074d1c9Sdrahn case 0x00000000: func (stream, "b"); break;
859c074d1c9Sdrahn case 0x00400000: func (stream, "h"); break;
860c074d1c9Sdrahn case 0x00000100: func (stream, "w"); break;
861c074d1c9Sdrahn case 0x00400100: func (stream, "d"); break;
862c074d1c9Sdrahn default:
863c074d1c9Sdrahn break;
864c074d1c9Sdrahn }
865c074d1c9Sdrahn break;
866c074d1c9Sdrahn
867c074d1c9Sdrahn case 'Z':
868c074d1c9Sdrahn {
869c074d1c9Sdrahn int value;
870c074d1c9Sdrahn /* given (20, 23) | given (0, 3) */
871c074d1c9Sdrahn value = ((given >> 16) & 0xf0) | (given & 0xf);
872c074d1c9Sdrahn func (stream, "%d", value);
873c074d1c9Sdrahn }
874c074d1c9Sdrahn break;
875c074d1c9Sdrahn
876c074d1c9Sdrahn case 'l':
877c074d1c9Sdrahn /* This is like the 'A' operator, except that if
878c074d1c9Sdrahn the width field "M" is zero, then the offset is
879c074d1c9Sdrahn *not* multiplied by four. */
880c074d1c9Sdrahn {
881c074d1c9Sdrahn int offset = given & 0xff;
882c074d1c9Sdrahn int multiplier = (given & 0x00000100) ? 4 : 1;
883c074d1c9Sdrahn
884c074d1c9Sdrahn func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
885c074d1c9Sdrahn
886c074d1c9Sdrahn if (offset)
887c074d1c9Sdrahn {
888c074d1c9Sdrahn if ((given & 0x01000000) != 0)
889*007c2a45Smiod func (stream, ", #%s%d]%s",
890c074d1c9Sdrahn ((given & 0x00800000) == 0 ? "-" : ""),
891c074d1c9Sdrahn offset * multiplier,
892c074d1c9Sdrahn ((given & 0x00200000) != 0 ? "!" : ""));
893c074d1c9Sdrahn else
894*007c2a45Smiod func (stream, "], #%s%d",
895c074d1c9Sdrahn ((given & 0x00800000) == 0 ? "-" : ""),
896c074d1c9Sdrahn offset * multiplier);
897c074d1c9Sdrahn }
898c074d1c9Sdrahn else
899c074d1c9Sdrahn func (stream, "]");
900c074d1c9Sdrahn }
901c074d1c9Sdrahn break;
902c074d1c9Sdrahn
9032159047fSniklas default:
9042159047fSniklas abort ();
9052159047fSniklas }
9062159047fSniklas }
9072159047fSniklas }
9082159047fSniklas else
9092159047fSniklas func (stream, "%c", *c);
9102159047fSniklas }
9112159047fSniklas return 4;
9122159047fSniklas }
9132159047fSniklas }
9142159047fSniklas abort ();
9152159047fSniklas }
9162159047fSniklas
917b305b0f1Sespie /* Print one instruction from PC on INFO->STREAM.
918b305b0f1Sespie Return the size of the instruction. */
919c074d1c9Sdrahn
920b305b0f1Sespie static int
print_insn_thumb(pc,info,given)921b305b0f1Sespie print_insn_thumb (pc, info, given)
922b305b0f1Sespie bfd_vma pc;
923b305b0f1Sespie struct disassemble_info *info;
924b305b0f1Sespie long given;
925b305b0f1Sespie {
926c074d1c9Sdrahn const struct thumb_opcode *insn;
927b305b0f1Sespie void *stream = info->stream;
928b305b0f1Sespie fprintf_ftype func = info->fprintf_func;
929b305b0f1Sespie
930b305b0f1Sespie for (insn = thumb_opcodes; insn->assembler; insn++)
931b305b0f1Sespie {
932b305b0f1Sespie if ((given & insn->mask) == insn->value)
933b305b0f1Sespie {
934b305b0f1Sespie char * c = insn->assembler;
935b305b0f1Sespie
936b305b0f1Sespie /* Special processing for Thumb 2 instruction BL sequence: */
937b305b0f1Sespie if (!*c) /* Check for empty (not NULL) assembler string. */
938b305b0f1Sespie {
939c074d1c9Sdrahn long offset;
940c074d1c9Sdrahn
941b305b0f1Sespie info->bytes_per_chunk = 4;
942b305b0f1Sespie info->bytes_per_line = 4;
943b305b0f1Sespie
944c074d1c9Sdrahn offset = BDISP23 (given);
945c074d1c9Sdrahn offset = offset * 2 + pc + 4;
946c074d1c9Sdrahn
947b55d4692Sfgsch if ((given & 0x10000000) == 0)
948c074d1c9Sdrahn {
949b55d4692Sfgsch func (stream, "blx\t");
950c074d1c9Sdrahn offset &= 0xfffffffc;
951c074d1c9Sdrahn }
952b55d4692Sfgsch else
953b305b0f1Sespie func (stream, "bl\t");
954b305b0f1Sespie
955c074d1c9Sdrahn info->print_address_func (offset, info);
956b305b0f1Sespie return 4;
957b305b0f1Sespie }
958b305b0f1Sespie else
959b305b0f1Sespie {
960b305b0f1Sespie info->bytes_per_chunk = 2;
961b305b0f1Sespie info->bytes_per_line = 4;
962b305b0f1Sespie
963b305b0f1Sespie given &= 0xffff;
964b305b0f1Sespie
965b305b0f1Sespie for (; *c; c++)
966b305b0f1Sespie {
967b305b0f1Sespie if (*c == '%')
968b305b0f1Sespie {
969b305b0f1Sespie int domaskpc = 0;
970b305b0f1Sespie int domasklr = 0;
971b305b0f1Sespie
972b305b0f1Sespie switch (*++c)
973b305b0f1Sespie {
974b305b0f1Sespie case '%':
975b305b0f1Sespie func (stream, "%%");
976b305b0f1Sespie break;
977b305b0f1Sespie
978b305b0f1Sespie case 'S':
979b305b0f1Sespie {
980b305b0f1Sespie long reg;
981b305b0f1Sespie
982b305b0f1Sespie reg = (given >> 3) & 0x7;
983b305b0f1Sespie if (given & (1 << 6))
984b305b0f1Sespie reg += 8;
985b305b0f1Sespie
986b305b0f1Sespie func (stream, "%s", arm_regnames[reg]);
987b305b0f1Sespie }
988b305b0f1Sespie break;
989b305b0f1Sespie
990b305b0f1Sespie case 'D':
991b305b0f1Sespie {
992b305b0f1Sespie long reg;
993b305b0f1Sespie
994b305b0f1Sespie reg = given & 0x7;
995b305b0f1Sespie if (given & (1 << 7))
996b305b0f1Sespie reg += 8;
997b305b0f1Sespie
998b305b0f1Sespie func (stream, "%s", arm_regnames[reg]);
999b305b0f1Sespie }
1000b305b0f1Sespie break;
1001b305b0f1Sespie
1002b305b0f1Sespie case 'T':
1003b305b0f1Sespie func (stream, "%s",
1004b305b0f1Sespie arm_conditional [(given >> 8) & 0xf]);
1005b305b0f1Sespie break;
1006b305b0f1Sespie
1007b305b0f1Sespie case 'N':
1008b305b0f1Sespie if (given & (1 << 8))
1009b305b0f1Sespie domasklr = 1;
1010b305b0f1Sespie /* Fall through. */
1011b305b0f1Sespie case 'O':
1012b305b0f1Sespie if (*c == 'O' && (given & (1 << 8)))
1013b305b0f1Sespie domaskpc = 1;
1014b305b0f1Sespie /* Fall through. */
1015b305b0f1Sespie case 'M':
1016b305b0f1Sespie {
1017b305b0f1Sespie int started = 0;
1018b305b0f1Sespie int reg;
1019b305b0f1Sespie
1020b305b0f1Sespie func (stream, "{");
1021b305b0f1Sespie
1022b305b0f1Sespie /* It would be nice if we could spot
1023b305b0f1Sespie ranges, and generate the rS-rE format: */
1024b305b0f1Sespie for (reg = 0; (reg < 8); reg++)
1025b305b0f1Sespie if ((given & (1 << reg)) != 0)
1026b305b0f1Sespie {
1027b305b0f1Sespie if (started)
1028b305b0f1Sespie func (stream, ", ");
1029b305b0f1Sespie started = 1;
1030b305b0f1Sespie func (stream, "%s", arm_regnames[reg]);
1031b305b0f1Sespie }
1032b305b0f1Sespie
1033b305b0f1Sespie if (domasklr)
1034b305b0f1Sespie {
1035b305b0f1Sespie if (started)
1036b305b0f1Sespie func (stream, ", ");
1037b305b0f1Sespie started = 1;
1038b305b0f1Sespie func (stream, arm_regnames[14] /* "lr" */);
1039b305b0f1Sespie }
1040b305b0f1Sespie
1041b305b0f1Sespie if (domaskpc)
1042b305b0f1Sespie {
1043b305b0f1Sespie if (started)
1044b305b0f1Sespie func (stream, ", ");
1045b305b0f1Sespie func (stream, arm_regnames[15] /* "pc" */);
1046b305b0f1Sespie }
1047b305b0f1Sespie
1048b305b0f1Sespie func (stream, "}");
1049b305b0f1Sespie }
1050b305b0f1Sespie break;
1051b305b0f1Sespie
1052b305b0f1Sespie
1053b305b0f1Sespie case '0': case '1': case '2': case '3': case '4':
1054b305b0f1Sespie case '5': case '6': case '7': case '8': case '9':
1055b305b0f1Sespie {
1056b305b0f1Sespie int bitstart = *c++ - '0';
1057b305b0f1Sespie int bitend = 0;
1058b305b0f1Sespie
1059b305b0f1Sespie while (*c >= '0' && *c <= '9')
1060b305b0f1Sespie bitstart = (bitstart * 10) + *c++ - '0';
1061b305b0f1Sespie
1062b305b0f1Sespie switch (*c)
1063b305b0f1Sespie {
1064b305b0f1Sespie case '-':
1065b305b0f1Sespie {
1066b305b0f1Sespie long reg;
1067b305b0f1Sespie
1068b305b0f1Sespie c++;
1069b305b0f1Sespie while (*c >= '0' && *c <= '9')
1070b305b0f1Sespie bitend = (bitend * 10) + *c++ - '0';
1071b305b0f1Sespie if (!bitend)
1072b305b0f1Sespie abort ();
1073b305b0f1Sespie reg = given >> bitstart;
1074b305b0f1Sespie reg &= (2 << (bitend - bitstart)) - 1;
1075b305b0f1Sespie switch (*c)
1076b305b0f1Sespie {
1077b305b0f1Sespie case 'r':
1078b305b0f1Sespie func (stream, "%s", arm_regnames[reg]);
1079b305b0f1Sespie break;
1080b305b0f1Sespie
1081b305b0f1Sespie case 'd':
1082b305b0f1Sespie func (stream, "%d", reg);
1083b305b0f1Sespie break;
1084b305b0f1Sespie
1085b305b0f1Sespie case 'H':
1086b305b0f1Sespie func (stream, "%d", reg << 1);
1087b305b0f1Sespie break;
1088b305b0f1Sespie
1089b305b0f1Sespie case 'W':
1090b305b0f1Sespie func (stream, "%d", reg << 2);
1091b305b0f1Sespie break;
1092b305b0f1Sespie
1093b305b0f1Sespie case 'a':
1094b305b0f1Sespie /* PC-relative address -- the bottom two
1095b305b0f1Sespie bits of the address are dropped
1096b305b0f1Sespie before the calculation. */
1097b305b0f1Sespie info->print_address_func
1098b305b0f1Sespie (((pc + 4) & ~3) + (reg << 2), info);
1099b305b0f1Sespie break;
1100b305b0f1Sespie
1101b305b0f1Sespie case 'x':
1102b305b0f1Sespie func (stream, "0x%04x", reg);
1103b305b0f1Sespie break;
1104b305b0f1Sespie
1105b305b0f1Sespie case 'I':
1106b305b0f1Sespie reg = ((reg ^ (1 << bitend)) - (1 << bitend));
1107b305b0f1Sespie func (stream, "%d", reg);
1108b305b0f1Sespie break;
1109b305b0f1Sespie
1110b305b0f1Sespie case 'B':
1111b305b0f1Sespie reg = ((reg ^ (1 << bitend)) - (1 << bitend));
1112b305b0f1Sespie (*info->print_address_func)
1113b305b0f1Sespie (reg * 2 + pc + 4, info);
1114b305b0f1Sespie break;
1115b305b0f1Sespie
1116b305b0f1Sespie default:
1117b305b0f1Sespie abort ();
1118b305b0f1Sespie }
1119b305b0f1Sespie }
1120b305b0f1Sespie break;
1121b305b0f1Sespie
1122b305b0f1Sespie case '\'':
1123b305b0f1Sespie c++;
1124b305b0f1Sespie if ((given & (1 << bitstart)) != 0)
1125b305b0f1Sespie func (stream, "%c", *c);
1126b305b0f1Sespie break;
1127b305b0f1Sespie
1128b305b0f1Sespie case '?':
1129b305b0f1Sespie ++c;
1130b305b0f1Sespie if ((given & (1 << bitstart)) != 0)
1131b305b0f1Sespie func (stream, "%c", *c++);
1132b305b0f1Sespie else
1133b305b0f1Sespie func (stream, "%c", *++c);
1134b305b0f1Sespie break;
1135b305b0f1Sespie
1136b305b0f1Sespie default:
1137b305b0f1Sespie abort ();
1138b305b0f1Sespie }
1139b305b0f1Sespie }
1140b305b0f1Sespie break;
1141b305b0f1Sespie
1142b305b0f1Sespie default:
1143b305b0f1Sespie abort ();
1144b305b0f1Sespie }
1145b305b0f1Sespie }
1146b305b0f1Sespie else
1147b305b0f1Sespie func (stream, "%c", *c);
1148b305b0f1Sespie }
1149b305b0f1Sespie }
1150b305b0f1Sespie return 2;
1151b305b0f1Sespie }
1152b305b0f1Sespie }
1153b305b0f1Sespie
1154b305b0f1Sespie /* No match. */
1155b305b0f1Sespie abort ();
1156b305b0f1Sespie }
1157b305b0f1Sespie
1158*007c2a45Smiod /* Disallow mapping symbols ($a, $b, $d, $t etc) from
1159*007c2a45Smiod being displayed in symbol relative addresses. */
1160*007c2a45Smiod
1161*007c2a45Smiod bfd_boolean
arm_symbol_is_valid(asymbol * sym,struct disassemble_info * info ATTRIBUTE_UNUSED)1162*007c2a45Smiod arm_symbol_is_valid (asymbol * sym,
1163*007c2a45Smiod struct disassemble_info * info ATTRIBUTE_UNUSED)
1164*007c2a45Smiod {
1165*007c2a45Smiod const char * name;
1166*007c2a45Smiod
1167*007c2a45Smiod if (sym == NULL)
1168*007c2a45Smiod return FALSE;
1169*007c2a45Smiod
1170*007c2a45Smiod name = bfd_asymbol_name (sym);
1171*007c2a45Smiod
1172*007c2a45Smiod return (name && *name != '$');
1173*007c2a45Smiod }
1174*007c2a45Smiod
1175b305b0f1Sespie /* Parse an individual disassembler option. */
1176c074d1c9Sdrahn
1177b305b0f1Sespie void
parse_arm_disassembler_option(option)1178b305b0f1Sespie parse_arm_disassembler_option (option)
1179b305b0f1Sespie char * option;
1180b305b0f1Sespie {
1181b305b0f1Sespie if (option == NULL)
1182b305b0f1Sespie return;
1183b305b0f1Sespie
1184b305b0f1Sespie if (strneq (option, "reg-names-", 10))
1185b305b0f1Sespie {
1186b305b0f1Sespie int i;
1187b305b0f1Sespie
1188b305b0f1Sespie option += 10;
1189b305b0f1Sespie
1190b305b0f1Sespie for (i = NUM_ARM_REGNAMES; i--;)
1191*007c2a45Smiod if (strneq (option, regnames[i].name, strlen (regnames[i].name)))
1192b305b0f1Sespie {
1193b305b0f1Sespie regname_selected = i;
1194b305b0f1Sespie break;
1195b305b0f1Sespie }
1196b305b0f1Sespie
1197b305b0f1Sespie if (i < 0)
1198*007c2a45Smiod /* XXX - should break 'option' at following delimiter. */
1199b305b0f1Sespie fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
1200b305b0f1Sespie }
1201*007c2a45Smiod else if (strneq (option, "force-thumb", 11))
1202b305b0f1Sespie force_thumb = 1;
1203*007c2a45Smiod else if (strneq (option, "no-force-thumb", 14))
1204b305b0f1Sespie force_thumb = 0;
1205b305b0f1Sespie else
1206*007c2a45Smiod /* XXX - should break 'option' at following delimiter. */
1207b305b0f1Sespie fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
1208b305b0f1Sespie
1209b305b0f1Sespie return;
1210b305b0f1Sespie }
1211b305b0f1Sespie
1212*007c2a45Smiod /* Parse the string of disassembler options, spliting it at whitespaces
1213*007c2a45Smiod or commas. (Whitespace separators supported for backwards compatibility). */
1214c074d1c9Sdrahn
1215b305b0f1Sespie static void
parse_disassembler_options(options)1216b305b0f1Sespie parse_disassembler_options (options)
1217b305b0f1Sespie char * options;
1218b305b0f1Sespie {
1219b305b0f1Sespie if (options == NULL)
1220b305b0f1Sespie return;
1221b305b0f1Sespie
1222*007c2a45Smiod while (*options)
1223b305b0f1Sespie {
1224*007c2a45Smiod parse_arm_disassembler_option (options);
1225b305b0f1Sespie
1226*007c2a45Smiod /* Skip forward to next seperator. */
1227*007c2a45Smiod while ((*options) && (! ISSPACE (*options)) && (*options != ','))
1228*007c2a45Smiod ++ options;
1229*007c2a45Smiod /* Skip forward past seperators. */
1230*007c2a45Smiod while (ISSPACE (*options) || (*options == ','))
1231*007c2a45Smiod ++ options;
1232b305b0f1Sespie }
1233b305b0f1Sespie }
1234b305b0f1Sespie
1235b305b0f1Sespie /* NOTE: There are no checks in these routines that
1236b305b0f1Sespie the relevant number of data bytes exist. */
1237c074d1c9Sdrahn
1238b305b0f1Sespie static int
print_insn(pc,info,little)1239b305b0f1Sespie print_insn (pc, info, little)
1240b305b0f1Sespie bfd_vma pc;
1241b305b0f1Sespie struct disassemble_info * info;
1242c074d1c9Sdrahn bfd_boolean little;
1243b305b0f1Sespie {
1244b305b0f1Sespie unsigned char b[4];
1245b305b0f1Sespie long given;
1246b305b0f1Sespie int status;
1247b305b0f1Sespie int is_thumb;
1248b305b0f1Sespie
1249b305b0f1Sespie if (info->disassembler_options)
1250b305b0f1Sespie {
1251b305b0f1Sespie parse_disassembler_options (info->disassembler_options);
1252b305b0f1Sespie
1253b305b0f1Sespie /* To avoid repeated parsing of these options, we remove them here. */
1254b305b0f1Sespie info->disassembler_options = NULL;
1255b305b0f1Sespie }
1256b305b0f1Sespie
1257b305b0f1Sespie is_thumb = force_thumb;
1258b305b0f1Sespie
1259b305b0f1Sespie if (!is_thumb && info->symbols != NULL)
1260b305b0f1Sespie {
1261b305b0f1Sespie if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
1262b305b0f1Sespie {
1263b305b0f1Sespie coff_symbol_type * cs;
1264b305b0f1Sespie
1265b305b0f1Sespie cs = coffsymbol (*info->symbols);
1266b305b0f1Sespie is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
1267b305b0f1Sespie || cs->native->u.syment.n_sclass == C_THUMBSTAT
1268b305b0f1Sespie || cs->native->u.syment.n_sclass == C_THUMBLABEL
1269b305b0f1Sespie || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
1270b305b0f1Sespie || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
1271b305b0f1Sespie }
1272b305b0f1Sespie else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
1273b305b0f1Sespie {
1274b305b0f1Sespie elf_symbol_type * es;
1275b305b0f1Sespie unsigned int type;
1276b305b0f1Sespie
1277b305b0f1Sespie es = *(elf_symbol_type **)(info->symbols);
1278b305b0f1Sespie type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
1279b305b0f1Sespie
1280b305b0f1Sespie is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
1281b305b0f1Sespie }
1282b305b0f1Sespie }
1283b305b0f1Sespie
1284b305b0f1Sespie info->bytes_per_chunk = 4;
1285b305b0f1Sespie info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
1286b305b0f1Sespie
1287b305b0f1Sespie if (little)
1288b305b0f1Sespie {
1289b305b0f1Sespie status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
1290b305b0f1Sespie if (status != 0 && is_thumb)
1291b305b0f1Sespie {
1292b305b0f1Sespie info->bytes_per_chunk = 2;
1293b305b0f1Sespie
1294b305b0f1Sespie status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1295b305b0f1Sespie b[3] = b[2] = 0;
1296b305b0f1Sespie }
1297b305b0f1Sespie
1298b305b0f1Sespie if (status != 0)
1299b305b0f1Sespie {
1300b305b0f1Sespie info->memory_error_func (status, pc, info);
1301b305b0f1Sespie return -1;
1302b305b0f1Sespie }
1303b305b0f1Sespie
1304b305b0f1Sespie given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
1305b305b0f1Sespie }
1306b305b0f1Sespie else
1307b305b0f1Sespie {
1308b305b0f1Sespie status = info->read_memory_func
1309b305b0f1Sespie (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
1310b305b0f1Sespie if (status != 0)
1311b305b0f1Sespie {
1312b305b0f1Sespie info->memory_error_func (status, pc, info);
1313b305b0f1Sespie return -1;
1314b305b0f1Sespie }
1315b305b0f1Sespie
1316b305b0f1Sespie if (is_thumb)
1317b305b0f1Sespie {
1318b305b0f1Sespie if (pc & 0x2)
1319b305b0f1Sespie {
1320b305b0f1Sespie given = (b[2] << 8) | b[3];
1321b305b0f1Sespie
1322b305b0f1Sespie status = info->read_memory_func
1323b305b0f1Sespie ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
1324b305b0f1Sespie if (status != 0)
1325b305b0f1Sespie {
1326b305b0f1Sespie info->memory_error_func (status, pc + 4, info);
1327b305b0f1Sespie return -1;
1328b305b0f1Sespie }
1329b305b0f1Sespie
1330b305b0f1Sespie given |= (b[0] << 24) | (b[1] << 16);
1331b305b0f1Sespie }
1332b305b0f1Sespie else
1333b305b0f1Sespie given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
1334b305b0f1Sespie }
1335b305b0f1Sespie else
1336b305b0f1Sespie given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
1337b305b0f1Sespie }
1338b305b0f1Sespie
1339b55d4692Sfgsch if (info->flags & INSN_HAS_RELOC)
1340b55d4692Sfgsch /* If the instruction has a reloc associated with it, then
1341b55d4692Sfgsch the offset field in the instruction will actually be the
1342b55d4692Sfgsch addend for the reloc. (We are using REL type relocs).
1343b55d4692Sfgsch In such cases, we can ignore the pc when computing
1344b55d4692Sfgsch addresses, since the addend is not currently pc-relative. */
1345b55d4692Sfgsch pc = 0;
1346b55d4692Sfgsch
1347b305b0f1Sespie if (is_thumb)
1348b305b0f1Sespie status = print_insn_thumb (pc, info, given);
1349b305b0f1Sespie else
1350b305b0f1Sespie status = print_insn_arm (pc, info, given);
1351b305b0f1Sespie
1352b305b0f1Sespie return status;
1353b305b0f1Sespie }
1354b305b0f1Sespie
13552159047fSniklas int
print_insn_big_arm(pc,info)13562159047fSniklas print_insn_big_arm (pc, info)
13572159047fSniklas bfd_vma pc;
13582159047fSniklas struct disassemble_info * info;
13592159047fSniklas {
1360c074d1c9Sdrahn return print_insn (pc, info, FALSE);
13612159047fSniklas }
13622159047fSniklas
13632159047fSniklas int
print_insn_little_arm(pc,info)13642159047fSniklas print_insn_little_arm (pc, info)
13652159047fSniklas bfd_vma pc;
13662159047fSniklas struct disassemble_info * info;
13672159047fSniklas {
1368c074d1c9Sdrahn return print_insn (pc, info, TRUE);
13692159047fSniklas }
13702159047fSniklas
1371b305b0f1Sespie void
print_arm_disassembler_options(FILE * stream)1372b305b0f1Sespie print_arm_disassembler_options (FILE * stream)
1373b305b0f1Sespie {
1374b305b0f1Sespie int i;
13752159047fSniklas
1376b305b0f1Sespie fprintf (stream, _("\n\
1377b305b0f1Sespie The following ARM specific disassembler options are supported for use with\n\
1378b305b0f1Sespie the -M switch:\n"));
1379b305b0f1Sespie
1380b305b0f1Sespie for (i = NUM_ARM_REGNAMES; i--;)
1381b305b0f1Sespie fprintf (stream, " reg-names-%s %*c%s\n",
1382b305b0f1Sespie regnames[i].name,
1383c074d1c9Sdrahn (int)(14 - strlen (regnames[i].name)), ' ',
1384b305b0f1Sespie regnames[i].description);
1385b305b0f1Sespie
1386b305b0f1Sespie fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
1387b305b0f1Sespie fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
13882159047fSniklas }
1389