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