~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to opcodes/cgen-dis.in

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Disassembler interface for targets using CGEN. -*- C -*-
 
2
   CGEN: Cpu tools GENerator
 
3
 
 
4
THIS FILE IS MACHINE GENERATED WITH CGEN.
 
5
- the resultant file is machine generated, cgen-dis.in isn't
 
6
 
 
7
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
 
8
Free Software Foundation, Inc.
 
9
 
 
10
This file is part of the GNU Binutils and GDB, the GNU debugger.
 
11
 
 
12
This program is free software; you can redistribute it and/or modify
 
13
it under the terms of the GNU General Public License as published by
 
14
the Free Software Foundation; either version 2, or (at your option)
 
15
any later version.
 
16
 
 
17
This program is distributed in the hope that it will be useful,
 
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
GNU General Public License for more details.
 
21
 
 
22
You should have received a copy of the GNU General Public License
 
23
along with this program; if not, write to the Free Software Foundation, Inc.,
 
24
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
25
 
 
26
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
 
27
   Keep that in mind.  */
 
28
 
 
29
#include "sysdep.h"
 
30
#include <stdio.h>
 
31
#include "ansidecl.h"
 
32
#include "dis-asm.h"
 
33
#include "bfd.h"
 
34
#include "symcat.h"
 
35
#include "libiberty.h"
 
36
#include "@prefix@-desc.h"
 
37
#include "@prefix@-opc.h"
 
38
#include "opintl.h"
 
39
 
 
40
/* Default text to print if an instruction isn't recognized.  */
 
41
#define UNKNOWN_INSN_MSG _("*unknown*")
 
42
 
 
43
static void print_normal
 
44
  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
 
45
static void print_address
 
46
  (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int);
 
47
static void print_keyword
 
48
  (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int);
 
49
static void print_insn_normal
 
50
  (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
 
51
static int print_insn
 
52
  (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned);
 
53
static int default_print_insn
 
54
  (CGEN_CPU_DESC, bfd_vma, disassemble_info *);
 
55
static int read_insn
 
56
  (CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, CGEN_EXTRACT_INFO *,
 
57
   unsigned long *);
 
58
 
 
59
/* -- disassembler routines inserted here */
 
60
 
 
61
/* Default print handler.  */
 
62
 
 
63
static void
 
64
print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
65
              void *dis_info,
 
66
              long value,
 
67
              unsigned int attrs,
 
68
              bfd_vma pc ATTRIBUTE_UNUSED,
 
69
              int length ATTRIBUTE_UNUSED)
 
70
{
 
71
  disassemble_info *info = (disassemble_info *) dis_info;
 
72
 
 
73
#ifdef CGEN_PRINT_NORMAL
 
74
  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
 
75
#endif
 
76
 
 
77
  /* Print the operand as directed by the attributes.  */
 
78
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
 
79
    ; /* nothing to do */
 
80
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
 
81
    (*info->fprintf_func) (info->stream, "%ld", value);
 
82
  else
 
83
    (*info->fprintf_func) (info->stream, "0x%lx", value);
 
84
}
 
85
 
 
86
/* Default address handler.  */
 
87
 
 
88
static void
 
89
print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
90
               void *dis_info,
 
91
               bfd_vma value,
 
92
               unsigned int attrs,
 
93
               bfd_vma pc ATTRIBUTE_UNUSED,
 
94
               int length ATTRIBUTE_UNUSED)
 
95
{
 
96
  disassemble_info *info = (disassemble_info *) dis_info;
 
97
 
 
98
#ifdef CGEN_PRINT_ADDRESS
 
99
  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
 
100
#endif
 
101
 
 
102
  /* Print the operand as directed by the attributes.  */
 
103
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
 
104
    ; /* nothing to do */
 
105
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
 
106
    (*info->print_address_func) (value, info);
 
107
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
 
108
    (*info->print_address_func) (value, info);
 
109
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
 
110
    (*info->fprintf_func) (info->stream, "%ld", (long) value);
 
111
  else
 
112
    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
 
113
}
 
114
 
 
115
/* Keyword print handler.  */
 
116
 
 
117
static void
 
118
print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
119
               void *dis_info,
 
