xref: /netbsd-src/external/gpl3/binutils.old/dist/cpu/bpf.opc (revision 867d70fc718005c0918b8b8b2f9d7f2d52d0a0db)
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