aboutsummaryrefslogtreecommitdiff
blob: e70ee04841df05bb8267961968c6b8d64e49f40c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/* 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);
}


/* -- */