120
               CGEN_KEYWORD *keyword_table,
 
121
               long value,
 
122
               unsigned int attrs ATTRIBUTE_UNUSED)
 
123
{
 
124
  disassemble_info *info = (disassemble_info *) dis_info;
 
125
  const CGEN_KEYWORD_ENTRY *ke;
 
126
 
 
127
  ke = cgen_keyword_lookup_value (keyword_table, value);
 
128
  if (ke != NULL)
 
129
    (*info->fprintf_func) (info->stream, "%s", ke->name);
 
130
  else
 
131
    (*info->fprintf_func) (info->stream, "???");
 
132
}
 
133
 
 
134
/* Default insn printer.
 
135
 
 
136
   DIS_INFO is defined as `void *' so the disassembler needn't know anything
 
137
   about disassemble_info.  */
 
138
 
 
139
static void
 
140
print_insn_normal (CGEN_CPU_DESC cd,
 
141
                   void *dis_info,
 
142
                   const CGEN_INSN *insn,
 
143
                   CGEN_FIELDS *fields,
 
144
                   bfd_vma pc,
 
145
                   int length)
 
146
{
 
147
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
 
148
  disassemble_info *info = (disassemble_info *) dis_info;
 
149
  const CGEN_SYNTAX_CHAR_TYPE *syn;
 
150
 
 
151
  CGEN_INIT_PRINT (cd);
 
152
 
 
153
  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
 
154
    {
 
155
      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
 
156
        {
 
157
          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
 
158
          continue;
 
159
        }
 
160
      if (CGEN_SYNTAX_CHAR_P (*syn))
 
161
        {
 
162
          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
 
163
          continue;
 
164
        }
 
165
 
 
166
      /* We have an operand.  */
 
167
      @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
 
168
                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
 
169
    }
 
170
}
 
171
 
 
172
/* Subroutine of print_insn. Reads an insn into the given buffers and updates
 
173
   the extract info.
 
174
   Returns 0 if all is well, non-zero otherwise.  */
 
175
 
 
176
static int
 
177
read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
178
           bfd_vma pc,
 
179
           disassemble_info *info,
 
180
           char *buf,
 
181
           int buflen,
 
182
           CGEN_EXTRACT_INFO *ex_info,
 
183
           unsigned long *insn_value)
 
184
{
 
185
  int status = (*info->read_memory_func) (pc, buf, buflen, info);
 
186
  if (status != 0)
 
187
    {
 
188
      (*info->memory_error_func) (status, pc, info);
 
189
      return -1;
 
190
    }
 
191
 
 
192
  ex_info->dis_info = info;
 
193
  ex_info->valid = (1 << buflen) - 1;
 
194
  ex_info->insn_bytes = buf;
 
195
 
 
196
  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
 
197
  return 0;
 
198
}
 
199
 
 
200
/* Utility to print an insn.
 
201
   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
 
202
   The result is the size of the insn in bytes or zero for an unknown insn
 
203
   or -1 if an error occurs fetching data (memory_error_func will have
 
204
   been called).  */
 
205
 
 
206
static int
 
207
print_insn (CGEN_CPU_DESC cd,
 
208
            bfd_vma pc,
 
209
            disassemble_info *info,
 
210
            char *buf,
 
211
            unsigned int buflen)
 
