Release 2.33.1
[external/binutils.git] / opcodes / cgen-dis.in
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 (C) 1996-2019 Free Software Foundation, Inc.
8
9    This file is part of libopcodes.
10
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.
15
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.
20
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.  */
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 "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"
38
39 /* Default text to print if an instruction isn't recognized.  */
40 #define UNKNOWN_INSN_MSG _("*unknown*")
41
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 *);
57 \f
58 /* -- disassembler routines inserted here.  */
59 \f
60 /* Default print handler.  */
61
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)
69 {
70   disassemble_info *info = (disassemble_info *) dis_info;
71
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);
79 }
80
81 /* Default address handler.  */
82
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)
90 {
91   disassemble_info *info = (disassemble_info *) dis_info;
92
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);
104 }
105
106 /* Keyword print handler.  */
107
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)
114 {
115   disassemble_info *info = (disassemble_info *) dis_info;
116   const CGEN_KEYWORD_ENTRY *ke;
117
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, "???");
123 }
124 \f
125 /* Default insn printer.
126
127    DIS_INFO is defined as `void *' so the disassembler needn't know anything
128    about disassemble_info.  */
129
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)
137 {
138   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
139   disassemble_info *info = (disassemble_info *) dis_info;
140   const CGEN_SYNTAX_CHAR_TYPE *syn;
141
142   CGEN_INIT_PRINT (cd);
143
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         }
156
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     }
161 }
162 \f
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.  */
166
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)
175 {
176   int status = (*info->read_memory_func) (pc, buf, buflen, info);
177
178   if (status != 0)
179     {
180       (*info->memory_error_func) (status, pc, info);
181       return -1;
182     }
183
184   ex_info->dis_info = info;
185   ex_info->valid = (1 << buflen) - 1;
186   ex_info->insn_bytes = buf;
187
188   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
189   return 0;
190 }
191
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).  */
197
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)
204 {
205   CGEN_INSN_INT insn_value;
206   const CGEN_INSN_LIST *insn_list;
207   CGEN_EXTRACT_INFO ex_info;
208   int basesize;
209
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);
214
215
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;
222
223   /* The instructions are stored in hash lists.
224      Pick the first one and keep trying until we find the right one.  */
225
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;
233
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
243
244       /* Basic bit mask must be correct.  */
245       /* ??? May wish to allow target to defer this check until the extract
246          handler.  */
247
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;
256
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.  */
263
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);
281
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         }
292
293       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
294     }
295
296   return 0;
297 }
298
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.  */
302
303 #ifndef CGEN_PRINT_INSN
304 #define CGEN_PRINT_INSN default_print_insn
305 #endif
306
307 static int
308 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
309 {
310   bfd_byte buf[CGEN_MAX_INSN_SIZE];
311   int buflen;
312   int status;
313
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);
317
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     }
324
325   if (status != 0)
326     {
327       (*info->memory_error_func) (status, pc, info);
328       return -1;
329     }
330
331   return print_insn (cd, pc, info, buf, buflen);
332 }
333
334 /* Main entry point.
335    Print one instruction from PC on INFO->STREAM.
336    Return the size of the instruction (in bytes).  */
337
338 typedef struct cpu_desc_list
339 {
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;
346
347 int
348 print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
349 {
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;
363
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;
371
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
379
380 #ifdef CGEN_COMPUTE_ISA
381   {
382     static CGEN_BITSET *permanent_isa;
383
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
393
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     }
413
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;
419
420       if (!arch_type)
421         abort ();
422       mach_name = arch_type->printable_name;
423
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 ();
433
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;
442
443       @arch@_cgen_init_dis (cd);
444     }
445
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;
456
457   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
458   return cd->default_insn_bitsize / 8;
459 }