/* 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. -opc.h additions use: "-- opc.h" -opc.c additions use: "-- opc.c" -asm.c additions use: "-- asm.c" -dis.c additions use: "-- dis.c" -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); } /* -- */