* config/obj-elf.c: (obj_elf_change_section): Add "group" param.
[deliverable/binutils-gdb.git] / opcodes / openrisc-dis.c
CommitLineData
87e6d782
NC
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4THIS FILE IS MACHINE GENERATED WITH CGEN.
5- the resultant file is machine generated, cgen-dis.in isn't
6
7Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
8
9This file is part of the GNU Binutils and GDB, the GNU debugger.
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2, or (at your option)
14any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software Foundation, Inc.,
2359 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24
25/* ??? Eventually more and more of this stuff can go to cpu-independent files.
26 Keep that in mind. */
27
28#include "sysdep.h"
29#include <stdio.h>
30#include "ansidecl.h"
31#include "dis-asm.h"
32#include "bfd.h"
33#include "symcat.h"
34#include "openrisc-desc.h"
35#include "openrisc-opc.h"
36#include "opintl.h"
37
38/* Default text to print if an instruction isn't recognized. */
39#define UNKNOWN_INSN_MSG _("*unknown*")
40
41static void print_normal
42 PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int));
43static void print_address
44 PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
45static void print_keyword
46 PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
47static void print_insn_normal
48 PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
49 bfd_vma, int));
50static int print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma,
51 disassemble_info *, char *, int));
52static int default_print_insn
53 PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
fc05c67f
NC
54void openrisc_cgen_print_operand
55 PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int));
56static int read_insn
57 PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, CGEN_EXTRACT_INFO *, unsigned long *));
87e6d782
NC
58\f
59/* -- disassembler routines inserted here */
60
61
62/* Main entry point for printing operands.
63 XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
64 of dis-asm.h on cgen.h.
65
66 This function is basically just a big switch statement. Earlier versions
67 used tables to look up the function to use, but
68 - if the table contains both assembler and disassembler functions then
69 the disassembler contains much of the assembler and vice-versa,
70 - there's a lot of inlining possibilities as things grow,
71 - using a switch statement avoids the function call overhead.
72
73 This function could be moved into `print_insn_normal', but keeping it
74 separate makes clear the interface between `print_insn_normal' and each of
75 the handlers.
76*/
77
78void
79openrisc_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
80 CGEN_CPU_DESC cd;
81 int opindex;
82 PTR xinfo;
83 CGEN_FIELDS *fields;
fc05c67f 84 void const *attrs ATTRIBUTE_UNUSED;
87e6d782
NC
85 bfd_vma pc;
86 int length;
87{
88 disassemble_info *info = (disassemble_info *) xinfo;
89
90 switch (opindex)
91 {
92 case OPENRISC_OPERAND_ABS_26 :
93 print_address (cd, info, fields->f_abs26, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
94 break;
95 case OPENRISC_OPERAND_DISP_26 :
96 print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
97 break;
98 case OPENRISC_OPERAND_HI16 :
99 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
100 break;
101 case OPENRISC_OPERAND_LO16 :
102 print_normal (cd, info, fields->f_lo16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
103 break;
104 case OPENRISC_OPERAND_OP_F_23 :
105 print_normal (cd, info, fields->f_op4, 0, pc, length);
106 break;
107 case OPENRISC_OPERAND_OP_F_3 :
108 print_normal (cd, info, fields->f_op5, 0, pc, length);
109 break;
110 case OPENRISC_OPERAND_RA :
111 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r2, 0);
112 break;
113 case OPENRISC_OPERAND_RB :
114 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r3, 0);
115 break;
116 case OPENRISC_OPERAND_RD :
117 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r1, 0);
118 break;
119 case OPENRISC_OPERAND_SIMM_16 :
120 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
121 break;
122 case OPENRISC_OPERAND_UI16NC :
123 print_normal (cd, info, fields->f_i16nc, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
124 break;
125 case OPENRISC_OPERAND_UIMM_16 :
126 print_normal (cd, info, fields->f_uimm16, 0, pc, length);
127 break;
128 case OPENRISC_OPERAND_UIMM_5 :
129 print_normal (cd, info, fields->f_uimm5, 0, pc, length);
130 break;
131
132 default :
133 /* xgettext:c-format */
134 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
135 opindex);
136 abort ();
137 }
138}
139
140cgen_print_fn * const openrisc_cgen_print_handlers[] =
141{
142 print_insn_normal,
143};
144
145
146void
147openrisc_cgen_init_dis (cd)
148 CGEN_CPU_DESC cd;
149{
150 openrisc_cgen_init_opcode_table (cd);
151 openrisc_cgen_init_ibld_table (cd);
152 cd->print_handlers = & openrisc_cgen_print_handlers[0];
153 cd->print_operand = openrisc_cgen_print_operand;
154}
155
156\f
157/* Default print handler. */
158
159static void
160print_normal (cd, dis_info, value, attrs, pc, length)
161#ifdef CGEN_PRINT_NORMAL
162 CGEN_CPU_DESC cd;
163#else
164 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
165#endif
166 PTR dis_info;
167 long value;
168 unsigned int attrs;
169#ifdef CGEN_PRINT_NORMAL
170 bfd_vma pc;
171 int length;
172#else
173 bfd_vma pc ATTRIBUTE_UNUSED;
174 int length ATTRIBUTE_UNUSED;
175#endif
176{
177 disassemble_info *info = (disassemble_info *) dis_info;
178
179#ifdef CGEN_PRINT_NORMAL
180 CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
181#endif
182
183 /* Print the operand as directed by the attributes. */
184 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
185 ; /* nothing to do */
186 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
187 (*info->fprintf_func) (info->stream, "%ld", value);
188 else
189 (*info->fprintf_func) (info->stream, "0x%lx", value);
190}
191
192/* Default address handler. */
193
194static void
195print_address (cd, dis_info, value, attrs, pc, length)
196#ifdef CGEN_PRINT_NORMAL
197 CGEN_CPU_DESC cd;
198#else
199 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
200#endif
201 PTR dis_info;
202 bfd_vma value;
203 unsigned int attrs;
204#ifdef CGEN_PRINT_NORMAL
205 bfd_vma pc;
206 int length;
207#else
208 bfd_vma pc ATTRIBUTE_UNUSED;
209 int length ATTRIBUTE_UNUSED;
210#endif
211{
212 disassemble_info *info = (disassemble_info *) dis_info;
213
214#ifdef CGEN_PRINT_ADDRESS
215 CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
216#endif
217
218 /* Print the operand as directed by the attributes. */
219 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
220 ; /* nothing to do */
221 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
222 (*info->print_address_func) (value, info);
223 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
224 (*info->print_address_func) (value, info);
225 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
226 (*info->fprintf_func) (info->stream, "%ld", (long) value);
227 else
228 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
229}
230
231/* Keyword print handler. */
232
233static void
234print_keyword (cd, dis_info, keyword_table, value, attrs)
235 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
236 PTR dis_info;
237 CGEN_KEYWORD *keyword_table;
238 long value;
239 unsigned int attrs ATTRIBUTE_UNUSED;
240{
241 disassemble_info *info = (disassemble_info *) dis_info;
242 const CGEN_KEYWORD_ENTRY *ke;
243
244 ke = cgen_keyword_lookup_value (keyword_table, value);
245 if (ke != NULL)
246 (*info->fprintf_func) (info->stream, "%s", ke->name);
247 else
248 (*info->fprintf_func) (info->stream, "???");
249}
250\f
251/* Default insn printer.
252
253 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
254 about disassemble_info. */
255
256static void
257print_insn_normal (cd, dis_info, insn, fields, pc, length)
258 CGEN_CPU_DESC cd;
259 PTR dis_info;
260 const CGEN_INSN *insn;
261 CGEN_FIELDS *fields;
262 bfd_vma pc;
263 int length;
264{
265 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
266 disassemble_info *info = (disassemble_info *) dis_info;
267 const CGEN_SYNTAX_CHAR_TYPE *syn;
268
269 CGEN_INIT_PRINT (cd);
270
271 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
272 {
273 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
274 {
275 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
276 continue;
277 }
278 if (CGEN_SYNTAX_CHAR_P (*syn))
279 {
280 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
281 continue;
282 }
283
284 /* We have an operand. */
285 openrisc_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
286 fields, CGEN_INSN_ATTRS (insn), pc, length);
287 }
288}
289\f
290/* Subroutine of print_insn. Reads an insn into the given buffers and updates
291 the extract info.
292 Returns 0 if all is well, non-zero otherwise. */
293static int
294read_insn (cd, pc, info, buf, buflen, ex_info, insn_value)
fc05c67f 295 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
87e6d782
NC
296 bfd_vma pc;
297 disassemble_info *info;
298 char *buf;
299 int buflen;
300 CGEN_EXTRACT_INFO *ex_info;
301 unsigned long *insn_value;
302{
303 int status = (*info->read_memory_func) (pc, buf, buflen, info);
304 if (status != 0)
305 {
306 (*info->memory_error_func) (status, pc, info);
307 return -1;
308 }
309
310 ex_info->dis_info = info;
311 ex_info->valid = (1 << buflen) - 1;
312 ex_info->insn_bytes = buf;
313
314 *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
315 return 0;
316}
317
318/* Utility to print an insn.
319 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
320 The result is the size of the insn in bytes or zero for an unknown insn
321 or -1 if an error occurs fetching data (memory_error_func will have
322 been called). */
323
324static int
325print_insn (cd, pc, info, buf, buflen)
326 CGEN_CPU_DESC cd;
327 bfd_vma pc;
328 disassemble_info *info;
329 char *buf;
330 int buflen;
331{
fc7bc883 332 CGEN_INSN_INT insn_value;
87e6d782
NC
333 const CGEN_INSN_LIST *insn_list;
334 CGEN_EXTRACT_INFO ex_info;
335
fc7bc883
RH
336 /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
337 insn_value = cgen_get_insn_value (cd, buf, buflen * 8);
338
339 /* Fill in ex_info fields like read_insn would. Don't actually call
340 read_insn, since the incoming buffer is already read (and possibly
341 modified a la m32r). */
342 ex_info.valid = (1 << buflen) - 1;
343 ex_info.dis_info = info;
344 ex_info.insn_bytes = buf;
87e6d782
NC
345
346 /* The instructions are stored in hash lists.
347 Pick the first one and keep trying until we find the right one. */
348
349 insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
350 while (insn_list != NULL)
351 {
352 const CGEN_INSN *insn = insn_list->insn;
353 CGEN_FIELDS fields;
354 int length;
fc7bc883 355 unsigned long insn_value_cropped;
87e6d782
NC
356
357#ifdef CGEN_VALIDATE_INSN_SUPPORTED
358 /* not needed as insn shouldn't be in hash lists if not supported */
359 /* Supported by this cpu? */
360 if (! openrisc_cgen_insn_supported (cd, insn))
361 {
362 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
363 continue;
364 }
365#endif
366
367 /* Basic bit mask must be correct. */
368 /* ??? May wish to allow target to defer this check until the extract
369 handler. */
fc7bc883
RH
370
371 /* Base size may exceed this instruction's size. Extract the
372 relevant part from the buffer. */
373 if ((CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
fc05c67f 374 ((unsigned) CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
fc7bc883
RH
375 insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
376 info->endian == BFD_ENDIAN_BIG);
377 else
378 insn_value_cropped = insn_value;
379
380 if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
87e6d782
NC
381 == CGEN_INSN_BASE_VALUE (insn))
382 {
383 /* Printing is handled in two passes. The first pass parses the
384 machine insn and extracts the fields. The second pass prints
385 them. */
386
387 /* Make sure the entire insn is loaded into insn_value, if it
388 can fit. */
fc05c67f
NC
389 if ( (unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize &&
390 ((unsigned) CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
87e6d782
NC
391 {
392 unsigned long full_insn_value;
393 int rc = read_insn (cd, pc, info, buf,
394 CGEN_INSN_BITSIZE (insn) / 8,
395 & ex_info, & full_insn_value);
396 if (rc != 0)
397 return rc;
398 length = CGEN_EXTRACT_FN (cd, insn)
399 (cd, insn, &ex_info, full_insn_value, &fields, pc);
400 }
401 else
402 length = CGEN_EXTRACT_FN (cd, insn)
fc7bc883 403 (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
87e6d782
NC
404
405 /* length < 0 -> error */
406 if (length < 0)
407 return length;
408 if (length > 0)
409 {
410 CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
411 /* length is in bits, result is in bytes */
412 return length / 8;
413 }
414 }
415
416 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
417 }
418
419 return 0;
420}
421
422/* Default value for CGEN_PRINT_INSN.
423 The result is the size of the insn in bytes or zero for an unknown insn
424 or -1 if an error occured fetching bytes. */
425
426#ifndef CGEN_PRINT_INSN
427#define CGEN_PRINT_INSN default_print_insn
428#endif
429
430static int
431default_print_insn (cd, pc, info)
432 CGEN_CPU_DESC cd;
433 bfd_vma pc;
434 disassemble_info *info;
435{
436 char buf[CGEN_MAX_INSN_SIZE];
fc7bc883 437 int buflen;
87e6d782
NC
438 int status;
439
fc7bc883
RH
440 /* Attempt to read the base part of the insn. */
441 buflen = cd->base_insn_bitsize / 8;
442 status = (*info->read_memory_func) (pc, buf, buflen, info);
443
444 /* Try again with the minimum part, if min < base. */
445 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
446 {
447 buflen = cd->min_insn_bitsize / 8;
448 status = (*info->read_memory_func) (pc, buf, buflen, info);
449 }
87e6d782 450
87e6d782
NC
451 if (status != 0)
452 {
453 (*info->memory_error_func) (status, pc, info);
454 return -1;
455 }
456
fc7bc883 457 return print_insn (cd, pc, info, buf, buflen);
87e6d782
NC
458}
459
460/* Main entry point.
461 Print one instruction from PC on INFO->STREAM.
462 Return the size of the instruction (in bytes). */
463
464int
465print_insn_openrisc (pc, info)
466 bfd_vma pc;
467 disassemble_info *info;
468{
469 static CGEN_CPU_DESC cd = 0;
470 static int prev_isa;
471 static int prev_mach;
472 static int prev_endian;
473 int length;
474 int isa,mach;
475 int endian = (info->endian == BFD_ENDIAN_BIG
476 ? CGEN_ENDIAN_BIG
477 : CGEN_ENDIAN_LITTLE);
478 enum bfd_architecture arch;
479
480 /* ??? gdb will set mach but leave the architecture as "unknown" */
481#ifndef CGEN_BFD_ARCH
482#define CGEN_BFD_ARCH bfd_arch_openrisc
483#endif
484 arch = info->arch;
485 if (arch == bfd_arch_unknown)
486 arch = CGEN_BFD_ARCH;
487
488 /* There's no standard way to compute the machine or isa number
489 so we leave it to the target. */
490#ifdef CGEN_COMPUTE_MACH
491 mach = CGEN_COMPUTE_MACH (info);
492#else
493 mach = info->mach;
494#endif
495
496#ifdef CGEN_COMPUTE_ISA
497 isa = CGEN_COMPUTE_ISA (info);
498#else
499 isa = 0;
500#endif
501
502 /* If we've switched cpu's, close the current table and open a new one. */
503 if (cd
504 && (isa != prev_isa
505 || mach != prev_mach
506 || endian != prev_endian))
507 {
508 openrisc_cgen_cpu_close (cd);
509 cd = 0;
510 }
511
512 /* If we haven't initialized yet, initialize the opcode table. */
513 if (! cd)
514 {
515 const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
516 const char *mach_name;
517
518 if (!arch_type)
519 abort ();
520 mach_name = arch_type->printable_name;
521
522 prev_isa = isa;
523 prev_mach = mach;
524 prev_endian = endian;
525 cd = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
526 CGEN_CPU_OPEN_BFDMACH, mach_name,
527 CGEN_CPU_OPEN_ENDIAN, prev_endian,
528 CGEN_CPU_OPEN_END);
529 if (!cd)
530 abort ();
531 openrisc_cgen_init_dis (cd);
532 }
533
534 /* We try to have as much common code as possible.
535 But at this point some targets need to take over. */
536 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
537 but if not possible try to move this hook elsewhere rather than
538 have two hooks. */
539 length = CGEN_PRINT_INSN (cd, pc, info);
540 if (length > 0)
541 return length;
542 if (length < 0)
543 return -1;
544
545 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
546 return cd->default_insn_bitsize / 8;
547}
This page took 0.064118 seconds and 4 git commands to generate.