| /* 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); | |
| } | |
| /* -- */ | |