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