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