xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/bpf-dis.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1867d70fcSchristos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
2867d70fcSchristos /* Disassembler interface for targets using CGEN. -*- C -*-
3867d70fcSchristos    CGEN: Cpu tools GENerator
4867d70fcSchristos 
5867d70fcSchristos    THIS FILE IS MACHINE GENERATED WITH CGEN.
6867d70fcSchristos    - the resultant file is machine generated, cgen-dis.in isn't
7867d70fcSchristos 
8*c42dbd0eSchristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
9867d70fcSchristos 
10867d70fcSchristos    This file is part of libopcodes.
11867d70fcSchristos 
12867d70fcSchristos    This library is free software; you can redistribute it and/or modify
13867d70fcSchristos    it under the terms of the GNU General Public License as published by
14867d70fcSchristos    the Free Software Foundation; either version 3, or (at your option)
15867d70fcSchristos    any later version.
16867d70fcSchristos 
17867d70fcSchristos    It is distributed in the hope that it will be useful, but WITHOUT
18867d70fcSchristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19867d70fcSchristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20867d70fcSchristos    License for more details.
21867d70fcSchristos 
22867d70fcSchristos    You should have received a copy of the GNU General Public License
23867d70fcSchristos    along with this program; if not, write to the Free Software Foundation, Inc.,
24867d70fcSchristos    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25867d70fcSchristos 
26867d70fcSchristos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
27867d70fcSchristos    Keep that in mind.  */
28867d70fcSchristos 
29867d70fcSchristos #include "sysdep.h"
30867d70fcSchristos #include <stdio.h>
31867d70fcSchristos #include "ansidecl.h"
32867d70fcSchristos #include "disassemble.h"
33867d70fcSchristos #include "bfd.h"
34867d70fcSchristos #include "symcat.h"
35867d70fcSchristos #include "libiberty.h"
36867d70fcSchristos #include "bpf-desc.h"
37867d70fcSchristos #include "bpf-opc.h"
38867d70fcSchristos #include "opintl.h"
39867d70fcSchristos 
40867d70fcSchristos /* Default text to print if an instruction isn't recognized.  */
41867d70fcSchristos #define UNKNOWN_INSN_MSG _("*unknown*")
42867d70fcSchristos 
43867d70fcSchristos static void print_normal
44867d70fcSchristos   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45867d70fcSchristos static void print_address
46867d70fcSchristos   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47867d70fcSchristos static void print_keyword
48867d70fcSchristos   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49867d70fcSchristos static void print_insn_normal
50867d70fcSchristos   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51867d70fcSchristos static int print_insn
52867d70fcSchristos   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53867d70fcSchristos static int default_print_insn
54867d70fcSchristos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55867d70fcSchristos static int read_insn
56867d70fcSchristos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
57867d70fcSchristos    unsigned long *);
58867d70fcSchristos 
59867d70fcSchristos /* -- disassembler routines inserted here.  */
60867d70fcSchristos 
61867d70fcSchristos /* -- dis.c */
62867d70fcSchristos 
63867d70fcSchristos /* We need to customize the disassembler a bit:
64867d70fcSchristos    - Use 8 bytes per line by default.
65867d70fcSchristos */
66867d70fcSchristos 
67867d70fcSchristos #define CGEN_PRINT_INSN bpf_print_insn
68867d70fcSchristos 
69867d70fcSchristos static int
bpf_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)70867d70fcSchristos bpf_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
71867d70fcSchristos {
72867d70fcSchristos   bfd_byte buf[CGEN_MAX_INSN_SIZE];
73867d70fcSchristos   int buflen;
74867d70fcSchristos   int status;
75867d70fcSchristos 
76867d70fcSchristos   info->bytes_per_chunk = 1;
77867d70fcSchristos   info->bytes_per_line = 8;
78867d70fcSchristos 
79867d70fcSchristos   /* Attempt to read the base part of the insn.  */
80867d70fcSchristos   buflen = cd->base_insn_bitsize / 8;
81867d70fcSchristos   status = (*info->read_memory_func) (pc, buf, buflen, info);
82867d70fcSchristos 
83867d70fcSchristos   /* Try again with the minimum part, if min < base.  */
84867d70fcSchristos   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
85867d70fcSchristos     {
86867d70fcSchristos       buflen = cd->min_insn_bitsize / 8;
87867d70fcSchristos       status = (*info->read_memory_func) (pc, buf, buflen, info);
88867d70fcSchristos     }
89867d70fcSchristos 
90867d70fcSchristos   if (status != 0)
91867d70fcSchristos     {
92867d70fcSchristos       (*info->memory_error_func) (status, pc, info);
93867d70fcSchristos       return -1;
94867d70fcSchristos     }
95867d70fcSchristos 
96867d70fcSchristos   return print_insn (cd, pc, info, buf, buflen);
97867d70fcSchristos }
98867d70fcSchristos 
99867d70fcSchristos /* Signed immediates should be printed in hexadecimal.  */
100867d70fcSchristos 
101867d70fcSchristos static void
print_immediate(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,int64_t value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)102867d70fcSchristos print_immediate (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
103867d70fcSchristos                  void *dis_info,
104867d70fcSchristos                  int64_t value,
105867d70fcSchristos                  unsigned int attrs ATTRIBUTE_UNUSED,
106867d70fcSchristos                  bfd_vma pc ATTRIBUTE_UNUSED,
107867d70fcSchristos                  int length ATTRIBUTE_UNUSED)
108867d70fcSchristos {
109867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
110867d70fcSchristos 
111867d70fcSchristos   if (value <= 9)
112867d70fcSchristos     (*info->fprintf_func) (info->stream, "%" PRId64, value);
113867d70fcSchristos   else
114867d70fcSchristos     (*info->fprintf_func) (info->stream, "%#" PRIx64, value);
115867d70fcSchristos 
116867d70fcSchristos   /* This is to avoid -Wunused-function for print_normal.  */
117867d70fcSchristos   if (0)
118867d70fcSchristos     print_normal (cd, dis_info, value, attrs, pc, length);
119867d70fcSchristos }
120867d70fcSchristos 
121867d70fcSchristos /* Endianness bit sizes should be printed in decimal.  */
122867d70fcSchristos 
123867d70fcSchristos static void
print_endsize(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,unsigned long value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)124867d70fcSchristos print_endsize (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
125867d70fcSchristos                void *dis_info,
126867d70fcSchristos                unsigned long value,
127867d70fcSchristos                unsigned int attrs ATTRIBUTE_UNUSED,
128867d70fcSchristos                bfd_vma pc ATTRIBUTE_UNUSED,
129867d70fcSchristos                int length ATTRIBUTE_UNUSED)
130867d70fcSchristos {
131867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
132867d70fcSchristos   (*info->fprintf_func) (info->stream, "%lu", value);
133867d70fcSchristos }
134867d70fcSchristos 
135867d70fcSchristos 
136867d70fcSchristos /* -- */
137867d70fcSchristos 
138867d70fcSchristos void bpf_cgen_print_operand
139*c42dbd0eSchristos   (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
140867d70fcSchristos 
141867d70fcSchristos /* Main entry point for printing operands.
142867d70fcSchristos    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
143867d70fcSchristos    of dis-asm.h on cgen.h.
144867d70fcSchristos 
145867d70fcSchristos    This function is basically just a big switch statement.  Earlier versions
146867d70fcSchristos    used tables to look up the function to use, but
147867d70fcSchristos    - if the table contains both assembler and disassembler functions then
148867d70fcSchristos      the disassembler contains much of the assembler and vice-versa,
149867d70fcSchristos    - there's a lot of inlining possibilities as things grow,
150867d70fcSchristos    - using a switch statement avoids the function call overhead.
151867d70fcSchristos 
152867d70fcSchristos    This function could be moved into `print_insn_normal', but keeping it
153867d70fcSchristos    separate makes clear the interface between `print_insn_normal' and each of
154867d70fcSchristos    the handlers.  */
155867d70fcSchristos 
156867d70fcSchristos void
bpf_cgen_print_operand(CGEN_CPU_DESC cd,int opindex,void * xinfo,CGEN_FIELDS * fields,void const * attrs ATTRIBUTE_UNUSED,bfd_vma pc,int length)157867d70fcSchristos bpf_cgen_print_operand (CGEN_CPU_DESC cd,
158867d70fcSchristos 			   int opindex,
159867d70fcSchristos 			   void * xinfo,
160867d70fcSchristos 			   CGEN_FIELDS *fields,
161867d70fcSchristos 			   void const *attrs ATTRIBUTE_UNUSED,
162867d70fcSchristos 			   bfd_vma pc,
163867d70fcSchristos 			   int length)
164867d70fcSchristos {
165867d70fcSchristos   disassemble_info *info = (disassemble_info *) xinfo;
166867d70fcSchristos 
167867d70fcSchristos   switch (opindex)
168867d70fcSchristos     {
169867d70fcSchristos     case BPF_OPERAND_DISP16 :
170867d70fcSchristos       print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
171867d70fcSchristos       break;
172867d70fcSchristos     case BPF_OPERAND_DISP32 :
173867d70fcSchristos       print_normal (cd, info, fields->f_imm32, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
174867d70fcSchristos       break;
175867d70fcSchristos     case BPF_OPERAND_DSTBE :
176867d70fcSchristos       print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_dstbe, 0);
177867d70fcSchristos       break;
178867d70fcSchristos     case BPF_OPERAND_DSTLE :
179867d70fcSchristos       print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_dstle, 0);
180867d70fcSchristos       break;
181867d70fcSchristos     case BPF_OPERAND_ENDSIZE :
182867d70fcSchristos       print_endsize (cd, info, fields->f_imm32, 0, pc, length);
183867d70fcSchristos       break;
184867d70fcSchristos     case BPF_OPERAND_IMM32 :
185867d70fcSchristos       print_immediate (cd, info, fields->f_imm32, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
186867d70fcSchristos       break;
187867d70fcSchristos     case BPF_OPERAND_IMM64 :
188867d70fcSchristos       print_immediate (cd, info, fields->f_imm64, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
189867d70fcSchristos       break;
190867d70fcSchristos     case BPF_OPERAND_OFFSET16 :
191867d70fcSchristos       print_immediate (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
192867d70fcSchristos       break;
193867d70fcSchristos     case BPF_OPERAND_SRCBE :
194867d70fcSchristos       print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_srcbe, 0);
195867d70fcSchristos       break;
196867d70fcSchristos     case BPF_OPERAND_SRCLE :
197867d70fcSchristos       print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_srcle, 0);
198867d70fcSchristos       break;
199867d70fcSchristos 
200867d70fcSchristos     default :
201867d70fcSchristos       /* xgettext:c-format */
202867d70fcSchristos       opcodes_error_handler
203867d70fcSchristos 	(_("internal error: unrecognized field %d while printing insn"),
204867d70fcSchristos 	 opindex);
205867d70fcSchristos       abort ();
206867d70fcSchristos   }
207867d70fcSchristos }
208867d70fcSchristos 
209867d70fcSchristos cgen_print_fn * const bpf_cgen_print_handlers[] =
210867d70fcSchristos {
211867d70fcSchristos   print_insn_normal,
212867d70fcSchristos };
213867d70fcSchristos 
214867d70fcSchristos 
215867d70fcSchristos void
bpf_cgen_init_dis(CGEN_CPU_DESC cd)216867d70fcSchristos bpf_cgen_init_dis (CGEN_CPU_DESC cd)
217867d70fcSchristos {
218867d70fcSchristos   bpf_cgen_init_opcode_table (cd);
219867d70fcSchristos   bpf_cgen_init_ibld_table (cd);
220867d70fcSchristos   cd->print_handlers = & bpf_cgen_print_handlers[0];
221867d70fcSchristos   cd->print_operand = bpf_cgen_print_operand;
222867d70fcSchristos }
223867d70fcSchristos 
224867d70fcSchristos 
225867d70fcSchristos /* Default print handler.  */
226867d70fcSchristos 
227867d70fcSchristos static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)228867d70fcSchristos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
229867d70fcSchristos 	      void *dis_info,
230867d70fcSchristos 	      long value,
231867d70fcSchristos 	      unsigned int attrs,
232867d70fcSchristos 	      bfd_vma pc ATTRIBUTE_UNUSED,
233867d70fcSchristos 	      int length ATTRIBUTE_UNUSED)
234867d70fcSchristos {
235867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
236867d70fcSchristos 
237867d70fcSchristos   /* Print the operand as directed by the attributes.  */
238867d70fcSchristos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
239867d70fcSchristos     ; /* nothing to do */
240867d70fcSchristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
241867d70fcSchristos     (*info->fprintf_func) (info->stream, "%ld", value);
242867d70fcSchristos   else
243867d70fcSchristos     (*info->fprintf_func) (info->stream, "0x%lx", value);
244867d70fcSchristos }
245867d70fcSchristos 
246867d70fcSchristos /* Default address handler.  */
247867d70fcSchristos 
248867d70fcSchristos static void
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)249867d70fcSchristos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
250867d70fcSchristos 	       void *dis_info,
251867d70fcSchristos 	       bfd_vma value,
252867d70fcSchristos 	       unsigned int attrs,
253867d70fcSchristos 	       bfd_vma pc ATTRIBUTE_UNUSED,
254867d70fcSchristos 	       int length ATTRIBUTE_UNUSED)
255867d70fcSchristos {
256867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
257867d70fcSchristos 
258867d70fcSchristos   /* Print the operand as directed by the attributes.  */
259867d70fcSchristos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
260867d70fcSchristos     ; /* Nothing to do.  */
261867d70fcSchristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
262867d70fcSchristos     (*info->print_address_func) (value, info);
263867d70fcSchristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
264867d70fcSchristos     (*info->print_address_func) (value, info);
265867d70fcSchristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
266867d70fcSchristos     (*info->fprintf_func) (info->stream, "%ld", (long) value);
267867d70fcSchristos   else
268867d70fcSchristos     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
269867d70fcSchristos }
270867d70fcSchristos 
271867d70fcSchristos /* Keyword print handler.  */
272867d70fcSchristos 
273867d70fcSchristos static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)274867d70fcSchristos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
275867d70fcSchristos 	       void *dis_info,
276867d70fcSchristos 	       CGEN_KEYWORD *keyword_table,
277867d70fcSchristos 	       long value,
278867d70fcSchristos 	       unsigned int attrs ATTRIBUTE_UNUSED)
279867d70fcSchristos {
280867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
281867d70fcSchristos   const CGEN_KEYWORD_ENTRY *ke;
282867d70fcSchristos 
283867d70fcSchristos   ke = cgen_keyword_lookup_value (keyword_table, value);
284867d70fcSchristos   if (ke != NULL)
285867d70fcSchristos     (*info->fprintf_func) (info->stream, "%s", ke->name);
286867d70fcSchristos   else
287867d70fcSchristos     (*info->fprintf_func) (info->stream, "???");
288867d70fcSchristos }
289867d70fcSchristos 
290867d70fcSchristos /* Default insn printer.
291867d70fcSchristos 
292867d70fcSchristos    DIS_INFO is defined as `void *' so the disassembler needn't know anything
293867d70fcSchristos    about disassemble_info.  */
294867d70fcSchristos 
295867d70fcSchristos static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)296867d70fcSchristos print_insn_normal (CGEN_CPU_DESC cd,
297867d70fcSchristos 		   void *dis_info,
298867d70fcSchristos 		   const CGEN_INSN *insn,
299867d70fcSchristos 		   CGEN_FIELDS *fields,
300867d70fcSchristos 		   bfd_vma pc,
301867d70fcSchristos 		   int length)
302867d70fcSchristos {
303867d70fcSchristos   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
304867d70fcSchristos   disassemble_info *info = (disassemble_info *) dis_info;
305867d70fcSchristos   const CGEN_SYNTAX_CHAR_TYPE *syn;
306867d70fcSchristos 
307867d70fcSchristos   CGEN_INIT_PRINT (cd);
308867d70fcSchristos 
309867d70fcSchristos   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
310867d70fcSchristos     {
311867d70fcSchristos       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
312867d70fcSchristos 	{
313867d70fcSchristos 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
314867d70fcSchristos 	  continue;
315867d70fcSchristos 	}
316867d70fcSchristos       if (CGEN_SYNTAX_CHAR_P (*syn))
317867d70fcSchristos 	{
318867d70fcSchristos 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
319867d70fcSchristos 	  continue;
320867d70fcSchristos 	}
321867d70fcSchristos 
322867d70fcSchristos       /* We have an operand.  */
323867d70fcSchristos       bpf_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
324867d70fcSchristos 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
325867d70fcSchristos     }
326867d70fcSchristos }
327867d70fcSchristos 
328867d70fcSchristos /* Subroutine of print_insn. Reads an insn into the given buffers and updates
329867d70fcSchristos    the extract info.
330867d70fcSchristos    Returns 0 if all is well, non-zero otherwise.  */
331867d70fcSchristos 
332867d70fcSchristos static int
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,bfd_byte * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)333867d70fcSchristos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
334867d70fcSchristos 	   bfd_vma pc,
335867d70fcSchristos 	   disassemble_info *info,
336867d70fcSchristos 	   bfd_byte *buf,
337867d70fcSchristos 	   int buflen,
338867d70fcSchristos 	   CGEN_EXTRACT_INFO *ex_info,
339867d70fcSchristos 	   unsigned long *insn_value)
340867d70fcSchristos {
341867d70fcSchristos   int status = (*info->read_memory_func) (pc, buf, buflen, info);
342867d70fcSchristos 
343867d70fcSchristos   if (status != 0)
344867d70fcSchristos     {
345867d70fcSchristos       (*info->memory_error_func) (status, pc, info);
346867d70fcSchristos       return -1;
347867d70fcSchristos     }
348867d70fcSchristos 
349867d70fcSchristos   ex_info->dis_info = info;
350867d70fcSchristos   ex_info->valid = (1 << buflen) - 1;
351867d70fcSchristos   ex_info->insn_bytes = buf;
352867d70fcSchristos 
353867d70fcSchristos   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
354867d70fcSchristos   return 0;
355867d70fcSchristos }
356867d70fcSchristos 
357867d70fcSchristos /* Utility to print an insn.
358867d70fcSchristos    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
359867d70fcSchristos    The result is the size of the insn in bytes or zero for an unknown insn
360867d70fcSchristos    or -1 if an error occurs fetching data (memory_error_func will have
361867d70fcSchristos    been called).  */
362867d70fcSchristos 
363867d70fcSchristos static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)364867d70fcSchristos print_insn (CGEN_CPU_DESC cd,
365867d70fcSchristos 	    bfd_vma pc,
366867d70fcSchristos 	    disassemble_info *info,
367867d70fcSchristos 	    bfd_byte *buf,
368867d70fcSchristos 	    unsigned int buflen)
369867d70fcSchristos {
370867d70fcSchristos   CGEN_INSN_INT insn_value;
371867d70fcSchristos   const CGEN_INSN_LIST *insn_list;
372867d70fcSchristos   CGEN_EXTRACT_INFO ex_info;
373867d70fcSchristos   int basesize;
374867d70fcSchristos 
375867d70fcSchristos   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
376867d70fcSchristos   basesize = cd->base_insn_bitsize < buflen * 8 ?
377867d70fcSchristos                                      cd->base_insn_bitsize : buflen * 8;
378*c42dbd0eSchristos   insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
379867d70fcSchristos 
380867d70fcSchristos 
381867d70fcSchristos   /* Fill in ex_info fields like read_insn would.  Don't actually call
382867d70fcSchristos      read_insn, since the incoming buffer is already read (and possibly
383867d70fcSchristos      modified a la m32r).  */
384867d70fcSchristos   ex_info.valid = (1 << buflen) - 1;
385867d70fcSchristos   ex_info.dis_info = info;
386867d70fcSchristos   ex_info.insn_bytes = buf;
387867d70fcSchristos 
388867d70fcSchristos   /* The instructions are stored in hash lists.
389867d70fcSchristos      Pick the first one and keep trying until we find the right one.  */
390867d70fcSchristos 
391867d70fcSchristos   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
392867d70fcSchristos   while (insn_list != NULL)
393867d70fcSchristos     {
394867d70fcSchristos       const CGEN_INSN *insn = insn_list->insn;
395867d70fcSchristos       CGEN_FIELDS fields;
396867d70fcSchristos       int length;
397867d70fcSchristos       unsigned long insn_value_cropped;
398867d70fcSchristos 
399867d70fcSchristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
400867d70fcSchristos       /* Not needed as insn shouldn't be in hash lists if not supported.  */
401867d70fcSchristos       /* Supported by this cpu?  */
402867d70fcSchristos       if (! bpf_cgen_insn_supported (cd, insn))
403867d70fcSchristos         {
404867d70fcSchristos           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
405867d70fcSchristos 	  continue;
406867d70fcSchristos         }
407867d70fcSchristos #endif
408867d70fcSchristos 
409867d70fcSchristos       /* Basic bit mask must be correct.  */
410867d70fcSchristos       /* ??? May wish to allow target to defer this check until the extract
411867d70fcSchristos 	 handler.  */
412867d70fcSchristos 
413867d70fcSchristos       /* Base size may exceed this instruction's size.  Extract the
414867d70fcSchristos          relevant part from the buffer. */
415867d70fcSchristos       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
416867d70fcSchristos 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
417867d70fcSchristos 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
418867d70fcSchristos 					   info->endian == BFD_ENDIAN_BIG);
419867d70fcSchristos       else
420867d70fcSchristos 	insn_value_cropped = insn_value;
421867d70fcSchristos 
422867d70fcSchristos       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
423867d70fcSchristos 	  == CGEN_INSN_BASE_VALUE (insn))
424867d70fcSchristos 	{
425867d70fcSchristos 	  /* Printing is handled in two passes.  The first pass parses the
426867d70fcSchristos 	     machine insn and extracts the fields.  The second pass prints
427867d70fcSchristos 	     them.  */
428867d70fcSchristos 
429867d70fcSchristos 	  /* Make sure the entire insn is loaded into insn_value, if it
430867d70fcSchristos 	     can fit.  */
431867d70fcSchristos 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
432867d70fcSchristos 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
433867d70fcSchristos 	    {
434867d70fcSchristos 	      unsigned long full_insn_value;
435867d70fcSchristos 	      int rc = read_insn (cd, pc, info, buf,
436867d70fcSchristos 				  CGEN_INSN_BITSIZE (insn) / 8,
437867d70fcSchristos 				  & ex_info, & full_insn_value);
438867d70fcSchristos 	      if (rc != 0)
439867d70fcSchristos 		return rc;
440867d70fcSchristos 	      length = CGEN_EXTRACT_FN (cd, insn)
441867d70fcSchristos 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
442867d70fcSchristos 	    }
443867d70fcSchristos 	  else
444867d70fcSchristos 	    length = CGEN_EXTRACT_FN (cd, insn)
445867d70fcSchristos 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
446867d70fcSchristos 
447867d70fcSchristos 	  /* Length < 0 -> error.  */
448867d70fcSchristos 	  if (length < 0)
449867d70fcSchristos 	    return length;
450867d70fcSchristos 	  if (length > 0)
451867d70fcSchristos 	    {
452867d70fcSchristos 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
453867d70fcSchristos 	      /* Length is in bits, result is in bytes.  */
454867d70fcSchristos 	      return length / 8;
455867d70fcSchristos 	    }
456867d70fcSchristos 	}
457867d70fcSchristos 
458867d70fcSchristos       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
459867d70fcSchristos     }
460867d70fcSchristos 
461867d70fcSchristos   return 0;
462867d70fcSchristos }
463867d70fcSchristos 
464867d70fcSchristos /* Default value for CGEN_PRINT_INSN.
465867d70fcSchristos    The result is the size of the insn in bytes or zero for an unknown insn
466867d70fcSchristos    or -1 if an error occured fetching bytes.  */
467867d70fcSchristos 
468867d70fcSchristos #ifndef CGEN_PRINT_INSN
469867d70fcSchristos #define CGEN_PRINT_INSN default_print_insn
470867d70fcSchristos #endif
471867d70fcSchristos 
472867d70fcSchristos static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)473867d70fcSchristos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
474867d70fcSchristos {
475867d70fcSchristos   bfd_byte buf[CGEN_MAX_INSN_SIZE];
476867d70fcSchristos   int buflen;
477867d70fcSchristos   int status;
478867d70fcSchristos 
479867d70fcSchristos   /* Attempt to read the base part of the insn.  */
480867d70fcSchristos   buflen = cd->base_insn_bitsize / 8;
481867d70fcSchristos   status = (*info->read_memory_func) (pc, buf, buflen, info);
482867d70fcSchristos 
483867d70fcSchristos   /* Try again with the minimum part, if min < base.  */
484867d70fcSchristos   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
485867d70fcSchristos     {
486867d70fcSchristos       buflen = cd->min_insn_bitsize / 8;
487867d70fcSchristos       status = (*info->read_memory_func) (pc, buf, buflen, info);
488867d70fcSchristos     }
489867d70fcSchristos 
490867d70fcSchristos   if (status != 0)
491867d70fcSchristos     {
492867d70fcSchristos       (*info->memory_error_func) (status, pc, info);
493867d70fcSchristos       return -1;
494867d70fcSchristos     }
495867d70fcSchristos 
496867d70fcSchristos   return print_insn (cd, pc, info, buf, buflen);
497867d70fcSchristos }
498867d70fcSchristos 
499867d70fcSchristos /* Main entry point.
500867d70fcSchristos    Print one instruction from PC on INFO->STREAM.
501867d70fcSchristos    Return the size of the instruction (in bytes).  */
502867d70fcSchristos 
503867d70fcSchristos typedef struct cpu_desc_list
504867d70fcSchristos {
505867d70fcSchristos   struct cpu_desc_list *next;
506867d70fcSchristos   CGEN_BITSET *isa;
507867d70fcSchristos   int mach;
508867d70fcSchristos   int endian;
509*c42dbd0eSchristos   int insn_endian;
510867d70fcSchristos   CGEN_CPU_DESC cd;
511867d70fcSchristos } cpu_desc_list;
512867d70fcSchristos 
513867d70fcSchristos int
print_insn_bpf(bfd_vma pc,disassemble_info * info)514867d70fcSchristos print_insn_bpf (bfd_vma pc, disassemble_info *info)
515867d70fcSchristos {
516867d70fcSchristos   static cpu_desc_list *cd_list = 0;
517867d70fcSchristos   cpu_desc_list *cl = 0;
518867d70fcSchristos   static CGEN_CPU_DESC cd = 0;
519867d70fcSchristos   static CGEN_BITSET *prev_isa;
520867d70fcSchristos   static int prev_mach;
521867d70fcSchristos   static int prev_endian;
522*c42dbd0eSchristos   static int prev_insn_endian;
523867d70fcSchristos   int length;
524867d70fcSchristos   CGEN_BITSET *isa;
525867d70fcSchristos   int mach;
526867d70fcSchristos   int endian = (info->endian == BFD_ENDIAN_BIG
527867d70fcSchristos 		? CGEN_ENDIAN_BIG
528867d70fcSchristos 		: CGEN_ENDIAN_LITTLE);
529*c42dbd0eSchristos   int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
530*c42dbd0eSchristos                      ? CGEN_ENDIAN_BIG
531*c42dbd0eSchristos                      : CGEN_ENDIAN_LITTLE);
532867d70fcSchristos   enum bfd_architecture arch;
533867d70fcSchristos 
534867d70fcSchristos   /* ??? gdb will set mach but leave the architecture as "unknown" */
535867d70fcSchristos #ifndef CGEN_BFD_ARCH
536867d70fcSchristos #define CGEN_BFD_ARCH bfd_arch_bpf
537867d70fcSchristos #endif
538867d70fcSchristos   arch = info->arch;
539867d70fcSchristos   if (arch == bfd_arch_unknown)
540867d70fcSchristos     arch = CGEN_BFD_ARCH;
541867d70fcSchristos 
542867d70fcSchristos   /* There's no standard way to compute the machine or isa number
543867d70fcSchristos      so we leave it to the target.  */
544867d70fcSchristos #ifdef CGEN_COMPUTE_MACH
545867d70fcSchristos   mach = CGEN_COMPUTE_MACH (info);
546867d70fcSchristos #else
547867d70fcSchristos   mach = info->mach;
548867d70fcSchristos #endif
549867d70fcSchristos 
550867d70fcSchristos #ifdef CGEN_COMPUTE_ISA
551867d70fcSchristos   {
552867d70fcSchristos     static CGEN_BITSET *permanent_isa;
553867d70fcSchristos 
554867d70fcSchristos     if (!permanent_isa)
555867d70fcSchristos       permanent_isa = cgen_bitset_create (MAX_ISAS);
556867d70fcSchristos     isa = permanent_isa;
557867d70fcSchristos     cgen_bitset_clear (isa);
558867d70fcSchristos     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
559867d70fcSchristos   }
560867d70fcSchristos #else
561867d70fcSchristos   isa = info->private_data;
562867d70fcSchristos #endif
563867d70fcSchristos 
564867d70fcSchristos   /* If we've switched cpu's, try to find a handle we've used before */
565867d70fcSchristos   if (cd
566867d70fcSchristos       && (cgen_bitset_compare (isa, prev_isa) != 0
567867d70fcSchristos 	  || mach != prev_mach
568867d70fcSchristos 	  || endian != prev_endian))
569867d70fcSchristos     {
570867d70fcSchristos       cd = 0;
571867d70fcSchristos       for (cl = cd_list; cl; cl = cl->next)
572867d70fcSchristos 	{
573867d70fcSchristos 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
574867d70fcSchristos 	      cl->mach == mach &&
575867d70fcSchristos 	      cl->endian == endian)
576867d70fcSchristos 	    {
577867d70fcSchristos 	      cd = cl->cd;
578867d70fcSchristos  	      prev_isa = cd->isas;
579867d70fcSchristos 	      break;
580867d70fcSchristos 	    }
581867d70fcSchristos 	}
582867d70fcSchristos     }
583867d70fcSchristos 
584867d70fcSchristos   /* If we haven't initialized yet, initialize the opcode table.  */
585867d70fcSchristos   if (! cd)
586867d70fcSchristos     {
587867d70fcSchristos       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
588867d70fcSchristos       const char *mach_name;
589867d70fcSchristos 
590867d70fcSchristos       if (!arch_type)
591867d70fcSchristos 	abort ();
592867d70fcSchristos       mach_name = arch_type->printable_name;
593867d70fcSchristos 
594867d70fcSchristos       prev_isa = cgen_bitset_copy (isa);
595867d70fcSchristos       prev_mach = mach;
596867d70fcSchristos       prev_endian = endian;
597*c42dbd0eSchristos       prev_insn_endian = insn_endian;
598867d70fcSchristos       cd = bpf_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
599867d70fcSchristos 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
600867d70fcSchristos 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
601*c42dbd0eSchristos                                  CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
602867d70fcSchristos 				 CGEN_CPU_OPEN_END);
603867d70fcSchristos       if (!cd)
604867d70fcSchristos 	abort ();
605867d70fcSchristos 
606867d70fcSchristos       /* Save this away for future reference.  */
607867d70fcSchristos       cl = xmalloc (sizeof (struct cpu_desc_list));
608867d70fcSchristos       cl->cd = cd;
609867d70fcSchristos       cl->isa = prev_isa;
610867d70fcSchristos       cl->mach = mach;
611867d70fcSchristos       cl->endian = endian;
612867d70fcSchristos       cl->next = cd_list;
613867d70fcSchristos       cd_list = cl;
614867d70fcSchristos 
615867d70fcSchristos       bpf_cgen_init_dis (cd);
616867d70fcSchristos     }
617867d70fcSchristos 
618867d70fcSchristos   /* We try to have as much common code as possible.
619867d70fcSchristos      But at this point some targets need to take over.  */
620867d70fcSchristos   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
621867d70fcSchristos      but if not possible try to move this hook elsewhere rather than
622867d70fcSchristos      have two hooks.  */
623867d70fcSchristos   length = CGEN_PRINT_INSN (cd, pc, info);
624867d70fcSchristos   if (length > 0)
625867d70fcSchristos     return length;
626867d70fcSchristos   if (length < 0)
627867d70fcSchristos     return -1;
628867d70fcSchristos 
629867d70fcSchristos   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
630867d70fcSchristos   return cd->default_insn_bitsize / 8;
631867d70fcSchristos }
632