1/* EBPF opcode support. -*- c -*- 2 3 Copyright (C) 2019 Free Software Foundation, Inc. 4 5 Contributed by Oracle, Inc. 6 7 This file is part of the GNU Binutils and of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 22 MA 02110-1301, USA. */ 23 24/* 25 Each section is delimited with start and end markers. 26 27 <arch>-opc.h additions use: "-- opc.h" 28 <arch>-opc.c additions use: "-- opc.c" 29 <arch>-asm.c additions use: "-- asm.c" 30 <arch>-dis.c additions use: "-- dis.c" 31 <arch>-ibd.h additions use: "-- ibd.h". */ 32 33/* -- opc.h */ 34 35#undef CGEN_DIS_HASH_SIZE 36#define CGEN_DIS_HASH_SIZE 1 37 38#undef CGEN_DIS_HASH 39#define CGEN_DIS_HASH(buffer, value) 0 40 41/* Allows reason codes to be output when assembler errors occur. */ 42#define CGEN_VERBOSE_ASSEMBLER_ERRORS 43 44#define CGEN_VALIDATE_INSN_SUPPORTED 45extern int bpf_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *); 46 47 48/* -- opc.c */ 49 50/* -- asm.c */ 51 52/* Parse a signed 64-bit immediate. */ 53 54static const char * 55parse_imm64 (CGEN_CPU_DESC cd, 56 const char **strp, 57 int opindex, 58 int64_t *valuep) 59{ 60 bfd_vma value; 61 enum cgen_parse_operand_result result; 62 const char *errmsg; 63 64 errmsg = (* cd->parse_operand_fn) 65 (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE, 66 &result, &value); 67 if (!errmsg) 68 *valuep = value; 69 70 return errmsg; 71} 72 73/* Endianness size operands are integer immediates whose values can be 74 16, 32 or 64. */ 75 76static const char * 77parse_endsize (CGEN_CPU_DESC cd, 78 const char **strp, 79 int opindex, 80 unsigned long *valuep) 81{ 82 const char *errmsg; 83 84 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 85 if (errmsg) 86 return errmsg; 87 88 switch (*valuep) 89 { 90 case 16: 91 case 32: 92 case 64: 93 break; 94 default: 95 return _("expected 16, 32 or 64 in"); 96 } 97 98 return NULL; 99} 100 101/* Special check to ensure that the right instruction variant is used 102 for the given endianness induced by the ISA selected in the CPU. 103 See bpf.cpu for a discussion on how eBPF is really two instruction 104 sets. */ 105 106int 107bpf_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn) 108{ 109 CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA); 110 111 return cgen_bitset_intersect_p (&isas, cd->isas); 112} 113 114 115/* -- dis.c */ 116 117/* We need to customize the disassembler a bit: 118 - Use 8 bytes per line by default. 119*/ 120 121#define CGEN_PRINT_INSN bpf_print_insn 122 123static int 124bpf_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 125{ 126 bfd_byte buf[CGEN_MAX_INSN_SIZE]; 127 int buflen; 128 int status; 129 130 info->bytes_per_chunk = 1; 131 info->bytes_per_line = 8; 132 133 /* Attempt to read the base part of the insn. */ 134 buflen = cd->base_insn_bitsize / 8; 135 status = (*info->read_memory_func) (pc, buf, buflen, info); 136 137 /* Try again with the minimum part, if min < base. */ 138 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 139 { 140 buflen = cd->min_insn_bitsize / 8; 141 status = (*info->read_memory_func) (pc, buf, buflen, info); 142 } 143 144 if (status != 0) 145 { 146 (*info->memory_error_func) (status, pc, info); 147 return -1; 148 } 149 150 return print_insn (cd, pc, info, buf, buflen); 151} 152 153/* Signed immediates should be printed in hexadecimal. */ 154 155static void 156print_immediate (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 157 void *dis_info, 158 int64_t value, 159 unsigned int attrs ATTRIBUTE_UNUSED, 160 bfd_vma pc ATTRIBUTE_UNUSED, 161 int length ATTRIBUTE_UNUSED) 162{ 163 disassemble_info *info = (disassemble_info *) dis_info; 164 165 if (value <= 9) 166 (*info->fprintf_func) (info->stream, "%" PRId64, value); 167 else 168 (*info->fprintf_func) (info->stream, "%#" PRIx64, value); 169 170 /* This is to avoid -Wunused-function for print_normal. */ 171 if (0) 172 print_normal (cd, dis_info, value, attrs, pc, length); 173} 174 175/* Endianness bit sizes should be printed in decimal. */ 176 177static void 178print_endsize (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 179 void *dis_info, 180 unsigned long value, 181 unsigned int attrs ATTRIBUTE_UNUSED, 182 bfd_vma pc ATTRIBUTE_UNUSED, 183 int length ATTRIBUTE_UNUSED) 184{ 185 disassemble_info *info = (disassemble_info *) dis_info; 186 (*info->fprintf_func) (info->stream, "%lu", value); 187} 188 189 190/* -- */ 191 192