212
{
 
213
  CGEN_INSN_INT insn_value;
 
214
  const CGEN_INSN_LIST *insn_list;
 
215
  CGEN_EXTRACT_INFO ex_info;
 
216
  int basesize;
 
217
 
 
218
  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
 
219
  basesize = cd->base_insn_bitsize < buflen * 8 ?
 
220
                                     cd->base_insn_bitsize : buflen * 8;
 
221
  insn_value = cgen_get_insn_value (cd, buf, basesize);
 
222
 
 
223
 
 
224
  /* Fill in ex_info fields like read_insn would.  Don't actually call
 
225
     read_insn, since the incoming buffer is already read (and possibly
 
226
     modified a la m32r).  */
 
227
  ex_info.valid = (1 << buflen) - 1;
 
228
  ex_info.dis_info = info;
 
229
  ex_info.insn_bytes = buf;
 
230
 
 
231
  /* The instructions are stored in hash lists.
 
232
     Pick the first one and keep trying until we find the right one.  */
 
233
 
 
234
  insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
 
235
  while (insn_list != NULL)
 
236
    {
 
237
      const CGEN_INSN *insn = insn_list->insn;
 
238
      CGEN_FIELDS fields;
 
239
      int length;
 
240
      unsigned long insn_value_cropped;
 
241
 
 
242
#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
 
243
      /* Not needed as insn shouldn't be in hash lists if not supported.  */
 
244
      /* Supported by this cpu?  */
 
245
      if (! @arch@_cgen_insn_supported (cd, insn))
 
246
        {
 
247
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
 
248
          continue;
 
249
        }
 
250
#endif
 
251
 
 
252
      /* Basic bit mask must be correct.  */
 
253
      /* ??? May wish to allow target to defer this check until the extract
 
254
         handler.  */
 
255
 
 
256
      /* Base size may exceed this instruction's size.  Extract the
 
257
         relevant part from the buffer. */
 
258
      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
 
259
          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
 
260
        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
 
261
                                           info->endian == BFD_ENDIAN_BIG);
 
262
      else
 
263
        insn_value_cropped = insn_value;
 
264
 
 
265
      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
 
266
          == CGEN_INSN_BASE_VALUE (insn))
 
267
        {
 
268
          /* Printing is handled in two passes.  The first pass parses the
 
269
             machine insn and extracts the fields.  The second pass prints
 
270
             them.  */
 
271
 
 
272
          /* Make sure the entire insn is loaded into insn_value, if it
 
273
             can fit.  */
 
274
          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
 
275
              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
 
276
            {
 
277
              unsigned long full_insn_value;
 
278
              int rc = read_insn (cd, pc, info, buf,
 
279
                                  CGEN_INSN_BITSIZE (insn) / 8,
 
280
                                  & ex_info, & full_insn_value);
 
281
              if (rc != 0)
 
282
                return rc;
 
283
              length = CGEN_EXTRACT_FN (cd, insn)
 
284
                (cd, insn, &ex_info, full_insn_value, &fields, pc);
 
285
            }
 
286
          else
 
287
            length = CGEN_EXTRACT_FN (cd, insn)
 
288
              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
 
289
 
 
290
          /* length < 0 -> error */
 
291
          if (length < 0)
 
292
            return length;
 
293
          if (length > 0)
 
294
            {
 
295
              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
 
296
              /* length is in bits, result is in bytes */
 
297
              return length / 8;
 
298
            }
 
299
        }
 
300
 
 
301
      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
 
302
    }
 
303
 
 
304
  return 0;
 
305
}
 
306
 
 
307
/* Default value for CGEN_PRINT_INSN.
 
308
   The result is the size of the insn in bytes or zero for an unknown insn
 
309
   or -1 if an error occured fetching bytes.  */
 
310
 
 
311
#ifndef CGEN_PRINT_INSN
 
312
#define CGEN_PRINT_INSN default_print_insn
 
313
#endif
 
314
 
 
315
static int
 
316
default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
 
317
{
 
318
  char buf[CGEN_MAX_INSN_SIZE];
 
319
  int buflen;
 
320
  int status;
 
321
 
 
322
  /* Attempt to read the base part of the insn.  */
 
323
  buflen = cd->base_insn_bitsize / 8;
 
324
  status = (*info->read_memory_func) (pc, buf, buflen, info);
 
325
 
 
326
  /* Try again with the minimum part, if min < base.  */
 
327
  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
 
328
    {
 
329
      buflen = cd->min_insn_bitsize / 8;
 
330
      status = (*info->read_memory_func) (pc, buf, buflen, info);
 
331
    }
 
332
 
 
333
  if (status != 0)
 
334
    {
 
335
      (*info->memory_error_func) (status, pc, info);
 
336
      return -1;
 
337
    }
 
338
 
 
339
  return print_insn (cd, pc, info, buf, buflen);
 
340
}
 
341
 
 
342
/* Main entry point.
 
343
   Print one instruction from PC on INFO->STREAM.
 
344
   Return the size of the instruction (in bytes).  */
 
