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