riscv-dis.c revision 1.1.1.3 1 1.1 christos /* RISC-V disassembler
2 1.1.1.3 christos Copyright (C) 2011-2020 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos Contributed by Andrew Waterman (andrew (at) sifive.com).
5 1.1 christos Based on MIPS target.
6 1.1 christos
7 1.1 christos This file is part of the GNU opcodes library.
8 1.1 christos
9 1.1 christos This library is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 3, or (at your option)
12 1.1 christos any later version.
13 1.1 christos
14 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
15 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 1.1 christos License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program; see the file COPYING3. If not,
21 1.1 christos see <http://www.gnu.org/licenses/>. */
22 1.1 christos
23 1.1 christos #include "sysdep.h"
24 1.1.1.2 christos #include "disassemble.h"
25 1.1 christos #include "libiberty.h"
26 1.1 christos #include "opcode/riscv.h"
27 1.1 christos #include "opintl.h"
28 1.1 christos #include "elf-bfd.h"
29 1.1 christos #include "elf/riscv.h"
30 1.1.1.3 christos #include "elfxx-riscv.h"
31 1.1 christos
32 1.1.1.2 christos #include "bfd_stdint.h"
33 1.1 christos #include <ctype.h>
34 1.1 christos
35 1.1.1.3 christos static enum riscv_priv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
36 1.1.1.3 christos
37 1.1 christos struct riscv_private_data
38 1.1 christos {
39 1.1 christos bfd_vma gp;
40 1.1 christos bfd_vma print_addr;
41 1.1 christos bfd_vma hi_addr[OP_MASK_RD + 1];
42 1.1 christos };
43 1.1 christos
44 1.1 christos static const char * const *riscv_gpr_names;
45 1.1 christos static const char * const *riscv_fpr_names;
46 1.1 christos
47 1.1 christos /* Other options. */
48 1.1 christos static int no_aliases; /* If set disassemble as most general inst. */
49 1.1 christos
50 1.1 christos static void
51 1.1 christos set_default_riscv_dis_options (void)
52 1.1 christos {
53 1.1 christos riscv_gpr_names = riscv_gpr_names_abi;
54 1.1 christos riscv_fpr_names = riscv_fpr_names_abi;
55 1.1 christos no_aliases = 0;
56 1.1 christos }
57 1.1 christos
58 1.1.1.3 christos static bfd_boolean
59 1.1.1.3 christos parse_riscv_dis_option_without_args (const char *option)
60 1.1 christos {
61 1.1 christos if (strcmp (option, "no-aliases") == 0)
62 1.1 christos no_aliases = 1;
63 1.1 christos else if (strcmp (option, "numeric") == 0)
64 1.1 christos {
65 1.1 christos riscv_gpr_names = riscv_gpr_names_numeric;
66 1.1 christos riscv_fpr_names = riscv_fpr_names_numeric;
67 1.1 christos }
68 1.1 christos else
69 1.1.1.3 christos return FALSE;
70 1.1.1.3 christos return TRUE;
71 1.1.1.3 christos }
72 1.1.1.3 christos
73 1.1.1.3 christos static void
74 1.1.1.3 christos parse_riscv_dis_option (const char *option)
75 1.1.1.3 christos {
76 1.1.1.3 christos char *equal, *value;
77 1.1.1.3 christos
78 1.1.1.3 christos if (parse_riscv_dis_option_without_args (option))
79 1.1.1.3 christos return;
80 1.1.1.3 christos
81 1.1.1.3 christos equal = strchr (option, '=');
82 1.1.1.3 christos if (equal == NULL)
83 1.1.1.3 christos {
84 1.1.1.3 christos /* The option without '=' should be defined above. */
85 1.1.1.3 christos opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
86 1.1.1.3 christos return;
87 1.1.1.3 christos }
88 1.1.1.3 christos if (equal == option
89 1.1.1.3 christos || *(equal + 1) == '\0')
90 1.1.1.3 christos {
91 1.1.1.3 christos /* Invalid options with '=', no option name before '=',
92 1.1.1.3 christos and no value after '='. */
93 1.1.1.3 christos opcodes_error_handler (_("unrecognized disassembler option with '=': %s"),
94 1.1.1.3 christos option);
95 1.1.1.3 christos return;
96 1.1.1.3 christos }
97 1.1.1.3 christos
98 1.1.1.3 christos *equal = '\0';
99 1.1.1.3 christos value = equal + 1;
100 1.1.1.3 christos if (strcmp (option, "priv-spec") == 0)
101 1.1.1.3 christos {
102 1.1.1.3 christos if (!riscv_get_priv_spec_class (value, &default_priv_spec))
103 1.1.1.3 christos opcodes_error_handler (_("unknown privilege spec set by %s=%s"),
104 1.1.1.3 christos option, value);
105 1.1.1.3 christos }
106 1.1.1.3 christos else
107 1.1 christos {
108 1.1.1.2 christos /* xgettext:c-format */
109 1.1.1.2 christos opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
110 1.1 christos }
111 1.1 christos }
112 1.1 christos
113 1.1 christos static void
114 1.1 christos parse_riscv_dis_options (const char *opts_in)
115 1.1 christos {
116 1.1 christos char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
117 1.1 christos
118 1.1 christos set_default_riscv_dis_options ();
119 1.1 christos
120 1.1 christos for ( ; opt_end != NULL; opt = opt_end + 1)
121 1.1 christos {
122 1.1 christos if ((opt_end = strchr (opt, ',')) != NULL)
123 1.1 christos *opt_end = 0;
124 1.1 christos parse_riscv_dis_option (opt);
125 1.1 christos }
126 1.1 christos
127 1.1 christos free (opts);
128 1.1 christos }
129 1.1 christos
130 1.1 christos /* Print one argument from an array. */
131 1.1 christos
132 1.1 christos static void
133 1.1 christos arg_print (struct disassemble_info *info, unsigned long val,
134 1.1 christos const char* const* array, size_t size)
135 1.1 christos {
136 1.1 christos const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
137 1.1 christos (*info->fprintf_func) (info->stream, "%s", s);
138 1.1 christos }
139 1.1 christos
140 1.1 christos static void
141 1.1 christos maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset)
142 1.1 christos {
143 1.1 christos if (pd->hi_addr[base_reg] != (bfd_vma)-1)
144 1.1 christos {
145 1.1.1.2 christos pd->print_addr = (base_reg != 0 ? pd->hi_addr[base_reg] : 0) + offset;
146 1.1 christos pd->hi_addr[base_reg] = -1;
147 1.1 christos }
148 1.1 christos else if (base_reg == X_GP && pd->gp != (bfd_vma)-1)
149 1.1 christos pd->print_addr = pd->gp + offset;
150 1.1 christos else if (base_reg == X_TP || base_reg == 0)
151 1.1 christos pd->print_addr = offset;
152 1.1 christos }
153 1.1 christos
154 1.1 christos /* Print insn arguments for 32/64-bit code. */
155 1.1 christos
156 1.1 christos static void
157 1.1 christos print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
158 1.1 christos {
159 1.1 christos struct riscv_private_data *pd = info->private_data;
160 1.1 christos int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
161 1.1 christos int rd = (l >> OP_SH_RD) & OP_MASK_RD;
162 1.1 christos fprintf_ftype print = info->fprintf_func;
163 1.1 christos
164 1.1 christos if (*d != '\0')
165 1.1 christos print (info->stream, "\t");
166 1.1 christos
167 1.1 christos for (; *d != '\0'; d++)
168 1.1 christos {
169 1.1 christos switch (*d)
170 1.1 christos {
171 1.1 christos case 'C': /* RVC */
172 1.1 christos switch (*++d)
173 1.1 christos {
174 1.1 christos case 's': /* RS1 x8-x15 */
175 1.1 christos case 'w': /* RS1 x8-x15 */
176 1.1 christos print (info->stream, "%s",
177 1.1 christos riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
178 1.1 christos break;
179 1.1 christos case 't': /* RS2 x8-x15 */
180 1.1 christos case 'x': /* RS2 x8-x15 */
181 1.1 christos print (info->stream, "%s",
182 1.1 christos riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
183 1.1 christos break;
184 1.1 christos case 'U': /* RS1, constrained to equal RD */
185 1.1 christos print (info->stream, "%s", riscv_gpr_names[rd]);
186 1.1 christos break;
187 1.1 christos case 'c': /* RS1, constrained to equal sp */
188 1.1 christos print (info->stream, "%s", riscv_gpr_names[X_SP]);
189 1.1 christos break;
190 1.1 christos case 'V': /* RS2 */
191 1.1 christos print (info->stream, "%s",
192 1.1 christos riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
193 1.1 christos break;
194 1.1 christos case 'i':
195 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_SIMM3 (l));
196 1.1 christos break;
197 1.1.1.2 christos case 'o':
198 1.1 christos case 'j':
199 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_IMM (l));
200 1.1 christos break;
201 1.1 christos case 'k':
202 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_LW_IMM (l));
203 1.1 christos break;
204 1.1 christos case 'l':
205 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_LD_IMM (l));
206 1.1 christos break;
207 1.1 christos case 'm':
208 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_LWSP_IMM (l));
209 1.1 christos break;
210 1.1 christos case 'n':
211 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
212 1.1 christos break;
213 1.1 christos case 'K':
214 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_ADDI4SPN_IMM (l));
215 1.1 christos break;
216 1.1 christos case 'L':
217 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_ADDI16SP_IMM (l));
218 1.1 christos break;
219 1.1 christos case 'M':
220 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_SWSP_IMM (l));
221 1.1 christos break;
222 1.1 christos case 'N':
223 1.1 christos print (info->stream, "%d", (int)EXTRACT_RVC_SDSP_IMM (l));
224 1.1 christos break;
225 1.1 christos case 'p':
226 1.1 christos info->target = EXTRACT_RVC_B_IMM (l) + pc;
227 1.1 christos (*info->print_address_func) (info->target, info);
228 1.1 christos break;
229 1.1 christos case 'a':
230 1.1 christos info->target = EXTRACT_RVC_J_IMM (l) + pc;
231 1.1 christos (*info->print_address_func) (info->target, info);
232 1.1 christos break;
233 1.1 christos case 'u':
234 1.1 christos print (info->stream, "0x%x",
235 1.1 christos (int)(EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
236 1.1 christos break;
237 1.1 christos case '>':
238 1.1 christos print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x3f);
239 1.1 christos break;
240 1.1 christos case '<':
241 1.1 christos print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x1f);
242 1.1 christos break;
243 1.1 christos case 'T': /* floating-point RS2 */
244 1.1 christos print (info->stream, "%s",
245 1.1 christos riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
246 1.1 christos break;
247 1.1 christos case 'D': /* floating-point RS2 x8-x15 */
248 1.1 christos print (info->stream, "%s",
249 1.1 christos riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
250 1.1 christos break;
251 1.1 christos }
252 1.1 christos break;
253 1.1 christos
254 1.1 christos case ',':
255 1.1 christos case '(':
256 1.1 christos case ')':
257 1.1 christos case '[':
258 1.1 christos case ']':
259 1.1 christos print (info->stream, "%c", *d);
260 1.1 christos break;
261 1.1 christos
262 1.1 christos case '0':
263 1.1 christos /* Only print constant 0 if it is the last argument */
264 1.1 christos if (!d[1])
265 1.1 christos print (info->stream, "0");
266 1.1 christos break;
267 1.1 christos
268 1.1 christos case 'b':
269 1.1 christos case 's':
270 1.1.1.2 christos if ((l & MASK_JALR) == MATCH_JALR)
271 1.1.1.2 christos maybe_print_address (pd, rs1, 0);
272 1.1 christos print (info->stream, "%s", riscv_gpr_names[rs1]);
273 1.1 christos break;
274 1.1 christos
275 1.1 christos case 't':
276 1.1 christos print (info->stream, "%s",
277 1.1 christos riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]);
278 1.1 christos break;
279 1.1 christos
280 1.1 christos case 'u':
281 1.1 christos print (info->stream, "0x%x",
282 1.1 christos (unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
283 1.1 christos break;
284 1.1 christos
285 1.1 christos case 'm':
286 1.1 christos arg_print (info, EXTRACT_OPERAND (RM, l),
287 1.1 christos riscv_rm, ARRAY_SIZE (riscv_rm));
288 1.1 christos break;
289 1.1 christos
290 1.1 christos case 'P':
291 1.1 christos arg_print (info, EXTRACT_OPERAND (PRED, l),
292 1.1 christos riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
293 1.1 christos break;
294 1.1 christos
295 1.1 christos case 'Q':
296 1.1 christos arg_print (info, EXTRACT_OPERAND (SUCC, l),
297 1.1 christos riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
298 1.1 christos break;
299 1.1 christos
300 1.1 christos case 'o':
301 1.1 christos maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
302 1.1 christos /* Fall through. */
303 1.1 christos case 'j':
304 1.1 christos if (((l & MASK_ADDI) == MATCH_ADDI && rs1 != 0)
305 1.1 christos || (l & MASK_JALR) == MATCH_JALR)
306 1.1 christos maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
307 1.1 christos print (info->stream, "%d", (int)EXTRACT_ITYPE_IMM (l));
308 1.1 christos break;
309 1.1 christos
310 1.1 christos case 'q':
311 1.1 christos maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l));
312 1.1 christos print (info->stream, "%d", (int)EXTRACT_STYPE_IMM (l));
313 1.1 christos break;
314 1.1 christos
315 1.1 christos case 'a':
316 1.1 christos info->target = EXTRACT_UJTYPE_IMM (l) + pc;
317 1.1 christos (*info->print_address_func) (info->target, info);
318 1.1 christos break;
319 1.1 christos
320 1.1 christos case 'p':
321 1.1 christos info->target = EXTRACT_SBTYPE_IMM (l) + pc;
322 1.1 christos (*info->print_address_func) (info->target, info);
323 1.1 christos break;
324 1.1 christos
325 1.1 christos case 'd':
326 1.1 christos if ((l & MASK_AUIPC) == MATCH_AUIPC)
327 1.1 christos pd->hi_addr[rd] = pc + EXTRACT_UTYPE_IMM (l);
328 1.1 christos else if ((l & MASK_LUI) == MATCH_LUI)
329 1.1 christos pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l);
330 1.1 christos else if ((l & MASK_C_LUI) == MATCH_C_LUI)
331 1.1 christos pd->hi_addr[rd] = EXTRACT_RVC_LUI_IMM (l);
332 1.1 christos print (info->stream, "%s", riscv_gpr_names[rd]);
333 1.1 christos break;
334 1.1 christos
335 1.1 christos case 'z':
336 1.1 christos print (info->stream, "%s", riscv_gpr_names[0]);
337 1.1 christos break;
338 1.1 christos
339 1.1 christos case '>':
340 1.1 christos print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMT, l));
341 1.1 christos break;
342 1.1 christos
343 1.1 christos case '<':
344 1.1 christos print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMTW, l));
345 1.1 christos break;
346 1.1 christos
347 1.1 christos case 'S':
348 1.1 christos case 'U':
349 1.1 christos print (info->stream, "%s", riscv_fpr_names[rs1]);
350 1.1 christos break;
351 1.1 christos
352 1.1 christos case 'T':
353 1.1 christos print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
354 1.1 christos break;
355 1.1 christos
356 1.1 christos case 'D':
357 1.1 christos print (info->stream, "%s", riscv_fpr_names[rd]);
358 1.1 christos break;
359 1.1 christos
360 1.1 christos case 'R':
361 1.1 christos print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
362 1.1 christos break;
363 1.1 christos
364 1.1 christos case 'E':
365 1.1 christos {
366 1.1.1.3 christos static const char *riscv_csr_hash[4096]; /* Total 2^12 CSR. */
367 1.1.1.3 christos static bfd_boolean init_csr = FALSE;
368 1.1 christos unsigned int csr = EXTRACT_OPERAND (CSR, l);
369 1.1.1.3 christos
370 1.1.1.3 christos if (!init_csr)
371 1.1 christos {
372 1.1.1.3 christos unsigned int i;
373 1.1.1.3 christos for (i = 0; i < 4096; i++)
374 1.1.1.3 christos riscv_csr_hash[i] = NULL;
375 1.1.1.3 christos
376 1.1.1.3 christos /* Set to the newest privilege version. */
377 1.1.1.3 christos if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
378 1.1.1.3 christos default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1;
379 1.1.1.3 christos
380 1.1.1.3 christos #define DECLARE_CSR(name, num, class, define_version, abort_version) \
381 1.1.1.3 christos if (riscv_csr_hash[num] == NULL \
382 1.1.1.3 christos && ((define_version == PRIV_SPEC_CLASS_NONE \
383 1.1.1.3 christos && abort_version == PRIV_SPEC_CLASS_NONE) \
384 1.1.1.3 christos || (default_priv_spec >= define_version \
385 1.1.1.3 christos && default_priv_spec < abort_version))) \
386 1.1.1.3 christos riscv_csr_hash[num] = #name;
387 1.1.1.3 christos #define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \
388 1.1.1.3 christos DECLARE_CSR (name, num, class, define_version, abort_version)
389 1.1 christos #include "opcode/riscv-opc.h"
390 1.1 christos #undef DECLARE_CSR
391 1.1 christos }
392 1.1.1.3 christos
393 1.1.1.3 christos if (riscv_csr_hash[csr] != NULL)
394 1.1.1.3 christos print (info->stream, "%s", riscv_csr_hash[csr]);
395 1.1 christos else
396 1.1 christos print (info->stream, "0x%x", csr);
397 1.1 christos break;
398 1.1 christos }
399 1.1 christos
400 1.1 christos case 'Z':
401 1.1 christos print (info->stream, "%d", rs1);
402 1.1 christos break;
403 1.1 christos
404 1.1 christos default:
405 1.1 christos /* xgettext:c-format */
406 1.1 christos print (info->stream, _("# internal error, undefined modifier (%c)"),
407 1.1 christos *d);
408 1.1 christos return;
409 1.1 christos }
410 1.1 christos }
411 1.1 christos }
412 1.1 christos
413 1.1 christos /* Print the RISC-V instruction at address MEMADDR in debugged memory,
414 1.1 christos on using INFO. Returns length of the instruction, in bytes.
415 1.1 christos BIGENDIAN must be 1 if this is big-endian code, 0 if
416 1.1 christos this is little-endian code. */
417 1.1 christos
418 1.1 christos static int
419 1.1 christos riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
420 1.1 christos {
421 1.1 christos const struct riscv_opcode *op;
422 1.1 christos static bfd_boolean init = 0;
423 1.1 christos static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
424 1.1 christos struct riscv_private_data *pd;
425 1.1 christos int insnlen;
426 1.1 christos
427 1.1 christos #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : OP_MASK_OP))
428 1.1 christos
429 1.1 christos /* Build a hash table to shorten the search time. */
430 1.1 christos if (! init)
431 1.1 christos {
432 1.1 christos for (op = riscv_opcodes; op->name; op++)
433 1.1 christos if (!riscv_hash[OP_HASH_IDX (op->match)])
434 1.1 christos riscv_hash[OP_HASH_IDX (op->match)] = op;
435 1.1 christos
436 1.1 christos init = 1;
437 1.1 christos }
438 1.1 christos
439 1.1 christos if (info->private_data == NULL)
440 1.1 christos {
441 1.1 christos int i;
442 1.1 christos
443 1.1 christos pd = info->private_data = xcalloc (1, sizeof (struct riscv_private_data));
444 1.1 christos pd->gp = -1;
445 1.1 christos pd->print_addr = -1;
446 1.1 christos for (i = 0; i < (int)ARRAY_SIZE (pd->hi_addr); i++)
447 1.1 christos pd->hi_addr[i] = -1;
448 1.1 christos
449 1.1 christos for (i = 0; i < info->symtab_size; i++)
450 1.1 christos if (strcmp (bfd_asymbol_name (info->symtab[i]), RISCV_GP_SYMBOL) == 0)
451 1.1 christos pd->gp = bfd_asymbol_value (info->symtab[i]);
452 1.1 christos }
453 1.1 christos else
454 1.1 christos pd = info->private_data;
455 1.1 christos
456 1.1 christos insnlen = riscv_insn_length (word);
457 1.1 christos
458 1.1.1.3 christos /* RISC-V instructions are always little-endian. */
459 1.1.1.3 christos info->endian_code = BFD_ENDIAN_LITTLE;
460 1.1.1.3 christos
461 1.1 christos info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
462 1.1 christos info->bytes_per_line = 8;
463 1.1.1.3 christos /* We don't support constant pools, so this must be code. */
464 1.1.1.3 christos info->display_endian = info->endian_code;
465 1.1 christos info->insn_info_valid = 1;
466 1.1 christos info->branch_delay_insns = 0;
467 1.1 christos info->data_size = 0;
468 1.1 christos info->insn_type = dis_nonbranch;
469 1.1 christos info->target = 0;
470 1.1 christos info->target2 = 0;
471 1.1 christos
472 1.1 christos op = riscv_hash[OP_HASH_IDX (word)];
473 1.1 christos if (op != NULL)
474 1.1 christos {
475 1.1.1.2 christos unsigned xlen = 0;
476 1.1 christos
477 1.1 christos /* If XLEN is not known, get its value from the ELF class. */
478 1.1 christos if (info->mach == bfd_mach_riscv64)
479 1.1 christos xlen = 64;
480 1.1 christos else if (info->mach == bfd_mach_riscv32)
481 1.1 christos xlen = 32;
482 1.1 christos else if (info->section != NULL)
483 1.1 christos {
484 1.1 christos Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
485 1.1 christos xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
486 1.1 christos }
487 1.1 christos
488 1.1 christos for (; op->name; op++)
489 1.1 christos {
490 1.1 christos /* Does the opcode match? */
491 1.1 christos if (! (op->match_func) (op, word))
492 1.1 christos continue;
493 1.1 christos /* Is this a pseudo-instruction and may we print it as such? */
494 1.1 christos if (no_aliases && (op->pinfo & INSN_ALIAS))
495 1.1 christos continue;
496 1.1 christos /* Is this instruction restricted to a certain value of XLEN? */
497 1.1.1.2 christos if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
498 1.1 christos continue;
499 1.1 christos
500 1.1 christos /* It's a match. */
501 1.1 christos (*info->fprintf_func) (info->stream, "%s", op->name);
502 1.1 christos print_insn_args (op->args, word, memaddr, info);
503 1.1 christos
504 1.1 christos /* Try to disassemble multi-instruction addressing sequences. */
505 1.1 christos if (pd->print_addr != (bfd_vma)-1)
506 1.1 christos {
507 1.1 christos info->target = pd->print_addr;
508 1.1 christos (*info->fprintf_func) (info->stream, " # ");
509 1.1 christos (*info->print_address_func) (info->target, info);
510 1.1 christos pd->print_addr = -1;
511 1.1 christos }
512 1.1 christos
513 1.1.1.2 christos /* Finish filling out insn_info fields. */
514 1.1.1.2 christos switch (op->pinfo & INSN_TYPE)
515 1.1.1.2 christos {
516 1.1.1.2 christos case INSN_BRANCH:
517 1.1.1.2 christos info->insn_type = dis_branch;
518 1.1.1.2 christos break;
519 1.1.1.2 christos case INSN_CONDBRANCH:
520 1.1.1.2 christos info->insn_type = dis_condbranch;
521 1.1.1.2 christos break;
522 1.1.1.2 christos case INSN_JSR:
523 1.1.1.2 christos info->insn_type = dis_jsr;
524 1.1.1.2 christos break;
525 1.1.1.2 christos case INSN_DREF:
526 1.1.1.2 christos info->insn_type = dis_dref;
527 1.1.1.2 christos break;
528 1.1.1.2 christos default:
529 1.1.1.2 christos break;
530 1.1.1.2 christos }
531 1.1.1.2 christos
532 1.1.1.2 christos if (op->pinfo & INSN_DATA_SIZE)
533 1.1.1.2 christos {
534 1.1.1.2 christos int size = ((op->pinfo & INSN_DATA_SIZE)
535 1.1.1.2 christos >> INSN_DATA_SIZE_SHIFT);
536 1.1.1.2 christos info->data_size = 1 << (size - 1);
537 1.1.1.2 christos }
538 1.1.1.2 christos
539 1.1 christos return insnlen;
540 1.1 christos }
541 1.1 christos }
542 1.1 christos
543 1.1 christos /* We did not find a match, so just print the instruction bits. */
544 1.1 christos info->insn_type = dis_noninsn;
545 1.1 christos (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long)word);
546 1.1 christos return insnlen;
547 1.1 christos }
548 1.1 christos
549 1.1 christos int
550 1.1 christos print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
551 1.1 christos {
552 1.1 christos bfd_byte packet[2];
553 1.1 christos insn_t insn = 0;
554 1.1 christos bfd_vma n;
555 1.1 christos int status;
556 1.1 christos
557 1.1 christos if (info->disassembler_options != NULL)
558 1.1 christos {
559 1.1 christos parse_riscv_dis_options (info->disassembler_options);
560 1.1 christos /* Avoid repeatedly parsing the options. */
561 1.1 christos info->disassembler_options = NULL;
562 1.1 christos }
563 1.1 christos else if (riscv_gpr_names == NULL)
564 1.1 christos set_default_riscv_dis_options ();
565 1.1 christos
566 1.1 christos /* Instructions are a sequence of 2-byte packets in little-endian order. */
567 1.1 christos for (n = 0; n < sizeof (insn) && n < riscv_insn_length (insn); n += 2)
568 1.1 christos {
569 1.1 christos status = (*info->read_memory_func) (memaddr + n, packet, 2, info);
570 1.1 christos if (status != 0)
571 1.1 christos {
572 1.1 christos /* Don't fail just because we fell off the end. */
573 1.1 christos if (n > 0)
574 1.1 christos break;
575 1.1 christos (*info->memory_error_func) (status, memaddr, info);
576 1.1 christos return status;
577 1.1 christos }
578 1.1 christos
579 1.1 christos insn |= ((insn_t) bfd_getl16 (packet)) << (8 * n);
580 1.1 christos }
581 1.1 christos
582 1.1 christos return riscv_disassemble_insn (memaddr, insn, info);
583 1.1 christos }
584 1.1 christos
585 1.1.1.2 christos /* Prevent use of the fake labels that are generated as part of the DWARF
586 1.1.1.2 christos and for relaxable relocations in the assembler. */
587 1.1.1.2 christos
588 1.1.1.2 christos bfd_boolean
589 1.1.1.2 christos riscv_symbol_is_valid (asymbol * sym,
590 1.1.1.2 christos struct disassemble_info * info ATTRIBUTE_UNUSED)
591 1.1.1.2 christos {
592 1.1.1.2 christos const char * name;
593 1.1.1.2 christos
594 1.1.1.2 christos if (sym == NULL)
595 1.1.1.2 christos return FALSE;
596 1.1.1.2 christos
597 1.1.1.2 christos name = bfd_asymbol_name (sym);
598 1.1.1.2 christos
599 1.1.1.2 christos return (strcmp (name, RISCV_FAKE_LABEL_NAME) != 0);
600 1.1.1.2 christos }
601 1.1.1.2 christos
602 1.1 christos void
603 1.1 christos print_riscv_disassembler_options (FILE *stream)
604 1.1 christos {
605 1.1 christos fprintf (stream, _("\n\
606 1.1 christos The following RISC-V-specific disassembler options are supported for use\n\
607 1.1 christos with the -M switch (multiple options should be separated by commas):\n"));
608 1.1 christos
609 1.1 christos fprintf (stream, _("\n\
610 1.1.1.3 christos numeric Print numeric register names, rather than ABI names.\n"));
611 1.1.1.3 christos
612 1.1.1.3 christos fprintf (stream, _("\n\
613 1.1.1.3 christos no-aliases Disassemble only into canonical instructions, rather\n\
614 1.1.1.3 christos than into pseudoinstructions.\n"));
615 1.1 christos
616 1.1 christos fprintf (stream, _("\n\
617 1.1.1.3 christos priv-spec=PRIV Print the CSR according to the chosen privilege spec\n\
618 1.1.1.3 christos (1.9, 1.9.1, 1.10, 1.11).\n"));
619 1.1 christos
620 1.1 christos fprintf (stream, _("\n"));
621 1.1 christos }
622