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