riscv-dis.c revision 1.3 1 1.1 matt /* RISC-V disassembler
2 1.1 matt Copyright 2011-2014 Free Software Foundation, Inc.
3 1.1 matt
4 1.1 matt Contributed by Andrew Waterman (waterman (at) cs.berkeley.edu) at UC Berkeley.
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.1 matt along with this program; if not, write to the Free Software
21 1.1 matt Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22 1.1 matt MA 02110-1301, USA. */
23 1.1 matt
24 1.1 matt #include "sysdep.h"
25 1.1 matt #include "dis-asm.h"
26 1.1 matt #include "libiberty.h"
27 1.1 matt #include "opcode/riscv.h"
28 1.1 matt #include "opintl.h"
29 1.1 matt #include "elf-bfd.h"
30 1.1 matt #include "elf/riscv.h"
31 1.1 matt
32 1.1 matt #include <stdint.h>
33 1.1 matt #include <assert.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.1 matt /* 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.1 matt if (CONST_STRNEQ (option, "no-aliases"))
60 1.3 matt no_aliases = 1;
61 1.3 matt else if (CONST_STRNEQ (option, "numeric"))
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.1 matt
67 1.1 matt /* Invalid option. */
68 1.3 matt fprintf (stderr, _("Unrecognized disassembler option: %s\n"), option);
69 1.1 matt }
70 1.1 matt
71 1.1 matt static void
72 1.3 matt parse_riscv_dis_options (const char *opts_in)
73 1.1 matt {
74 1.3 matt char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
75 1.1 matt
76 1.3 matt set_default_riscv_dis_options ();
77 1.1 matt
78 1.3 matt for ( ; opt_end != NULL; opt = opt_end + 1)
79 1.1 matt {
80 1.3 matt if ((opt_end = strchr (opt, ',')) != NULL)
81 1.3 matt *opt_end = 0;
82 1.3 matt parse_riscv_dis_option (opt);
83 1.3 matt }
84 1.1 matt
85 1.3 matt free (opts);
86 1.1 matt }
87 1.1 matt
88 1.1 matt /* Print one argument from an array. */
89 1.1 matt
90 1.1 matt static void
91 1.1 matt arg_print (struct disassemble_info *info, unsigned long val,
92 1.1 matt const char* const* array, size_t size)
93 1.1 matt {
94 1.1 matt const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
95 1.1 matt (*info->fprintf_func) (info->stream, "%s", s);
96 1.1 matt }
97 1.1 matt
98 1.1 matt static void
99 1.1 matt maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset)
100 1.1 matt {
101 1.1 matt if (pd->hi_addr[base_reg] != (bfd_vma)-1)
102 1.1 matt {
103 1.1 matt pd->print_addr = pd->hi_addr[base_reg] + offset;
104 1.1 matt pd->hi_addr[base_reg] = -1;
105 1.1 matt }
106 1.3 matt else if (base_reg == X_GP && pd->gp != (bfd_vma)-1)
107 1.1 matt pd->print_addr = pd->gp + offset;
108 1.3 matt else if (base_reg == X_TP)
109 1.1 matt pd->print_addr = offset;
110 1.1 matt }
111 1.1 matt
112 1.1 matt /* Print insn arguments for 32/64-bit code. */
113 1.1 matt
114 1.1 matt static void
115 1.1 matt print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
116 1.1 matt {
117 1.1 matt struct riscv_private_data *pd = info->private_data;
118 1.1 matt int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
119 1.1 matt int rd = (l >> OP_SH_RD) & OP_MASK_RD;
120 1.1 matt
121 1.1 matt if (*d != '\0')
122 1.1 matt (*info->fprintf_func) (info->stream, "\t");
123 1.1 matt
124 1.1 matt for (; *d != '\0'; d++)
125 1.1 matt {
126 1.1 matt switch (*d)
127 1.1 matt {
128 1.1 matt /* Xcustom */
129 1.1 matt case '^':
130 1.1 matt switch (*++d)
131 1.1 matt {
132 1.1 matt case 'd':
133 1.1 matt (*info->fprintf_func) (info->stream, "%d", rd);
134 1.1 matt break;
135 1.1 matt case 's':
136 1.1 matt (*info->fprintf_func) (info->stream, "%d", rs1);
137 1.1 matt break;
138 1.1 matt case 't':
139 1.1 matt (*info->fprintf_func)
140 1.1 matt ( info->stream, "%d", (int)((l >> OP_SH_RS2) & OP_MASK_RS2));
141 1.1 matt break;
142 1.1 matt case 'j':
143 1.1 matt (*info->fprintf_func)
144 1.1 matt ( info->stream, "%d", (int)((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM));
145 1.1 matt break;
146 1.1 matt }
147 1.1 matt break;
148 1.1 matt
149 1.1 matt /* Xhwacha */
150 1.1 matt case '#':
151 1.1 matt switch ( *++d ) {
152 1.1 matt case 'g':
153 1.1 matt (*info->fprintf_func)
154 1.1 matt ( info->stream, "%d",
155 1.1 matt (int)((l >> OP_SH_IMMNGPR) & OP_MASK_IMMNGPR));
156 1.1 matt break;
157 1.1 matt case 'f':
158 1.1 matt (*info->fprintf_func)
159 1.1 matt ( info->stream, "%d",
160 1.1 matt (int)((l >> OP_SH_IMMNFPR) & OP_MASK_IMMNFPR));
161 1.1 matt break;
162 1.1 matt case 'p':
163 1.1 matt (*info->fprintf_func)
164 1.1 matt ( info->stream, "%d",
165 1.1 matt (int)((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM));
166 1.1 matt break;
167 1.1 matt case 'n':
168 1.1 matt (*info->fprintf_func)
169 1.1 matt ( info->stream, "%d",
170 1.1 matt (int)(((l >> OP_SH_IMMSEGNELM) & OP_MASK_IMMSEGNELM) + 1));
171 1.1 matt break;
172 1.1 matt case 'd':
173 1.1 matt (*info->fprintf_func)
174 1.1 matt ( info->stream, "%s",
175 1.3 matt riscv_vec_gpr_names[(l >> OP_SH_VRD) & OP_MASK_VRD]);
176 1.1 matt break;
177 1.1 matt case 's':
178 1.1 matt (*info->fprintf_func)
179 1.1 matt ( info->stream, "%s",
180 1.3 matt riscv_vec_gpr_names[(l >> OP_SH_VRS) & OP_MASK_VRS]);
181 1.1 matt break;
182 1.1 matt case 't':
183 1.1 matt (*info->fprintf_func)
184 1.1 matt ( info->stream, "%s",
185 1.3 matt riscv_vec_gpr_names[(l >> OP_SH_VRT) & OP_MASK_VRT]);
186 1.1 matt break;
187 1.1 matt case 'r':
188 1.1 matt (*info->fprintf_func)
189 1.1 matt ( info->stream, "%s",
190 1.3 matt riscv_vec_gpr_names[(l >> OP_SH_VRR) & OP_MASK_VRR]);
191 1.1 matt break;
192 1.1 matt case 'D':
193 1.1 matt (*info->fprintf_func)
194 1.1 matt ( info->stream, "%s",
195 1.3 matt riscv_vec_fpr_names[(l >> OP_SH_VFD) & OP_MASK_VFD]);
196 1.1 matt break;
197 1.1 matt case 'S':
198 1.1 matt (*info->fprintf_func)
199 1.1 matt ( info->stream, "%s",
200 1.3 matt riscv_vec_fpr_names[(l >> OP_SH_VFS) & OP_MASK_VFS]);
201 1.1 matt break;
202 1.1 matt case 'T':
203 1.1 matt (*info->fprintf_func)
204 1.1 matt ( info->stream, "%s",
205 1.3 matt riscv_vec_fpr_names[(l >> OP_SH_VFT) & OP_MASK_VFT]);
206 1.1 matt break;
207 1.1 matt case 'R':
208 1.1 matt (*info->fprintf_func)
209 1.1 matt ( info->stream, "%s",
210 1.3 matt riscv_vec_fpr_names[(l >> OP_SH_VFR) & OP_MASK_VFR]);
211 1.1 matt break;
212 1.1 matt }
213 1.1 matt break;
214 1.1 matt
215 1.1 matt case ',':
216 1.1 matt case '(':
217 1.1 matt case ')':
218 1.1 matt case '[':
219 1.1 matt case ']':
220 1.1 matt (*info->fprintf_func) (info->stream, "%c", *d);
221 1.1 matt break;
222 1.1 matt
223 1.1 matt case '0':
224 1.1 matt break;
225 1.1 matt
226 1.1 matt case 'b':
227 1.1 matt case 's':
228 1.1 matt (*info->fprintf_func) (info->stream, "%s", riscv_gpr_names[rs1]);
229 1.1 matt break;
230 1.1 matt
231 1.1 matt case 't':
232 1.1 matt (*info->fprintf_func) (info->stream, "%s",
233 1.1 matt riscv_gpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]);
234 1.1 matt break;
235 1.1 matt
236 1.1 matt case 'u':
237 1.3 matt (*info->fprintf_func) (info->stream, "0x%x", (unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
238 1.1 matt break;
239 1.1 matt
240 1.1 matt case 'm':
241 1.1 matt arg_print(info, (l >> OP_SH_RM) & OP_MASK_RM,
242 1.1 matt riscv_rm, ARRAY_SIZE(riscv_rm));
243 1.1 matt break;
244 1.1 matt
245 1.1 matt case 'P':
246 1.1 matt arg_print(info, (l >> OP_SH_PRED) & OP_MASK_PRED,
247 1.1 matt riscv_pred_succ, ARRAY_SIZE(riscv_pred_succ));
248 1.1 matt break;
249 1.1 matt
250 1.1 matt case 'Q':
251 1.1 matt arg_print(info, (l >> OP_SH_SUCC) & OP_MASK_SUCC,
252 1.1 matt riscv_pred_succ, ARRAY_SIZE(riscv_pred_succ));
253 1.1 matt break;
254 1.1 matt
255 1.1 matt case 'o':
256 1.1 matt maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
257 1.1 matt case 'j':
258 1.2 matt if ((l & MASK_ADDI) == MATCH_ADDI || (l & MASK_JALR) == MATCH_JALR)
259 1.1 matt maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
260 1.1 matt (*info->fprintf_func) (info->stream, "%d", (int)EXTRACT_ITYPE_IMM (l));
261 1.1 matt break;
262 1.1 matt
263 1.1 matt case 'q':
264 1.1 matt maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l));
265 1.1 matt (*info->fprintf_func) (info->stream, "%d", (int)EXTRACT_STYPE_IMM (l));
266 1.1 matt break;
267 1.1 matt
268 1.1 matt case 'a':
269 1.1 matt info->target = EXTRACT_UJTYPE_IMM (l) + pc;
270 1.1 matt (*info->print_address_func) (info->target, info);
271 1.1 matt break;
272 1.1 matt
273 1.1 matt case 'p':
274 1.1 matt info->target = EXTRACT_SBTYPE_IMM (l) + pc;
275 1.1 matt (*info->print_address_func) (info->target, info);
276 1.1 matt break;
277 1.1 matt
278 1.1 matt case 'd':
279 1.1 matt if ((l & MASK_AUIPC) == MATCH_AUIPC)
280 1.3 matt pd->hi_addr[rd] = pc + EXTRACT_UTYPE_IMM (l);
281 1.1 matt else if ((l & MASK_LUI) == MATCH_LUI)
282 1.3 matt pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l);
283 1.1 matt (*info->fprintf_func) (info->stream, "%s", riscv_gpr_names[rd]);
284 1.1 matt break;
285 1.1 matt
286 1.1 matt case 'z':
287 1.1 matt (*info->fprintf_func) (info->stream, "%s", riscv_gpr_names[0]);
288 1.1 matt break;
289 1.1 matt
290 1.1 matt case '>':
291 1.1 matt (*info->fprintf_func) (info->stream, "0x%x",
292 1.1 matt (unsigned)((l >> OP_SH_SHAMT) & OP_MASK_SHAMT));
293 1.1 matt break;
294 1.1 matt
295 1.1 matt case '<':
296 1.1 matt (*info->fprintf_func) (info->stream, "0x%x",
297 1.1 matt (unsigned)((l >> OP_SH_SHAMTW) & OP_MASK_SHAMTW));
298 1.1 matt break;
299 1.1 matt
300 1.1 matt case 'S':
301 1.1 matt case 'U':
302 1.1 matt (*info->fprintf_func) (info->stream, "%s", riscv_fpr_names[rs1]);
303 1.1 matt break;
304 1.1 matt
305 1.1 matt case 'T':
306 1.1 matt (*info->fprintf_func) (info->stream, "%s",
307 1.1 matt riscv_fpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]);
308 1.1 matt break;
309 1.1 matt
310 1.1 matt case 'D':
311 1.1 matt (*info->fprintf_func) (info->stream, "%s", riscv_fpr_names[rd]);
312 1.1 matt break;
313 1.1 matt
314 1.1 matt case 'R':
315 1.1 matt (*info->fprintf_func) (info->stream, "%s",
316 1.1 matt riscv_fpr_names[(l >> OP_SH_RS3) & OP_MASK_RS3]);
317 1.1 matt break;
318 1.1 matt
319 1.1 matt case 'E':
320 1.1 matt {
321 1.3 matt const char* csr_name = NULL;
322 1.3 matt unsigned int csr = (l >> OP_SH_CSR) & OP_MASK_CSR;
323 1.3 matt switch (csr)
324 1.1 matt {
325 1.1 matt #define DECLARE_CSR(name, num) case num: csr_name = #name; break;
326 1.1 matt #include "opcode/riscv-opc.h"
327 1.1 matt #undef DECLARE_CSR
328 1.1 matt }
329 1.3 matt if (csr_name)
330 1.3 matt (*info->fprintf_func) (info->stream, "%s", csr_name);
331 1.3 matt else
332 1.3 matt (*info->fprintf_func) (info->stream, "0x%x", csr);
333 1.1 matt break;
334 1.1 matt }
335 1.1 matt
336 1.1 matt case 'Z':
337 1.1 matt (*info->fprintf_func) (info->stream, "%d", rs1);
338 1.1 matt break;
339 1.1 matt
340 1.1 matt default:
341 1.1 matt /* xgettext:c-format */
342 1.1 matt (*info->fprintf_func) (info->stream,
343 1.1 matt _("# internal error, undefined modifier (%c)"),
344 1.1 matt *d);
345 1.1 matt return;
346 1.1 matt }
347 1.1 matt }
348 1.1 matt }
349 1.1 matt
350 1.1 matt /* Print the RISC-V instruction at address MEMADDR in debugged memory,
351 1.1 matt on using INFO. Returns length of the instruction, in bytes.
352 1.1 matt BIGENDIAN must be 1 if this is big-endian code, 0 if
353 1.1 matt this is little-endian code. */
354 1.1 matt
355 1.1 matt static int
356 1.1 matt riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
357 1.1 matt {
358 1.1 matt const struct riscv_opcode *op;
359 1.1 matt static bfd_boolean init = 0;
360 1.1 matt static const char *extension = NULL;
361 1.1 matt static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
362 1.1 matt struct riscv_private_data *pd;
363 1.1 matt int insnlen;
364 1.1 matt
365 1.1 matt /* Build a hash table to shorten the search time. */
366 1.1 matt if (! init)
367 1.1 matt {
368 1.1 matt unsigned int i;
369 1.1 matt unsigned int e_flags = elf_elfheader (info->section->owner)->e_flags;
370 1.1 matt extension = riscv_elf_flag_to_name(EF_GET_RISCV_EXT(e_flags));
371 1.1 matt
372 1.1 matt for (i = 0; i <= OP_MASK_OP; i++)
373 1.1 matt for (op = riscv_opcodes; op < &riscv_opcodes[NUMOPCODES]; op++)
374 1.1 matt if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
375 1.1 matt {
376 1.1 matt riscv_hash[i] = op;
377 1.1 matt break;
378 1.1 matt }
379 1.1 matt
380 1.1 matt init = 1;
381 1.1 matt }
382 1.1 matt
383 1.1 matt if (info->private_data == NULL)
384 1.1 matt {
385 1.1 matt int i;
386 1.1 matt
387 1.1 matt pd = info->private_data = calloc(1, sizeof (struct riscv_private_data));
388 1.1 matt pd->gp = -1;
389 1.1 matt pd->print_addr = -1;
390 1.1 matt for (i = 0; i < (int) ARRAY_SIZE(pd->hi_addr); i++)
391 1.1 matt pd->hi_addr[i] = -1;
392 1.1 matt
393 1.1 matt for (i = 0; i < info->symtab_size; i++)
394 1.1 matt if (strcmp (bfd_asymbol_name (info->symtab[i]), "_gp") == 0)
395 1.1 matt pd->gp = bfd_asymbol_value (info->symtab[i]);
396 1.1 matt }
397 1.1 matt else
398 1.1 matt pd = info->private_data;
399 1.1 matt
400 1.1 matt insnlen = riscv_insn_length (word);
401 1.1 matt
402 1.1 matt info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
403 1.1 matt info->bytes_per_line = 8;
404 1.1 matt info->display_endian = info->endian;
405 1.1 matt info->insn_info_valid = 1;
406 1.1 matt info->branch_delay_insns = 0;
407 1.1 matt info->data_size = 0;
408 1.1 matt info->insn_type = dis_nonbranch;
409 1.1 matt info->target = 0;
410 1.1 matt info->target2 = 0;
411 1.1 matt
412 1.1 matt op = riscv_hash[(word >> OP_SH_OP) & OP_MASK_OP];
413 1.1 matt if (op != NULL)
414 1.1 matt {
415 1.1 matt for (; op < &riscv_opcodes[NUMOPCODES]; op++)
416 1.1 matt {
417 1.1 matt if ((op->match_func) (op, word)
418 1.1 matt && !(no_aliases && (op->pinfo & INSN_ALIAS))
419 1.1 matt && !(op->subset[0] == 'X' && strcmp(op->subset, extension)))
420 1.1 matt {
421 1.1 matt (*info->fprintf_func) (info->stream, "%s", op->name);
422 1.1 matt print_insn_args (op->args, word, memaddr, info);
423 1.1 matt if (pd->print_addr != (bfd_vma)-1)
424 1.1 matt {
425 1.1 matt info->target = pd->print_addr;
426 1.1 matt (*info->fprintf_func) (info->stream, " # ");
427 1.1 matt (*info->print_address_func) (info->target, info);
428 1.1 matt pd->print_addr = -1;
429 1.1 matt }
430 1.1 matt return insnlen;
431 1.1 matt }
432 1.1 matt }
433 1.1 matt }
434 1.1 matt
435 1.1 matt /* Handle undefined instructions. */
436 1.1 matt info->insn_type = dis_noninsn;
437 1.1 matt (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long)word);
438 1.1 matt return insnlen;
439 1.1 matt }
440 1.1 matt
441 1.1 matt int
442 1.1 matt print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
443 1.1 matt {
444 1.1 matt uint16_t i2;
445 1.1 matt insn_t insn = 0;
446 1.1 matt bfd_vma n;
447 1.1 matt int status;
448 1.1 matt
449 1.3 matt if (info->disassembler_options != NULL)
450 1.3 matt {
451 1.3 matt parse_riscv_dis_options (info->disassembler_options);
452 1.3 matt /* Avoid repeatedly parsing the options. */
453 1.3 matt info->disassembler_options = NULL;
454 1.3 matt }
455 1.3 matt else if (riscv_gpr_names == NULL)
456 1.3 matt set_default_riscv_dis_options ();
457 1.1 matt
458 1.1 matt /* Instructions are a sequence of 2-byte packets in little-endian order. */
459 1.1 matt for (n = 0; n < sizeof(insn) && n < riscv_insn_length (insn); n += 2)
460 1.1 matt {
461 1.1 matt status = (*info->read_memory_func) (memaddr + n, (bfd_byte*)&i2, 2, info);
462 1.1 matt if (status != 0)
463 1.1 matt {
464 1.1 matt if (n > 0) /* Don't fail just because we fell off the end. */
465 1.1 matt break;
466 1.1 matt (*info->memory_error_func) (status, memaddr, info);
467 1.1 matt return status;
468 1.1 matt }
469 1.1 matt
470 1.1 matt i2 = bfd_getl16 (&i2);
471 1.1 matt insn |= (insn_t)i2 << (8*n);
472 1.1 matt }
473 1.1 matt
474 1.1 matt return riscv_disassemble_insn (memaddr, insn, info);
475 1.1 matt }
476 1.1 matt
477 1.1 matt void
478 1.1 matt print_riscv_disassembler_options (FILE *stream)
479 1.1 matt {
480 1.1 matt fprintf (stream, _("\n\
481 1.1 matt The following RISC-V-specific disassembler options are supported for use\n\
482 1.1 matt with the -M switch (multiple options should be separated by commas):\n"));
483 1.1 matt
484 1.1 matt fprintf (stream, _("\n\
485 1.3 matt numeric Print numeric reigster names, rather than ABI names.\n"));
486 1.1 matt
487 1.1 matt fprintf (stream, _("\n\
488 1.3 matt no-aliases Disassemble only into canonical instructions, rather\n\
489 1.3 matt than into pseudoinstructions.\n"));
490 1.1 matt
491 1.1 matt fprintf (stream, _("\n"));
492 1.1 matt }
493