You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
4.9 KiB
C

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/* EBPF opcode support. -*- c -*-
Copyright (C) 2019 Free Software Foundation, Inc.
Contributed by Oracle, Inc.
This file is part of the GNU Binutils and of GDB.
This program 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 of the License, or
(at your option) any later version.
This program 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. */
/*
Each section is delimited with start and end markers.
<arch>-opc.h additions use: "-- opc.h"
<arch>-opc.c additions use: "-- opc.c"
<arch>-asm.c additions use: "-- asm.c"
<arch>-dis.c additions use: "-- dis.c"
<arch>-ibd.h additions use: "-- ibd.h". */
/* -- 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 */
/* -- 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 */
/* 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);
}
/* -- */