Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: opcodes/ppc-dis.c

Issue 11969036: Merge GDB 7.5.1 (Closed) Base URL: http://git.chromium.org/native_client/nacl-gdb.git@master
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « opcodes/po/vi.po ('k') | opcodes/ppc-opc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* ppc-dis.c -- Disassemble PowerPC instructions 1 /* ppc-dis.c -- Disassemble PowerPC instructions
2 Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2 Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008, 2009, 2010 Free Software Foundation, Inc. 3 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support 4 Written by Ian Lance Taylor, Cygnus Support
5 5
6 This file is part of the GNU opcodes library. 6 This file is part of the GNU opcodes library.
7 7
8 This library is free software; you can redistribute it and/or modify 8 This library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option) 10 the Free Software Foundation; either version 3, or (at your option)
11 any later version. 11 any later version.
12 12
13 It is distributed in the hope that it will be useful, but WITHOUT 13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details. 16 License for more details.
17 17
18 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
19 along with this file; see the file COPYING. If not, write to the 19 along with this file; see the file COPYING. If not, write to the
20 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */ 21 MA 02110-1301, USA. */
22 22
23 #include "sysdep.h"
23 #include <stdio.h> 24 #include <stdio.h>
24 #include "sysdep.h"
25 #include "dis-asm.h" 25 #include "dis-asm.h"
26 #include "elf-bfd.h"
27 #include "elf/ppc.h"
26 #include "opintl.h" 28 #include "opintl.h"
27 #include "opcode/ppc.h" 29 #include "opcode/ppc.h"
28 30
29 /* This file provides several disassembler functions, all of which use 31 /* This file provides several disassembler functions, all of which use
30 the disassembler interface defined in dis-asm.h. Several functions 32 the disassembler interface defined in dis-asm.h. Several functions
31 are provided because this file handles disassembly for the PowerPC 33 are provided because this file handles disassembly for the PowerPC
32 in both big and little endian mode and also for the POWER (RS/6000) 34 in both big and little endian mode and also for the POWER (RS/6000)
33 chip. */ 35 chip. */
34 static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, 36 static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int,
35 ppc_cpu_t); 37 ppc_cpu_t);
36 38
37 struct dis_private 39 struct dis_private
38 { 40 {
39 /* Stash the result of parsing disassembler_options here. */ 41 /* Stash the result of parsing disassembler_options here. */
40 ppc_cpu_t dialect; 42 ppc_cpu_t dialect;
41 }; 43 } private;
42 44
43 #define POWERPC_DIALECT(INFO) \ 45 #define POWERPC_DIALECT(INFO) \
44 (((struct dis_private *) ((INFO)->private_data))->dialect) 46 (((struct dis_private *) ((INFO)->private_data))->dialect)
45 47
46 struct ppc_mopt { 48 struct ppc_mopt {
47 const char *opt; 49 const char *opt;
48 ppc_cpu_t cpu; 50 ppc_cpu_t cpu;
49 ppc_cpu_t sticky; 51 ppc_cpu_t sticky;
50 }; 52 };
51 53
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 0 }, 109 0 },
108 { "e500mc", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 110 { "e500mc", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
109 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 111 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
110 | PPC_OPCODE_E500MC), 112 | PPC_OPCODE_E500MC),
111 0 }, 113 0 },
112 { "e500mc64", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 114 { "e500mc64", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
113 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 115 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
114 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5 116 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5
115 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7), 117 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
116 0 }, 118 0 },
119 { "e5500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
120 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
121 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
122 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
123 | PPC_OPCODE_POWER7),
124 0 },
125 { "e6500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
126 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
127 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_ALTIVEC
128 | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_E6500 | PPC_OPCODE_POWER4
129 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
130 0 },
117 { "e500x2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 131 { "e500x2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
118 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 132 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
119 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 133 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
120 | PPC_OPCODE_E500), 134 | PPC_OPCODE_E500),
121 0 }, 135 0 },
122 { "efs", (PPC_OPCODE_PPC | PPC_OPCODE_EFS), 136 { "efs", (PPC_OPCODE_PPC | PPC_OPCODE_EFS),
123 0 }, 137 0 },
124 { "power4", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4), 138 { "power4", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4),
125 0 }, 139 0 },
126 { "power5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 140 { "power5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 176 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
163 | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 177 | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
164 0 }, 178 0 },
165 { "pwrx", (PPC_OPCODE_POWER | PPC_OPCODE_POWER2), 179 { "pwrx", (PPC_OPCODE_POWER | PPC_OPCODE_POWER2),
166 0 }, 180 0 },
167 { "spe", (PPC_OPCODE_PPC | PPC_OPCODE_EFS), 181 { "spe", (PPC_OPCODE_PPC | PPC_OPCODE_EFS),
168 PPC_OPCODE_SPE }, 182 PPC_OPCODE_SPE },
169 { "titan", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR 183 { "titan", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR
170 | PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN), 184 | PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN),
171 0 }, 185 0 },
186 { "vle", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_VLE),
187 PPC_OPCODE_VLE },
172 { "vsx", (PPC_OPCODE_PPC), 188 { "vsx", (PPC_OPCODE_PPC),
173 PPC_OPCODE_VSX }, 189 PPC_OPCODE_VSX },
174 }; 190 };
175 191
192 /* Switch between Booke and VLE dialects for interlinked dumps. */
193 static ppc_cpu_t
194 get_powerpc_dialect (struct disassemble_info *info)
195 {
196 ppc_cpu_t dialect = 0;
197
198 dialect = POWERPC_DIALECT (info);
199
200 /* Disassemble according to the section headers flags for VLE-mode. */
201 if (dialect & PPC_OPCODE_VLE
202 && info->section->owner != NULL
203 && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour
204 && elf_object_id (info->section->owner) == PPC32_ELF_DATA
205 && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0)
206 return dialect;
207 else
208 return dialect & ~ PPC_OPCODE_VLE;
209 }
210
176 /* Handle -m and -M options that set cpu type, and .machine arg. */ 211 /* Handle -m and -M options that set cpu type, and .machine arg. */
177 212
178 ppc_cpu_t 213 ppc_cpu_t
179 ppc_parse_cpu (ppc_cpu_t ppc_cpu, const char *arg) 214 ppc_parse_cpu (ppc_cpu_t ppc_cpu, const char *arg)
180 { 215 {
216 const ppc_cpu_t retain_mask = (PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX
217 | PPC_OPCODE_SPE | PPC_OPCODE_ANY
218 | PPC_OPCODE_VLE | PPC_OPCODE_PMR);
181 /* Sticky bits. */ 219 /* Sticky bits. */
182 ppc_cpu_t retain_flags = ppc_cpu & (PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX 220 ppc_cpu_t retain_flags = ppc_cpu & retain_mask;
183 » » » » | PPC_OPCODE_SPE | PPC_OPCODE_ANY);
184 unsigned int i; 221 unsigned int i;
185 222
186 for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++) 223 for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
187 if (strcmp (ppc_opts[i].opt, arg) == 0) 224 if (strcmp (ppc_opts[i].opt, arg) == 0)
188 { 225 {
189 if (ppc_opts[i].sticky) 226 if (ppc_opts[i].sticky)
190 { 227 {
191 retain_flags |= ppc_opts[i].sticky; 228 retain_flags |= ppc_opts[i].sticky;
192 » if ((ppc_cpu & ~(ppc_cpu_t) (PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX 229 » if ((ppc_cpu & ~retain_mask) != 0)
193 » » » » » | PPC_OPCODE_SPE | PPC_OPCODE_ANY)) != 0)
194 break; 230 break;
195 } 231 }
196 ppc_cpu = ppc_opts[i].cpu; 232 ppc_cpu = ppc_opts[i].cpu;
197 break; 233 break;
198 } 234 }
199 if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0])) 235 if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0]))
200 return 0; 236 return 0;
201 237
202 ppc_cpu |= retain_flags; 238 ppc_cpu |= retain_flags;
203 return ppc_cpu; 239 return ppc_cpu;
204 } 240 }
205 241
206 /* Determine which set of machines to disassemble for. */ 242 /* Determine which set of machines to disassemble for. */
207 243
208 static int 244 static void
209 powerpc_init_dialect (struct disassemble_info *info) 245 powerpc_init_dialect (struct disassemble_info *info)
210 { 246 {
211 ppc_cpu_t dialect = 0; 247 ppc_cpu_t dialect = 0;
212 char *arg; 248 char *arg;
213 struct dis_private *priv = calloc (sizeof (*priv), 1); 249 struct dis_private *priv = calloc (sizeof (*priv), 1);
214 250
215 if (priv == NULL) 251 if (priv == NULL)
216 return FALSE; 252 priv = &private;
217 253
218 arg = info->disassembler_options; 254 arg = info->disassembler_options;
219 while (arg != NULL) 255 while (arg != NULL)
220 { 256 {
221 ppc_cpu_t new_cpu = 0; 257 ppc_cpu_t new_cpu = 0;
222 char *end = strchr (arg, ','); 258 char *end = strchr (arg, ',');
223 259
224 if (end != NULL) 260 if (end != NULL)
225 *end = 0; 261 *end = 0;
226 262
(...skipping 10 matching lines...) Expand all
237 *end++ = ','; 273 *end++ = ',';
238 arg = end; 274 arg = end;
239 } 275 }
240 276
241 if ((dialect & ~(ppc_cpu_t) PPC_OPCODE_64) == 0) 277 if ((dialect & ~(ppc_cpu_t) PPC_OPCODE_64) == 0)
242 { 278 {
243 if (info->mach == bfd_mach_ppc64) 279 if (info->mach == bfd_mach_ppc64)
244 dialect |= PPC_OPCODE_64; 280 dialect |= PPC_OPCODE_64;
245 else 281 else
246 dialect &= ~(ppc_cpu_t) PPC_OPCODE_64; 282 dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
247 /* Choose a reasonable default. */ 283 if (info->mach == bfd_mach_ppc_vle)
248 dialect |= (PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_601 284 dialect |= PPC_OPCODE_PPC | PPC_OPCODE_VLE;
249 » » | PPC_OPCODE_ALTIVEC); 285 else
286 /* Choose a reasonable default. */
287 dialect |= (PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_601
288 » » | PPC_OPCODE_ALTIVEC);
250 } 289 }
251 290
252 info->private_data = priv; 291 info->private_data = priv;
253 POWERPC_DIALECT(info) = dialect; 292 POWERPC_DIALECT(info) = dialect;
293 }
254 294
255 return TRUE; 295 #define PPC_OPCD_SEGS 64
296 static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS+1];
297 #define VLE_OPCD_SEGS 32
298 static unsigned short vle_opcd_indices[VLE_OPCD_SEGS+1];
299
300 /* Calculate opcode table indices to speed up disassembly,
301 and init dialect. */
302
303 void
304 disassemble_init_powerpc (struct disassemble_info *info)
305 {
306 int i;
307 unsigned short last;
308
309 i = powerpc_num_opcodes;
310 while (--i >= 0)
311 {
312 unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
313
314 powerpc_opcd_indices[op] = i;
315 }
316
317 last = powerpc_num_opcodes;
318 for (i = PPC_OPCD_SEGS; i > 0; --i)
319 {
320 if (powerpc_opcd_indices[i] == 0)
321 » powerpc_opcd_indices[i] = last;
322 last = powerpc_opcd_indices[i];
323 }
324
325 i = vle_num_opcodes;
326 while (--i >= 0)
327 {
328 unsigned op = VLE_OP (vle_opcodes[i].opcode, vle_opcodes[i].mask);
329 unsigned seg = VLE_OP_TO_SEG (op);
330
331 vle_opcd_indices[seg] = i;
332 }
333
334 last = vle_num_opcodes;
335 for (i = VLE_OPCD_SEGS; i > 0; --i)
336 {
337 if (vle_opcd_indices[i] == 0)
338 » vle_opcd_indices[i] = last;
339 last = vle_opcd_indices[i];
340 }
341
342 if (info->arch == bfd_arch_powerpc)
343 powerpc_init_dialect (info);
256 } 344 }
257 345
258 /* Print a big endian PowerPC instruction. */ 346 /* Print a big endian PowerPC instruction. */
259 347
260 int 348 int
261 print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) 349 print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
262 { 350 {
263 if (info->private_data == NULL && !powerpc_init_dialect (info)) 351 return print_insn_powerpc (memaddr, info, 1, get_powerpc_dialect (info));
264 return -1;
265 return print_insn_powerpc (memaddr, info, 1, POWERPC_DIALECT(info));
266 } 352 }
267 353
268 /* Print a little endian PowerPC instruction. */ 354 /* Print a little endian PowerPC instruction. */
269 355
270 int 356 int
271 print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) 357 print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
272 { 358 {
273 if (info->private_data == NULL && !powerpc_init_dialect (info)) 359 return print_insn_powerpc (memaddr, info, 0, get_powerpc_dialect (info));
274 return -1;
275 return print_insn_powerpc (memaddr, info, 0, POWERPC_DIALECT(info));
276 } 360 }
277 361
278 /* Print a POWER (RS/6000) instruction. */ 362 /* Print a POWER (RS/6000) instruction. */
279 363
280 int 364 int
281 print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) 365 print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
282 { 366 {
283 return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); 367 return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
284 } 368 }
285 369
286 /* Extract the operand value from the PowerPC or POWER instruction. */ 370 /* Extract the operand value from the PowerPC or POWER instruction. */
287 371
288 static long 372 static long
289 operand_value_powerpc (const struct powerpc_operand *operand, 373 operand_value_powerpc (const struct powerpc_operand *operand,
290 unsigned long insn, ppc_cpu_t dialect) 374 unsigned long insn, ppc_cpu_t dialect)
291 { 375 {
292 long value; 376 long value;
293 int invalid; 377 int invalid;
294 /* Extract the value from the instruction. */ 378 /* Extract the value from the instruction. */
295 if (operand->extract) 379 if (operand->extract)
296 value = (*operand->extract) (insn, dialect, &invalid); 380 value = (*operand->extract) (insn, dialect, &invalid);
297 else 381 else
298 { 382 {
299 value = (insn >> operand->shift) & operand->bitm; 383 if (operand->shift >= 0)
384 » value = (insn >> operand->shift) & operand->bitm;
385 else
386 » value = (insn << -operand->shift) & operand->bitm;
300 if ((operand->flags & PPC_OPERAND_SIGNED) != 0) 387 if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
301 { 388 {
302 /* BITM is always some number of zeros followed by some 389 /* BITM is always some number of zeros followed by some
303 » number of ones, followed by some numer of zeros. */ 390 » number of ones, followed by some number of zeros. */
304 unsigned long top = operand->bitm; 391 unsigned long top = operand->bitm;
305 /* top & -top gives the rightmost 1 bit, so this 392 /* top & -top gives the rightmost 1 bit, so this
306 fills in any trailing zeros. */ 393 fills in any trailing zeros. */
307 top |= (top & -top) - 1; 394 top |= (top & -top) - 1;
308 top &= ~(top >> 1); 395 top &= ~(top >> 1);
309 value = (value ^ top) - top; 396 value = (value ^ top) - top;
310 } 397 }
311 } 398 }
312 399
313 return value; 400 return value;
(...skipping 12 matching lines...) Expand all
326 operand = &powerpc_operands[*opindex]; 413 operand = &powerpc_operands[*opindex];
327 if ((operand->flags & PPC_OPERAND_NEXT) != 0 414 if ((operand->flags & PPC_OPERAND_NEXT) != 0
328 || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 415 || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
329 && operand_value_powerpc (operand, insn, dialect) != 0)) 416 && operand_value_powerpc (operand, insn, dialect) != 0))
330 return 0; 417 return 0;
331 } 418 }
332 419
333 return 1; 420 return 1;
334 } 421 }
335 422
423 /* Find a match for INSN in the opcode table, given machine DIALECT.
424 A DIALECT of -1 is special, matching all machine opcode variations. */
425
426 static const struct powerpc_opcode *
427 lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
428 {
429 const struct powerpc_opcode *opcode;
430 const struct powerpc_opcode *opcode_end;
431 unsigned long op;
432
433 /* Get the major opcode of the instruction. */
434 op = PPC_OP (insn);
435
436 /* Find the first match in the opcode table for this major opcode. */
437 opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1];
438 for (opcode = powerpc_opcodes + powerpc_opcd_indices[op];
439 opcode < opcode_end;
440 ++opcode)
441 {
442 const unsigned char *opindex;
443 const struct powerpc_operand *operand;
444 int invalid;
445
446 if ((insn & opcode->mask) != opcode->opcode
447 || (dialect != (ppc_cpu_t) -1
448 && ((opcode->flags & dialect) == 0
449 || (opcode->deprecated & dialect) != 0)))
450 continue;
451
452 /* Check validity of operands. */
453 invalid = 0;
454 for (opindex = opcode->operands; *opindex != 0; opindex++)
455 {
456 operand = powerpc_operands + *opindex;
457 if (operand->extract)
458 (*operand->extract) (insn, dialect, &invalid);
459 }
460 if (invalid)
461 continue;
462
463 return opcode;
464 }
465
466 return NULL;
467 }
468
469 /* Find a match for INSN in the VLE opcode table. */
470
471 static const struct powerpc_opcode *
472 lookup_vle (unsigned long insn)
473 {
474 const struct powerpc_opcode *opcode;
475 const struct powerpc_opcode *opcode_end;
476 unsigned op, seg;
477
478 op = PPC_OP (insn);
479 if (op >= 0x20 && op <= 0x37)
480 {
481 /* This insn has a 4-bit opcode. */
482 op &= 0x3c;
483 }
484 seg = VLE_OP_TO_SEG (op);
485
486 /* Find the first match in the opcode table for this major opcode. */
487 opcode_end = vle_opcodes + vle_opcd_indices[seg + 1];
488 for (opcode = vle_opcodes + vle_opcd_indices[seg];
489 opcode < opcode_end;
490 ++opcode)
491 {
492 unsigned long table_opcd = opcode->opcode;
493 unsigned long table_mask = opcode->mask;
494 bfd_boolean table_op_is_short = PPC_OP_SE_VLE(table_mask);
495 unsigned long insn2;
496 const unsigned char *opindex;
497 const struct powerpc_operand *operand;
498 int invalid;
499
500 insn2 = insn;
501 if (table_op_is_short)
502 insn2 >>= 16;
503 if ((insn2 & table_mask) != table_opcd)
504 continue;
505
506 /* Check validity of operands. */
507 invalid = 0;
508 for (opindex = opcode->operands; *opindex != 0; ++opindex)
509 {
510 operand = powerpc_operands + *opindex;
511 if (operand->extract)
512 (*operand->extract) (insn, (ppc_cpu_t)0, &invalid);
513 }
514 if (invalid)
515 continue;
516
517 return opcode;
518 }
519
520 return NULL;
521 }
522
336 /* Print a PowerPC or POWER instruction. */ 523 /* Print a PowerPC or POWER instruction. */
337 524
338 static int 525 static int
339 print_insn_powerpc (bfd_vma memaddr, 526 print_insn_powerpc (bfd_vma memaddr,
340 struct disassemble_info *info, 527 struct disassemble_info *info,
341 int bigendian, 528 int bigendian,
342 ppc_cpu_t dialect) 529 ppc_cpu_t dialect)
343 { 530 {
344 bfd_byte buffer[4]; 531 bfd_byte buffer[4];
345 int status; 532 int status;
346 unsigned long insn; 533 unsigned long insn;
347 const struct powerpc_opcode *opcode; 534 const struct powerpc_opcode *opcode;
348 const struct powerpc_opcode *opcode_end; 535 bfd_boolean insn_is_short;
349 unsigned long op;
350 536
351 status = (*info->read_memory_func) (memaddr, buffer, 4, info); 537 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
352 if (status != 0) 538 if (status != 0)
353 { 539 {
354 (*info->memory_error_func) (status, memaddr, info); 540 /* The final instruction may be a 2-byte VLE insn. */
355 return -1; 541 if ((dialect & PPC_OPCODE_VLE) != 0)
542 {
543 /* Clear buffer so unused bytes will not have garbage in them. */
544 buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
545 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
546 if (status != 0)
547 {
548 (*info->memory_error_func) (status, memaddr, info);
549 return -1;
550 }
551 }
552 else
553 {
554 (*info->memory_error_func) (status, memaddr, info);
555 return -1;
556 }
356 } 557 }
357 558
358 if (bigendian) 559 if (bigendian)
359 insn = bfd_getb32 (buffer); 560 insn = bfd_getb32 (buffer);
360 else 561 else
361 insn = bfd_getl32 (buffer); 562 insn = bfd_getl32 (buffer);
362 563
363 /* Get the major opcode of the instruction. */ 564 /* Get the major opcode of the insn. */
364 op = PPC_OP (insn); 565 opcode = NULL;
566 insn_is_short = FALSE;
567 if ((dialect & PPC_OPCODE_VLE) != 0)
568 {
569 opcode = lookup_vle (insn);
570 if (opcode != NULL)
571 » insn_is_short = PPC_OP_SE_VLE(opcode->mask);
572 }
573 if (opcode == NULL)
574 opcode = lookup_powerpc (insn, dialect);
575 if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
576 opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
365 577
366 /* Find the first match in the opcode table. We could speed this up 578 if (opcode != NULL)
367 a bit by doing a binary search on the major opcode. */
368 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
369 again:
370 for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
371 { 579 {
372 unsigned long table_op;
373 const unsigned char *opindex; 580 const unsigned char *opindex;
374 const struct powerpc_operand *operand; 581 const struct powerpc_operand *operand;
375 int invalid;
376 int need_comma; 582 int need_comma;
377 int need_paren; 583 int need_paren;
378 int skip_optional; 584 int skip_optional;
379 585
380 table_op = PPC_OP (opcode->opcode);
381 if (op < table_op)
382 break;
383 if (op > table_op)
384 continue;
385
386 if ((insn & opcode->mask) != opcode->opcode
387 || (opcode->flags & dialect) == 0
388 || (dialect != ~(ppc_cpu_t) PPC_OPCODE_ANY
389 && (opcode->deprecated & dialect) != 0))
390 continue;
391
392 /* Make two passes over the operands. First see if any of them
393 have extraction functions, and, if they do, make sure the
394 instruction is valid. */
395 invalid = 0;
396 for (opindex = opcode->operands; *opindex != 0; opindex++)
397 {
398 operand = powerpc_operands + *opindex;
399 if (operand->extract)
400 (*operand->extract) (insn, dialect, &invalid);
401 }
402 if (invalid)
403 continue;
404
405 /* The instruction is valid. */
406 if (opcode->operands[0] != 0) 586 if (opcode->operands[0] != 0)
407 (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); 587 (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
408 else 588 else
409 (*info->fprintf_func) (info->stream, "%s", opcode->name); 589 (*info->fprintf_func) (info->stream, "%s", opcode->name);
410 590
591 if (insn_is_short)
592 /* The operands will be fetched out of the 16-bit instruction. */
593 insn >>= 16;
594
411 /* Now extract and print the operands. */ 595 /* Now extract and print the operands. */
412 need_comma = 0; 596 need_comma = 0;
413 need_paren = 0; 597 need_paren = 0;
414 skip_optional = -1; 598 skip_optional = -1;
415 for (opindex = opcode->operands; *opindex != 0; opindex++) 599 for (opindex = opcode->operands; *opindex != 0; opindex++)
416 { 600 {
417 long value; 601 long value;
418 602
419 operand = powerpc_operands + *opindex; 603 operand = powerpc_operands + *opindex;
420 604
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 640 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
457 (*info->print_address_func) (memaddr + value, info); 641 (*info->print_address_func) (memaddr + value, info);
458 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 642 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
459 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 643 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
460 else if ((operand->flags & PPC_OPERAND_FSL) != 0) 644 else if ((operand->flags & PPC_OPERAND_FSL) != 0)
461 (*info->fprintf_func) (info->stream, "fsl%ld", value); 645 (*info->fprintf_func) (info->stream, "fsl%ld", value);
462 else if ((operand->flags & PPC_OPERAND_FCR) != 0) 646 else if ((operand->flags & PPC_OPERAND_FCR) != 0)
463 (*info->fprintf_func) (info->stream, "fcr%ld", value); 647 (*info->fprintf_func) (info->stream, "fcr%ld", value);
464 else if ((operand->flags & PPC_OPERAND_UDI) != 0) 648 else if ((operand->flags & PPC_OPERAND_UDI) != 0)
465 (*info->fprintf_func) (info->stream, "%ld", value); 649 (*info->fprintf_func) (info->stream, "%ld", value);
466 » else if ((operand->flags & PPC_OPERAND_CR) != 0 650 » else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
467 » » && (dialect & PPC_OPCODE_PPC) != 0) 651 » » && (((dialect & PPC_OPCODE_PPC) != 0)
652 » » || ((dialect & PPC_OPCODE_VLE) != 0)))
653 » (*info->fprintf_func) (info->stream, "cr%ld", value);
654 » else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
655 » » && (((dialect & PPC_OPCODE_PPC) != 0)
656 » » || ((dialect & PPC_OPCODE_VLE) != 0)))
468 { 657 {
469 » if (operand->bitm == 7) 658 » static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
470 » » (*info->fprintf_func) (info->stream, "cr%ld", value); 659 » int cr;
471 » else 660 » int cc;
472 » » {
473 » » static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
474 » » int cr;
475 » » int cc;
476 661
477 » » cr = value >> 2; 662 » cr = value >> 2;
478 » » if (cr != 0) 663 » if (cr != 0)
479 » » (*info->fprintf_func) (info->stream, "4*cr%d+", cr); 664 » » (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
480 » » cc = value & 3; 665 » cc = value & 3;
481 » » (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); 666 » (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
482 » » }
483 } 667 }
484 else 668 else
485 » (*info->fprintf_func) (info->stream, "%ld", value); 669 » (*info->fprintf_func) (info->stream, "%d", value);
486 670
487 if (need_paren) 671 if (need_paren)
488 { 672 {
489 (*info->fprintf_func) (info->stream, ")"); 673 (*info->fprintf_func) (info->stream, ")");
490 need_paren = 0; 674 need_paren = 0;
491 } 675 }
492 676
493 if ((operand->flags & PPC_OPERAND_PARENS) == 0) 677 if ((operand->flags & PPC_OPERAND_PARENS) == 0)
494 need_comma = 1; 678 need_comma = 1;
495 else 679 else
496 { 680 {
497 (*info->fprintf_func) (info->stream, "("); 681 (*info->fprintf_func) (info->stream, "(");
498 need_paren = 1; 682 need_paren = 1;
499 } 683 }
500 } 684 }
501 685
502 /* We have found and printed an instruction; return. */ 686 /* We have found and printed an instruction.
503 return 4; 687 If it was a short VLE instruction we have more to do. */
504 } 688 if (insn_is_short)
505 689 {
506 if ((dialect & PPC_OPCODE_ANY) != 0) 690 memaddr += 2;
507 { 691 return 2;
508 dialect = ~(ppc_cpu_t) PPC_OPCODE_ANY; 692 }
509 goto again; 693 else
694 /* Otherwise, return. */
695 return 4;
510 } 696 }
511 697
512 /* We could not find a match. */ 698 /* We could not find a match. */
513 (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); 699 (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
514 700
515 return 4; 701 return 4;
516 } 702 }
517 703
518 void 704 void
519 print_ppc_disassembler_options (FILE *stream) 705 print_ppc_disassembler_options (FILE *stream)
520 { 706 {
521 unsigned int i, col; 707 unsigned int i, col;
522 708
523 fprintf (stream, _("\n\ 709 fprintf (stream, _("\n\
524 The following PPC specific disassembler options are supported for use with\n\ 710 The following PPC specific disassembler options are supported for use with\n\
525 the -M switch:\n")); 711 the -M switch:\n"));
526 712
527 for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++) 713 for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
528 { 714 {
529 col += fprintf (stream, " %s,", ppc_opts[i].opt); 715 col += fprintf (stream, " %s,", ppc_opts[i].opt);
530 if (col > 66) 716 if (col > 66)
531 { 717 {
532 fprintf (stream, "\n"); 718 fprintf (stream, "\n");
533 col = 0; 719 col = 0;
534 } 720 }
535 } 721 }
536 fprintf (stream, " 32, 64\n"); 722 fprintf (stream, " 32, 64\n");
537 } 723 }
OLDNEW
« no previous file with comments | « opcodes/po/vi.po ('k') | opcodes/ppc-opc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698