ppc-dis.c revision 1.6 1 1.1 christos /* ppc-dis.c -- Disassemble PowerPC instructions
2 1.6 christos Copyright (C) 1994-2016 Free Software Foundation, Inc.
3 1.1 christos Written by Ian Lance Taylor, Cygnus Support
4 1.1 christos
5 1.1 christos This file is part of the GNU opcodes library.
6 1.1 christos
7 1.1 christos This library is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3, or (at your option)
10 1.1 christos any later version.
11 1.1 christos
12 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
13 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 1.1 christos License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this file; see the file COPYING. If not, write to the
19 1.1 christos Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20 1.1 christos MA 02110-1301, USA. */
21 1.1 christos
22 1.1 christos #include "sysdep.h"
23 1.1 christos #include <stdio.h>
24 1.1 christos #include "dis-asm.h"
25 1.1 christos #include "elf-bfd.h"
26 1.1 christos #include "elf/ppc.h"
27 1.1 christos #include "opintl.h"
28 1.1 christos #include "opcode/ppc.h"
29 1.1 christos
30 1.1 christos /* This file provides several disassembler functions, all of which use
31 1.1 christos the disassembler interface defined in dis-asm.h. Several functions
32 1.1 christos are provided because this file handles disassembly for the PowerPC
33 1.1 christos in both big and little endian mode and also for the POWER (RS/6000)
34 1.1 christos chip. */
35 1.1 christos static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int,
36 1.1 christos ppc_cpu_t);
37 1.1 christos
38 1.1 christos struct dis_private
39 1.1 christos {
40 1.1 christos /* Stash the result of parsing disassembler_options here. */
41 1.1 christos ppc_cpu_t dialect;
42 1.1 christos } private;
43 1.1 christos
44 1.1 christos #define POWERPC_DIALECT(INFO) \
45 1.1 christos (((struct dis_private *) ((INFO)->private_data))->dialect)
46 1.1 christos
47 1.1 christos struct ppc_mopt {
48 1.1 christos const char *opt;
49 1.1 christos ppc_cpu_t cpu;
50 1.1 christos ppc_cpu_t sticky;
51 1.1 christos };
52 1.1 christos
53 1.1 christos struct ppc_mopt ppc_opts[] = {
54 1.6 christos { "403", PPC_OPCODE_PPC | PPC_OPCODE_403,
55 1.1 christos 0 },
56 1.6 christos { "405", PPC_OPCODE_PPC | PPC_OPCODE_403 | PPC_OPCODE_405,
57 1.1 christos 0 },
58 1.1 christos { "440", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
59 1.1 christos | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
60 1.1 christos 0 },
61 1.1 christos { "464", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
62 1.1 christos | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
63 1.1 christos 0 },
64 1.1 christos { "476", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_440
65 1.1 christos | PPC_OPCODE_476 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5),
66 1.1 christos 0 },
67 1.6 christos { "601", PPC_OPCODE_PPC | PPC_OPCODE_601,
68 1.1 christos 0 },
69 1.6 christos { "603", PPC_OPCODE_PPC,
70 1.1 christos 0 },
71 1.6 christos { "604", PPC_OPCODE_PPC,
72 1.1 christos 0 },
73 1.6 christos { "620", PPC_OPCODE_PPC | PPC_OPCODE_64,
74 1.1 christos 0 },
75 1.6 christos { "7400", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
76 1.1 christos 0 },
77 1.6 christos { "7410", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
78 1.1 christos 0 },
79 1.6 christos { "7450", PPC_OPCODE_PPC | PPC_OPCODE_7450 | PPC_OPCODE_ALTIVEC,
80 1.1 christos 0 },
81 1.6 christos { "7455", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
82 1.1 christos 0 },
83 1.6 christos { "750cl", PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS
84 1.1 christos , 0 },
85 1.6 christos { "821", PPC_OPCODE_PPC | PPC_OPCODE_860,
86 1.5 christos 0 },
87 1.6 christos { "850", PPC_OPCODE_PPC | PPC_OPCODE_860,
88 1.5 christos 0 },
89 1.6 christos { "860", PPC_OPCODE_PPC | PPC_OPCODE_860,
90 1.5 christos 0 },
91 1.1 christos { "a2", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_POWER4
92 1.1 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_CACHELCK | PPC_OPCODE_64
93 1.1 christos | PPC_OPCODE_A2),
94 1.1 christos 0 },
95 1.6 christos { "altivec", PPC_OPCODE_PPC,
96 1.1 christos PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 },
97 1.1 christos { "any", 0,
98 1.1 christos PPC_OPCODE_ANY },
99 1.6 christos { "booke", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE,
100 1.1 christos 0 },
101 1.6 christos { "booke32", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE,
102 1.1 christos 0 },
103 1.1 christos { "cell", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
104 1.1 christos | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC),
105 1.1 christos 0 },
106 1.6 christos { "com", PPC_OPCODE_COMMON,
107 1.1 christos 0 },
108 1.6 christos { "e300", PPC_OPCODE_PPC | PPC_OPCODE_E300,
109 1.1 christos 0 },
110 1.1 christos { "e500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
111 1.1 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
112 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
113 1.1 christos | PPC_OPCODE_E500),
114 1.1 christos 0 },
115 1.1 christos { "e500mc", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
116 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
117 1.1 christos | PPC_OPCODE_E500MC),
118 1.1 christos 0 },
119 1.1 christos { "e500mc64", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
120 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
121 1.1 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5
122 1.1 christos | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
123 1.1 christos 0 },
124 1.1 christos { "e5500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
125 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
126 1.1 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
127 1.1 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
128 1.1 christos | PPC_OPCODE_POWER7),
129 1.1 christos 0 },
130 1.1 christos { "e6500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
131 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
132 1.1 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_ALTIVEC
133 1.1 christos | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_E6500 | PPC_OPCODE_POWER4
134 1.1 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
135 1.1 christos 0 },
136 1.1 christos { "e500x2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
137 1.1 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
138 1.1 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
139 1.1 christos | PPC_OPCODE_E500),
140 1.1 christos 0 },
141 1.6 christos { "efs", PPC_OPCODE_PPC | PPC_OPCODE_EFS,
142 1.1 christos 0 },
143 1.6 christos { "power4", PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4,
144 1.1 christos 0 },
145 1.1 christos { "power5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
146 1.1 christos | PPC_OPCODE_POWER5),
147 1.1 christos 0 },
148 1.1 christos { "power6", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
149 1.1 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
150 1.1 christos 0 },
151 1.1 christos { "power7", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
152 1.1 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
153 1.1 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
154 1.1 christos 0 },
155 1.1 christos { "power8", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
156 1.1 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
157 1.1 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
158 1.1 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
159 1.1 christos 0 },
160 1.6 christos { "power9", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
161 1.6 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
162 1.6 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
163 1.6 christos | PPC_OPCODE_HTM | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
164 1.6 christos | PPC_OPCODE_VSX | PPC_OPCODE_VSX3 ),
165 1.6 christos 0 },
166 1.6 christos { "ppc", PPC_OPCODE_PPC,
167 1.1 christos 0 },
168 1.6 christos { "ppc32", PPC_OPCODE_PPC,
169 1.1 christos 0 },
170 1.6 christos { "ppc64", PPC_OPCODE_PPC | PPC_OPCODE_64,
171 1.1 christos 0 },
172 1.6 christos { "ppc64bridge", PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE,
173 1.1 christos 0 },
174 1.6 christos { "ppcps", PPC_OPCODE_PPC | PPC_OPCODE_PPCPS,
175 1.1 christos 0 },
176 1.6 christos { "pwr", PPC_OPCODE_POWER,
177 1.1 christos 0 },
178 1.6 christos { "pwr2", PPC_OPCODE_POWER | PPC_OPCODE_POWER2,
179 1.1 christos 0 },
180 1.6 christos { "pwr4", PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4,
181 1.1 christos 0 },
182 1.1 christos { "pwr5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
183 1.1 christos | PPC_OPCODE_POWER5),
184 1.1 christos 0 },
185 1.1 christos { "pwr5x", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
186 1.1 christos | PPC_OPCODE_POWER5),
187 1.1 christos 0 },
188 1.1 christos { "pwr6", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
189 1.1 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
190 1.1 christos 0 },
191 1.1 christos { "pwr7", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
192 1.1 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
193 1.1 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
194 1.1 christos 0 },
195 1.1 christos { "pwr8", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
196 1.1 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
197 1.1 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
198 1.1 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
199 1.1 christos 0 },
200 1.6 christos { "pwr9", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
201 1.6 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
202 1.6 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
203 1.6 christos | PPC_OPCODE_HTM | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
204 1.6 christos | PPC_OPCODE_VSX | PPC_OPCODE_VSX3 ),
205 1.6 christos 0 },
206 1.6 christos { "pwrx", PPC_OPCODE_POWER | PPC_OPCODE_POWER2,
207 1.1 christos 0 },
208 1.6 christos { "spe", PPC_OPCODE_PPC | PPC_OPCODE_EFS,
209 1.1 christos PPC_OPCODE_SPE },
210 1.1 christos { "titan", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR
211 1.1 christos | PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN),
212 1.1 christos 0 },
213 1.6 christos { "vle", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE
214 1.6 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
215 1.6 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
216 1.6 christos | PPC_OPCODE_E500),
217 1.1 christos PPC_OPCODE_VLE },
218 1.6 christos { "vsx", PPC_OPCODE_PPC,
219 1.6 christos PPC_OPCODE_VSX | PPC_OPCODE_VSX3 },
220 1.6 christos { "htm", PPC_OPCODE_PPC,
221 1.1 christos PPC_OPCODE_HTM },
222 1.1 christos };
223 1.1 christos
224 1.1 christos /* Switch between Booke and VLE dialects for interlinked dumps. */
225 1.1 christos static ppc_cpu_t
226 1.1 christos get_powerpc_dialect (struct disassemble_info *info)
227 1.1 christos {
228 1.1 christos ppc_cpu_t dialect = 0;
229 1.1 christos
230 1.1 christos dialect = POWERPC_DIALECT (info);
231 1.1 christos
232 1.1 christos /* Disassemble according to the section headers flags for VLE-mode. */
233 1.1 christos if (dialect & PPC_OPCODE_VLE
234 1.1 christos && info->section->owner != NULL
235 1.1 christos && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour
236 1.1 christos && elf_object_id (info->section->owner) == PPC32_ELF_DATA
237 1.1 christos && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0)
238 1.1 christos return dialect;
239 1.1 christos else
240 1.1 christos return dialect & ~ PPC_OPCODE_VLE;
241 1.1 christos }
242 1.1 christos
243 1.1 christos /* Handle -m and -M options that set cpu type, and .machine arg. */
244 1.1 christos
245 1.1 christos ppc_cpu_t
246 1.1 christos ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg)
247 1.1 christos {
248 1.1 christos unsigned int i;
249 1.1 christos
250 1.1 christos for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
251 1.1 christos if (strcmp (ppc_opts[i].opt, arg) == 0)
252 1.1 christos {
253 1.1 christos if (ppc_opts[i].sticky)
254 1.1 christos {
255 1.1 christos *sticky |= ppc_opts[i].sticky;
256 1.1 christos if ((ppc_cpu & ~*sticky) != 0)
257 1.1 christos break;
258 1.1 christos }
259 1.1 christos ppc_cpu = ppc_opts[i].cpu;
260 1.1 christos break;
261 1.1 christos }
262 1.1 christos if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0]))
263 1.1 christos return 0;
264 1.1 christos
265 1.1 christos ppc_cpu |= *sticky;
266 1.1 christos return ppc_cpu;
267 1.1 christos }
268 1.1 christos
269 1.1 christos /* Determine which set of machines to disassemble for. */
270 1.1 christos
271 1.1 christos static void
272 1.1 christos powerpc_init_dialect (struct disassemble_info *info)
273 1.1 christos {
274 1.1 christos ppc_cpu_t dialect = 0;
275 1.1 christos ppc_cpu_t sticky = 0;
276 1.1 christos char *arg;
277 1.1 christos struct dis_private *priv = calloc (sizeof (*priv), 1);
278 1.1 christos
279 1.1 christos if (priv == NULL)
280 1.1 christos priv = &private;
281 1.1 christos
282 1.1 christos switch (info->mach)
283 1.1 christos {
284 1.1 christos case bfd_mach_ppc_403:
285 1.1 christos case bfd_mach_ppc_403gc:
286 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "403");
287 1.1 christos break;
288 1.1 christos case bfd_mach_ppc_405:
289 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "405");
290 1.1 christos break;
291 1.1 christos case bfd_mach_ppc_601:
292 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "601");
293 1.1 christos break;
294 1.1 christos case bfd_mach_ppc_a35:
295 1.1 christos case bfd_mach_ppc_rs64ii:
296 1.1 christos case bfd_mach_ppc_rs64iii:
297 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "pwr2") | PPC_OPCODE_64;
298 1.1 christos break;
299 1.1 christos case bfd_mach_ppc_e500:
300 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "e500");
301 1.1 christos break;
302 1.1 christos case bfd_mach_ppc_e500mc:
303 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "e500mc");
304 1.1 christos break;
305 1.1 christos case bfd_mach_ppc_e500mc64:
306 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "e500mc64");
307 1.1 christos break;
308 1.1 christos case bfd_mach_ppc_e5500:
309 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "e5500");
310 1.1 christos break;
311 1.1 christos case bfd_mach_ppc_e6500:
312 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "e6500");
313 1.1 christos break;
314 1.1 christos case bfd_mach_ppc_titan:
315 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "titan");
316 1.1 christos break;
317 1.1 christos case bfd_mach_ppc_vle:
318 1.1 christos dialect = ppc_parse_cpu (dialect, &sticky, "vle");
319 1.1 christos break;
320 1.1 christos default:
321 1.6 christos dialect = ppc_parse_cpu (dialect, &sticky, "power9") | PPC_OPCODE_ANY;
322 1.1 christos }
323 1.1 christos
324 1.1 christos arg = info->disassembler_options;
325 1.1 christos while (arg != NULL)
326 1.1 christos {
327 1.1 christos ppc_cpu_t new_cpu = 0;
328 1.1 christos char *end = strchr (arg, ',');
329 1.1 christos
330 1.1 christos if (end != NULL)
331 1.1 christos *end = 0;
332 1.1 christos
333 1.1 christos if ((new_cpu = ppc_parse_cpu (dialect, &sticky, arg)) != 0)
334 1.1 christos dialect = new_cpu;
335 1.1 christos else if (strcmp (arg, "32") == 0)
336 1.1 christos dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
337 1.1 christos else if (strcmp (arg, "64") == 0)
338 1.1 christos dialect |= PPC_OPCODE_64;
339 1.1 christos else
340 1.1 christos fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg);
341 1.1 christos
342 1.1 christos if (end != NULL)
343 1.1 christos *end++ = ',';
344 1.1 christos arg = end;
345 1.1 christos }
346 1.1 christos
347 1.1 christos info->private_data = priv;
348 1.1 christos POWERPC_DIALECT(info) = dialect;
349 1.1 christos }
350 1.1 christos
351 1.1 christos #define PPC_OPCD_SEGS 64
352 1.1 christos static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS+1];
353 1.1 christos #define VLE_OPCD_SEGS 32
354 1.1 christos static unsigned short vle_opcd_indices[VLE_OPCD_SEGS+1];
355 1.1 christos
356 1.1 christos /* Calculate opcode table indices to speed up disassembly,
357 1.1 christos and init dialect. */
358 1.1 christos
359 1.1 christos void
360 1.1 christos disassemble_init_powerpc (struct disassemble_info *info)
361 1.1 christos {
362 1.1 christos int i;
363 1.1 christos unsigned short last;
364 1.1 christos
365 1.5 christos if (powerpc_opcd_indices[PPC_OPCD_SEGS] == 0)
366 1.1 christos {
367 1.1 christos
368 1.5 christos i = powerpc_num_opcodes;
369 1.5 christos while (--i >= 0)
370 1.5 christos {
371 1.5 christos unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
372 1.5 christos
373 1.5 christos powerpc_opcd_indices[op] = i;
374 1.5 christos }
375 1.1 christos
376 1.5 christos last = powerpc_num_opcodes;
377 1.5 christos for (i = PPC_OPCD_SEGS; i > 0; --i)
378 1.5 christos {
379 1.5 christos if (powerpc_opcd_indices[i] == 0)
380 1.5 christos powerpc_opcd_indices[i] = last;
381 1.5 christos last = powerpc_opcd_indices[i];
382 1.5 christos }
383 1.1 christos
384 1.5 christos i = vle_num_opcodes;
385 1.5 christos while (--i >= 0)
386 1.5 christos {
387 1.5 christos unsigned op = VLE_OP (vle_opcodes[i].opcode, vle_opcodes[i].mask);
388 1.5 christos unsigned seg = VLE_OP_TO_SEG (op);
389 1.1 christos
390 1.5 christos vle_opcd_indices[seg] = i;
391 1.5 christos }
392 1.1 christos
393 1.5 christos last = vle_num_opcodes;
394 1.5 christos for (i = VLE_OPCD_SEGS; i > 0; --i)
395 1.5 christos {
396 1.5 christos if (vle_opcd_indices[i] == 0)
397 1.5 christos vle_opcd_indices[i] = last;
398 1.5 christos last = vle_opcd_indices[i];
399 1.5 christos }
400 1.1 christos }
401 1.1 christos
402 1.1 christos if (info->arch == bfd_arch_powerpc)
403 1.1 christos powerpc_init_dialect (info);
404 1.1 christos }
405 1.1 christos
406 1.1 christos /* Print a big endian PowerPC instruction. */
407 1.1 christos
408 1.1 christos int
409 1.1 christos print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
410 1.1 christos {
411 1.1 christos return print_insn_powerpc (memaddr, info, 1, get_powerpc_dialect (info));
412 1.1 christos }
413 1.1 christos
414 1.1 christos /* Print a little endian PowerPC instruction. */
415 1.1 christos
416 1.1 christos int
417 1.1 christos print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
418 1.1 christos {
419 1.1 christos return print_insn_powerpc (memaddr, info, 0, get_powerpc_dialect (info));
420 1.1 christos }
421 1.1 christos
422 1.1 christos /* Print a POWER (RS/6000) instruction. */
423 1.1 christos
424 1.1 christos int
425 1.1 christos print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
426 1.1 christos {
427 1.1 christos return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
428 1.1 christos }
429 1.1 christos
430 1.1 christos /* Extract the operand value from the PowerPC or POWER instruction. */
431 1.1 christos
432 1.1 christos static long
433 1.1 christos operand_value_powerpc (const struct powerpc_operand *operand,
434 1.1 christos unsigned long insn, ppc_cpu_t dialect)
435 1.1 christos {
436 1.1 christos long value;
437 1.1 christos int invalid;
438 1.1 christos /* Extract the value from the instruction. */
439 1.1 christos if (operand->extract)
440 1.1 christos value = (*operand->extract) (insn, dialect, &invalid);
441 1.1 christos else
442 1.1 christos {
443 1.1 christos if (operand->shift >= 0)
444 1.1 christos value = (insn >> operand->shift) & operand->bitm;
445 1.1 christos else
446 1.1 christos value = (insn << -operand->shift) & operand->bitm;
447 1.1 christos if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
448 1.1 christos {
449 1.1 christos /* BITM is always some number of zeros followed by some
450 1.1 christos number of ones, followed by some number of zeros. */
451 1.1 christos unsigned long top = operand->bitm;
452 1.1 christos /* top & -top gives the rightmost 1 bit, so this
453 1.1 christos fills in any trailing zeros. */
454 1.1 christos top |= (top & -top) - 1;
455 1.1 christos top &= ~(top >> 1);
456 1.1 christos value = (value ^ top) - top;
457 1.1 christos }
458 1.1 christos }
459 1.1 christos
460 1.1 christos return value;
461 1.1 christos }
462 1.1 christos
463 1.1 christos /* Determine whether the optional operand(s) should be printed. */
464 1.1 christos
465 1.1 christos static int
466 1.1 christos skip_optional_operands (const unsigned char *opindex,
467 1.1 christos unsigned long insn, ppc_cpu_t dialect)
468 1.1 christos {
469 1.1 christos const struct powerpc_operand *operand;
470 1.1 christos
471 1.1 christos for (; *opindex != 0; opindex++)
472 1.1 christos {
473 1.1 christos operand = &powerpc_operands[*opindex];
474 1.1 christos if ((operand->flags & PPC_OPERAND_NEXT) != 0
475 1.1 christos || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
476 1.5 christos && operand_value_powerpc (operand, insn, dialect) !=
477 1.5 christos ppc_optional_operand_value (operand)))
478 1.1 christos return 0;
479 1.1 christos }
480 1.1 christos
481 1.1 christos return 1;
482 1.1 christos }
483 1.1 christos
484 1.1 christos /* Find a match for INSN in the opcode table, given machine DIALECT.
485 1.1 christos A DIALECT of -1 is special, matching all machine opcode variations. */
486 1.1 christos
487 1.1 christos static const struct powerpc_opcode *
488 1.1 christos lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
489 1.1 christos {
490 1.1 christos const struct powerpc_opcode *opcode;
491 1.1 christos const struct powerpc_opcode *opcode_end;
492 1.1 christos unsigned long op;
493 1.1 christos
494 1.1 christos /* Get the major opcode of the instruction. */
495 1.1 christos op = PPC_OP (insn);
496 1.1 christos
497 1.1 christos /* Find the first match in the opcode table for this major opcode. */
498 1.1 christos opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1];
499 1.1 christos for (opcode = powerpc_opcodes + powerpc_opcd_indices[op];
500 1.1 christos opcode < opcode_end;
501 1.1 christos ++opcode)
502 1.1 christos {
503 1.1 christos const unsigned char *opindex;
504 1.1 christos const struct powerpc_operand *operand;
505 1.1 christos int invalid;
506 1.1 christos
507 1.1 christos if ((insn & opcode->mask) != opcode->opcode
508 1.1 christos || (dialect != (ppc_cpu_t) -1
509 1.1 christos && ((opcode->flags & dialect) == 0
510 1.1 christos || (opcode->deprecated & dialect) != 0)))
511 1.1 christos continue;
512 1.1 christos
513 1.1 christos /* Check validity of operands. */
514 1.1 christos invalid = 0;
515 1.1 christos for (opindex = opcode->operands; *opindex != 0; opindex++)
516 1.1 christos {
517 1.1 christos operand = powerpc_operands + *opindex;
518 1.1 christos if (operand->extract)
519 1.1 christos (*operand->extract) (insn, dialect, &invalid);
520 1.1 christos }
521 1.1 christos if (invalid)
522 1.1 christos continue;
523 1.1 christos
524 1.1 christos return opcode;
525 1.1 christos }
526 1.1 christos
527 1.1 christos return NULL;
528 1.1 christos }
529 1.1 christos
530 1.1 christos /* Find a match for INSN in the VLE opcode table. */
531 1.1 christos
532 1.1 christos static const struct powerpc_opcode *
533 1.1 christos lookup_vle (unsigned long insn)
534 1.1 christos {
535 1.1 christos const struct powerpc_opcode *opcode;
536 1.1 christos const struct powerpc_opcode *opcode_end;
537 1.1 christos unsigned op, seg;
538 1.1 christos
539 1.1 christos op = PPC_OP (insn);
540 1.1 christos if (op >= 0x20 && op <= 0x37)
541 1.1 christos {
542 1.1 christos /* This insn has a 4-bit opcode. */
543 1.1 christos op &= 0x3c;
544 1.1 christos }
545 1.1 christos seg = VLE_OP_TO_SEG (op);
546 1.1 christos
547 1.1 christos /* Find the first match in the opcode table for this major opcode. */
548 1.1 christos opcode_end = vle_opcodes + vle_opcd_indices[seg + 1];
549 1.1 christos for (opcode = vle_opcodes + vle_opcd_indices[seg];
550 1.1 christos opcode < opcode_end;
551 1.1 christos ++opcode)
552 1.1 christos {
553 1.1 christos unsigned long table_opcd = opcode->opcode;
554 1.1 christos unsigned long table_mask = opcode->mask;
555 1.1 christos bfd_boolean table_op_is_short = PPC_OP_SE_VLE(table_mask);
556 1.1 christos unsigned long insn2;
557 1.1 christos const unsigned char *opindex;
558 1.1 christos const struct powerpc_operand *operand;
559 1.1 christos int invalid;
560 1.1 christos
561 1.1 christos insn2 = insn;
562 1.1 christos if (table_op_is_short)
563 1.1 christos insn2 >>= 16;
564 1.1 christos if ((insn2 & table_mask) != table_opcd)
565 1.1 christos continue;
566 1.1 christos
567 1.1 christos /* Check validity of operands. */
568 1.1 christos invalid = 0;
569 1.1 christos for (opindex = opcode->operands; *opindex != 0; ++opindex)
570 1.1 christos {
571 1.1 christos operand = powerpc_operands + *opindex;
572 1.1 christos if (operand->extract)
573 1.1 christos (*operand->extract) (insn, (ppc_cpu_t)0, &invalid);
574 1.1 christos }
575 1.1 christos if (invalid)
576 1.1 christos continue;
577 1.1 christos
578 1.1 christos return opcode;
579 1.1 christos }
580 1.1 christos
581 1.1 christos return NULL;
582 1.1 christos }
583 1.1 christos
584 1.1 christos /* Print a PowerPC or POWER instruction. */
585 1.1 christos
586 1.1 christos static int
587 1.1 christos print_insn_powerpc (bfd_vma memaddr,
588 1.1 christos struct disassemble_info *info,
589 1.1 christos int bigendian,
590 1.1 christos ppc_cpu_t dialect)
591 1.1 christos {
592 1.1 christos bfd_byte buffer[4];
593 1.1 christos int status;
594 1.1 christos unsigned long insn;
595 1.1 christos const struct powerpc_opcode *opcode;
596 1.1 christos bfd_boolean insn_is_short;
597 1.1 christos
598 1.1 christos status = (*info->read_memory_func) (memaddr, buffer, 4, info);
599 1.1 christos if (status != 0)
600 1.1 christos {
601 1.1 christos /* The final instruction may be a 2-byte VLE insn. */
602 1.1 christos if ((dialect & PPC_OPCODE_VLE) != 0)
603 1.1 christos {
604 1.1 christos /* Clear buffer so unused bytes will not have garbage in them. */
605 1.1 christos buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
606 1.1 christos status = (*info->read_memory_func) (memaddr, buffer, 2, info);
607 1.1 christos if (status != 0)
608 1.1 christos {
609 1.1 christos (*info->memory_error_func) (status, memaddr, info);
610 1.1 christos return -1;
611 1.1 christos }
612 1.1 christos }
613 1.1 christos else
614 1.1 christos {
615 1.1 christos (*info->memory_error_func) (status, memaddr, info);
616 1.1 christos return -1;
617 1.1 christos }
618 1.1 christos }
619 1.1 christos
620 1.1 christos if (bigendian)
621 1.1 christos insn = bfd_getb32 (buffer);
622 1.1 christos else
623 1.1 christos insn = bfd_getl32 (buffer);
624 1.1 christos
625 1.1 christos /* Get the major opcode of the insn. */
626 1.1 christos opcode = NULL;
627 1.1 christos insn_is_short = FALSE;
628 1.1 christos if ((dialect & PPC_OPCODE_VLE) != 0)
629 1.1 christos {
630 1.1 christos opcode = lookup_vle (insn);
631 1.1 christos if (opcode != NULL)
632 1.1 christos insn_is_short = PPC_OP_SE_VLE(opcode->mask);
633 1.1 christos }
634 1.1 christos if (opcode == NULL)
635 1.1 christos opcode = lookup_powerpc (insn, dialect);
636 1.1 christos if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
637 1.1 christos opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
638 1.1 christos
639 1.1 christos if (opcode != NULL)
640 1.1 christos {
641 1.1 christos const unsigned char *opindex;
642 1.1 christos const struct powerpc_operand *operand;
643 1.1 christos int need_comma;
644 1.1 christos int need_paren;
645 1.1 christos int skip_optional;
646 1.1 christos
647 1.1 christos if (opcode->operands[0] != 0)
648 1.1 christos (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
649 1.1 christos else
650 1.1 christos (*info->fprintf_func) (info->stream, "%s", opcode->name);
651 1.1 christos
652 1.1 christos if (insn_is_short)
653 1.1 christos /* The operands will be fetched out of the 16-bit instruction. */
654 1.1 christos insn >>= 16;
655 1.1 christos
656 1.1 christos /* Now extract and print the operands. */
657 1.1 christos need_comma = 0;
658 1.1 christos need_paren = 0;
659 1.1 christos skip_optional = -1;
660 1.1 christos for (opindex = opcode->operands; *opindex != 0; opindex++)
661 1.1 christos {
662 1.1 christos long value;
663 1.1 christos
664 1.1 christos operand = powerpc_operands + *opindex;
665 1.1 christos
666 1.1 christos /* Operands that are marked FAKE are simply ignored. We
667 1.1 christos already made sure that the extract function considered
668 1.1 christos the instruction to be valid. */
669 1.1 christos if ((operand->flags & PPC_OPERAND_FAKE) != 0)
670 1.1 christos continue;
671 1.1 christos
672 1.1 christos /* If all of the optional operands have the value zero,
673 1.1 christos then don't print any of them. */
674 1.1 christos if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
675 1.1 christos {
676 1.1 christos if (skip_optional < 0)
677 1.1 christos skip_optional = skip_optional_operands (opindex, insn,
678 1.1 christos dialect);
679 1.1 christos if (skip_optional)
680 1.1 christos continue;
681 1.1 christos }
682 1.1 christos
683 1.1 christos value = operand_value_powerpc (operand, insn, dialect);
684 1.1 christos
685 1.1 christos if (need_comma)
686 1.1 christos {
687 1.1 christos (*info->fprintf_func) (info->stream, ",");
688 1.1 christos need_comma = 0;
689 1.1 christos }
690 1.1 christos
691 1.1 christos /* Print the operand as directed by the flags. */
692 1.1 christos if ((operand->flags & PPC_OPERAND_GPR) != 0
693 1.1 christos || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
694 1.1 christos (*info->fprintf_func) (info->stream, "r%ld", value);
695 1.1 christos else if ((operand->flags & PPC_OPERAND_FPR) != 0)
696 1.1 christos (*info->fprintf_func) (info->stream, "f%ld", value);
697 1.1 christos else if ((operand->flags & PPC_OPERAND_VR) != 0)
698 1.1 christos (*info->fprintf_func) (info->stream, "v%ld", value);
699 1.1 christos else if ((operand->flags & PPC_OPERAND_VSR) != 0)
700 1.1 christos (*info->fprintf_func) (info->stream, "vs%ld", value);
701 1.1 christos else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
702 1.1 christos (*info->print_address_func) (memaddr + value, info);
703 1.1 christos else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
704 1.1 christos (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
705 1.6 christos else if ((operand->flags & PPC_OPERAND_FSL) != 0)
706 1.1 christos (*info->fprintf_func) (info->stream, "fsl%ld", value);
707 1.1 christos else if ((operand->flags & PPC_OPERAND_FCR) != 0)
708 1.1 christos (*info->fprintf_func) (info->stream, "fcr%ld", value);
709 1.1 christos else if ((operand->flags & PPC_OPERAND_UDI) != 0)
710 1.1 christos (*info->fprintf_func) (info->stream, "%ld", value);
711 1.1 christos else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
712 1.1 christos && (((dialect & PPC_OPCODE_PPC) != 0)
713 1.1 christos || ((dialect & PPC_OPCODE_VLE) != 0)))
714 1.1 christos (*info->fprintf_func) (info->stream, "cr%ld", value);
715 1.1 christos else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
716 1.1 christos && (((dialect & PPC_OPCODE_PPC) != 0)
717 1.1 christos || ((dialect & PPC_OPCODE_VLE) != 0)))
718 1.1 christos {
719 1.1 christos static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
720 1.1 christos int cr;
721 1.1 christos int cc;
722 1.1 christos
723 1.1 christos cr = value >> 2;
724 1.1 christos if (cr != 0)
725 1.1 christos (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
726 1.1 christos cc = value & 3;
727 1.1 christos (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
728 1.1 christos }
729 1.1 christos else
730 1.1 christos (*info->fprintf_func) (info->stream, "%d", (int) value);
731 1.1 christos
732 1.1 christos if (need_paren)
733 1.1 christos {
734 1.1 christos (*info->fprintf_func) (info->stream, ")");
735 1.1 christos need_paren = 0;
736 1.1 christos }
737 1.1 christos
738 1.1 christos if ((operand->flags & PPC_OPERAND_PARENS) == 0)
739 1.1 christos need_comma = 1;
740 1.1 christos else
741 1.1 christos {
742 1.1 christos (*info->fprintf_func) (info->stream, "(");
743 1.1 christos need_paren = 1;
744 1.1 christos }
745 1.1 christos }
746 1.1 christos
747 1.1 christos /* We have found and printed an instruction.
748 1.1 christos If it was a short VLE instruction we have more to do. */
749 1.1 christos if (insn_is_short)
750 1.1 christos {
751 1.1 christos memaddr += 2;
752 1.1 christos return 2;
753 1.1 christos }
754 1.1 christos else
755 1.1 christos /* Otherwise, return. */
756 1.1 christos return 4;
757 1.1 christos }
758 1.1 christos
759 1.1 christos /* We could not find a match. */
760 1.1 christos (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
761 1.1 christos
762 1.1 christos return 4;
763 1.1 christos }
764 1.1 christos
765 1.1 christos void
766 1.1 christos print_ppc_disassembler_options (FILE *stream)
767 1.1 christos {
768 1.1 christos unsigned int i, col;
769 1.1 christos
770 1.1 christos fprintf (stream, _("\n\
771 1.1 christos The following PPC specific disassembler options are supported for use with\n\
772 1.1 christos the -M switch:\n"));
773 1.1 christos
774 1.1 christos for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
775 1.1 christos {
776 1.1 christos col += fprintf (stream, " %s,", ppc_opts[i].opt);
777 1.1 christos if (col > 66)
778 1.1 christos {
779 1.1 christos fprintf (stream, "\n");
780 1.1 christos col = 0;
781 1.1 christos }
782 1.1 christos }
783 1.1 christos fprintf (stream, " 32, 64\n");
784 1.1 christos }
785