345
 
 
346
typedef struct cpu_desc_list {
 
347
  struct cpu_desc_list *next;
 
348
  int isa;
 
349
  int mach;
 
350
  int endian;
 
351
  CGEN_CPU_DESC cd;
 
352
} cpu_desc_list;
 
353
 
 
354
int
 
355
print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
 
356
{
 
357
  static cpu_desc_list *cd_list = 0;
 
358
  cpu_desc_list *cl = 0;
 
359
  static CGEN_CPU_DESC cd = 0;
 
360
  static int prev_isa;
 
361
  static int prev_mach;
 
362
  static int prev_endian;
 
363
  int length;
 
364
  int isa,mach;
 
365
  int endian = (info->endian == BFD_ENDIAN_BIG
 
366
                ? CGEN_ENDIAN_BIG
 
367
                : CGEN_ENDIAN_LITTLE);
 
368
  enum bfd_architecture arch;
 
369
 
 
370
  /* ??? gdb will set mach but leave the architecture as "unknown" */
 
371
#ifndef CGEN_BFD_ARCH
 
372
#define CGEN_BFD_ARCH bfd_arch_@arch@
 
373
#endif
 
374
  arch = info->arch;
 
375
  if (arch == bfd_arch_unknown)
 
376
    arch = CGEN_BFD_ARCH;
 
377
   
 
378
  /* There's no standard way to compute the machine or isa number
 
379
     so we leave it to the target.  */
 
380
#ifdef CGEN_COMPUTE_MACH
 
381
  mach = CGEN_COMPUTE_MACH (info);
 
382
#else
 
383
  mach = info->mach;
 
384
#endif
 
385
 
 
386
#ifdef CGEN_COMPUTE_ISA
 
387
  isa = CGEN_COMPUTE_ISA (info);
 
388
#else
 
389
  isa = info->insn_sets;
 
390
#endif
 
391
 
 
392
  /* If we've switched cpu's, try to find a handle we've used before */
 
393
  if (cd
 
394
      && (isa != prev_isa
 
395
          || mach != prev_mach
 
396
          || endian != prev_endian))
 
397
    {
 
398
      cd = 0;
 
399
      for (cl = cd_list; cl; cl = cl->next)
 
400
        {
 
401
          if (cl->isa == isa &&
 
402
              cl->mach == mach &&
 
403
              cl->endian == endian)
 
404
            {
 
405
              cd = cl->cd;
 
406
              break;
 
407
            }
 
408
        }
 
409
    } 
 
410
 
 
411
  /* If we haven't initialized yet, initialize the opcode table.  */
 
412
  if (! cd)
 
413
    {
 
414
      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
 
415
      const char *mach_name;
 
416
 
 
417
      if (!arch_type)
 
418
        abort ();
 
419
      mach_name = arch_type->printable_name;
 
420
 
 
421
      prev_isa = isa;
 
422
      prev_mach = mach;
 
423
      prev_endian = endian;
 
424
      cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
 
425
                                 CGEN_CPU_OPEN_BFDMACH, mach_name,
 
426
                                 CGEN_CPU_OPEN_ENDIAN, prev_endian,
 
427
                                 CGEN_CPU_OPEN_END);
 
428
      if (!cd)
 
429
        abort ();
 
430
 
 
431
      /* save this away for future reference */
 
432
      cl = xmalloc (sizeof (struct cpu_desc_list));
 
433
      cl->cd = cd;
 
434
      cl->isa = isa;
 
435
      cl->mach = mach;
 
436
      cl->endian = endian;
 
437
      cl->next = cd_list;
 
438
      cd_list = cl;
 
439
 
 
440
      @arch@_cgen_init_dis (cd);
 
441
    }
 
442
 
 
443
  /* We try to have as much common code as possible.
 
444
     But at this point some targets need to take over.  */
 
445
  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
 
446
     but if not possible try to move this hook elsewhere rather than
 
447
     have two hooks.  */
 
448
  length = CGEN_PRINT_INSN (cd, pc, info);
 
449
  if (length > 0)
 
450
    return length;
 
451
  if (length < 0)
 
452
    return -1;
 
453
 
 
454
  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
 
455
  return cd->default_insn_bitsize / 8;
 
456
}