[opcodes, ARM, 14/16] Add mode availability to coprocessor table entries
[binutils-gdb.git] / opcodes / cgen-dis.in
blobd1e06bf7b86f61adbb437af1b755d28583ec20d0
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-2019 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);
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   CGEN_CPU_DESC cd;
345 } cpu_desc_list;
348 print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
350   static cpu_desc_list *cd_list = 0;
351   cpu_desc_list *cl = 0;
352   static CGEN_CPU_DESC cd = 0;
353   static CGEN_BITSET *prev_isa;
354   static int prev_mach;
355   static int prev_endian;
356   int length;
357   CGEN_BITSET *isa;
358   int mach;
359   int endian = (info->endian == BFD_ENDIAN_BIG
360                 ? CGEN_ENDIAN_BIG
361                 : CGEN_ENDIAN_LITTLE);
362   enum bfd_architecture arch;
364   /* ??? gdb will set mach but leave the architecture as "unknown" */
365 #ifndef CGEN_BFD_ARCH
366 #define CGEN_BFD_ARCH bfd_arch_@arch@
367 #endif
368   arch = info->arch;
369   if (arch == bfd_arch_unknown)
370     arch = CGEN_BFD_ARCH;
372   /* There's no standard way to compute the machine or isa number
373      so we leave it to the target.  */
374 #ifdef CGEN_COMPUTE_MACH
375   mach = CGEN_COMPUTE_MACH (info);
376 #else
377   mach = info->mach;
378 #endif
380 #ifdef CGEN_COMPUTE_ISA
381   {
382     static CGEN_BITSET *permanent_isa;
384     if (!permanent_isa)
385       permanent_isa = cgen_bitset_create (MAX_ISAS);
386     isa = permanent_isa;
387     cgen_bitset_clear (isa);
388     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
389   }
390 #else
391   isa = info->insn_sets;
392 #endif
394   /* If we've switched cpu's, try to find a handle we've used before */
395   if (cd
396       && (cgen_bitset_compare (isa, prev_isa) != 0
397           || mach != prev_mach
398           || endian != prev_endian))
399     {
400       cd = 0;
401       for (cl = cd_list; cl; cl = cl->next)
402         {
403           if (cgen_bitset_compare (cl->isa, isa) == 0 &&
404               cl->mach == mach &&
405               cl->endian == endian)
406             {
407               cd = cl->cd;
408               prev_isa = cd->isas;
409               break;
410             }
411         }
412     }
414   /* If we haven't initialized yet, initialize the opcode table.  */
415   if (! cd)
416     {
417       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
418       const char *mach_name;
420       if (!arch_type)
421         abort ();
422       mach_name = arch_type->printable_name;
424       prev_isa = cgen_bitset_copy (isa);
425       prev_mach = mach;
426       prev_endian = endian;
427       cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
428                                  CGEN_CPU_OPEN_BFDMACH, mach_name,
429                                  CGEN_CPU_OPEN_ENDIAN, prev_endian,
430                                  CGEN_CPU_OPEN_END);
431       if (!cd)
432         abort ();
434       /* Save this away for future reference.  */
435       cl = xmalloc (sizeof (struct cpu_desc_list));
436       cl->cd = cd;
437       cl->isa = prev_isa;
438       cl->mach = mach;
439       cl->endian = endian;
440       cl->next = cd_list;
441       cd_list = cl;
443       @arch@_cgen_init_dis (cd);
444     }
446   /* We try to have as much common code as possible.
447      But at this point some targets need to take over.  */
448   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
449      but if not possible try to move this hook elsewhere rather than
450      have two hooks.  */
451   length = CGEN_PRINT_INSN (cd, pc, info);
452   if (length > 0)
453     return length;
454   if (length < 0)
455     return -1;
457   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
458   return cd->default_insn_bitsize / 8;