opcodes: add support for eBPF
This patch adds support for the Linux kernel eBPF architecture to the opcodes. The port is based on CGEN. opcodes/ChangeLog: 2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com> * configure.ac (SHARED_DEPENDENCIES): Add case for bfd_bpf_arch. * configure: Regenerated. * Makefile.am: Add rules for the files generated from cpu/bpf.cpu and cpu/bpf.opc. (HFILES): Add bpf-desc.h and bpf-opc.h. (TARGET_LIBOPCODES_CFILES): Add bpf-asm.c, bpf-desc.c, bpf-dis.c, bpf-ibld.c and bpf-opc.c. (BPF_DEPS): Define. * Makefile.in: Regenerated. * disassemble.c (ARCH_bpf): Define. (disassembler): Add case for bfd_arch_bpf. (disassemble_init_for_target): Likewise. (enum epbf_isa_attr): Define. * disassemble.h: extern print_insn_bpf. * bpf-asm.c: Generated. * bpf-opc.h: Likewise. * bpf-opc.c: Likewise. * bpf-ibld.c: Likewise. * bpf-dis.c: Likewise. * bpf-desc.h: Likewise. * bpf-desc.c: Likewise.
This commit is contained in:
parent
ea195bb04c
commit
79472b4532
@ -1,3 +1,27 @@
|
||||
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
|
||||
|
||||
* configure.ac (SHARED_DEPENDENCIES): Add case for bfd_bpf_arch.
|
||||
* configure: Regenerated.
|
||||
* Makefile.am: Add rules for the files generated from cpu/bpf.cpu
|
||||
and cpu/bpf.opc.
|
||||
(HFILES): Add bpf-desc.h and bpf-opc.h.
|
||||
(TARGET_LIBOPCODES_CFILES): Add bpf-asm.c, bpf-desc.c, bpf-dis.c,
|
||||
bpf-ibld.c and bpf-opc.c.
|
||||
(BPF_DEPS): Define.
|
||||
* Makefile.in: Regenerated.
|
||||
* disassemble.c (ARCH_bpf): Define.
|
||||
(disassembler): Add case for bfd_arch_bpf.
|
||||
(disassemble_init_for_target): Likewise.
|
||||
(enum epbf_isa_attr): Define.
|
||||
* disassemble.h: extern print_insn_bpf.
|
||||
* bpf-asm.c: Generated.
|
||||
* bpf-opc.h: Likewise.
|
||||
* bpf-opc.c: Likewise.
|
||||
* bpf-ibld.c: Likewise.
|
||||
* bpf-dis.c: Likewise.
|
||||
* bpf-desc.h: Likewise.
|
||||
* bpf-desc.c: Likewise.
|
||||
|
||||
2019-05-21 Sudakshina Das <sudi.das@arm.com>
|
||||
|
||||
* arm-dis.c (coprocessor_opcodes): New instructions for VMRS
|
||||
|
@ -59,6 +59,7 @@ BUILD_LIB_DEPS = @BUILD_LIB_DEPS@
|
||||
# Header files.
|
||||
HFILES = \
|
||||
aarch64-asm.h aarch64-dis.h aarch64-opc.h aarch64-tbl.h \
|
||||
bpf-desc.h bpf-opc.h \
|
||||
epiphany-desc.h epiphany-opc.h \
|
||||
fr30-desc.h fr30-opc.h \
|
||||
frv-desc.h frv-opc.h \
|
||||
@ -117,6 +118,11 @@ TARGET_LIBOPCODES_CFILES = \
|
||||
d30v-dis.c \
|
||||
d30v-opc.c \
|
||||
dlx-dis.c \
|
||||
bpf-asm.c \
|
||||
bpf-desc.c \
|
||||
bpf-dis.c \
|
||||
bpf-ibld.c \
|
||||
bpf-opc.c \
|
||||
epiphany-asm.c \
|
||||
epiphany-desc.c \
|
||||
epiphany-dis.c \
|
||||
@ -370,6 +376,7 @@ CGENDEPS = \
|
||||
CGEN_CPUS = epiphany fr30 frv ip2k iq2000 lm32 m32c m32r mep mt or1k xc16x xstormy16
|
||||
|
||||
if CGEN_MAINT
|
||||
BPF_DEPS = stamp-bpf
|
||||
EPIPHANY_DEPS = stamp-epiphany
|
||||
FR30_DEPS = stamp-fr30
|
||||
FRV_DEPS = stamp-frv
|
||||
@ -384,6 +391,7 @@ OR1K_DEPS = stamp-or1k
|
||||
XC16X_DEPS = stamp-xc16x
|
||||
XSTORMY16_DEPS = stamp-xstormy16
|
||||
else
|
||||
BPF_DEPS =
|
||||
EPIPHANY_DEPS =
|
||||
FR30_DEPS =
|
||||
FRV_DEPS =
|
||||
@ -416,6 +424,15 @@ run-cgen-all:
|
||||
|
||||
# For now, require developers to configure with --enable-cgen-maint.
|
||||
|
||||
$(srcdir)/bpf-desc.h $(srcdir)/bpf-desc.c $(srcdir)/bpf-opc.h \
|
||||
$(srcdir)/bpf-opc.c $(srcdir)/bpf-ibld.c \
|
||||
$(srcdir)/bpf-asm.c $(srcdir)/bpf-dis.c: $(BPF_DEPS)
|
||||
@true
|
||||
|
||||
stamp-bpf: $(CGENDEPS) $(CPUDIR)/bpf.cpu $(CPUDIR)/bpf.opc
|
||||
$(MAKE) run-cgen arch=bpf prefix=bpf \
|
||||
archfile=$(CPUDIR)/bpf.cpu opcfile=$(CPUDIR)/bpf.opc
|
||||
|
||||
$(srcdir)/epiphany-desc.h $(srcdir)/epiphany-desc.c $(srcdir)/epiphany-opc.h \
|
||||
$(srcdir)/epiphany-opc.c $(srcdir)/epiphany-ibld.c \
|
||||
$(srcdir)/epiphany-opinst.c $(srcdir)/epiphany-asm.c \
|
||||
|
@ -408,6 +408,7 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
@ -448,6 +449,7 @@ BFD_H = ../bfd/bfd.h
|
||||
# Header files.
|
||||
HFILES = \
|
||||
aarch64-asm.h aarch64-dis.h aarch64-opc.h aarch64-tbl.h \
|
||||
bpf-desc.h bpf-opc.h \
|
||||
epiphany-desc.h epiphany-opc.h \
|
||||
fr30-desc.h fr30-opc.h \
|
||||
frv-desc.h frv-opc.h \
|
||||
@ -507,6 +509,11 @@ TARGET_LIBOPCODES_CFILES = \
|
||||
d30v-dis.c \
|
||||
d30v-opc.c \
|
||||
dlx-dis.c \
|
||||
bpf-asm.c \
|
||||
bpf-desc.c \
|
||||
bpf-dis.c \
|
||||
bpf-ibld.c \
|
||||
bpf-opc.c \
|
||||
epiphany-asm.c \
|
||||
epiphany-desc.c \
|
||||
epiphany-dis.c \
|
||||
@ -725,6 +732,8 @@ CGENDEPS = \
|
||||
cgen-asm.in cgen-dis.in cgen-ibld.in
|
||||
|
||||
CGEN_CPUS = epiphany fr30 frv ip2k iq2000 lm32 m32c m32r mep mt or1k xc16x xstormy16
|
||||
@CGEN_MAINT_FALSE@BPF_DEPS =
|
||||
@CGEN_MAINT_TRUE@BPF_DEPS = stamp-bpf
|
||||
@CGEN_MAINT_FALSE@EPIPHANY_DEPS =
|
||||
@CGEN_MAINT_TRUE@EPIPHANY_DEPS = stamp-epiphany
|
||||
@CGEN_MAINT_FALSE@FR30_DEPS =
|
||||
@ -897,6 +906,11 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm-dis.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr-dis.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfin-dis.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-asm.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-desc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-dis.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-ibld.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-opc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen-asm.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen-bitset.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen-dis.Plo@am__quote@
|
||||
@ -1398,6 +1412,15 @@ run-cgen-all:
|
||||
|
||||
# For now, require developers to configure with --enable-cgen-maint.
|
||||
|
||||
$(srcdir)/bpf-desc.h $(srcdir)/bpf-desc.c $(srcdir)/bpf-opc.h \
|
||||
$(srcdir)/bpf-opc.c $(srcdir)/bpf-ibld.c \
|
||||
$(srcdir)/bpf-asm.c $(srcdir)/bpf-dis.c: $(BPF_DEPS)
|
||||
@true
|
||||
|
||||
stamp-bpf: $(CGENDEPS) $(CPUDIR)/bpf.cpu $(CPUDIR)/bpf.opc
|
||||
$(MAKE) run-cgen arch=bpf prefix=bpf \
|
||||
archfile=$(CPUDIR)/bpf.cpu opcfile=$(CPUDIR)/bpf.opc
|
||||
|
||||
$(srcdir)/epiphany-desc.h $(srcdir)/epiphany-desc.c $(srcdir)/epiphany-opc.h \
|
||||
$(srcdir)/epiphany-opc.c $(srcdir)/epiphany-ibld.c \
|
||||
$(srcdir)/epiphany-opinst.c $(srcdir)/epiphany-asm.c \
|
||||
|
590
opcodes/bpf-asm.c
Normal file
590
opcodes/bpf-asm.c
Normal file
@ -0,0 +1,590 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
|
||||
/* Assembler interface for targets using CGEN. -*- C -*-
|
||||
CGEN: Cpu tools GENerator
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
- the resultant file is machine generated, cgen-asm.in isn't
|
||||
|
||||
Copyright (C) 1996-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of libopcodes.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
|
||||
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
|
||||
Keep that in mind. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <stdio.h>
|
||||
#include "ansidecl.h"
|
||||
#include "bfd.h"
|
||||
#include "symcat.h"
|
||||
#include "bpf-desc.h"
|
||||
#include "bpf-opc.h"
|
||||
#include "opintl.h"
|
||||
#include "xregex.h"
|
||||
#include "libiberty.h"
|
||||
#include "safe-ctype.h"
|
||||
|
||||
#undef min
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#undef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static const char * parse_insn_normal
|
||||
(CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
|
||||
|
||||
/* -- assembler routines inserted here. */
|
||||
|
||||
/* -- asm.c */
|
||||
|
||||
/* Parse a signed 64-bit immediate. */
|
||||
|
||||
static const char *
|
||||
parse_imm64 (CGEN_CPU_DESC cd,
|
||||
const char **strp,
|
||||
int opindex,
|
||||
int64_t *valuep)
|
||||
{
|
||||
bfd_vma value;
|
||||
enum cgen_parse_operand_result result;
|
||||
const char *errmsg;
|
||||
|
||||
errmsg = (* cd->parse_operand_fn)
|
||||
(cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
|
||||
&result, &value);
|
||||
if (!errmsg)
|
||||
*valuep = value;
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
/* Endianness size operands are integer immediates whose values can be
|
||||
16, 32 or 64. */
|
||||
|
||||
static const char *
|
||||
parse_endsize (CGEN_CPU_DESC cd,
|
||||
const char **strp,
|
||||
int opindex,
|
||||
unsigned long *valuep)
|
||||
{
|
||||
const char *errmsg;
|
||||
|
||||
errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
|
||||
if (errmsg)
|
||||
return errmsg;
|
||||
|
||||
switch (*valuep)
|
||||
{
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
break;
|
||||
default:
|
||||
return _("expected 16, 32 or 64 in");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Special check to ensure that the right instruction variant is used
|
||||
for the given endianness induced by the ISA selected in the CPU.
|
||||
See bpf.cpu for a discussion on how eBPF is really two instruction
|
||||
sets. */
|
||||
|
||||
int
|
||||
bpf_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
|
||||
{
|
||||
CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
|
||||
|
||||
return cgen_bitset_intersect_p (&isas, cd->isas);
|
||||
}
|
||||
|
||||
|
||||
/* -- dis.c */
|
||||
|
||||
const char * bpf_cgen_parse_operand
|
||||
(CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
|
||||
|
||||
/* Main entry point for operand parsing.
|
||||
|
||||
This function is basically just a big switch statement. Earlier versions
|
||||
used tables to look up the function to use, but
|
||||
- if the table contains both assembler and disassembler functions then
|
||||
the disassembler contains much of the assembler and vice-versa,
|
||||
- there's a lot of inlining possibilities as things grow,
|
||||
- using a switch statement avoids the function call overhead.
|
||||
|
||||
This function could be moved into `parse_insn_normal', but keeping it
|
||||
separate makes clear the interface between `parse_insn_normal' and each of
|
||||
the handlers. */
|
||||
|
||||
const char *
|
||||
bpf_cgen_parse_operand (CGEN_CPU_DESC cd,
|
||||
int opindex,
|
||||
const char ** strp,
|
||||
CGEN_FIELDS * fields)
|
||||
{
|
||||
const char * errmsg = NULL;
|
||||
/* Used by scalar operands that still need to be parsed. */
|
||||
long junk ATTRIBUTE_UNUSED;
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_DISP16, (long *) (& fields->f_offset16));
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_DISP32, (long *) (& fields->f_imm32));
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_dstbe);
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_dstle);
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
errmsg = parse_endsize (cd, strp, BPF_OPERAND_ENDSIZE, (unsigned long *) (& fields->f_imm32));
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_IMM32, (long *) (& fields->f_imm32));
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
errmsg = parse_imm64 (cd, strp, BPF_OPERAND_IMM64, (int64_t *) (& fields->f_imm64));
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
errmsg = cgen_parse_signed_integer (cd, strp, BPF_OPERAND_OFFSET16, (long *) (& fields->f_offset16));
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_srcbe);
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
errmsg = cgen_parse_keyword (cd, strp, & bpf_cgen_opval_h_gpr, & fields->f_srcle);
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while parsing"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
cgen_parse_fn * const bpf_cgen_parse_handlers[] =
|
||||
{
|
||||
parse_insn_normal,
|
||||
};
|
||||
|
||||
void
|
||||
bpf_cgen_init_asm (CGEN_CPU_DESC cd)
|
||||
{
|
||||
bpf_cgen_init_opcode_table (cd);
|
||||
bpf_cgen_init_ibld_table (cd);
|
||||
cd->parse_handlers = & bpf_cgen_parse_handlers[0];
|
||||
cd->parse_operand = bpf_cgen_parse_operand;
|
||||
#ifdef CGEN_ASM_INIT_HOOK
|
||||
CGEN_ASM_INIT_HOOK
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Regex construction routine.
|
||||
|
||||
This translates an opcode syntax string into a regex string,
|
||||
by replacing any non-character syntax element (such as an
|
||||
opcode) with the pattern '.*'
|
||||
|
||||
It then compiles the regex and stores it in the opcode, for
|
||||
later use by bpf_cgen_assemble_insn
|
||||
|
||||
Returns NULL for success, an error message for failure. */
|
||||
|
||||
char *
|
||||
bpf_cgen_build_insn_regex (CGEN_INSN *insn)
|
||||
{
|
||||
CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
|
||||
const char *mnem = CGEN_INSN_MNEMONIC (insn);
|
||||
char rxbuf[CGEN_MAX_RX_ELEMENTS];
|
||||
char *rx = rxbuf;
|
||||
const CGEN_SYNTAX_CHAR_TYPE *syn;
|
||||
int reg_err;
|
||||
|
||||
syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
|
||||
|
||||
/* Mnemonics come first in the syntax string. */
|
||||
if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
|
||||
return _("missing mnemonic in syntax string");
|
||||
++syn;
|
||||
|
||||
/* Generate a case sensitive regular expression that emulates case
|
||||
insensitive matching in the "C" locale. We cannot generate a case
|
||||
insensitive regular expression because in Turkish locales, 'i' and 'I'
|
||||
are not equal modulo case conversion. */
|
||||
|
||||
/* Copy the literal mnemonic out of the insn. */
|
||||
for (; *mnem; mnem++)
|
||||
{
|
||||
char c = *mnem;
|
||||
|
||||
if (ISALPHA (c))
|
||||
{
|
||||
*rx++ = '[';
|
||||
*rx++ = TOLOWER (c);
|
||||
*rx++ = TOUPPER (c);
|
||||
*rx++ = ']';
|
||||
}
|
||||
else
|
||||
*rx++ = c;
|
||||
}
|
||||
|
||||
/* Copy any remaining literals from the syntax string into the rx. */
|
||||
for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
|
||||
{
|
||||
if (CGEN_SYNTAX_CHAR_P (* syn))
|
||||
{
|
||||
char c = CGEN_SYNTAX_CHAR (* syn);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
/* Escape any regex metacharacters in the syntax. */
|
||||
case '.': case '[': case '\\':
|
||||
case '*': case '^': case '$':
|
||||
|
||||
#ifdef CGEN_ESCAPE_EXTENDED_REGEX
|
||||
case '?': case '{': case '}':
|
||||
case '(': case ')': case '*':
|
||||
case '|': case '+': case ']':
|
||||
#endif
|
||||
*rx++ = '\\';
|
||||
*rx++ = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ISALPHA (c))
|
||||
{
|
||||
*rx++ = '[';
|
||||
*rx++ = TOLOWER (c);
|
||||
*rx++ = TOUPPER (c);
|
||||
*rx++ = ']';
|
||||
}
|
||||
else
|
||||
*rx++ = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Replace non-syntax fields with globs. */
|
||||
*rx++ = '.';
|
||||
*rx++ = '*';
|
||||
}
|
||||
}
|
||||
|
||||
/* Trailing whitespace ok. */
|
||||
* rx++ = '[';
|
||||
* rx++ = ' ';
|
||||
* rx++ = '\t';
|
||||
* rx++ = ']';
|
||||
* rx++ = '*';
|
||||
|
||||
/* But anchor it after that. */
|
||||
* rx++ = '$';
|
||||
* rx = '\0';
|
||||
|
||||
CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
|
||||
reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
|
||||
|
||||
if (reg_err == 0)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
static char msg[80];
|
||||
|
||||
regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
|
||||
regfree ((regex_t *) CGEN_INSN_RX (insn));
|
||||
free (CGEN_INSN_RX (insn));
|
||||
(CGEN_INSN_RX (insn)) = NULL;
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Default insn parser.
|
||||
|
||||
The syntax string is scanned and operands are parsed and stored in FIELDS.
|
||||
Relocs are queued as we go via other callbacks.
|
||||
|
||||
??? Note that this is currently an all-or-nothing parser. If we fail to
|
||||
parse the instruction, we return 0 and the caller will start over from
|
||||
the beginning. Backtracking will be necessary in parsing subexpressions,
|
||||
but that can be handled there. Not handling backtracking here may get
|
||||
expensive in the case of the m68k. Deal with later.
|
||||
|
||||
Returns NULL for success, an error message for failure. */
|
||||
|
||||
static const char *
|
||||
parse_insn_normal (CGEN_CPU_DESC cd,
|
||||
const CGEN_INSN *insn,
|
||||
const char **strp,
|
||||
CGEN_FIELDS *fields)
|
||||
{
|
||||
/* ??? Runtime added insns not handled yet. */
|
||||
const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
|
||||
const char *str = *strp;
|
||||
const char *errmsg;
|
||||
const char *p;
|
||||
const CGEN_SYNTAX_CHAR_TYPE * syn;
|
||||
#ifdef CGEN_MNEMONIC_OPERANDS
|
||||
/* FIXME: wip */
|
||||
int past_opcode_p;
|
||||
#endif
|
||||
|
||||
/* For now we assume the mnemonic is first (there are no leading operands).
|
||||
We can parse it without needing to set up operand parsing.
|
||||
GAS's input scrubber will ensure mnemonics are lowercase, but we may
|
||||
not be called from GAS. */
|
||||
p = CGEN_INSN_MNEMONIC (insn);
|
||||
while (*p && TOLOWER (*p) == TOLOWER (*str))
|
||||
++p, ++str;
|
||||
|
||||
if (* p)
|
||||
return _("unrecognized instruction");
|
||||
|
||||
#ifndef CGEN_MNEMONIC_OPERANDS
|
||||
if (* str && ! ISSPACE (* str))
|
||||
return _("unrecognized instruction");
|
||||
#endif
|
||||
|
||||
CGEN_INIT_PARSE (cd);
|
||||
cgen_init_parse_operand (cd);
|
||||
#ifdef CGEN_MNEMONIC_OPERANDS
|
||||
past_opcode_p = 0;
|
||||
#endif
|
||||
|
||||
/* We don't check for (*str != '\0') here because we want to parse
|
||||
any trailing fake arguments in the syntax string. */
|
||||
syn = CGEN_SYNTAX_STRING (syntax);
|
||||
|
||||
/* Mnemonics come first for now, ensure valid string. */
|
||||
if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
|
||||
abort ();
|
||||
|
||||
++syn;
|
||||
|
||||
while (* syn != 0)
|
||||
{
|
||||
/* Non operand chars must match exactly. */
|
||||
if (CGEN_SYNTAX_CHAR_P (* syn))
|
||||
{
|
||||
/* FIXME: While we allow for non-GAS callers above, we assume the
|
||||
first char after the mnemonic part is a space. */
|
||||
/* FIXME: We also take inappropriate advantage of the fact that
|
||||
GAS's input scrubber will remove extraneous blanks. */
|
||||
if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
|
||||
{
|
||||
#ifdef CGEN_MNEMONIC_OPERANDS
|
||||
if (CGEN_SYNTAX_CHAR(* syn) == ' ')
|
||||
past_opcode_p = 1;
|
||||
#endif
|
||||
++ syn;
|
||||
++ str;
|
||||
}
|
||||
else if (*str)
|
||||
{
|
||||
/* Syntax char didn't match. Can't be this insn. */
|
||||
static char msg [80];
|
||||
|
||||
/* xgettext:c-format */
|
||||
sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
|
||||
CGEN_SYNTAX_CHAR(*syn), *str);
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ran out of input. */
|
||||
static char msg [80];
|
||||
|
||||
/* xgettext:c-format */
|
||||
sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
|
||||
CGEN_SYNTAX_CHAR(*syn));
|
||||
return msg;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef CGEN_MNEMONIC_OPERANDS
|
||||
(void) past_opcode_p;
|
||||
#endif
|
||||
/* We have an operand of some sort. */
|
||||
errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
|
||||
if (errmsg)
|
||||
return errmsg;
|
||||
|
||||
/* Done with this operand, continue with next one. */
|
||||
++ syn;
|
||||
}
|
||||
|
||||
/* If we're at the end of the syntax string, we're done. */
|
||||
if (* syn == 0)
|
||||
{
|
||||
/* FIXME: For the moment we assume a valid `str' can only contain
|
||||
blanks now. IE: We needn't try again with a longer version of
|
||||
the insn and it is assumed that longer versions of insns appear
|
||||
before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
|
||||
while (ISSPACE (* str))
|
||||
++ str;
|
||||
|
||||
if (* str != '\0')
|
||||
return _("junk at end of line"); /* FIXME: would like to include `str' */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We couldn't parse it. */
|
||||
return _("unrecognized instruction");
|
||||
}
|
||||
|
||||
/* Main entry point.
|
||||
This routine is called for each instruction to be assembled.
|
||||
STR points to the insn to be assembled.
|
||||
We assume all necessary tables have been initialized.
|
||||
The assembled instruction, less any fixups, is stored in BUF.
|
||||
Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
|
||||
still needs to be converted to target byte order, otherwise BUF is an array
|
||||
of bytes in target byte order.
|
||||
The result is a pointer to the insn's entry in the opcode table,
|
||||
or NULL if an error occured (an error message will have already been
|
||||
printed).
|
||||
|
||||
Note that when processing (non-alias) macro-insns,
|
||||
this function recurses.
|
||||
|
||||
??? It's possible to make this cpu-independent.
|
||||
One would have to deal with a few minor things.
|
||||
At this point in time doing so would be more of a curiosity than useful
|
||||
[for example this file isn't _that_ big], but keeping the possibility in
|
||||
mind helps keep the design clean. */
|
||||
|
||||
const CGEN_INSN *
|
||||
bpf_cgen_assemble_insn (CGEN_CPU_DESC cd,
|
||||
const char *str,
|
||||
CGEN_FIELDS *fields,
|
||||
CGEN_INSN_BYTES_PTR buf,
|
||||
char **errmsg)
|
||||
{
|
||||
const char *start;
|
||||
CGEN_INSN_LIST *ilist;
|
||||
const char *parse_errmsg = NULL;
|
||||
const char *insert_errmsg = NULL;
|
||||
int recognized_mnemonic = 0;
|
||||
|
||||
/* Skip leading white space. */
|
||||
while (ISSPACE (* str))
|
||||
++ str;
|
||||
|
||||
/* The instructions are stored in hashed lists.
|
||||
Get the first in the list. */
|
||||
ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
|
||||
|
||||
/* Keep looking until we find a match. */
|
||||
start = str;
|
||||
for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
|
||||
{
|
||||
const CGEN_INSN *insn = ilist->insn;
|
||||
recognized_mnemonic = 1;
|
||||
|
||||
#ifdef CGEN_VALIDATE_INSN_SUPPORTED
|
||||
/* Not usually needed as unsupported opcodes
|
||||
shouldn't be in the hash lists. */
|
||||
/* Is this insn supported by the selected cpu? */
|
||||
if (! bpf_cgen_insn_supported (cd, insn))
|
||||
continue;
|
||||
#endif
|
||||
/* If the RELAXED attribute is set, this is an insn that shouldn't be
|
||||
chosen immediately. Instead, it is used during assembler/linker
|
||||
relaxation if possible. */
|
||||
if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
|
||||
continue;
|
||||
|
||||
str = start;
|
||||
|
||||
/* Skip this insn if str doesn't look right lexically. */
|
||||
if (CGEN_INSN_RX (insn) != NULL &&
|
||||
regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
|
||||
continue;
|
||||
|
||||
/* Allow parse/insert handlers to obtain length of insn. */
|
||||
CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
|
||||
|
||||
parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
|
||||
if (parse_errmsg != NULL)
|
||||
continue;
|
||||
|
||||
/* ??? 0 is passed for `pc'. */
|
||||
insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
|
||||
(bfd_vma) 0);
|
||||
if (insert_errmsg != NULL)
|
||||
continue;
|
||||
|
||||
/* It is up to the caller to actually output the insn and any
|
||||
queued relocs. */
|
||||
return insn;
|
||||
}
|
||||
|
||||
{
|
||||
static char errbuf[150];
|
||||
const char *tmp_errmsg;
|
||||
#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
|
||||
#define be_verbose 1
|
||||
#else
|
||||
#define be_verbose 0
|
||||
#endif
|
||||
|
||||
if (be_verbose)
|
||||
{
|
||||
/* If requesting verbose error messages, use insert_errmsg.
|
||||
Failing that, use parse_errmsg. */
|
||||
tmp_errmsg = (insert_errmsg ? insert_errmsg :
|
||||
parse_errmsg ? parse_errmsg :
|
||||
recognized_mnemonic ?
|
||||
_("unrecognized form of instruction") :
|
||||
_("unrecognized instruction"));
|
||||
|
||||
if (strlen (start) > 50)
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
|
||||
else
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen (start) > 50)
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf, _("bad instruction `%.50s...'"), start);
|
||||
else
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf, _("bad instruction `%.50s'"), start);
|
||||
}
|
||||
|
||||
*errmsg = errbuf;
|
||||
return NULL;
|
||||
}
|
||||
}
|
1638
opcodes/bpf-desc.c
Normal file
1638
opcodes/bpf-desc.c
Normal file
File diff suppressed because it is too large
Load Diff
266
opcodes/bpf-desc.h
Normal file
266
opcodes/bpf-desc.h
Normal file
@ -0,0 +1,266 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
|
||||
/* CPU data header for bpf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright (C) 1996-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Binutils and/or GDB, the GNU debugger.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BPF_CPU_H
|
||||
#define BPF_CPU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CGEN_ARCH bpf
|
||||
|
||||
/* Given symbol S, return bpf_cgen_<S>. */
|
||||
#define CGEN_SYM(s) bpf##_cgen_##s
|
||||
|
||||
|
||||
/* Selected cpu families. */
|
||||
#define HAVE_CPU_BPFBF
|
||||
|
||||
#define CGEN_INSN_LSB0_P 1
|
||||
|
||||
/* Minimum size of any insn (in bytes). */
|
||||
#define CGEN_MIN_INSN_SIZE 8
|
||||
|
||||
/* Maximum size of any insn (in bytes). */
|
||||
#define CGEN_MAX_INSN_SIZE 16
|
||||
|
||||
#define CGEN_INT_INSN_P 0
|
||||
|
||||
/* Maximum number of syntax elements in an instruction. */
|
||||
#define CGEN_ACTUAL_MAX_SYNTAX_ELEMENTS 16
|
||||
|
||||
/* CGEN_MNEMONIC_OPERANDS is defined if mnemonics have operands.
|
||||
e.g. In "b,a foo" the ",a" is an operand. If mnemonics have operands
|
||||
we can't hash on everything up to the space. */
|
||||
#define CGEN_MNEMONIC_OPERANDS
|
||||
|
||||
/* Maximum number of fields in an instruction. */
|
||||
#define CGEN_ACTUAL_MAX_IFMT_OPERANDS 7
|
||||
|
||||
/* Enums. */
|
||||
|
||||
/* Enum declaration for eBPF instruction codes. */
|
||||
typedef enum insn_op_code_alu {
|
||||
OP_CODE_ADD = 0, OP_CODE_SUB = 1, OP_CODE_MUL = 2, OP_CODE_DIV = 3
|
||||
, OP_CODE_OR = 4, OP_CODE_AND = 5, OP_CODE_LSH = 6, OP_CODE_RSH = 7
|
||||
, OP_CODE_NEG = 8, OP_CODE_MOD = 9, OP_CODE_XOR = 10, OP_CODE_MOV = 11
|
||||
, OP_CODE_ARSH = 12, OP_CODE_END = 13, OP_CODE_JA = 0, OP_CODE_JEQ = 1
|
||||
, OP_CODE_JGT = 2, OP_CODE_JGE = 3, OP_CODE_JSET = 4, OP_CODE_JNE = 5
|
||||
, OP_CODE_JSGT = 6, OP_CODE_JSGE = 7, OP_CODE_CALL = 8, OP_CODE_EXIT = 9
|
||||
, OP_CODE_JLT = 10, OP_CODE_JLE = 11, OP_CODE_JSLT = 12, OP_CODE_JSLE = 13
|
||||
} INSN_OP_CODE_ALU;
|
||||
|
||||
/* Enum declaration for eBPF instruction source. */
|
||||
typedef enum insn_op_src {
|
||||
OP_SRC_K, OP_SRC_X
|
||||
} INSN_OP_SRC;
|
||||
|
||||
/* Enum declaration for eBPF instruction class. */
|
||||
typedef enum insn_op_class {
|
||||
OP_CLASS_LD = 0, OP_CLASS_LDX = 1, OP_CLASS_ST = 2, OP_CLASS_STX = 3
|
||||
, OP_CLASS_ALU = 4, OP_CLASS_JMP = 5, OP_CLASS_ALU64 = 7
|
||||
} INSN_OP_CLASS;
|
||||
|
||||
/* Enum declaration for eBPF load/store instruction modes. */
|
||||
typedef enum insn_op_mode {
|
||||
OP_MODE_IMM = 0, OP_MODE_ABS = 1, OP_MODE_IND = 2, OP_MODE_MEM = 3
|
||||
, OP_MODE_XADD = 6
|
||||
} INSN_OP_MODE;
|
||||
|
||||
/* Enum declaration for eBPF load/store instruction sizes. */
|
||||
typedef enum insn_op_size {
|
||||
OP_SIZE_W, OP_SIZE_H, OP_SIZE_B, OP_SIZE_DW
|
||||
} INSN_OP_SIZE;
|
||||
|
||||
/* Attributes. */
|
||||
|
||||
/* Enum declaration for machine type selection. */
|
||||
typedef enum mach_attr {
|
||||
MACH_BASE, MACH_BPF, MACH_MAX
|
||||
} MACH_ATTR;
|
||||
|
||||
/* Enum declaration for instruction set selection. */
|
||||
typedef enum isa_attr {
|
||||
ISA_EBPFLE, ISA_EBPFBE, ISA_MAX
|
||||
} ISA_ATTR;
|
||||
|
||||
/* Number of architecture variants. */
|
||||
#define MAX_ISAS ((int) ISA_MAX)
|
||||
#define MAX_MACHS ((int) MACH_MAX)
|
||||
|
||||
/* Ifield support. */
|
||||
|
||||
/* Ifield attribute indices. */
|
||||
|
||||
/* Enum declaration for cgen_ifld attrs. */
|
||||
typedef enum cgen_ifld_attr {
|
||||
CGEN_IFLD_VIRTUAL, CGEN_IFLD_PCREL_ADDR, CGEN_IFLD_ABS_ADDR, CGEN_IFLD_RESERVED
|
||||
, CGEN_IFLD_SIGN_OPT, CGEN_IFLD_SIGNED, CGEN_IFLD_END_BOOLS, CGEN_IFLD_START_NBOOLS = 31
|
||||
, CGEN_IFLD_MACH, CGEN_IFLD_ISA, CGEN_IFLD_END_NBOOLS
|
||||
} CGEN_IFLD_ATTR;
|
||||
|
||||
/* Number of non-boolean elements in cgen_ifld_attr. */
|
||||
#define CGEN_IFLD_NBOOL_ATTRS (CGEN_IFLD_END_NBOOLS - CGEN_IFLD_START_NBOOLS - 1)
|
||||
|
||||
/* cgen_ifld attribute accessor macros. */
|
||||
#define CGEN_ATTR_CGEN_IFLD_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_IFLD_MACH-CGEN_IFLD_START_NBOOLS-1].nonbitset)
|
||||
#define CGEN_ATTR_CGEN_IFLD_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_IFLD_ISA-CGEN_IFLD_START_NBOOLS-1].bitset)
|
||||
#define CGEN_ATTR_CGEN_IFLD_VIRTUAL_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_VIRTUAL)) != 0)
|
||||
#define CGEN_ATTR_CGEN_IFLD_PCREL_ADDR_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_PCREL_ADDR)) != 0)
|
||||
#define CGEN_ATTR_CGEN_IFLD_ABS_ADDR_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_ABS_ADDR)) != 0)
|
||||
#define CGEN_ATTR_CGEN_IFLD_RESERVED_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_RESERVED)) != 0)
|
||||
#define CGEN_ATTR_CGEN_IFLD_SIGN_OPT_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_SIGN_OPT)) != 0)
|
||||
#define CGEN_ATTR_CGEN_IFLD_SIGNED_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_IFLD_SIGNED)) != 0)
|
||||
|
||||
/* Enum declaration for bpf ifield types. */
|
||||
typedef enum ifield_type {
|
||||
BPF_F_NIL, BPF_F_ANYOF, BPF_F_OP_CODE, BPF_F_OP_SRC
|
||||
, BPF_F_OP_CLASS, BPF_F_OP_MODE, BPF_F_OP_SIZE, BPF_F_DSTLE
|
||||
, BPF_F_SRCLE, BPF_F_DSTBE, BPF_F_SRCBE, BPF_F_REGS
|
||||
, BPF_F_OFFSET16, BPF_F_IMM32, BPF_F_IMM64_A, BPF_F_IMM64_B
|
||||
, BPF_F_IMM64_C, BPF_F_IMM64, BPF_F_MAX
|
||||
} IFIELD_TYPE;
|
||||
|
||||
#define MAX_IFLD ((int) BPF_F_MAX)
|
||||
|
||||
/* Hardware attribute indices. */
|
||||
|
||||
/* Enum declaration for cgen_hw attrs. */
|
||||
typedef enum cgen_hw_attr {
|
||||
CGEN_HW_VIRTUAL, CGEN_HW_CACHE_ADDR, CGEN_HW_PC, CGEN_HW_PROFILE
|
||||
, CGEN_HW_END_BOOLS, CGEN_HW_START_NBOOLS = 31, CGEN_HW_MACH, CGEN_HW_ISA
|
||||
, CGEN_HW_END_NBOOLS
|
||||
} CGEN_HW_ATTR;
|
||||
|
||||
/* Number of non-boolean elements in cgen_hw_attr. */
|
||||
#define CGEN_HW_NBOOL_ATTRS (CGEN_HW_END_NBOOLS - CGEN_HW_START_NBOOLS - 1)
|
||||
|
||||
/* cgen_hw attribute accessor macros. */
|
||||
#define CGEN_ATTR_CGEN_HW_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_HW_MACH-CGEN_HW_START_NBOOLS-1].nonbitset)
|
||||
#define CGEN_ATTR_CGEN_HW_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_HW_ISA-CGEN_HW_START_NBOOLS-1].bitset)
|
||||
#define CGEN_ATTR_CGEN_HW_VIRTUAL_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_HW_VIRTUAL)) != 0)
|
||||
#define CGEN_ATTR_CGEN_HW_CACHE_ADDR_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_HW_CACHE_ADDR)) != 0)
|
||||
#define CGEN_ATTR_CGEN_HW_PC_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_HW_PC)) != 0)
|
||||
#define CGEN_ATTR_CGEN_HW_PROFILE_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_HW_PROFILE)) != 0)
|
||||
|
||||
/* Enum declaration for bpf hardware types. */
|
||||
typedef enum cgen_hw_type {
|
||||
HW_H_MEMORY, HW_H_SINT, HW_H_UINT, HW_H_ADDR
|
||||
, HW_H_IADDR, HW_H_GPR, HW_H_PC, HW_H_SINT64
|
||||
, HW_MAX
|
||||
} CGEN_HW_TYPE;
|
||||
|
||||
#define MAX_HW ((int) HW_MAX)
|
||||
|
||||
/* Operand attribute indices. */
|
||||
|
||||
/* Enum declaration for cgen_operand attrs. */
|
||||
typedef enum cgen_operand_attr {
|
||||
CGEN_OPERAND_VIRTUAL, CGEN_OPERAND_PCREL_ADDR, CGEN_OPERAND_ABS_ADDR, CGEN_OPERAND_SIGN_OPT
|
||||
, CGEN_OPERAND_SIGNED, CGEN_OPERAND_NEGATIVE, CGEN_OPERAND_RELAX, CGEN_OPERAND_SEM_ONLY
|
||||
, CGEN_OPERAND_END_BOOLS, CGEN_OPERAND_START_NBOOLS = 31, CGEN_OPERAND_MACH, CGEN_OPERAND_ISA
|
||||
, CGEN_OPERAND_END_NBOOLS
|
||||
} CGEN_OPERAND_ATTR;
|
||||
|
||||
/* Number of non-boolean elements in cgen_operand_attr. */
|
||||
#define CGEN_OPERAND_NBOOL_ATTRS (CGEN_OPERAND_END_NBOOLS - CGEN_OPERAND_START_NBOOLS - 1)
|
||||
|
||||
/* cgen_operand attribute accessor macros. */
|
||||
#define CGEN_ATTR_CGEN_OPERAND_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_OPERAND_MACH-CGEN_OPERAND_START_NBOOLS-1].nonbitset)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_OPERAND_ISA-CGEN_OPERAND_START_NBOOLS-1].bitset)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_VIRTUAL_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_VIRTUAL)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_PCREL_ADDR_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_PCREL_ADDR)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_ABS_ADDR_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_ABS_ADDR)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_SIGN_OPT_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_SIGN_OPT)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_SIGNED_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_SIGNED)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_NEGATIVE_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_NEGATIVE)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_RELAX_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_RELAX)) != 0)
|
||||
#define CGEN_ATTR_CGEN_OPERAND_SEM_ONLY_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_OPERAND_SEM_ONLY)) != 0)
|
||||
|
||||
/* Enum declaration for bpf operand types. */
|
||||
typedef enum cgen_operand_type {
|
||||
BPF_OPERAND_PC, BPF_OPERAND_DSTLE, BPF_OPERAND_SRCLE, BPF_OPERAND_DSTBE
|
||||
, BPF_OPERAND_SRCBE, BPF_OPERAND_DISP16, BPF_OPERAND_DISP32, BPF_OPERAND_IMM32
|
||||
, BPF_OPERAND_OFFSET16, BPF_OPERAND_IMM64, BPF_OPERAND_ENDSIZE, BPF_OPERAND_MAX
|
||||
} CGEN_OPERAND_TYPE;
|
||||
|
||||
/* Number of operands types. */
|
||||
#define MAX_OPERANDS 11
|
||||
|
||||
/* Maximum number of operands referenced by any insn. */
|
||||
#define MAX_OPERAND_INSTANCES 8
|
||||
|
||||
/* Insn attribute indices. */
|
||||
|
||||
/* Enum declaration for cgen_insn attrs. */
|
||||
typedef enum cgen_insn_attr {
|
||||
CGEN_INSN_ALIAS, CGEN_INSN_VIRTUAL, CGEN_INSN_UNCOND_CTI, CGEN_INSN_COND_CTI
|
||||
, CGEN_INSN_SKIP_CTI, CGEN_INSN_DELAY_SLOT, CGEN_INSN_RELAXABLE, CGEN_INSN_RELAXED
|
||||
, CGEN_INSN_NO_DIS, CGEN_INSN_PBB, CGEN_INSN_END_BOOLS, CGEN_INSN_START_NBOOLS = 31
|
||||
, CGEN_INSN_MACH, CGEN_INSN_ISA, CGEN_INSN_END_NBOOLS
|
||||
} CGEN_INSN_ATTR;
|
||||
|
||||
/* Number of non-boolean elements in cgen_insn_attr. */
|
||||
#define CGEN_INSN_NBOOL_ATTRS (CGEN_INSN_END_NBOOLS - CGEN_INSN_START_NBOOLS - 1)
|
||||
|
||||
/* cgen_insn attribute accessor macros. */
|
||||
#define CGEN_ATTR_CGEN_INSN_MACH_VALUE(attrs) ((attrs)->nonbool[CGEN_INSN_MACH-CGEN_INSN_START_NBOOLS-1].nonbitset)
|
||||
#define CGEN_ATTR_CGEN_INSN_ISA_VALUE(attrs) ((attrs)->nonbool[CGEN_INSN_ISA-CGEN_INSN_START_NBOOLS-1].bitset)
|
||||
#define CGEN_ATTR_CGEN_INSN_ALIAS_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_ALIAS)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_VIRTUAL_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_VIRTUAL)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_UNCOND_CTI_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_UNCOND_CTI)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_COND_CTI_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_COND_CTI)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_SKIP_CTI_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_SKIP_CTI)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_DELAY_SLOT_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_DELAY_SLOT)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_RELAXABLE_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_RELAXABLE)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_RELAXED_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_RELAXED)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_NO_DIS_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_NO_DIS)) != 0)
|
||||
#define CGEN_ATTR_CGEN_INSN_PBB_VALUE(attrs) (((attrs)->bool_ & (1 << CGEN_INSN_PBB)) != 0)
|
||||
|
||||
/* cgen.h uses things we just defined. */
|
||||
#include "opcode/cgen.h"
|
||||
|
||||
extern const struct cgen_ifld bpf_cgen_ifld_table[];
|
||||
|
||||
/* Attributes. */
|
||||
extern const CGEN_ATTR_TABLE bpf_cgen_hardware_attr_table[];
|
||||
extern const CGEN_ATTR_TABLE bpf_cgen_ifield_attr_table[];
|
||||
extern const CGEN_ATTR_TABLE bpf_cgen_operand_attr_table[];
|
||||
extern const CGEN_ATTR_TABLE bpf_cgen_insn_attr_table[];
|
||||
|
||||
/* Hardware decls. */
|
||||
|
||||
extern CGEN_KEYWORD bpf_cgen_opval_h_gpr;
|
||||
|
||||
extern const CGEN_HW_ENTRY bpf_cgen_hw_table[];
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BPF_CPU_H */
|
624
opcodes/bpf-dis.c
Normal file
624
opcodes/bpf-dis.c
Normal file
@ -0,0 +1,624 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
|
||||
/* Disassembler interface for targets using CGEN. -*- C -*-
|
||||
CGEN: Cpu tools GENerator
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
- the resultant file is machine generated, cgen-dis.in isn't
|
||||
|
||||
Copyright (C) 1996-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of libopcodes.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
|
||||
Keep that in mind. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <stdio.h>
|
||||
#include "ansidecl.h"
|
||||
#include "disassemble.h"
|
||||
#include "bfd.h"
|
||||
#include "symcat.h"
|
||||
#include "libiberty.h"
|
||||
#include "bpf-desc.h"
|
||||
#include "bpf-opc.h"
|
||||
#include "opintl.h"
|
||||
|
||||
/* Default text to print if an instruction isn't recognized. */
|
||||
#define UNKNOWN_INSN_MSG _("*unknown*")
|
||||
|
||||
static void print_normal
|
||||
(CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
|
||||
static void print_address
|
||||
(CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
|
||||
static void print_keyword
|
||||
(CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
|
||||
static void print_insn_normal
|
||||
(CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
|
||||
static int print_insn
|
||||
(CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned);
|
||||
static int default_print_insn
|
||||
(CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
|
||||
static int read_insn
|
||||
(CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
|
||||
unsigned long *);
|
||||
|
||||
/* -- disassembler routines inserted here. */
|
||||
|
||||
/* -- dis.c */
|
||||
|
||||
/* We need to customize the disassembler a bit:
|
||||
- Use 8 bytes per line by default.
|
||||
*/
|
||||
|
||||
#define CGEN_PRINT_INSN bpf_print_insn
|
||||
|
||||
static int
|
||||
bpf_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
bfd_byte buf[CGEN_MAX_INSN_SIZE];
|
||||
int buflen;
|
||||
int status;
|
||||
|
||||
info->bytes_per_chunk = 1;
|
||||
info->bytes_per_line = 8;
|
||||
|
||||
/* Attempt to read the base part of the insn. */
|
||||
buflen = cd->base_insn_bitsize / 8;
|
||||
status = (*info->read_memory_func) (pc, buf, buflen, info);
|
||||
|
||||
/* Try again with the minimum part, if min < base. */
|
||||
if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
|
||||
{
|
||||
buflen = cd->min_insn_bitsize / 8;
|
||||
status = (*info->read_memory_func) (pc, buf, buflen, info);
|
||||
}
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
(*info->memory_error_func) (status, pc, info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return print_insn (cd, pc, info, buf, buflen);
|
||||
}
|
||||
|
||||
/* Signed immediates should be printed in hexadecimal. */
|
||||
|
||||
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)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
|
||||
if (value <= 9)
|
||||
(*info->fprintf_func) (info->stream, "%" PRId64, value);
|
||||
else
|
||||
(*info->fprintf_func) (info->stream, "%#" PRIx64, value);
|
||||
|
||||
/* This is to avoid -Wunused-function for print_normal. */
|
||||
if (0)
|
||||
print_normal (cd, dis_info, value, attrs, pc, length);
|
||||
}
|
||||
|
||||
/* Endianness bit sizes should be printed in decimal. */
|
||||
|
||||
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)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
(*info->fprintf_func) (info->stream, "%lu", value);
|
||||
}
|
||||
|
||||
|
||||
/* -- */
|
||||
|
||||
void bpf_cgen_print_operand
|
||||
(CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
|
||||
|
||||
/* Main entry point for printing operands.
|
||||
XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
|
||||
of dis-asm.h on cgen.h.
|
||||
|
||||
This function is basically just a big switch statement. Earlier versions
|
||||
used tables to look up the function to use, but
|
||||
- if the table contains both assembler and disassembler functions then
|
||||
the disassembler contains much of the assembler and vice-versa,
|
||||
- there's a lot of inlining possibilities as things grow,
|
||||
- using a switch statement avoids the function call overhead.
|
||||
|
||||
This function could be moved into `print_insn_normal', but keeping it
|
||||
separate makes clear the interface between `print_insn_normal' and each of
|
||||
the handlers. */
|
||||
|
||||
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)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) xinfo;
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
print_normal (cd, info, fields->f_imm32, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_dstbe, 0);
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_dstle, 0);
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
print_endsize (cd, info, fields->f_imm32, 0, pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
print_immediate (cd, info, fields->f_imm32, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
print_immediate (cd, info, fields->f_imm64, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
print_immediate (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_srcbe, 0);
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
print_keyword (cd, info, & bpf_cgen_opval_h_gpr, fields->f_srcle, 0);
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while printing insn"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
cgen_print_fn * const bpf_cgen_print_handlers[] =
|
||||
{
|
||||
print_insn_normal,
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
bpf_cgen_init_dis (CGEN_CPU_DESC cd)
|
||||
{
|
||||
bpf_cgen_init_opcode_table (cd);
|
||||
bpf_cgen_init_ibld_table (cd);
|
||||
cd->print_handlers = & bpf_cgen_print_handlers[0];
|
||||
cd->print_operand = bpf_cgen_print_operand;
|
||||
}
|
||||
|
||||
|
||||
/* Default print handler. */
|
||||
|
||||
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)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
|
||||
/* Print the operand as directed by the attributes. */
|
||||
if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
|
||||
; /* nothing to do */
|
||||
else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
|
||||
(*info->fprintf_func) (info->stream, "%ld", value);
|
||||
else
|
||||
(*info->fprintf_func) (info->stream, "0x%lx", value);
|
||||
}
|
||||
|
||||
/* Default address handler. */
|
||||
|
||||
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)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
|
||||
/* Print the operand as directed by the attributes. */
|
||||
if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
|
||||
; /* Nothing to do. */
|
||||
else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
|
||||
(*info->print_address_func) (value, info);
|
||||
else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
|
||||
(*info->print_address_func) (value, info);
|
||||
else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
|
||||
(*info->fprintf_func) (info->stream, "%ld", (long) value);
|
||||
else
|
||||
(*info->fprintf_func) (info->stream, "0x%lx", (long) value);
|
||||
}
|
||||
|
||||
/* Keyword print handler. */
|
||||
|
||||
static void
|
||||
print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
void *dis_info,
|
||||
CGEN_KEYWORD *keyword_table,
|
||||
long value,
|
||||
unsigned int attrs ATTRIBUTE_UNUSED)
|
||||
{
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
const CGEN_KEYWORD_ENTRY *ke;
|
||||
|
||||
ke = cgen_keyword_lookup_value (keyword_table, value);
|
||||
if (ke != NULL)
|
||||
(*info->fprintf_func) (info->stream, "%s", ke->name);
|
||||
else
|
||||
(*info->fprintf_func) (info->stream, "???");
|
||||
}
|
||||
|
||||
/* Default insn printer.
|
||||
|
||||
DIS_INFO is defined as `void *' so the disassembler needn't know anything
|
||||
about disassemble_info. */
|
||||
|
||||
static void
|
||||
print_insn_normal (CGEN_CPU_DESC cd,
|
||||
void *dis_info,
|
||||
const CGEN_INSN *insn,
|
||||
CGEN_FIELDS *fields,
|
||||
bfd_vma pc,
|
||||
int length)
|
||||
{
|
||||
const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
|
||||
disassemble_info *info = (disassemble_info *) dis_info;
|
||||
const CGEN_SYNTAX_CHAR_TYPE *syn;
|
||||
|
||||
CGEN_INIT_PRINT (cd);
|
||||
|
||||
for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
|
||||
{
|
||||
if (CGEN_SYNTAX_MNEMONIC_P (*syn))
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
|
||||
continue;
|
||||
}
|
||||
if (CGEN_SYNTAX_CHAR_P (*syn))
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have an operand. */
|
||||
bpf_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
|
||||
fields, CGEN_INSN_ATTRS (insn), pc, length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Subroutine of print_insn. Reads an insn into the given buffers and updates
|
||||
the extract info.
|
||||
Returns 0 if all is well, non-zero otherwise. */
|
||||
|
||||
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)
|
||||
{
|
||||
int status = (*info->read_memory_func) (pc, buf, buflen, info);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
(*info->memory_error_func) (status, pc, info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ex_info->dis_info = info;
|
||||
ex_info->valid = (1 << buflen) - 1;
|
||||
ex_info->insn_bytes = buf;
|
||||
|
||||
*insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Utility to print an insn.
|
||||
BUF is the base part of the insn, target byte order, BUFLEN bytes long.
|
||||
The result is the size of the insn in bytes or zero for an unknown insn
|
||||
or -1 if an error occurs fetching data (memory_error_func will have
|
||||
been called). */
|
||||
|
||||
static int
|
||||
print_insn (CGEN_CPU_DESC cd,
|
||||
bfd_vma pc,
|
||||
disassemble_info *info,
|
||||
bfd_byte *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
CGEN_INSN_INT insn_value;
|
||||
const CGEN_INSN_LIST *insn_list;
|
||||
CGEN_EXTRACT_INFO ex_info;
|
||||
int basesize;
|
||||
|
||||
/* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
|
||||
basesize = cd->base_insn_bitsize < buflen * 8 ?
|
||||
cd->base_insn_bitsize : buflen * 8;
|
||||
insn_value = cgen_get_insn_value (cd, buf, basesize);
|
||||
|
||||
|
||||
/* Fill in ex_info fields like read_insn would. Don't actually call
|
||||
read_insn, since the incoming buffer is already read (and possibly
|
||||
modified a la m32r). */
|
||||
ex_info.valid = (1 << buflen) - 1;
|
||||
ex_info.dis_info = info;
|
||||
ex_info.insn_bytes = buf;
|
||||
|
||||
/* The instructions are stored in hash lists.
|
||||
Pick the first one and keep trying until we find the right one. */
|
||||
|
||||
insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
|
||||
while (insn_list != NULL)
|
||||
{
|
||||
const CGEN_INSN *insn = insn_list->insn;
|
||||
CGEN_FIELDS fields;
|
||||
int length;
|
||||
unsigned long insn_value_cropped;
|
||||
|
||||
#ifdef CGEN_VALIDATE_INSN_SUPPORTED
|
||||
/* Not needed as insn shouldn't be in hash lists if not supported. */
|
||||
/* Supported by this cpu? */
|
||||
if (! bpf_cgen_insn_supported (cd, insn))
|
||||
{
|
||||
insn_list = CGEN_DIS_NEXT_INSN (insn_list);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Basic bit mask must be correct. */
|
||||
/* ??? May wish to allow target to defer this check until the extract
|
||||
handler. */
|
||||
|
||||
/* Base size may exceed this instruction's size. Extract the
|
||||
relevant part from the buffer. */
|
||||
if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
|
||||
(unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
|
||||
insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
|
||||
info->endian == BFD_ENDIAN_BIG);
|
||||
else
|
||||
insn_value_cropped = insn_value;
|
||||
|
||||
if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
|
||||
== CGEN_INSN_BASE_VALUE (insn))
|
||||
{
|
||||
/* Printing is handled in two passes. The first pass parses the
|
||||
machine insn and extracts the fields. The second pass prints
|
||||
them. */
|
||||
|
||||
/* Make sure the entire insn is loaded into insn_value, if it
|
||||
can fit. */
|
||||
if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
|
||||
(unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
|
||||
{
|
||||
unsigned long full_insn_value;
|
||||
int rc = read_insn (cd, pc, info, buf,
|
||||
CGEN_INSN_BITSIZE (insn) / 8,
|
||||
& ex_info, & full_insn_value);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
length = CGEN_EXTRACT_FN (cd, insn)
|
||||
(cd, insn, &ex_info, full_insn_value, &fields, pc);
|
||||
}
|
||||
else
|
||||
length = CGEN_EXTRACT_FN (cd, insn)
|
||||
(cd, insn, &ex_info, insn_value_cropped, &fields, pc);
|
||||
|
||||
/* Length < 0 -> error. */
|
||||
if (length < 0)
|
||||
return length;
|
||||
if (length > 0)
|
||||
{
|
||||
CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
|
||||
/* Length is in bits, result is in bytes. */
|
||||
return length / 8;
|
||||
}
|
||||
}
|
||||
|
||||
insn_list = CGEN_DIS_NEXT_INSN (insn_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Default value for CGEN_PRINT_INSN.
|
||||
The result is the size of the insn in bytes or zero for an unknown insn
|
||||
or -1 if an error occured fetching bytes. */
|
||||
|
||||
#ifndef CGEN_PRINT_INSN
|
||||
#define CGEN_PRINT_INSN default_print_insn
|
||||
#endif
|
||||
|
||||
static int
|
||||
default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
bfd_byte buf[CGEN_MAX_INSN_SIZE];
|
||||
int buflen;
|
||||
int status;
|
||||
|
||||
/* Attempt to read the base part of the insn. */
|
||||
buflen = cd->base_insn_bitsize / 8;
|
||||
status = (*info->read_memory_func) (pc, buf, buflen, info);
|
||||
|
||||
/* Try again with the minimum part, if min < base. */
|
||||
if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
|
||||
{
|
||||
buflen = cd->min_insn_bitsize / 8;
|
||||
status = (*info->read_memory_func) (pc, buf, buflen, info);
|
||||
}
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
(*info->memory_error_func) (status, pc, info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return print_insn (cd, pc, info, buf, buflen);
|
||||
}
|
||||
|
||||
/* Main entry point.
|
||||
Print one instruction from PC on INFO->STREAM.
|
||||
Return the size of the instruction (in bytes). */
|
||||
|
||||
typedef struct cpu_desc_list
|
||||
{
|
||||
struct cpu_desc_list *next;
|
||||
CGEN_BITSET *isa;
|
||||
int mach;
|
||||
int endian;
|
||||
CGEN_CPU_DESC cd;
|
||||
} cpu_desc_list;
|
||||
|
||||
int
|
||||
print_insn_bpf (bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
static cpu_desc_list *cd_list = 0;
|
||||
cpu_desc_list *cl = 0;
|
||||
static CGEN_CPU_DESC cd = 0;
|
||||
static CGEN_BITSET *prev_isa;
|
||||
static int prev_mach;
|
||||
static int prev_endian;
|
||||
int length;
|
||||
CGEN_BITSET *isa;
|
||||
int mach;
|
||||
int endian = (info->endian == BFD_ENDIAN_BIG
|
||||
? CGEN_ENDIAN_BIG
|
||||
: CGEN_ENDIAN_LITTLE);
|
||||
enum bfd_architecture arch;
|
||||
|
||||
/* ??? gdb will set mach but leave the architecture as "unknown" */
|
||||
#ifndef CGEN_BFD_ARCH
|
||||
#define CGEN_BFD_ARCH bfd_arch_bpf
|
||||
#endif
|
||||
arch = info->arch;
|
||||
if (arch == bfd_arch_unknown)
|
||||
arch = CGEN_BFD_ARCH;
|
||||
|
||||
/* There's no standard way to compute the machine or isa number
|
||||
so we leave it to the target. */
|
||||
#ifdef CGEN_COMPUTE_MACH
|
||||
mach = CGEN_COMPUTE_MACH (info);
|
||||
#else
|
||||
mach = info->mach;
|
||||
#endif
|
||||
|
||||
#ifdef CGEN_COMPUTE_ISA
|
||||
{
|
||||
static CGEN_BITSET *permanent_isa;
|
||||
|
||||
if (!permanent_isa)
|
||||
permanent_isa = cgen_bitset_create (MAX_ISAS);
|
||||
isa = permanent_isa;
|
||||
cgen_bitset_clear (isa);
|
||||
cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
|
||||
}
|
||||
#else
|
||||
isa = info->insn_sets;
|
||||
#endif
|
||||
|
||||
/* If we've switched cpu's, try to find a handle we've used before */
|
||||
if (cd
|
||||
&& (cgen_bitset_compare (isa, prev_isa) != 0
|
||||
|| mach != prev_mach
|
||||
|| endian != prev_endian))
|
||||
{
|
||||
cd = 0;
|
||||
for (cl = cd_list; cl; cl = cl->next)
|
||||
{
|
||||
if (cgen_bitset_compare (cl->isa, isa) == 0 &&
|
||||
cl->mach == mach &&
|
||||
cl->endian == endian)
|
||||
{
|
||||
cd = cl->cd;
|
||||
prev_isa = cd->isas;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we haven't initialized yet, initialize the opcode table. */
|
||||
if (! cd)
|
||||
{
|
||||
const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
|
||||
const char *mach_name;
|
||||
|
||||
if (!arch_type)
|
||||
abort ();
|
||||
mach_name = arch_type->printable_name;
|
||||
|
||||
prev_isa = cgen_bitset_copy (isa);
|
||||
prev_mach = mach;
|
||||
prev_endian = endian;
|
||||
cd = bpf_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
|
||||
CGEN_CPU_OPEN_BFDMACH, mach_name,
|
||||
CGEN_CPU_OPEN_ENDIAN, prev_endian,
|
||||
CGEN_CPU_OPEN_END);
|
||||
if (!cd)
|
||||
abort ();
|
||||
|
||||
/* Save this away for future reference. */
|
||||
cl = xmalloc (sizeof (struct cpu_desc_list));
|
||||
cl->cd = cd;
|
||||
cl->isa = prev_isa;
|
||||
cl->mach = mach;
|
||||
cl->endian = endian;
|
||||
cl->next = cd_list;
|
||||
cd_list = cl;
|
||||
|
||||
bpf_cgen_init_dis (cd);
|
||||
}
|
||||
|
||||
/* We try to have as much common code as possible.
|
||||
But at this point some targets need to take over. */
|
||||
/* ??? Some targets may need a hook elsewhere. Try to avoid this,
|
||||
but if not possible try to move this hook elsewhere rather than
|
||||
have two hooks. */
|
||||
length = CGEN_PRINT_INSN (cd, pc, info);
|
||||
if (length > 0)
|
||||
return length;
|
||||
if (length < 0)
|
||||
return -1;
|
||||
|
||||
(*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
|
||||
return cd->default_insn_bitsize / 8;
|
||||
}
|
956
opcodes/bpf-ibld.c
Normal file
956
opcodes/bpf-ibld.c
Normal file
@ -0,0 +1,956 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
|
||||
/* Instruction building/extraction support for bpf. -*- C -*-
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
|
||||
- the resultant file is machine generated, cgen-ibld.in isn't
|
||||
|
||||
Copyright (C) 1996-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of libopcodes.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
|
||||
Keep that in mind. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <stdio.h>
|
||||
#include "ansidecl.h"
|
||||
#include "dis-asm.h"
|
||||
#include "bfd.h"
|
||||
#include "symcat.h"
|
||||
#include "bpf-desc.h"
|
||||
#include "bpf-opc.h"
|
||||
#include "cgen/basic-modes.h"
|
||||
#include "opintl.h"
|
||||
#include "safe-ctype.h"
|
||||
|
||||
#undef min
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#undef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
/* Used by the ifield rtx function. */
|
||||
#define FLD(f) (fields->f)
|
||||
|
||||
static const char * insert_normal
|
||||
(CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
|
||||
static const char * insert_insn_normal
|
||||
(CGEN_CPU_DESC, const CGEN_INSN *,
|
||||
CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
|
||||
static int extract_normal
|
||||
(CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int, bfd_vma, long *);
|
||||
static int extract_insn_normal
|
||||
(CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
|
||||
CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
|
||||
#if CGEN_INT_INSN_P
|
||||
static void put_insn_int_value
|
||||
(CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
|
||||
#endif
|
||||
#if ! CGEN_INT_INSN_P
|
||||
static CGEN_INLINE void insert_1
|
||||
(CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
|
||||
static CGEN_INLINE int fill_cache
|
||||
(CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma);
|
||||
static CGEN_INLINE long extract_1
|
||||
(CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
|
||||
#endif
|
||||
|
||||
/* Operand insertion. */
|
||||
|
||||
#if ! CGEN_INT_INSN_P
|
||||
|
||||
/* Subroutine of insert_normal. */
|
||||
|
||||
static CGEN_INLINE void
|
||||
insert_1 (CGEN_CPU_DESC cd,
|
||||
unsigned long value,
|
||||
int start,
|
||||
int length,
|
||||
int word_length,
|
||||
unsigned char *bufp)
|
||||
{
|
||||
unsigned long x,mask;
|
||||
int shift;
|
||||
|
||||
x = cgen_get_insn_value (cd, bufp, word_length);
|
||||
|
||||
/* Written this way to avoid undefined behaviour. */
|
||||
mask = (((1L << (length - 1)) - 1) << 1) | 1;
|
||||
if (CGEN_INSN_LSB0_P)
|
||||
shift = (start + 1) - length;
|
||||
else
|
||||
shift = (word_length - (start + length));
|
||||
x = (x & ~(mask << shift)) | ((value & mask) << shift);
|
||||
|
||||
cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
|
||||
}
|
||||
|
||||
#endif /* ! CGEN_INT_INSN_P */
|
||||
|
||||
/* Default insertion routine.
|
||||
|
||||
ATTRS is a mask of the boolean attributes.
|
||||
WORD_OFFSET is the offset in bits from the start of the insn of the value.
|
||||
WORD_LENGTH is the length of the word in bits in which the value resides.
|
||||
START is the starting bit number in the word, architecture origin.
|
||||
LENGTH is the length of VALUE in bits.
|
||||
TOTAL_LENGTH is the total length of the insn in bits.
|
||||
|
||||
The result is an error message or NULL if success. */
|
||||
|
||||
/* ??? This duplicates functionality with bfd's howto table and
|
||||
bfd_install_relocation. */
|
||||
/* ??? This doesn't handle bfd_vma's. Create another function when
|
||||
necessary. */
|
||||
|
||||
static const char *
|
||||
insert_normal (CGEN_CPU_DESC cd,
|
||||
long value,
|
||||
unsigned int attrs,
|
||||
unsigned int word_offset,
|
||||
unsigned int start,
|
||||
unsigned int length,
|
||||
unsigned int word_length,
|
||||
unsigned int total_length,
|
||||
CGEN_INSN_BYTES_PTR buffer)
|
||||
{
|
||||
static char errbuf[100];
|
||||
/* Written this way to avoid undefined behaviour. */
|
||||
unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
|
||||
|
||||
/* If LENGTH is zero, this operand doesn't contribute to the value. */
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
if (word_length > 8 * sizeof (CGEN_INSN_INT))
|
||||
abort ();
|
||||
|
||||
/* For architectures with insns smaller than the base-insn-bitsize,
|
||||
word_length may be too big. */
|
||||
if (cd->min_insn_bitsize < cd->base_insn_bitsize)
|
||||
{
|
||||
if (word_offset == 0
|
||||
&& word_length > total_length)
|
||||
word_length = total_length;
|
||||
}
|
||||
|
||||
/* Ensure VALUE will fit. */
|
||||
if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
|
||||
{
|
||||
long minval = - (1L << (length - 1));
|
||||
unsigned long maxval = mask;
|
||||
|
||||
if ((value > 0 && (unsigned long) value > maxval)
|
||||
|| value < minval)
|
||||
{
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf,
|
||||
_("operand out of range (%ld not between %ld and %lu)"),
|
||||
value, minval, maxval);
|
||||
return errbuf;
|
||||
}
|
||||
}
|
||||
else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
|
||||
{
|
||||
unsigned long maxval = mask;
|
||||
unsigned long val = (unsigned long) value;
|
||||
|
||||
/* For hosts with a word size > 32 check to see if value has been sign
|
||||
extended beyond 32 bits. If so then ignore these higher sign bits
|
||||
as the user is attempting to store a 32-bit signed value into an
|
||||
unsigned 32-bit field which is allowed. */
|
||||
if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
|
||||
val &= 0xFFFFFFFF;
|
||||
|
||||
if (val > maxval)
|
||||
{
|
||||
/* xgettext:c-format */
|
||||
sprintf (errbuf,
|
||||
_("operand out of range (0x%lx not between 0 and 0x%lx)"),
|
||||
val, maxval);
|
||||
return errbuf;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! cgen_signed_overflow_ok_p (cd))
|
||||
{
|
||||
long minval = - (1L << (length - 1));
|
||||
long maxval = (1L << (length - 1)) - 1;
|
||||
|
||||
if (value < minval || value > maxval)
|
||||
{
|
||||
sprintf
|
||||
/* xgettext:c-format */
|
||||
(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
|
||||
value, minval, maxval);
|
||||
return errbuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if CGEN_INT_INSN_P
|
||||
|
||||
{
|
||||
int shift_within_word, shift_to_word, shift;
|
||||
|
||||
/* How to shift the value to BIT0 of the word. */
|
||||
shift_to_word = total_length - (word_offset + word_length);
|
||||
|
||||
/* How to shift the value to the field within the word. */
|
||||
if (CGEN_INSN_LSB0_P)
|
||||
shift_within_word = start + 1 - length;
|
||||
else
|
||||
shift_within_word = word_length - start - length;
|
||||
|
||||
/* The total SHIFT, then mask in the value. */
|
||||
shift = shift_to_word + shift_within_word;
|
||||
*buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
|
||||
}
|
||||
|
||||
#else /* ! CGEN_INT_INSN_P */
|
||||
|
||||
{
|
||||
unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
|
||||
|
||||
insert_1 (cd, value, start, length, word_length, bufp);
|
||||
}
|
||||
|
||||
#endif /* ! CGEN_INT_INSN_P */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Default insn builder (insert handler).
|
||||
The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
|
||||
that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
|
||||
recorded in host byte order, otherwise BUFFER is an array of bytes
|
||||
and the value is recorded in target byte order).
|
||||
The result is an error message or NULL if success. */
|
||||
|
||||
static const char *
|
||||
insert_insn_normal (CGEN_CPU_DESC cd,
|
||||
const CGEN_INSN * insn,
|
||||
CGEN_FIELDS * fields,
|
||||
CGEN_INSN_BYTES_PTR buffer,
|
||||
bfd_vma pc)
|
||||
{
|
||||
const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
|
||||
unsigned long value;
|
||||
const CGEN_SYNTAX_CHAR_TYPE * syn;
|
||||
|
||||
CGEN_INIT_INSERT (cd);
|
||||
value = CGEN_INSN_BASE_VALUE (insn);
|
||||
|
||||
/* If we're recording insns as numbers (rather than a string of bytes),
|
||||
target byte order handling is deferred until later. */
|
||||
|
||||
#if CGEN_INT_INSN_P
|
||||
|
||||
put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
|
||||
CGEN_FIELDS_BITSIZE (fields), value);
|
||||
|
||||
#else
|
||||
|
||||
cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
|
||||
(unsigned) CGEN_FIELDS_BITSIZE (fields)),
|
||||
value);
|
||||
|
||||
#endif /* ! CGEN_INT_INSN_P */
|
||||
|
||||
/* ??? It would be better to scan the format's fields.
|
||||
Still need to be able to insert a value based on the operand though;
|
||||
e.g. storing a branch displacement that got resolved later.
|
||||
Needs more thought first. */
|
||||
|
||||
for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
|
||||
{
|
||||
const char *errmsg;
|
||||
|
||||
if (CGEN_SYNTAX_CHAR_P (* syn))
|
||||
continue;
|
||||
|
||||
errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
|
||||
fields, buffer, pc);
|
||||
if (errmsg)
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CGEN_INT_INSN_P
|
||||
/* Cover function to store an insn value into an integral insn. Must go here
|
||||
because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
|
||||
|
||||
static void
|
||||
put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
CGEN_INSN_BYTES_PTR buf,
|
||||
int length,
|
||||
int insn_length,
|
||||
CGEN_INSN_INT value)
|
||||
{
|
||||
/* For architectures with insns smaller than the base-insn-bitsize,
|
||||
length may be too big. */
|
||||
if (length > insn_length)
|
||||
*buf = value;
|
||||
else
|
||||
{
|
||||
int shift = insn_length - length;
|
||||
/* Written this way to avoid undefined behaviour. */
|
||||
CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
|
||||
|
||||
*buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Operand extraction. */
|
||||
|
||||
#if ! CGEN_INT_INSN_P
|
||||
|
||||
/* Subroutine of extract_normal.
|
||||
Ensure sufficient bytes are cached in EX_INFO.
|
||||
OFFSET is the offset in bytes from the start of the insn of the value.
|
||||
BYTES is the length of the needed value.
|
||||
Returns 1 for success, 0 for failure. */
|
||||
|
||||
static CGEN_INLINE int
|
||||
fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
CGEN_EXTRACT_INFO *ex_info,
|
||||
int offset,
|
||||
int bytes,
|
||||
bfd_vma pc)
|
||||
{
|
||||
/* It's doubtful that the middle part has already been fetched so
|
||||
we don't optimize that case. kiss. */
|
||||
unsigned int mask;
|
||||
disassemble_info *info = (disassemble_info *) ex_info->dis_info;
|
||||
|
||||
/* First do a quick check. */
|
||||
mask = (1 << bytes) - 1;
|
||||
if (((ex_info->valid >> offset) & mask) == mask)
|
||||
return 1;
|
||||
|
||||
/* Search for the first byte we need to read. */
|
||||
for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
|
||||
if (! (mask & ex_info->valid))
|
||||
break;
|
||||
|
||||
if (bytes)
|
||||
{
|
||||
int status;
|
||||
|
||||
pc += offset;
|
||||
status = (*info->read_memory_func)
|
||||
(pc, ex_info->insn_bytes + offset, bytes, info);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
(*info->memory_error_func) (status, pc, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ex_info->valid |= ((1 << bytes) - 1) << offset;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Subroutine of extract_normal. */
|
||||
|
||||
static CGEN_INLINE long
|
||||
extract_1 (CGEN_CPU_DESC cd,
|
||||
CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
|
||||
int start,
|
||||
int length,
|
||||
int word_length,
|
||||
unsigned char *bufp,
|
||||
bfd_vma pc ATTRIBUTE_UNUSED)
|
||||
{
|
||||
unsigned long x;
|
||||
int shift;
|
||||
|
||||
x = cgen_get_insn_value (cd, bufp, word_length);
|
||||
|
||||
if (CGEN_INSN_LSB0_P)
|
||||
shift = (start + 1) - length;
|
||||
else
|
||||
shift = (word_length - (start + length));
|
||||
return x >> shift;
|
||||
}
|
||||
|
||||
#endif /* ! CGEN_INT_INSN_P */
|
||||
|
||||
/* Default extraction routine.
|
||||
|
||||
INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
|
||||
or sometimes less for cases like the m32r where the base insn size is 32
|
||||
but some insns are 16 bits.
|
||||
ATTRS is a mask of the boolean attributes. We only need `SIGNED',
|
||||
but for generality we take a bitmask of all of them.
|
||||
WORD_OFFSET is the offset in bits from the start of the insn of the value.
|
||||
WORD_LENGTH is the length of the word in bits in which the value resides.
|
||||
START is the starting bit number in the word, architecture origin.
|
||||
LENGTH is the length of VALUE in bits.
|
||||
TOTAL_LENGTH is the total length of the insn in bits.
|
||||
|
||||
Returns 1 for success, 0 for failure. */
|
||||
|
||||
/* ??? The return code isn't properly used. wip. */
|
||||
|
||||
/* ??? This doesn't handle bfd_vma's. Create another function when
|
||||
necessary. */
|
||||
|
||||
static int
|
||||
extract_normal (CGEN_CPU_DESC cd,
|
||||
#if ! CGEN_INT_INSN_P
|
||||
CGEN_EXTRACT_INFO *ex_info,
|
||||
#else
|
||||
CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
|
||||
#endif
|
||||
CGEN_INSN_INT insn_value,
|
||||
unsigned int attrs,
|
||||
unsigned int word_offset,
|
||||
unsigned int start,
|
||||
unsigned int length,
|
||||
unsigned int word_length,
|
||||
unsigned int total_length,
|
||||
#if ! CGEN_INT_INSN_P
|
||||
bfd_vma pc,
|
||||
#else
|
||||
bfd_vma pc ATTRIBUTE_UNUSED,
|
||||
#endif
|
||||
long *valuep)
|
||||
{
|
||||
long value, mask;
|
||||
|
||||
/* If LENGTH is zero, this operand doesn't contribute to the value
|
||||
so give it a standard value of zero. */
|
||||
if (length == 0)
|
||||
{
|
||||
*valuep = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (word_length > 8 * sizeof (CGEN_INSN_INT))
|
||||
abort ();
|
||||
|
||||
/* For architectures with insns smaller than the insn-base-bitsize,
|
||||
word_length may be too big. */
|
||||
if (cd->min_insn_bitsize < cd->base_insn_bitsize)
|
||||
{
|
||||
if (word_offset + word_length > total_length)
|
||||
word_length = total_length - word_offset;
|
||||
}
|
||||
|
||||
/* Does the value reside in INSN_VALUE, and at the right alignment? */
|
||||
|
||||
if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
|
||||
{
|
||||
if (CGEN_INSN_LSB0_P)
|
||||
value = insn_value >> ((word_offset + start + 1) - length);
|
||||
else
|
||||
value = insn_value >> (total_length - ( word_offset + start + length));
|
||||
}
|
||||
|
||||
#if ! CGEN_INT_INSN_P
|
||||
|
||||
else
|
||||
{
|
||||
unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
|
||||
|
||||
if (word_length > 8 * sizeof (CGEN_INSN_INT))
|
||||
abort ();
|
||||
|
||||
if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
|
||||
return 0;
|
||||
|
||||
value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
|
||||
}
|
||||
|
||||
#endif /* ! CGEN_INT_INSN_P */
|
||||
|
||||
/* Written this way to avoid undefined behaviour. */
|
||||
mask = (((1L << (length - 1)) - 1) << 1) | 1;
|
||||
|
||||
value &= mask;
|
||||
/* sign extend? */
|
||||
if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
|
||||
&& (value & (1L << (length - 1))))
|
||||
value |= ~mask;
|
||||
|
||||
*valuep = value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Default insn extractor.
|
||||
|
||||
INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
|
||||
The extracted fields are stored in FIELDS.
|
||||
EX_INFO is used to handle reading variable length insns.
|
||||
Return the length of the insn in bits, or 0 if no match,
|
||||
or -1 if an error occurs fetching data (memory_error_func will have
|
||||
been called). */
|
||||
|
||||
static int
|
||||
extract_insn_normal (CGEN_CPU_DESC cd,
|
||||
const CGEN_INSN *insn,
|
||||
CGEN_EXTRACT_INFO *ex_info,
|
||||
CGEN_INSN_INT insn_value,
|
||||
CGEN_FIELDS *fields,
|
||||
bfd_vma pc)
|
||||
{
|
||||
const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
|
||||
const CGEN_SYNTAX_CHAR_TYPE *syn;
|
||||
|
||||
CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
|
||||
|
||||
CGEN_INIT_EXTRACT (cd);
|
||||
|
||||
for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
|
||||
{
|
||||
int length;
|
||||
|
||||
if (CGEN_SYNTAX_CHAR_P (*syn))
|
||||
continue;
|
||||
|
||||
length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
|
||||
ex_info, insn_value, fields, pc);
|
||||
if (length <= 0)
|
||||
return length;
|
||||
}
|
||||
|
||||
/* We recognized and successfully extracted this insn. */
|
||||
return CGEN_INSN_BITSIZE (insn);
|
||||
}
|
||||
|
||||
/* Machine generated code added here. */
|
||||
|
||||
const char * bpf_cgen_insert_operand
|
||||
(CGEN_CPU_DESC, int, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
|
||||
|
||||
/* Main entry point for operand insertion.
|
||||
|
||||
This function is basically just a big switch statement. Earlier versions
|
||||
used tables to look up the function to use, but
|
||||
- if the table contains both assembler and disassembler functions then
|
||||
the disassembler contains much of the assembler and vice-versa,
|
||||
- there's a lot of inlining possibilities as things grow,
|
||||
- using a switch statement avoids the function call overhead.
|
||||
|
||||
This function could be moved into `parse_insn_normal', but keeping it
|
||||
separate makes clear the interface between `parse_insn_normal' and each of
|
||||
the handlers. It's also needed by GAS to insert operands that couldn't be
|
||||
resolved during parsing. */
|
||||
|
||||
const char *
|
||||
bpf_cgen_insert_operand (CGEN_CPU_DESC cd,
|
||||
int opindex,
|
||||
CGEN_FIELDS * fields,
|
||||
CGEN_INSN_BYTES_PTR buffer,
|
||||
bfd_vma pc ATTRIBUTE_UNUSED)
|
||||
{
|
||||
const char * errmsg = NULL;
|
||||
unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
errmsg = insert_normal (cd, fields->f_offset16, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
errmsg = insert_normal (cd, fields->f_dstbe, 0, 8, 7, 4, 8, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
errmsg = insert_normal (cd, fields->f_dstle, 0, 8, 3, 4, 8, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
errmsg = insert_normal (cd, fields->f_imm32, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
{
|
||||
{
|
||||
FLD (f_imm64_b) = 0;
|
||||
FLD (f_imm64_c) = ((UDI) (FLD (f_imm64)) >> (32));
|
||||
FLD (f_imm64_a) = ((FLD (f_imm64)) & (MAKEDI (0, 0xffffffff)));
|
||||
}
|
||||
errmsg = insert_normal (cd, fields->f_imm64_a, 0, 32, 31, 32, 32, total_length, buffer);
|
||||
if (errmsg)
|
||||
break;
|
||||
errmsg = insert_normal (cd, fields->f_imm64_b, 0, 64, 31, 32, 32, total_length, buffer);
|
||||
if (errmsg)
|
||||
break;
|
||||
errmsg = insert_normal (cd, fields->f_imm64_c, 0, 96, 31, 32, 32, total_length, buffer);
|
||||
if (errmsg)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
errmsg = insert_normal (cd, fields->f_offset16, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
errmsg = insert_normal (cd, fields->f_srcbe, 0, 8, 3, 4, 8, total_length, buffer);
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
errmsg = insert_normal (cd, fields->f_srcle, 0, 8, 7, 4, 8, total_length, buffer);
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while building insn"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
int bpf_cgen_extract_operand
|
||||
(CGEN_CPU_DESC, int, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
|
||||
|
||||
/* Main entry point for operand extraction.
|
||||
The result is <= 0 for error, >0 for success.
|
||||
??? Actual values aren't well defined right now.
|
||||
|
||||
This function is basically just a big switch statement. Earlier versions
|
||||
used tables to look up the function to use, but
|
||||
- if the table contains both assembler and disassembler functions then
|
||||
the disassembler contains much of the assembler and vice-versa,
|
||||
- there's a lot of inlining possibilities as things grow,
|
||||
- using a switch statement avoids the function call overhead.
|
||||
|
||||
This function could be moved into `print_insn_normal', but keeping it
|
||||
separate makes clear the interface between `print_insn_normal' and each of
|
||||
the handlers. */
|
||||
|
||||
int
|
||||
bpf_cgen_extract_operand (CGEN_CPU_DESC cd,
|
||||
int opindex,
|
||||
CGEN_EXTRACT_INFO *ex_info,
|
||||
CGEN_INSN_INT insn_value,
|
||||
CGEN_FIELDS * fields,
|
||||
bfd_vma pc)
|
||||
{
|
||||
/* Assume success (for those operands that are nops). */
|
||||
int length = 1;
|
||||
unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, pc, & fields->f_offset16);
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 8, 7, 4, 8, total_length, pc, & fields->f_dstbe);
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 8, 3, 4, 8, total_length, pc, & fields->f_dstle);
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 32, 31, 32, 32, total_length, pc, & fields->f_imm32);
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
{
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 32, 31, 32, 32, total_length, pc, & fields->f_imm64_a);
|
||||
if (length <= 0) break;
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 64, 31, 32, 32, total_length, pc, & fields->f_imm64_b);
|
||||
if (length <= 0) break;
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 96, 31, 32, 32, total_length, pc, & fields->f_imm64_c);
|
||||
if (length <= 0) break;
|
||||
{
|
||||
FLD (f_imm64) = ((((((DI) (UINT) (FLD (f_imm64_c)))) << (32))) | (((DI) (UINT) (FLD (f_imm64_a)))));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED), 16, 15, 16, 16, total_length, pc, & fields->f_offset16);
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 8, 3, 4, 8, total_length, pc, & fields->f_srcbe);
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
length = extract_normal (cd, ex_info, insn_value, 0, 8, 7, 4, 8, total_length, pc, & fields->f_srcle);
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while decoding insn"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
cgen_insert_fn * const bpf_cgen_insert_handlers[] =
|
||||
{
|
||||
insert_insn_normal,
|
||||
};
|
||||
|
||||
cgen_extract_fn * const bpf_cgen_extract_handlers[] =
|
||||
{
|
||||
extract_insn_normal,
|
||||
};
|
||||
|
||||
int bpf_cgen_get_int_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
|
||||
bfd_vma bpf_cgen_get_vma_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
|
||||
|
||||
/* Getting values from cgen_fields is handled by a collection of functions.
|
||||
They are distinguished by the type of the VALUE argument they return.
|
||||
TODO: floating point, inlining support, remove cases where result type
|
||||
not appropriate. */
|
||||
|
||||
int
|
||||
bpf_cgen_get_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
int opindex,
|
||||
const CGEN_FIELDS * fields)
|
||||
{
|
||||
int value;
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
value = fields->f_offset16;
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
value = fields->f_dstbe;
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
value = fields->f_dstle;
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
value = fields->f_imm64;
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
value = fields->f_offset16;
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
value = fields->f_srcbe;
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
value = fields->f_srcle;
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while getting int operand"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bfd_vma
|
||||
bpf_cgen_get_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
int opindex,
|
||||
const CGEN_FIELDS * fields)
|
||||
{
|
||||
bfd_vma value;
|
||||
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
value = fields->f_offset16;
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
value = fields->f_dstbe;
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
value = fields->f_dstle;
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
value = fields->f_imm32;
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
value = fields->f_imm64;
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
value = fields->f_offset16;
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
value = fields->f_srcbe;
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
value = fields->f_srcle;
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while getting vma operand"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void bpf_cgen_set_int_operand (CGEN_CPU_DESC, int, CGEN_FIELDS *, int);
|
||||
void bpf_cgen_set_vma_operand (CGEN_CPU_DESC, int, CGEN_FIELDS *, bfd_vma);
|
||||
|
||||
/* Stuffing values in cgen_fields is handled by a collection of functions.
|
||||
They are distinguished by the type of the VALUE argument they accept.
|
||||
TODO: floating point, inlining support, remove cases where argument type
|
||||
not appropriate. */
|
||||
|
||||
void
|
||||
bpf_cgen_set_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
int opindex,
|
||||
CGEN_FIELDS * fields,
|
||||
int value)
|
||||
{
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
fields->f_offset16 = value;
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
fields->f_dstbe = value;
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
fields->f_dstle = value;
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
fields->f_imm64 = value;
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
fields->f_offset16 = value;
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
fields->f_srcbe = value;
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
fields->f_srcle = value;
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while setting int operand"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bpf_cgen_set_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
|
||||
int opindex,
|
||||
CGEN_FIELDS * fields,
|
||||
bfd_vma value)
|
||||
{
|
||||
switch (opindex)
|
||||
{
|
||||
case BPF_OPERAND_DISP16 :
|
||||
fields->f_offset16 = value;
|
||||
break;
|
||||
case BPF_OPERAND_DISP32 :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_DSTBE :
|
||||
fields->f_dstbe = value;
|
||||
break;
|
||||
case BPF_OPERAND_DSTLE :
|
||||
fields->f_dstle = value;
|
||||
break;
|
||||
case BPF_OPERAND_ENDSIZE :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_IMM32 :
|
||||
fields->f_imm32 = value;
|
||||
break;
|
||||
case BPF_OPERAND_IMM64 :
|
||||
fields->f_imm64 = value;
|
||||
break;
|
||||
case BPF_OPERAND_OFFSET16 :
|
||||
fields->f_offset16 = value;
|
||||
break;
|
||||
case BPF_OPERAND_SRCBE :
|
||||
fields->f_srcbe = value;
|
||||
break;
|
||||
case BPF_OPERAND_SRCLE :
|
||||
fields->f_srcle = value;
|
||||
break;
|
||||
|
||||
default :
|
||||
/* xgettext:c-format */
|
||||
opcodes_error_handler
|
||||
(_("internal error: unrecognized field %d while setting vma operand"),
|
||||
opindex);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to call before using the instruction builder tables. */
|
||||
|
||||
void
|
||||
bpf_cgen_init_ibld_table (CGEN_CPU_DESC cd)
|
||||
{
|
||||
cd->insert_handlers = & bpf_cgen_insert_handlers[0];
|
||||
cd->extract_handlers = & bpf_cgen_extract_handlers[0];
|
||||
|
||||
cd->insert_operand = bpf_cgen_insert_operand;
|
||||
cd->extract_operand = bpf_cgen_extract_operand;
|
||||
|
||||
cd->get_int_operand = bpf_cgen_get_int_operand;
|
||||
cd->set_int_operand = bpf_cgen_set_int_operand;
|
||||
cd->get_vma_operand = bpf_cgen_get_vma_operand;
|
||||
cd->set_vma_operand = bpf_cgen_set_vma_operand;
|
||||
}
|
1495
opcodes/bpf-opc.c
Normal file
1495
opcodes/bpf-opc.c
Normal file
File diff suppressed because it is too large
Load Diff
151
opcodes/bpf-opc.h
Normal file
151
opcodes/bpf-opc.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
|
||||
/* Instruction opcode header for bpf.
|
||||
|
||||
THIS FILE IS MACHINE GENERATED WITH CGEN.
|
||||
|
||||
Copyright (C) 1996-2019 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Binutils and/or GDB, the GNU debugger.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BPF_OPC_H
|
||||
#define BPF_OPC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* -- opc.h */
|
||||
|
||||
#undef CGEN_DIS_HASH_SIZE
|
||||
#define CGEN_DIS_HASH_SIZE 1
|
||||
|
||||
#undef CGEN_DIS_HASH
|
||||
#define CGEN_DIS_HASH(buffer, value) 0
|
||||
|
||||
/* Allows reason codes to be output when assembler errors occur. */
|
||||
#define CGEN_VERBOSE_ASSEMBLER_ERRORS
|
||||
|
||||
#define CGEN_VALIDATE_INSN_SUPPORTED
|
||||
extern int bpf_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
|
||||
|
||||
|
||||
/* -- opc.c */
|
||||
/* Enum declaration for bpf instruction types. */
|
||||
typedef enum cgen_insn_type {
|
||||
BPF_INSN_INVALID, BPF_INSN_ADDILE, BPF_INSN_ADDRLE, BPF_INSN_ADD32ILE
|
||||
, BPF_INSN_ADD32RLE, BPF_INSN_SUBILE, BPF_INSN_SUBRLE, BPF_INSN_SUB32ILE
|
||||
, BPF_INSN_SUB32RLE, BPF_INSN_MULILE, BPF_INSN_MULRLE, BPF_INSN_MUL32ILE
|
||||
, BPF_INSN_MUL32RLE, BPF_INSN_DIVILE, BPF_INSN_DIVRLE, BPF_INSN_DIV32ILE
|
||||
, BPF_INSN_DIV32RLE, BPF_INSN_ORILE, BPF_INSN_ORRLE, BPF_INSN_OR32ILE
|
||||
, BPF_INSN_OR32RLE, BPF_INSN_ANDILE, BPF_INSN_ANDRLE, BPF_INSN_AND32ILE
|
||||
, BPF_INSN_AND32RLE, BPF_INSN_LSHILE, BPF_INSN_LSHRLE, BPF_INSN_LSH32ILE
|
||||
, BPF_INSN_LSH32RLE, BPF_INSN_RSHILE, BPF_INSN_RSHRLE, BPF_INSN_RSH32ILE
|
||||
, BPF_INSN_RSH32RLE, BPF_INSN_MODILE, BPF_INSN_MODRLE, BPF_INSN_MOD32ILE
|
||||
, BPF_INSN_MOD32RLE, BPF_INSN_XORILE, BPF_INSN_XORRLE, BPF_INSN_XOR32ILE
|
||||
, BPF_INSN_XOR32RLE, BPF_INSN_MOVILE, BPF_INSN_MOVRLE, BPF_INSN_MOV32ILE
|
||||
, BPF_INSN_MOV32RLE, BPF_INSN_ARSHILE, BPF_INSN_ARSHRLE, BPF_INSN_ARSH32ILE
|
||||
, BPF_INSN_ARSH32RLE, BPF_INSN_NEGLE, BPF_INSN_NEG32LE, BPF_INSN_ADDIBE
|
||||
, BPF_INSN_ADDRBE, BPF_INSN_ADD32IBE, BPF_INSN_ADD32RBE, BPF_INSN_SUBIBE
|
||||
, BPF_INSN_SUBRBE, BPF_INSN_SUB32IBE, BPF_INSN_SUB32RBE, BPF_INSN_MULIBE
|
||||
, BPF_INSN_MULRBE, BPF_INSN_MUL32IBE, BPF_INSN_MUL32RBE, BPF_INSN_DIVIBE
|
||||
, BPF_INSN_DIVRBE, BPF_INSN_DIV32IBE, BPF_INSN_DIV32RBE, BPF_INSN_ORIBE
|
||||
, BPF_INSN_ORRBE, BPF_INSN_OR32IBE, BPF_INSN_OR32RBE, BPF_INSN_ANDIBE
|
||||
, BPF_INSN_ANDRBE, BPF_INSN_AND32IBE, BPF_INSN_AND32RBE, BPF_INSN_LSHIBE
|
||||
, BPF_INSN_LSHRBE, BPF_INSN_LSH32IBE, BPF_INSN_LSH32RBE, BPF_INSN_RSHIBE
|
||||
, BPF_INSN_RSHRBE, BPF_INSN_RSH32IBE, BPF_INSN_RSH32RBE, BPF_INSN_MODIBE
|
||||
, BPF_INSN_MODRBE, BPF_INSN_MOD32IBE, BPF_INSN_MOD32RBE, BPF_INSN_XORIBE
|
||||
, BPF_INSN_XORRBE, BPF_INSN_XOR32IBE, BPF_INSN_XOR32RBE, BPF_INSN_MOVIBE
|
||||
, BPF_INSN_MOVRBE, BPF_INSN_MOV32IBE, BPF_INSN_MOV32RBE, BPF_INSN_ARSHIBE
|
||||
, BPF_INSN_ARSHRBE, BPF_INSN_ARSH32IBE, BPF_INSN_ARSH32RBE, BPF_INSN_NEGBE
|
||||
, BPF_INSN_NEG32BE, BPF_INSN_ENDLELE, BPF_INSN_ENDBELE, BPF_INSN_ENDLEBE
|
||||
, BPF_INSN_ENDBEBE, BPF_INSN_LDDWLE, BPF_INSN_LDDWBE, BPF_INSN_LDABSWLE
|
||||
, BPF_INSN_LDABSHLE, BPF_INSN_LDABSBLE, BPF_INSN_LDABSDWLE, BPF_INSN_LDINDWLE
|
||||
, BPF_INSN_LDINDHLE, BPF_INSN_LDINDBLE, BPF_INSN_LDINDDWLE, BPF_INSN_LDABSWBE
|
||||
, BPF_INSN_LDABSHBE, BPF_INSN_LDABSBBE, BPF_INSN_LDABSDWBE, BPF_INSN_LDINDWBE
|
||||
, BPF_INSN_LDINDHBE, BPF_INSN_LDINDBBE, BPF_INSN_LDINDDWBE, BPF_INSN_LDXWLE
|
||||
, BPF_INSN_LDXHLE, BPF_INSN_LDXBLE, BPF_INSN_LDXDWLE, BPF_INSN_STXWLE
|
||||
, BPF_INSN_STXHLE, BPF_INSN_STXBLE, BPF_INSN_STXDWLE, BPF_INSN_LDXWBE
|
||||
, BPF_INSN_LDXHBE, BPF_INSN_LDXBBE, BPF_INSN_LDXDWBE, BPF_INSN_STXWBE
|
||||
, BPF_INSN_STXHBE, BPF_INSN_STXBBE, BPF_INSN_STXDWBE, BPF_INSN_STBLE
|
||||
, BPF_INSN_STHLE, BPF_INSN_STWLE, BPF_INSN_STDWLE, BPF_INSN_STBBE
|
||||
, BPF_INSN_STHBE, BPF_INSN_STWBE, BPF_INSN_STDWBE, BPF_INSN_JEQILE
|
||||
, BPF_INSN_JEQRLE, BPF_INSN_JGTILE, BPF_INSN_JGTRLE, BPF_INSN_JGEILE
|
||||
, BPF_INSN_JGERLE, BPF_INSN_JLTILE, BPF_INSN_JLTRLE, BPF_INSN_JLEILE
|
||||
, BPF_INSN_JLERLE, BPF_INSN_JSETILE, BPF_INSN_JSETRLE, BPF_INSN_JNEILE
|
||||
, BPF_INSN_JNERLE, BPF_INSN_JSGTILE, BPF_INSN_JSGTRLE, BPF_INSN_JSGEILE
|
||||
, BPF_INSN_JSGERLE, BPF_INSN_JSLTILE, BPF_INSN_JSLTRLE, BPF_INSN_JSLEILE
|
||||
, BPF_INSN_JSLERLE, BPF_INSN_JEQIBE, BPF_INSN_JEQRBE, BPF_INSN_JGTIBE
|
||||
, BPF_INSN_JGTRBE, BPF_INSN_JGEIBE, BPF_INSN_JGERBE, BPF_INSN_JLTIBE
|
||||
, BPF_INSN_JLTRBE, BPF_INSN_JLEIBE, BPF_INSN_JLERBE, BPF_INSN_JSETIBE
|
||||
, BPF_INSN_JSETRBE, BPF_INSN_JNEIBE, BPF_INSN_JNERBE, BPF_INSN_JSGTIBE
|
||||
, BPF_INSN_JSGTRBE, BPF_INSN_JSGEIBE, BPF_INSN_JSGERBE, BPF_INSN_JSLTIBE
|
||||
, BPF_INSN_JSLTRBE, BPF_INSN_JSLEIBE, BPF_INSN_JSLERBE, BPF_INSN_JA
|
||||
, BPF_INSN_CALL, BPF_INSN_EXIT, BPF_INSN_XADDDWLE, BPF_INSN_XADDWLE
|
||||
, BPF_INSN_XADDDWBE, BPF_INSN_XADDWBE
|
||||
} CGEN_INSN_TYPE;
|
||||
|
||||
/* Index of `invalid' insn place holder. */
|
||||
#define CGEN_INSN_INVALID BPF_INSN_INVALID
|
||||
|
||||
/* Total number of insns in table. */
|
||||
#define MAX_INSNS ((int) BPF_INSN_XADDWBE + 1)
|
||||
|
||||
/* This struct records data prior to insertion or after extraction. */
|
||||
struct cgen_fields
|
||||
{
|
||||
int length;
|
||||
long f_nil;
|
||||
long f_anyof;
|
||||
long f_op_code;
|
||||
long f_op_src;
|
||||
long f_op_class;
|
||||
long f_op_mode;
|
||||
long f_op_size;
|
||||
long f_dstle;
|
||||
long f_srcle;
|
||||
long f_dstbe;
|
||||
long f_srcbe;
|
||||
long f_regs;
|
||||
long f_offset16;
|
||||
long f_imm32;
|
||||
long f_imm64_a;
|
||||
long f_imm64_b;
|
||||
long f_imm64_c;
|
||||
int64_t f_imm64;
|
||||
};
|
||||
|
||||
#define CGEN_INIT_PARSE(od) \
|
||||
{\
|
||||
}
|
||||
#define CGEN_INIT_INSERT(od) \
|
||||
{\
|
||||
}
|
||||
#define CGEN_INIT_EXTRACT(od) \
|
||||
{\
|
||||
}
|
||||
#define CGEN_INIT_PRINT(od) \
|
||||
{\
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BPF_OPC_H */
|
19
opcodes/configure
vendored
19
opcodes/configure
vendored
@ -769,6 +769,7 @@ infodir
|
||||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
@ -854,6 +855,7 @@ datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||
@ -1106,6 +1108,15 @@ do
|
||||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||
| --run | --ru | --r)
|
||||
ac_prev=runstatedir ;;
|
||||
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||
| --run=* | --ru=* | --r=*)
|
||||
runstatedir=$ac_optarg ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
@ -1243,7 +1254,7 @@ fi
|
||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||
libdir localedir mandir
|
||||
libdir localedir mandir runstatedir
|
||||
do
|
||||
eval ac_val=\$$ac_var
|
||||
# Remove trailing slashes.
|
||||
@ -1396,6 +1407,7 @@ Fine tuning of the installation directories:
|
||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||
--includedir=DIR C header files [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||
@ -11439,7 +11451,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11442 "configure"
|
||||
#line 11454 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -11545,7 +11557,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11548 "configure"
|
||||
#line 11560 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -12949,6 +12961,7 @@ if test x${all_targets} = xfalse ; then
|
||||
bfd_xtensa_arch) ta="$ta xtensa-dis.lo" ;;
|
||||
bfd_z80_arch) ta="$ta z80-dis.lo" ;;
|
||||
bfd_z8k_arch) ta="$ta z8k-dis.lo" ;;
|
||||
bfd_bpf_arch) ta="$ta bpf-asm.lo bpf-desc.lo bpf-dis.lo bpf-ibld.lo bpf-opc.lo" using_cgen=yes ;;
|
||||
|
||||
"") ;;
|
||||
*) as_fn_error $? "*** unknown target architecture $arch" "$LINENO" 5 ;;
|
||||
|
@ -340,6 +340,7 @@ if test x${all_targets} = xfalse ; then
|
||||
bfd_xtensa_arch) ta="$ta xtensa-dis.lo" ;;
|
||||
bfd_z80_arch) ta="$ta z80-dis.lo" ;;
|
||||
bfd_z8k_arch) ta="$ta z8k-dis.lo" ;;
|
||||
bfd_bpf_arch) ta="$ta bpf-asm.lo bpf-desc.lo bpf-dis.lo bpf-ibld.lo bpf-opc.lo" using_cgen=yes ;;
|
||||
|
||||
"") ;;
|
||||
*) AC_MSG_ERROR(*** unknown target architecture $arch) ;;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define ARCH_d10v
|
||||
#define ARCH_d30v
|
||||
#define ARCH_dlx
|
||||
#define ARCH_bpf
|
||||
#define ARCH_epiphany
|
||||
#define ARCH_fr30
|
||||
#define ARCH_frv
|
||||
@ -106,6 +107,23 @@
|
||||
#include "m32c-desc.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_bpf
|
||||
/* XXX this should be including bpf-desc.h instead of this hackery,
|
||||
but at the moment it is not possible to include several CGEN
|
||||
generated *-desc.h files simultaneously. To be fixed in
|
||||
CGEN... */
|
||||
|
||||
# ifdef ARCH_m32c
|
||||
enum epbf_isa_attr
|
||||
{
|
||||
ISA_EBPFLE, ISA_EBPFBE, ISA_EBPFMAX
|
||||
};
|
||||
# else
|
||||
# include "bpf-desc.h"
|
||||
# define ISA_EBPFMAX ISA_MAX
|
||||
# endif
|
||||
#endif /* ARCH_bpf */
|
||||
|
||||
disassembler_ftype
|
||||
disassembler (enum bfd_architecture a,
|
||||
bfd_boolean big ATTRIBUTE_UNUSED,
|
||||
@ -224,6 +242,11 @@ disassembler (enum bfd_architecture a,
|
||||
disassemble = print_insn_ip2k;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCH_bpf
|
||||
case bfd_arch_bpf:
|
||||
disassemble = print_insn_bpf;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCH_epiphany
|
||||
case bfd_arch_epiphany:
|
||||
disassemble = print_insn_epiphany;
|
||||
@ -641,6 +664,18 @@ disassemble_init_for_target (struct disassemble_info * info)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCH_bpf
|
||||
case bfd_arch_bpf:
|
||||
if (!info->insn_sets)
|
||||
{
|
||||
info->insn_sets = cgen_bitset_create (ISA_EBPFMAX);
|
||||
if (info->endian == BFD_ENDIAN_BIG)
|
||||
cgen_bitset_set (info->insn_sets, ISA_EBPFBE);
|
||||
else
|
||||
cgen_bitset_set (info->insn_sets, ISA_EBPFLE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCH_pru
|
||||
case bfd_arch_pru:
|
||||
info->disassembler_needs_relocs = TRUE;
|
||||
|
@ -36,6 +36,7 @@ extern int print_insn_csky (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_d10v (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_d30v (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_dlx (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_bpf (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_epiphany (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_fr30 (bfd_vma, disassemble_info *);
|
||||
extern int print_insn_frv (bfd_vma, disassemble_info *);
|
||||
|
Loading…
Reference in New Issue
Block a user