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