riscv-dis.c revision 1.8.2.1 1 1.1 matt /* RISC-V disassembler
2 1.8.2.1 perseant Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 1.1 matt
4 1.4 christos 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.4 christos along with this program; see the file COPYING3. If not,
21 1.4 christos see <http://www.gnu.org/licenses/>. */
22 1.1 matt
23 1.1 matt #include "sysdep.h"
24 1.4 christos #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.8 christos #include "elfxx-riscv.h"
31 1.1 matt
32 1.8 christos #include <stdint.h>
33 1.4 christos #include <ctype.h>
34 1.1 matt
35 1.8.2.1 perseant /* Current XLEN for the disassembler. */
36 1.8.2.1 perseant static unsigned xlen = 0;
37 1.8.2.1 perseant
38 1.8.2.1 perseant /* Default ISA specification version (constant as of now). */
39 1.8 christos static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
40 1.8 christos
41 1.8.2.1 perseant /* Default privileged specification
42 1.8.2.1 perseant (as specified by the ELF attributes or the `priv-spec' option). */
43 1.8.2.1 perseant static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
44 1.8 christos
45 1.8 christos static riscv_subset_list_t riscv_subsets;
46 1.8 christos static riscv_parse_subset_t riscv_rps_dis =
47 1.8 christos {
48 1.8 christos &riscv_subsets, /* subset_list. */
49 1.8 christos opcodes_error_handler,/* error_handler. */
50 1.8 christos &xlen, /* xlen. */
51 1.8 christos &default_isa_spec, /* isa_spec. */
52 1.8 christos false, /* check_unknown_prefixed_ext. */
53 1.8 christos };
54 1.8 christos
55 1.1 matt struct riscv_private_data
56 1.1 matt {
57 1.1 matt bfd_vma gp;
58 1.1 matt bfd_vma print_addr;
59 1.1 matt bfd_vma hi_addr[OP_MASK_RD + 1];
60 1.8.2.1 perseant bool to_print_addr;
61 1.8.2.1 perseant bool has_gp;
62 1.1 matt };
63 1.1 matt
64 1.8 christos /* Used for mapping symbols. */
65 1.8 christos static int last_map_symbol = -1;
66 1.8 christos static bfd_vma last_stop_offset = 0;
67 1.8.2.1 perseant static bfd_vma last_map_symbol_boundary = 0;
68 1.8.2.1 perseant static enum riscv_seg_mstate last_map_state = MAP_NONE;
69 1.8.2.1 perseant static asection *last_map_section = NULL;
70 1.8.2.1 perseant
71 1.8.2.1 perseant /* Register names as used by the disassembler. */
72 1.8.2.1 perseant static const char (*riscv_gpr_names)[NRC];
73 1.8.2.1 perseant static const char (*riscv_fpr_names)[NRC];
74 1.1 matt
75 1.8 christos /* If set, disassemble as most general instruction. */
76 1.8.2.1 perseant static bool no_aliases = false;
77 1.8.2.1 perseant
78 1.8.2.1 perseant
79 1.8.2.1 perseant /* Set default RISC-V disassembler options. */
80 1.1 matt
81 1.1 matt static void
82 1.3 matt set_default_riscv_dis_options (void)
83 1.1 matt {
84 1.1 matt riscv_gpr_names = riscv_gpr_names_abi;
85 1.1 matt riscv_fpr_names = riscv_fpr_names_abi;
86 1.8.2.1 perseant no_aliases = false;
87 1.1 matt }
88 1.1 matt
89 1.8.2.1 perseant /* Parse RISC-V disassembler option (without arguments). */
90 1.8.2.1 perseant
91 1.8 christos static bool
92 1.8 christos parse_riscv_dis_option_without_args (const char *option)
93 1.1 matt {
94 1.4 christos if (strcmp (option, "no-aliases") == 0)
95 1.8.2.1 perseant no_aliases = true;
96 1.4 christos else if (strcmp (option, "numeric") == 0)
97 1.1 matt {
98 1.3 matt riscv_gpr_names = riscv_gpr_names_numeric;
99 1.3 matt riscv_fpr_names = riscv_fpr_names_numeric;
100 1.1 matt }
101 1.4 christos else
102 1.8 christos return false;
103 1.8 christos return true;
104 1.8 christos }
105 1.8 christos
106 1.8.2.1 perseant /* Parse RISC-V disassembler option (possibly with arguments). */
107 1.8.2.1 perseant
108 1.8 christos static void
109 1.8 christos parse_riscv_dis_option (const char *option)
110 1.8 christos {
111 1.8 christos char *equal, *value;
112 1.8 christos
113 1.8 christos if (parse_riscv_dis_option_without_args (option))
114 1.8 christos return;
115 1.8 christos
116 1.8 christos equal = strchr (option, '=');
117 1.8 christos if (equal == NULL)
118 1.8 christos {
119 1.8 christos /* The option without '=' should be defined above. */
120 1.8 christos opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
121 1.8 christos return;
122 1.8 christos }
123 1.8 christos if (equal == option
124 1.8 christos || *(equal + 1) == '\0')
125 1.8 christos {
126 1.8 christos /* Invalid options with '=', no option name before '=',
127 1.8 christos and no value after '='. */
128 1.8 christos opcodes_error_handler (_("unrecognized disassembler option with '=': %s"),
129 1.8 christos option);
130 1.8 christos return;
131 1.8 christos }
132 1.8 christos
133 1.8 christos *equal = '\0';
134 1.8 christos value = equal + 1;
135 1.8 christos if (strcmp (option, "priv-spec") == 0)
136 1.8 christos {
137 1.8 christos enum riscv_spec_class priv_spec = PRIV_SPEC_CLASS_NONE;
138 1.8 christos const char *name = NULL;
139 1.8 christos
140 1.8 christos RISCV_GET_PRIV_SPEC_CLASS (value, priv_spec);
141 1.8 christos if (priv_spec == PRIV_SPEC_CLASS_NONE)
142 1.8 christos opcodes_error_handler (_("unknown privileged spec set by %s=%s"),
143 1.8 christos option, value);
144 1.8 christos else if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
145 1.8 christos default_priv_spec = priv_spec;
146 1.8 christos else if (default_priv_spec != priv_spec)
147 1.8 christos {
148 1.8 christos RISCV_GET_PRIV_SPEC_NAME (name, default_priv_spec);
149 1.8 christos opcodes_error_handler (_("mis-matched privilege spec set by %s=%s, "
150 1.8 christos "the elf privilege attribute is %s"),
151 1.8 christos option, value, name);
152 1.8 christos }
153 1.8 christos }
154 1.8 christos else
155 1.4 christos {
156 1.5 christos /* xgettext:c-format */
157 1.5 christos opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
158 1.4 christos }
159 1.1 matt }
160 1.1 matt
161 1.8.2.1 perseant /* Parse RISC-V disassembler options. */
162 1.8.2.1 perseant
163 1.1 matt static void
164 1.3 matt parse_riscv_dis_options (const char *opts_in)
165 1.1 matt {
166 1.3 matt char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
167 1.1 matt
168 1.3 matt set_default_riscv_dis_options ();
169 1.1 matt
170 1.3 matt for ( ; opt_end != NULL; opt = opt_end + 1)
171 1.1 matt {
172 1.3 matt if ((opt_end = strchr (opt, ',')) != NULL)
173 1.3 matt *opt_end = 0;
174 1.3 matt parse_riscv_dis_option (opt);
175 1.3 matt }
176 1.1 matt
177 1.3 matt free (opts);
178 1.1 matt }
179 1.1 matt
180 1.4 christos /* Print one argument from an array. */
181 1.1 matt
182 1.1 matt static void
183 1.1 matt arg_print (struct disassemble_info *info, unsigned long val,
184 1.1 matt const char* const* array, size_t size)
185 1.1 matt {
186 1.1 matt const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
187 1.8 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "%s", s);
188 1.1 matt }
189 1.1 matt
190 1.8.2.1 perseant /* If we need to print an address, set its value and state. */
191 1.8.2.1 perseant
192 1.1 matt static void
193 1.8 christos maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
194 1.8 christos int wide)
195 1.1 matt {
196 1.1 matt if (pd->hi_addr[base_reg] != (bfd_vma)-1)
197 1.1 matt {
198 1.4 christos pd->print_addr = (base_reg != 0 ? pd->hi_addr[base_reg] : 0) + offset;
199 1.1 matt pd->hi_addr[base_reg] = -1;
200 1.1 matt }
201 1.8.2.1 perseant else if (base_reg == X_GP && pd->has_gp)
202 1.1 matt pd->print_addr = pd->gp + offset;
203 1.4 christos else if (base_reg == X_TP || base_reg == 0)
204 1.1 matt pd->print_addr = offset;
205 1.8.2.1 perseant else
206 1.8.2.1 perseant return; /* Don't print the address. */
207 1.8.2.1 perseant pd->to_print_addr = true;
208 1.8 christos
209 1.8 christos /* Sign-extend a 32-bit value to a 64-bit value. */
210 1.8 christos if (wide)
211 1.8 christos pd->print_addr = (bfd_vma)(int32_t) pd->print_addr;
212 1.8.2.1 perseant
213 1.8.2.1 perseant /* Fit into a 32-bit value on RV32. */
214 1.8.2.1 perseant if (xlen == 32)
215 1.8.2.1 perseant pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
216 1.1 matt }
217 1.1 matt
218 1.1 matt /* Print insn arguments for 32/64-bit code. */
219 1.1 matt
220 1.1 matt static void
221 1.8 christos print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info)
222 1.1 matt {
223 1.1 matt struct riscv_private_data *pd = info->private_data;
224 1.1 matt int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
225 1.1 matt int rd = (l >> OP_SH_RD) & OP_MASK_RD;
226 1.8 christos fprintf_styled_ftype print = info->fprintf_styled_func;
227 1.8 christos const char *opargStart;
228 1.1 matt
229 1.8 christos if (*oparg != '\0')
230 1.8 christos print (info->stream, dis_style_text, "\t");
231 1.1 matt
232 1.8 christos for (; *oparg != '\0'; oparg++)
233 1.1 matt {
234 1.8 christos opargStart = oparg;
235 1.8 christos switch (*oparg)
236 1.1 matt {
237 1.4 christos case 'C': /* RVC */
238 1.8 christos switch (*++oparg)
239 1.4 christos {
240 1.8 christos case 's': /* RS1 x8-x15. */
241 1.8 christos case 'w': /* RS1 x8-x15. */
242 1.8 christos print (info->stream, dis_style_register, "%s",
243 1.4 christos riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
244 1.4 christos break;
245 1.8 christos case 't': /* RS2 x8-x15. */
246 1.8 christos case 'x': /* RS2 x8-x15. */
247 1.8 christos print (info->stream, dis_style_register, "%s",
248 1.4 christos riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
249 1.4 christos break;
250 1.8 christos case 'U': /* RS1, constrained to equal RD. */
251 1.8 christos print (info->stream, dis_style_register,
252 1.8 christos "%s", riscv_gpr_names[rd]);
253 1.8 christos break;
254 1.8 christos case 'c': /* RS1, constrained to equal sp. */
255 1.8 christos print (info->stream, dis_style_register, "%s",
256 1.8 christos riscv_gpr_names[X_SP]);
257 1.4 christos break;
258 1.4 christos case 'V': /* RS2 */
259 1.8 christos print (info->stream, dis_style_register, "%s",
260 1.4 christos riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
261 1.4 christos break;
262 1.4 christos case 'o':
263 1.4 christos case 'j':
264 1.8 christos if (((l & MASK_C_ADDI) == MATCH_C_ADDI) && rd != 0)
265 1.8 christos maybe_print_address (pd, rd, EXTRACT_CITYPE_IMM (l), 0);
266 1.8 christos if (info->mach == bfd_mach_riscv64
267 1.8 christos && ((l & MASK_C_ADDIW) == MATCH_C_ADDIW) && rd != 0)
268 1.8 christos maybe_print_address (pd, rd, EXTRACT_CITYPE_IMM (l), 1);
269 1.8 christos print (info->stream, dis_style_immediate, "%d",
270 1.8 christos (int)EXTRACT_CITYPE_IMM (l));
271 1.4 christos break;
272 1.4 christos case 'k':
273 1.8 christos print (info->stream, dis_style_address_offset, "%d",
274 1.8 christos (int)EXTRACT_CLTYPE_LW_IMM (l));
275 1.4 christos break;
276 1.4 christos case 'l':
277 1.8 christos print (info->stream, dis_style_address_offset, "%d",
278 1.8 christos (int)EXTRACT_CLTYPE_LD_IMM (l));
279 1.4 christos break;
280 1.4 christos case 'm':
281 1.8 christos print (info->stream, dis_style_address_offset, "%d",
282 1.8 christos (int)EXTRACT_CITYPE_LWSP_IMM (l));
283 1.4 christos break;
284 1.4 christos case 'n':
285 1.8 christos print (info->stream, dis_style_address_offset, "%d",
286 1.8 christos (int)EXTRACT_CITYPE_LDSP_IMM (l));
287 1.4 christos break;
288 1.4 christos case 'K':
289 1.8 christos print (info->stream, dis_style_immediate, "%d",
290 1.8 christos (int)EXTRACT_CIWTYPE_ADDI4SPN_IMM (l));
291 1.4 christos break;
292 1.4 christos case 'L':
293 1.8 christos print (info->stream, dis_style_immediate, "%d",
294 1.8 christos (int)EXTRACT_CITYPE_ADDI16SP_IMM (l));
295 1.4 christos break;
296 1.4 christos case 'M':
297 1.8 christos print (info->stream, dis_style_address_offset, "%d",
298 1.8 christos (int)EXTRACT_CSSTYPE_SWSP_IMM (l));
299 1.4 christos break;
300 1.4 christos case 'N':
301 1.8 christos print (info->stream, dis_style_address_offset, "%d",
302 1.8 christos (int)EXTRACT_CSSTYPE_SDSP_IMM (l));
303 1.4 christos break;
304 1.4 christos case 'p':
305 1.8 christos info->target = EXTRACT_CBTYPE_IMM (l) + pc;
306 1.4 christos (*info->print_address_func) (info->target, info);
307 1.4 christos break;
308 1.4 christos case 'a':
309 1.8 christos info->target = EXTRACT_CJTYPE_IMM (l) + pc;
310 1.4 christos (*info->print_address_func) (info->target, info);
311 1.4 christos break;
312 1.4 christos case 'u':
313 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
314 1.8.2.1 perseant (unsigned)(EXTRACT_CITYPE_IMM (l) & (RISCV_BIGIMM_REACH-1)));
315 1.4 christos break;
316 1.4 christos case '>':
317 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
318 1.8.2.1 perseant (unsigned)EXTRACT_CITYPE_IMM (l) & 0x3f);
319 1.4 christos break;
320 1.4 christos case '<':
321 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
322 1.8.2.1 perseant (unsigned)EXTRACT_CITYPE_IMM (l) & 0x1f);
323 1.4 christos break;
324 1.8 christos case 'T': /* Floating-point RS2. */
325 1.8 christos print (info->stream, dis_style_register, "%s",
326 1.4 christos riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
327 1.4 christos break;
328 1.8 christos case 'D': /* Floating-point RS2 x8-x15. */
329 1.8 christos print (info->stream, dis_style_register, "%s",
330 1.4 christos riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
331 1.4 christos break;
332 1.4 christos }
333 1.4 christos break;
334 1.1 matt
335 1.8 christos case 'V': /* RVV */
336 1.8 christos switch (*++oparg)
337 1.8 christos {
338 1.8 christos case 'd':
339 1.8 christos case 'f':
340 1.8 christos print (info->stream, dis_style_register, "%s",
341 1.8 christos riscv_vecr_names_numeric[EXTRACT_OPERAND (VD, l)]);
342 1.8 christos break;
343 1.8 christos case 'e':
344 1.8 christos if (!EXTRACT_OPERAND (VWD, l))
345 1.8 christos print (info->stream, dis_style_register, "%s",
346 1.8 christos riscv_gpr_names[0]);
347 1.8 christos else
348 1.8 christos print (info->stream, dis_style_register, "%s",
349 1.8 christos riscv_vecr_names_numeric[EXTRACT_OPERAND (VD, l)]);
350 1.8 christos break;
351 1.8 christos case 's':
352 1.8 christos print (info->stream, dis_style_register, "%s",
353 1.8 christos riscv_vecr_names_numeric[EXTRACT_OPERAND (VS1, l)]);
354 1.8 christos break;
355 1.8 christos case 't':
356 1.8 christos case 'u': /* VS1 == VS2 already verified at this point. */
357 1.8 christos case 'v': /* VD == VS1 == VS2 already verified at this point. */
358 1.8 christos print (info->stream, dis_style_register, "%s",
359 1.8 christos riscv_vecr_names_numeric[EXTRACT_OPERAND (VS2, l)]);
360 1.8 christos break;
361 1.8 christos case '0':
362 1.8 christos print (info->stream, dis_style_register, "%s",
363 1.8 christos riscv_vecr_names_numeric[0]);
364 1.8 christos break;
365 1.8 christos case 'b':
366 1.8 christos case 'c':
367 1.8 christos {
368 1.8 christos int imm = (*oparg == 'b') ? EXTRACT_RVV_VB_IMM (l)
369 1.8 christos : EXTRACT_RVV_VC_IMM (l);
370 1.8 christos unsigned int imm_vlmul = EXTRACT_OPERAND (VLMUL, imm);
371 1.8 christos unsigned int imm_vsew = EXTRACT_OPERAND (VSEW, imm);
372 1.8 christos unsigned int imm_vta = EXTRACT_OPERAND (VTA, imm);
373 1.8 christos unsigned int imm_vma = EXTRACT_OPERAND (VMA, imm);
374 1.8 christos unsigned int imm_vtype_res = (imm >> 8);
375 1.8 christos
376 1.8 christos if (imm_vsew < ARRAY_SIZE (riscv_vsew)
377 1.8 christos && imm_vlmul < ARRAY_SIZE (riscv_vlmul)
378 1.8 christos && imm_vta < ARRAY_SIZE (riscv_vta)
379 1.8 christos && imm_vma < ARRAY_SIZE (riscv_vma)
380 1.8 christos && !imm_vtype_res
381 1.8 christos && riscv_vsew[imm_vsew] != NULL
382 1.8 christos && riscv_vlmul[imm_vlmul] != NULL)
383 1.8 christos print (info->stream, dis_style_text, "%s,%s,%s,%s",
384 1.8 christos riscv_vsew[imm_vsew],
385 1.8 christos riscv_vlmul[imm_vlmul], riscv_vta[imm_vta],
386 1.8 christos riscv_vma[imm_vma]);
387 1.8 christos else
388 1.8 christos print (info->stream, dis_style_immediate, "%d", imm);
389 1.8 christos }
390 1.8 christos break;
391 1.8 christos case 'i':
392 1.8 christos print (info->stream, dis_style_immediate, "%d",
393 1.8 christos (int)EXTRACT_RVV_VI_IMM (l));
394 1.8 christos break;
395 1.8 christos case 'j':
396 1.8 christos print (info->stream, dis_style_immediate, "%d",
397 1.8 christos (int)EXTRACT_RVV_VI_UIMM (l));
398 1.8 christos break;
399 1.8 christos case 'k':
400 1.8 christos print (info->stream, dis_style_immediate, "%d",
401 1.8 christos (int)EXTRACT_RVV_OFFSET (l));
402 1.8 christos break;
403 1.8.2.1 perseant case 'l':
404 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d",
405 1.8.2.1 perseant (int)EXTRACT_RVV_VI_UIMM6 (l));
406 1.8.2.1 perseant break;
407 1.8 christos case 'm':
408 1.8.2.1 perseant if (!EXTRACT_OPERAND (VMASK, l))
409 1.8.2.1 perseant {
410 1.8.2.1 perseant print (info->stream, dis_style_text, ",");
411 1.8.2.1 perseant print (info->stream, dis_style_register, "%s",
412 1.8.2.1 perseant riscv_vecm_names_numeric[0]);
413 1.8.2.1 perseant }
414 1.8 christos break;
415 1.8 christos }
416 1.8 christos break;
417 1.8 christos
418 1.1 matt case ',':
419 1.1 matt case '(':
420 1.1 matt case ')':
421 1.1 matt case '[':
422 1.1 matt case ']':
423 1.8 christos print (info->stream, dis_style_text, "%c", *oparg);
424 1.1 matt break;
425 1.1 matt
426 1.1 matt case '0':
427 1.8 christos /* Only print constant 0 if it is the last argument. */
428 1.8 christos if (!oparg[1])
429 1.8 christos print (info->stream, dis_style_immediate, "0");
430 1.1 matt break;
431 1.1 matt
432 1.1 matt case 's':
433 1.4 christos if ((l & MASK_JALR) == MATCH_JALR)
434 1.8.2.1 perseant maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 0);
435 1.8 christos print (info->stream, dis_style_register, "%s", riscv_gpr_names[rs1]);
436 1.1 matt break;
437 1.1 matt
438 1.1 matt case 't':
439 1.8 christos print (info->stream, dis_style_register, "%s",
440 1.4 christos riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]);
441 1.1 matt break;
442 1.1 matt
443 1.1 matt case 'u':
444 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
445 1.4 christos (unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
446 1.1 matt break;
447 1.1 matt
448 1.1 matt case 'm':
449 1.4 christos arg_print (info, EXTRACT_OPERAND (RM, l),
450 1.4 christos riscv_rm, ARRAY_SIZE (riscv_rm));
451 1.1 matt break;
452 1.1 matt
453 1.1 matt case 'P':
454 1.4 christos arg_print (info, EXTRACT_OPERAND (PRED, l),
455 1.4 christos riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
456 1.1 matt break;
457 1.1 matt
458 1.1 matt case 'Q':
459 1.4 christos arg_print (info, EXTRACT_OPERAND (SUCC, l),
460 1.4 christos riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
461 1.1 matt break;
462 1.1 matt
463 1.1 matt case 'o':
464 1.8 christos maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 0);
465 1.4 christos /* Fall through. */
466 1.1 matt case 'j':
467 1.4 christos if (((l & MASK_ADDI) == MATCH_ADDI && rs1 != 0)
468 1.4 christos || (l & MASK_JALR) == MATCH_JALR)
469 1.8 christos maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 0);
470 1.8 christos if (info->mach == bfd_mach_riscv64
471 1.8 christos && ((l & MASK_ADDIW) == MATCH_ADDIW) && rs1 != 0)
472 1.8 christos maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 1);
473 1.8 christos print (info->stream, dis_style_immediate, "%d",
474 1.8 christos (int)EXTRACT_ITYPE_IMM (l));
475 1.1 matt break;
476 1.1 matt
477 1.1 matt case 'q':
478 1.8 christos maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l), 0);
479 1.8 christos print (info->stream, dis_style_address_offset, "%d",
480 1.8 christos (int)EXTRACT_STYPE_IMM (l));
481 1.8 christos break;
482 1.8 christos
483 1.1 matt case 'a':
484 1.8 christos info->target = EXTRACT_JTYPE_IMM (l) + pc;
485 1.1 matt (*info->print_address_func) (info->target, info);
486 1.1 matt break;
487 1.1 matt
488 1.1 matt case 'p':
489 1.8 christos info->target = EXTRACT_BTYPE_IMM (l) + pc;
490 1.1 matt (*info->print_address_func) (info->target, info);
491 1.1 matt break;
492 1.1 matt
493 1.1 matt case 'd':
494 1.1 matt if ((l & MASK_AUIPC) == MATCH_AUIPC)
495 1.3 matt pd->hi_addr[rd] = pc + EXTRACT_UTYPE_IMM (l);
496 1.1 matt else if ((l & MASK_LUI) == MATCH_LUI)
497 1.3 matt pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l);
498 1.4 christos else if ((l & MASK_C_LUI) == MATCH_C_LUI)
499 1.8 christos pd->hi_addr[rd] = EXTRACT_CITYPE_LUI_IMM (l);
500 1.8 christos print (info->stream, dis_style_register, "%s", riscv_gpr_names[rd]);
501 1.8 christos break;
502 1.8 christos
503 1.8 christos case 'y':
504 1.8.2.1 perseant print (info->stream, dis_style_immediate, "0x%x",
505 1.8.2.1 perseant EXTRACT_OPERAND (BS, l));
506 1.1 matt break;
507 1.1 matt
508 1.1 matt case 'z':
509 1.8 christos print (info->stream, dis_style_register, "%s", riscv_gpr_names[0]);
510 1.1 matt break;
511 1.1 matt
512 1.1 matt case '>':
513 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
514 1.8.2.1 perseant EXTRACT_OPERAND (SHAMT, l));
515 1.1 matt break;
516 1.1 matt
517 1.1 matt case '<':
518 1.8 christos print (info->stream, dis_style_immediate, "0x%x",
519 1.8.2.1 perseant EXTRACT_OPERAND (SHAMTW, l));
520 1.1 matt break;
521 1.1 matt
522 1.1 matt case 'S':
523 1.1 matt case 'U':
524 1.8 christos print (info->stream, dis_style_register, "%s", riscv_fpr_names[rs1]);
525 1.1 matt break;
526 1.1 matt
527 1.1 matt case 'T':
528 1.8 christos print (info->stream, dis_style_register, "%s",
529 1.8 christos riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
530 1.1 matt break;
531 1.1 matt
532 1.1 matt case 'D':
533 1.8 christos print (info->stream, dis_style_register, "%s", riscv_fpr_names[rd]);
534 1.1 matt break;
535 1.1 matt
536 1.1 matt case 'R':
537 1.8 christos print (info->stream, dis_style_register, "%s",
538 1.8 christos riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
539 1.1 matt break;
540 1.1 matt
541 1.1 matt case 'E':
542 1.1 matt {
543 1.8 christos static const char *riscv_csr_hash[4096]; /* Total 2^12 CSRs. */
544 1.8 christos static bool init_csr = false;
545 1.4 christos unsigned int csr = EXTRACT_OPERAND (CSR, l);
546 1.8 christos
547 1.8 christos if (!init_csr)
548 1.1 matt {
549 1.8 christos unsigned int i;
550 1.8 christos for (i = 0; i < 4096; i++)
551 1.8 christos riscv_csr_hash[i] = NULL;
552 1.8 christos
553 1.8 christos /* Set to the newest privileged version. */
554 1.8 christos if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
555 1.8 christos default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1;
556 1.8 christos
557 1.8 christos #define DECLARE_CSR(name, num, class, define_version, abort_version) \
558 1.8 christos if (riscv_csr_hash[num] == NULL \
559 1.8 christos && ((define_version == PRIV_SPEC_CLASS_NONE \
560 1.8 christos && abort_version == PRIV_SPEC_CLASS_NONE) \
561 1.8 christos || (default_priv_spec >= define_version \
562 1.8 christos && default_priv_spec < abort_version))) \
563 1.8 christos riscv_csr_hash[num] = #name;
564 1.8 christos #define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \
565 1.8 christos DECLARE_CSR (name, num, class, define_version, abort_version)
566 1.4 christos #include "opcode/riscv-opc.h"
567 1.4 christos #undef DECLARE_CSR
568 1.1 matt }
569 1.8 christos
570 1.8 christos if (riscv_csr_hash[csr] != NULL)
571 1.8.2.1 perseant if (riscv_subset_supports (&riscv_rps_dis, "xtheadvector")
572 1.8.2.1 perseant && (csr == CSR_VSTART
573 1.8.2.1 perseant || csr == CSR_VXSAT
574 1.8.2.1 perseant || csr == CSR_VXRM
575 1.8.2.1 perseant || csr == CSR_VL
576 1.8.2.1 perseant || csr == CSR_VTYPE
577 1.8.2.1 perseant || csr == CSR_VLENB))
578 1.8.2.1 perseant print (info->stream, dis_style_register, "%s",
579 1.8.2.1 perseant concat ("th.", riscv_csr_hash[csr], NULL));
580 1.8.2.1 perseant else
581 1.8.2.1 perseant print (info->stream, dis_style_register, "%s",
582 1.8.2.1 perseant riscv_csr_hash[csr]);
583 1.3 matt else
584 1.8.2.1 perseant print (info->stream, dis_style_immediate, "0x%x", csr);
585 1.1 matt break;
586 1.1 matt }
587 1.1 matt
588 1.8 christos case 'Y':
589 1.8.2.1 perseant print (info->stream, dis_style_immediate, "0x%x",
590 1.8.2.1 perseant EXTRACT_OPERAND (RNUM, l));
591 1.8 christos break;
592 1.8 christos
593 1.1 matt case 'Z':
594 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d", rs1);
595 1.8.2.1 perseant break;
596 1.8.2.1 perseant
597 1.8.2.1 perseant case 'W': /* Various operands for standard z extensions. */
598 1.8.2.1 perseant switch (*++oparg)
599 1.8.2.1 perseant {
600 1.8.2.1 perseant case 'i':
601 1.8.2.1 perseant switch (*++oparg)
602 1.8.2.1 perseant {
603 1.8.2.1 perseant case 'f':
604 1.8.2.1 perseant print (info->stream, dis_style_address_offset, "%d",
605 1.8.2.1 perseant (int) EXTRACT_STYPE_IMM (l));
606 1.8.2.1 perseant break;
607 1.8.2.1 perseant default:
608 1.8.2.1 perseant goto undefined_modifier;
609 1.8.2.1 perseant }
610 1.8.2.1 perseant break;
611 1.8.2.1 perseant case 'f':
612 1.8.2.1 perseant switch (*++oparg)
613 1.8.2.1 perseant {
614 1.8.2.1 perseant case 'v':
615 1.8.2.1 perseant if (riscv_fli_symval[rs1])
616 1.8.2.1 perseant print (info->stream, dis_style_text, "%s",
617 1.8.2.1 perseant riscv_fli_symval[rs1]);
618 1.8.2.1 perseant else
619 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%a",
620 1.8.2.1 perseant riscv_fli_numval[rs1]);
621 1.8.2.1 perseant break;
622 1.8.2.1 perseant default:
623 1.8.2.1 perseant goto undefined_modifier;
624 1.8.2.1 perseant }
625 1.8.2.1 perseant break;
626 1.8.2.1 perseant case 'c': /* Zcb extension 16 bits length instruction fields. */
627 1.8.2.1 perseant switch (*++oparg)
628 1.8.2.1 perseant {
629 1.8.2.1 perseant case 'b':
630 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d",
631 1.8.2.1 perseant (int)EXTRACT_ZCB_BYTE_UIMM (l));
632 1.8.2.1 perseant break;
633 1.8.2.1 perseant case 'h':
634 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d",
635 1.8.2.1 perseant (int)EXTRACT_ZCB_HALFWORD_UIMM (l));
636 1.8.2.1 perseant break;
637 1.8.2.1 perseant default:
638 1.8.2.1 perseant goto undefined_modifier;
639 1.8.2.1 perseant }
640 1.8.2.1 perseant break;
641 1.8.2.1 perseant default:
642 1.8.2.1 perseant goto undefined_modifier;
643 1.8.2.1 perseant }
644 1.8.2.1 perseant break;
645 1.8.2.1 perseant
646 1.8.2.1 perseant case 'X': /* Vendor-specific operands. */
647 1.8.2.1 perseant switch (*++oparg)
648 1.8.2.1 perseant {
649 1.8.2.1 perseant case 't': /* Vendor-specific (T-head) operands. */
650 1.8.2.1 perseant {
651 1.8.2.1 perseant size_t n;
652 1.8.2.1 perseant size_t s;
653 1.8.2.1 perseant bool sign;
654 1.8.2.1 perseant switch (*++oparg)
655 1.8.2.1 perseant {
656 1.8.2.1 perseant case 'V':
657 1.8.2.1 perseant ++oparg;
658 1.8.2.1 perseant if (*oparg != 'c')
659 1.8.2.1 perseant goto undefined_modifier;
660 1.8.2.1 perseant
661 1.8.2.1 perseant int imm = (*oparg == 'b') ? EXTRACT_RVV_VB_IMM (l)
662 1.8.2.1 perseant : EXTRACT_RVV_VC_IMM (l);
663 1.8.2.1 perseant unsigned int imm_vediv = EXTRACT_OPERAND (XTHEADVEDIV, imm);
664 1.8.2.1 perseant unsigned int imm_vlmul = EXTRACT_OPERAND (XTHEADVLMUL, imm);
665 1.8.2.1 perseant unsigned int imm_vsew = EXTRACT_OPERAND (XTHEADVSEW, imm);
666 1.8.2.1 perseant unsigned int imm_vtype_res
667 1.8.2.1 perseant = EXTRACT_OPERAND (XTHEADVTYPE_RES, imm);
668 1.8.2.1 perseant if (imm_vsew < ARRAY_SIZE (riscv_vsew)
669 1.8.2.1 perseant && imm_vlmul < ARRAY_SIZE (riscv_th_vlen)
670 1.8.2.1 perseant && imm_vediv < ARRAY_SIZE (riscv_th_vediv)
671 1.8.2.1 perseant && ! imm_vtype_res)
672 1.8.2.1 perseant print (info->stream, dis_style_text, "%s,%s,%s",
673 1.8.2.1 perseant riscv_vsew[imm_vsew], riscv_th_vlen[imm_vlmul],
674 1.8.2.1 perseant riscv_th_vediv[imm_vediv]);
675 1.8.2.1 perseant else
676 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d", imm);
677 1.8.2.1 perseant break;
678 1.8.2.1 perseant case 'l': /* Integer immediate, literal. */
679 1.8.2.1 perseant oparg++;
680 1.8.2.1 perseant while (*oparg && *oparg != ',')
681 1.8.2.1 perseant {
682 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%c", *oparg);
683 1.8.2.1 perseant oparg++;
684 1.8.2.1 perseant }
685 1.8.2.1 perseant oparg--;
686 1.8.2.1 perseant break;
687 1.8.2.1 perseant case 's': /* Integer immediate, 'XsN@S' ... N-bit signed immediate at bit S. */
688 1.8.2.1 perseant sign = true;
689 1.8.2.1 perseant goto print_imm;
690 1.8.2.1 perseant case 'u': /* Integer immediate, 'XuN@S' ... N-bit unsigned immediate at bit S. */
691 1.8.2.1 perseant sign = false;
692 1.8.2.1 perseant goto print_imm;
693 1.8.2.1 perseant print_imm:
694 1.8.2.1 perseant n = strtol (oparg + 1, (char **)&oparg, 10);
695 1.8.2.1 perseant if (*oparg != '@')
696 1.8.2.1 perseant goto undefined_modifier;
697 1.8.2.1 perseant s = strtol (oparg + 1, (char **)&oparg, 10);
698 1.8.2.1 perseant oparg--;
699 1.8.2.1 perseant
700 1.8.2.1 perseant if (!sign)
701 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%lu",
702 1.8.2.1 perseant (unsigned long)EXTRACT_U_IMM (n, s, l));
703 1.8.2.1 perseant else
704 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%li",
705 1.8.2.1 perseant (signed long)EXTRACT_S_IMM (n, s, l));
706 1.8.2.1 perseant break;
707 1.8.2.1 perseant default:
708 1.8.2.1 perseant goto undefined_modifier;
709 1.8.2.1 perseant }
710 1.8.2.1 perseant }
711 1.8.2.1 perseant break;
712 1.8.2.1 perseant case 'c': /* Vendor-specific (CORE-V) operands. */
713 1.8.2.1 perseant switch (*++oparg)
714 1.8.2.1 perseant {
715 1.8.2.1 perseant case '2':
716 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d",
717 1.8.2.1 perseant ((int) EXTRACT_CV_IS2_UIMM5 (l)));
718 1.8.2.1 perseant break;
719 1.8.2.1 perseant case '3':
720 1.8.2.1 perseant print (info->stream, dis_style_immediate, "%d",
721 1.8.2.1 perseant ((int) EXTRACT_CV_IS3_UIMM5 (l)));
722 1.8.2.1 perseant break;
723 1.8.2.1 perseant default:
724 1.8.2.1 perseant goto undefined_modifier;
725 1.8.2.1 perseant }
726 1.8.2.1 perseant break;
727 1.8.2.1 perseant case 's': /* Vendor-specific (SiFive) operands. */
728 1.8.2.1 perseant switch (*++oparg)
729 1.8.2.1 perseant {
730 1.8.2.1 perseant /* SiFive vector coprocessor interface. */
731 1.8.2.1 perseant case 'd':
732 1.8.2.1 perseant print (info->stream, dis_style_register, "0x%x",
733 1.8.2.1 perseant (unsigned) EXTRACT_OPERAND (RD, l));
734 1.8.2.1 perseant break;
735 1.8.2.1 perseant case 't':
736 1.8.2.1 perseant print (info->stream, dis_style_register, "0x%x",
737 1.8.2.1 perseant (unsigned) EXTRACT_OPERAND (RS2, l));
738 1.8.2.1 perseant break;
739 1.8.2.1 perseant case 'O':
740 1.8.2.1 perseant switch (*++oparg)
741 1.8.2.1 perseant {
742 1.8.2.1 perseant case '2':
743 1.8.2.1 perseant print (info->stream, dis_style_register, "0x%x",
744 1.8.2.1 perseant (unsigned) EXTRACT_OPERAND (XSO2, l));
745 1.8.2.1 perseant break;
746 1.8.2.1 perseant case '1':
747 1.8.2.1 perseant print (info->stream, dis_style_register, "0x%x",
748 1.8.2.1 perseant (unsigned) EXTRACT_OPERAND (XSO1, l));
749 1.8.2.1 perseant break;
750 1.8.2.1 perseant }
751 1.8.2.1 perseant break;
752 1.8.2.1 perseant }
753 1.8.2.1 perseant break;
754 1.8.2.1 perseant default:
755 1.8.2.1 perseant goto undefined_modifier;
756 1.8.2.1 perseant }
757 1.1 matt break;
758 1.1 matt
759 1.1 matt default:
760 1.8.2.1 perseant undefined_modifier:
761 1.1 matt /* xgettext:c-format */
762 1.8 christos print (info->stream, dis_style_text,
763 1.8 christos _("# internal error, undefined modifier (%c)"),
764 1.8 christos *opargStart);
765 1.1 matt return;
766 1.1 matt }
767 1.1 matt }
768 1.1 matt }
769 1.1 matt
770 1.1 matt /* Print the RISC-V instruction at address MEMADDR in debugged memory,
771 1.1 matt on using INFO. Returns length of the instruction, in bytes.
772 1.1 matt BIGENDIAN must be 1 if this is big-endian code, 0 if
773 1.1 matt this is little-endian code. */
774 1.1 matt
775 1.1 matt static int
776 1.8.2.1 perseant riscv_disassemble_insn (bfd_vma memaddr,
777 1.8.2.1 perseant insn_t word,
778 1.8.2.1 perseant const bfd_byte *packet,
779 1.8.2.1 perseant disassemble_info *info)
780 1.1 matt {
781 1.1 matt const struct riscv_opcode *op;
782 1.8.2.1 perseant static bool init = false;
783 1.1 matt static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
784 1.8.2.1 perseant struct riscv_private_data *pd = info->private_data;
785 1.8.2.1 perseant int insnlen, i;
786 1.8.2.1 perseant bool printed;
787 1.1 matt
788 1.4 christos #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : OP_MASK_OP))
789 1.4 christos
790 1.1 matt /* Build a hash table to shorten the search time. */
791 1.1 matt if (! init)
792 1.1 matt {
793 1.4 christos for (op = riscv_opcodes; op->name; op++)
794 1.4 christos if (!riscv_hash[OP_HASH_IDX (op->match)])
795 1.4 christos riscv_hash[OP_HASH_IDX (op->match)] = op;
796 1.1 matt
797 1.8.2.1 perseant init = true;
798 1.1 matt }
799 1.1 matt
800 1.1 matt insnlen = riscv_insn_length (word);
801 1.1 matt
802 1.7 christos /* RISC-V instructions are always little-endian. */
803 1.7 christos info->endian_code = BFD_ENDIAN_LITTLE;
804 1.7 christos
805 1.1 matt info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
806 1.1 matt info->bytes_per_line = 8;
807 1.7 christos /* We don't support constant pools, so this must be code. */
808 1.7 christos info->display_endian = info->endian_code;
809 1.1 matt info->insn_info_valid = 1;
810 1.1 matt info->branch_delay_insns = 0;
811 1.1 matt info->data_size = 0;
812 1.1 matt info->insn_type = dis_nonbranch;
813 1.1 matt info->target = 0;
814 1.1 matt info->target2 = 0;
815 1.1 matt
816 1.4 christos op = riscv_hash[OP_HASH_IDX (word)];
817 1.1 matt if (op != NULL)
818 1.1 matt {
819 1.4 christos /* If XLEN is not known, get its value from the ELF class. */
820 1.4 christos if (info->mach == bfd_mach_riscv64)
821 1.4 christos xlen = 64;
822 1.4 christos else if (info->mach == bfd_mach_riscv32)
823 1.4 christos xlen = 32;
824 1.4 christos else if (info->section != NULL)
825 1.1 matt {
826 1.4 christos Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
827 1.4 christos xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
828 1.4 christos }
829 1.4 christos
830 1.8.2.1 perseant /* If arch has the Zfinx extension, replace FPR with GPR. */
831 1.8.2.1 perseant if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
832 1.8 christos riscv_fpr_names = riscv_gpr_names;
833 1.8.2.1 perseant else
834 1.8.2.1 perseant riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi ?
835 1.8.2.1 perseant riscv_fpr_names_abi : riscv_fpr_names_numeric;
836 1.8 christos
837 1.4 christos for (; op->name; op++)
838 1.4 christos {
839 1.8.2.1 perseant /* Ignore macro insns. */
840 1.8.2.1 perseant if (op->pinfo == INSN_MACRO)
841 1.8.2.1 perseant continue;
842 1.4 christos /* Does the opcode match? */
843 1.4 christos if (! (op->match_func) (op, word))
844 1.4 christos continue;
845 1.4 christos /* Is this a pseudo-instruction and may we print it as such? */
846 1.4 christos if (no_aliases && (op->pinfo & INSN_ALIAS))
847 1.4 christos continue;
848 1.4 christos /* Is this instruction restricted to a certain value of XLEN? */
849 1.7 christos if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
850 1.4 christos continue;
851 1.8.2.1 perseant /* Is this instruction supported by the current architecture? */
852 1.8 christos if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
853 1.8 christos continue;
854 1.8 christos
855 1.4 christos /* It's a match. */
856 1.8 christos (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
857 1.8 christos "%s", op->name);
858 1.4 christos print_insn_args (op->args, word, memaddr, info);
859 1.4 christos
860 1.4 christos /* Try to disassemble multi-instruction addressing sequences. */
861 1.8.2.1 perseant if (pd->to_print_addr)
862 1.1 matt {
863 1.4 christos info->target = pd->print_addr;
864 1.8 christos (*info->fprintf_styled_func)
865 1.8 christos (info->stream, dis_style_comment_start, " # ");
866 1.4 christos (*info->print_address_func) (info->target, info);
867 1.8.2.1 perseant pd->to_print_addr = false;
868 1.1 matt }
869 1.4 christos
870 1.7 christos /* Finish filling out insn_info fields. */
871 1.7 christos switch (op->pinfo & INSN_TYPE)
872 1.7 christos {
873 1.7 christos case INSN_BRANCH:
874 1.7 christos info->insn_type = dis_branch;
875 1.7 christos break;
876 1.7 christos case INSN_CONDBRANCH:
877 1.7 christos info->insn_type = dis_condbranch;
878 1.7 christos break;
879 1.7 christos case INSN_JSR:
880 1.7 christos info->insn_type = dis_jsr;
881 1.7 christos break;
882 1.7 christos case INSN_DREF:
883 1.7 christos info->insn_type = dis_dref;
884 1.7 christos break;
885 1.7 christos default:
886 1.7 christos break;
887 1.7 christos }
888 1.7 christos
889 1.7 christos if (op->pinfo & INSN_DATA_SIZE)
890 1.7 christos {
891 1.7 christos int size = ((op->pinfo & INSN_DATA_SIZE)
892 1.7 christos >> INSN_DATA_SIZE_SHIFT);
893 1.7 christos info->data_size = 1 << (size - 1);
894 1.7 christos }
895 1.7 christos
896 1.4 christos return insnlen;
897 1.1 matt }
898 1.1 matt }
899 1.1 matt
900 1.8.2.1 perseant /* We did not find a match, so just print the instruction bits in
901 1.8.2.1 perseant the shape of an assembler .insn directive. */
902 1.1 matt info->insn_type = dis_noninsn;
903 1.8.2.1 perseant (*info->fprintf_styled_func)
904 1.8.2.1 perseant (info->stream, dis_style_assembler_directive, ".insn");
905 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
906 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
907 1.8.2.1 perseant "%d", insnlen);
908 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, ", ");
909 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate, "0x");
910 1.8.2.1 perseant for (i = insnlen, printed = false; i >= 2; )
911 1.8.2.1 perseant {
912 1.8.2.1 perseant i -= 2;
913 1.8.2.1 perseant word = bfd_get_bits (packet + i, 16, false);
914 1.8.2.1 perseant if (!word && !printed)
915 1.8.2.1 perseant continue;
916 1.8.2.1 perseant
917 1.8 christos (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
918 1.8.2.1 perseant "%04x", (unsigned int) word);
919 1.8.2.1 perseant printed = true;
920 1.8 christos }
921 1.8.2.1 perseant
922 1.1 matt return insnlen;
923 1.1 matt }
924 1.1 matt
925 1.8.2.1 perseant /* If we find the suitable mapping symbol update the STATE.
926 1.8.2.1 perseant Otherwise, do nothing. */
927 1.8 christos
928 1.8.2.1 perseant static void
929 1.8.2.1 perseant riscv_update_map_state (int n,
930 1.8.2.1 perseant enum riscv_seg_mstate *state,
931 1.8.2.1 perseant struct disassemble_info *info)
932 1.8 christos {
933 1.8 christos const char *name;
934 1.8 christos
935 1.8 christos /* If the symbol is in a different section, ignore it. */
936 1.8 christos if (info->section != NULL
937 1.8 christos && info->section != info->symtab[n]->section)
938 1.8.2.1 perseant return;
939 1.8 christos
940 1.8 christos name = bfd_asymbol_name(info->symtab[n]);
941 1.8 christos if (strcmp (name, "$x") == 0)
942 1.8 christos *state = MAP_INSN;
943 1.8 christos else if (strcmp (name, "$d") == 0)
944 1.8 christos *state = MAP_DATA;
945 1.8.2.1 perseant else if (strncmp (name, "$xrv", 4) == 0)
946 1.8.2.1 perseant {
947 1.8.2.1 perseant *state = MAP_INSN;
948 1.8.2.1 perseant riscv_release_subset_list (&riscv_subsets);
949 1.8.2.1 perseant
950 1.8.2.1 perseant /* ISA mapping string may be numbered, suffixed with '.n'. Do not
951 1.8.2.1 perseant consider this as part of the ISA string. */
952 1.8.2.1 perseant char *suffix = strchr (name, '.');
953 1.8.2.1 perseant if (suffix)
954 1.8.2.1 perseant {
955 1.8.2.1 perseant int suffix_index = (int)(suffix - name);
956 1.8.2.1 perseant char *name_substr = xmalloc (suffix_index + 1);
957 1.8.2.1 perseant strncpy (name_substr, name, suffix_index);
958 1.8.2.1 perseant name_substr[suffix_index] = '\0';
959 1.8.2.1 perseant riscv_parse_subset (&riscv_rps_dis, name_substr + 2);
960 1.8.2.1 perseant free (name_substr);
961 1.8.2.1 perseant }
962 1.8.2.1 perseant else
963 1.8.2.1 perseant riscv_parse_subset (&riscv_rps_dis, name + 2);
964 1.8.2.1 perseant }
965 1.8.2.1 perseant }
966 1.8.2.1 perseant
967 1.8.2.1 perseant /* Return true if we find the suitable mapping symbol.
968 1.8.2.1 perseant Otherwise, return false. */
969 1.8.2.1 perseant
970 1.8.2.1 perseant static bool
971 1.8.2.1 perseant riscv_is_valid_mapping_symbol (int n,
972 1.8.2.1 perseant struct disassemble_info *info)
973 1.8.2.1 perseant {
974 1.8.2.1 perseant const char *name;
975 1.8.2.1 perseant
976 1.8.2.1 perseant /* If the symbol is in a different section, ignore it. */
977 1.8.2.1 perseant if (info->section != NULL
978 1.8.2.1 perseant && info->section != info->symtab[n]->section)
979 1.8 christos return false;
980 1.8 christos
981 1.8.2.1 perseant name = bfd_asymbol_name(info->symtab[n]);
982 1.8.2.1 perseant return riscv_elf_is_mapping_symbols (name);
983 1.8 christos }
984 1.8 christos
985 1.8 christos /* Check the sorted symbol table (sorted by the symbol value), find the
986 1.8 christos suitable mapping symbols. */
987 1.8 christos
988 1.8 christos static enum riscv_seg_mstate
989 1.8 christos riscv_search_mapping_symbol (bfd_vma memaddr,
990 1.8 christos struct disassemble_info *info)
991 1.8 christos {
992 1.8 christos enum riscv_seg_mstate mstate;
993 1.8 christos bool from_last_map_symbol;
994 1.8 christos bool found = false;
995 1.8 christos int symbol = -1;
996 1.8 christos int n;
997 1.8 christos
998 1.8.2.1 perseant /* Return the last map state if the address is still within the range of the
999 1.8.2.1 perseant last mapping symbol. */
1000 1.8.2.1 perseant if (last_map_section == info->section
1001 1.8.2.1 perseant && (memaddr < last_map_symbol_boundary))
1002 1.8.2.1 perseant return last_map_state;
1003 1.8.2.1 perseant
1004 1.8.2.1 perseant last_map_section = info->section;
1005 1.8.2.1 perseant
1006 1.8 christos /* Decide whether to print the data or instruction by default, in case
1007 1.8 christos we can not find the corresponding mapping symbols. */
1008 1.8 christos mstate = MAP_DATA;
1009 1.8 christos if ((info->section
1010 1.8 christos && info->section->flags & SEC_CODE)
1011 1.8 christos || !info->section)
1012 1.8 christos mstate = MAP_INSN;
1013 1.8 christos
1014 1.8 christos if (info->symtab_size == 0
1015 1.8 christos || bfd_asymbol_flavour (*info->symtab) != bfd_target_elf_flavour)
1016 1.8 christos return mstate;
1017 1.8 christos
1018 1.8 christos /* Reset the last_map_symbol if we start to dump a new section. */
1019 1.8 christos if (memaddr <= 0)
1020 1.8 christos last_map_symbol = -1;
1021 1.8 christos
1022 1.8 christos /* If the last stop offset is different from the current one, then
1023 1.8 christos don't use the last_map_symbol to search. We usually reset the
1024 1.8 christos info->stop_offset when handling a new section. */
1025 1.8 christos from_last_map_symbol = (last_map_symbol >= 0
1026 1.8 christos && info->stop_offset == last_stop_offset);
1027 1.8 christos
1028 1.8 christos /* Start scanning at the start of the function, or wherever
1029 1.8 christos we finished last time. */
1030 1.8 christos n = info->symtab_pos + 1;
1031 1.8 christos if (from_last_map_symbol && n >= last_map_symbol)
1032 1.8 christos n = last_map_symbol;
1033 1.8 christos
1034 1.8 christos /* Find the suitable mapping symbol to dump. */
1035 1.8 christos for (; n < info->symtab_size; n++)
1036 1.8 christos {
1037 1.8 christos bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
1038 1.8 christos /* We have searched all possible symbols in the range. */
1039 1.8 christos if (addr > memaddr)
1040 1.8 christos break;
1041 1.8.2.1 perseant if (riscv_is_valid_mapping_symbol (n, info))
1042 1.8 christos {
1043 1.8 christos symbol = n;
1044 1.8 christos found = true;
1045 1.8 christos /* Do not stop searching, in case there are some mapping
1046 1.8 christos symbols have the same value, but have different names.
1047 1.8 christos Use the last one. */
1048 1.8 christos }
1049 1.8 christos }
1050 1.8 christos
1051 1.8 christos /* We can not find the suitable mapping symbol above. Therefore, we
1052 1.8.2.1 perseant look forwards and try to find it again, but don't go past the start
1053 1.8 christos of the section. Otherwise a data section without mapping symbols
1054 1.8 christos can pick up a text mapping symbol of a preceeding section. */
1055 1.8 christos if (!found)
1056 1.8 christos {
1057 1.8 christos n = info->symtab_pos;
1058 1.8 christos if (from_last_map_symbol && n >= last_map_symbol)
1059 1.8 christos n = last_map_symbol;
1060 1.8 christos
1061 1.8 christos for (; n >= 0; n--)
1062 1.8 christos {
1063 1.8 christos bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
1064 1.8 christos /* We have searched all possible symbols in the range. */
1065 1.8 christos if (addr < (info->section ? info->section->vma : 0))
1066 1.8 christos break;
1067 1.8 christos /* Stop searching once we find the closed mapping symbol. */
1068 1.8.2.1 perseant if (riscv_is_valid_mapping_symbol (n, info))
1069 1.8 christos {
1070 1.8 christos symbol = n;
1071 1.8 christos found = true;
1072 1.8 christos break;
1073 1.8 christos }
1074 1.8 christos }
1075 1.8 christos }
1076 1.8 christos
1077 1.8.2.1 perseant if (found)
1078 1.8.2.1 perseant {
1079 1.8.2.1 perseant riscv_update_map_state (symbol, &mstate, info);
1080 1.8.2.1 perseant
1081 1.8.2.1 perseant /* Find the next mapping symbol to determine the boundary of this mapping
1082 1.8.2.1 perseant symbol. */
1083 1.8.2.1 perseant
1084 1.8.2.1 perseant bool found_next = false;
1085 1.8.2.1 perseant /* Try to found next mapping symbol. */
1086 1.8.2.1 perseant for (n = symbol + 1; n < info->symtab_size; n++)
1087 1.8.2.1 perseant {
1088 1.8.2.1 perseant if (info->symtab[symbol]->section != info->symtab[n]->section)
1089 1.8.2.1 perseant continue;
1090 1.8.2.1 perseant
1091 1.8.2.1 perseant bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
1092 1.8.2.1 perseant const char *sym_name = bfd_asymbol_name(info->symtab[n]);
1093 1.8.2.1 perseant if (sym_name[0] == '$' && (sym_name[1] == 'x' || sym_name[1] == 'd'))
1094 1.8.2.1 perseant {
1095 1.8.2.1 perseant /* The next mapping symbol has been found, and it represents the
1096 1.8.2.1 perseant boundary of this mapping symbol. */
1097 1.8.2.1 perseant found_next = true;
1098 1.8.2.1 perseant last_map_symbol_boundary = addr;
1099 1.8.2.1 perseant break;
1100 1.8.2.1 perseant }
1101 1.8.2.1 perseant }
1102 1.8.2.1 perseant
1103 1.8.2.1 perseant /* No further mapping symbol has been found, indicating that the boundary
1104 1.8.2.1 perseant of the current mapping symbol is the end of this section. */
1105 1.8.2.1 perseant if (!found_next)
1106 1.8.2.1 perseant last_map_symbol_boundary = info->section->vma + info->section->size;
1107 1.8.2.1 perseant }
1108 1.8.2.1 perseant
1109 1.8 christos /* Save the information for next use. */
1110 1.8 christos last_map_symbol = symbol;
1111 1.8 christos last_stop_offset = info->stop_offset;
1112 1.8 christos
1113 1.8 christos return mstate;
1114 1.8 christos }
1115 1.8 christos
1116 1.8 christos /* Decide which data size we should print. */
1117 1.8 christos
1118 1.8 christos static bfd_vma
1119 1.8 christos riscv_data_length (bfd_vma memaddr,
1120 1.8 christos disassemble_info *info)
1121 1.8 christos {
1122 1.8 christos bfd_vma length;
1123 1.8 christos bool found = false;
1124 1.8 christos
1125 1.8 christos length = 4;
1126 1.8 christos if (info->symtab_size != 0
1127 1.8 christos && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour
1128 1.8 christos && last_map_symbol >= 0)
1129 1.8 christos {
1130 1.8 christos int n;
1131 1.8 christos enum riscv_seg_mstate m = MAP_NONE;
1132 1.8 christos for (n = last_map_symbol + 1; n < info->symtab_size; n++)
1133 1.8 christos {
1134 1.8 christos bfd_vma addr = bfd_asymbol_value (info->symtab[n]);
1135 1.8 christos if (addr > memaddr
1136 1.8.2.1 perseant && riscv_is_valid_mapping_symbol (n, info))
1137 1.8 christos {
1138 1.8 christos if (addr - memaddr < length)
1139 1.8 christos length = addr - memaddr;
1140 1.8 christos found = true;
1141 1.8.2.1 perseant riscv_update_map_state (n, &m, info);
1142 1.8 christos break;
1143 1.8 christos }
1144 1.8 christos }
1145 1.8 christos }
1146 1.8 christos if (!found)
1147 1.8 christos {
1148 1.8 christos /* Do not set the length which exceeds the section size. */
1149 1.8 christos bfd_vma offset = info->section->vma + info->section->size;
1150 1.8 christos offset -= memaddr;
1151 1.8 christos length = (offset < length) ? offset : length;
1152 1.8 christos }
1153 1.8 christos length = length == 3 ? 2 : length;
1154 1.8 christos return length;
1155 1.8 christos }
1156 1.8 christos
1157 1.8 christos /* Dump the data contents. */
1158 1.8 christos
1159 1.8 christos static int
1160 1.8 christos riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED,
1161 1.8 christos insn_t data,
1162 1.8.2.1 perseant const bfd_byte *packet ATTRIBUTE_UNUSED,
1163 1.8 christos disassemble_info *info)
1164 1.8 christos {
1165 1.8 christos info->display_endian = info->endian;
1166 1.8 christos
1167 1.8 christos switch (info->bytes_per_chunk)
1168 1.8 christos {
1169 1.8 christos case 1:
1170 1.8 christos info->bytes_per_line = 6;
1171 1.8 christos (*info->fprintf_styled_func)
1172 1.8.2.1 perseant (info->stream, dis_style_assembler_directive, ".byte");
1173 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1174 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1175 1.8.2.1 perseant "0x%02x", (unsigned)data);
1176 1.8 christos break;
1177 1.8 christos case 2:
1178 1.8 christos info->bytes_per_line = 8;
1179 1.8 christos (*info->fprintf_styled_func)
1180 1.8.2.1 perseant (info->stream, dis_style_assembler_directive, ".short");
1181 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1182 1.8 christos (*info->fprintf_styled_func)
1183 1.8.2.1 perseant (info->stream, dis_style_immediate, "0x%04x", (unsigned) data);
1184 1.8 christos break;
1185 1.8 christos case 4:
1186 1.8 christos info->bytes_per_line = 8;
1187 1.8 christos (*info->fprintf_styled_func)
1188 1.8.2.1 perseant (info->stream, dis_style_assembler_directive, ".word");
1189 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1190 1.8 christos (*info->fprintf_styled_func)
1191 1.8.2.1 perseant (info->stream, dis_style_immediate, "0x%08lx",
1192 1.8.2.1 perseant (unsigned long) data);
1193 1.8 christos break;
1194 1.8 christos case 8:
1195 1.8 christos info->bytes_per_line = 8;
1196 1.8 christos (*info->fprintf_styled_func)
1197 1.8.2.1 perseant (info->stream, dis_style_assembler_directive, ".dword");
1198 1.8.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1199 1.8 christos (*info->fprintf_styled_func)
1200 1.8 christos (info->stream, dis_style_immediate, "0x%016llx",
1201 1.8 christos (unsigned long long) data);
1202 1.8 christos break;
1203 1.8 christos default:
1204 1.8 christos abort ();
1205 1.8 christos }
1206 1.8 christos return info->bytes_per_chunk;
1207 1.8 christos }
1208 1.8 christos
1209 1.8.2.1 perseant static bool
1210 1.8.2.1 perseant riscv_init_disasm_info (struct disassemble_info *info)
1211 1.8.2.1 perseant {
1212 1.8.2.1 perseant int i;
1213 1.8.2.1 perseant
1214 1.8.2.1 perseant struct riscv_private_data *pd =
1215 1.8.2.1 perseant xcalloc (1, sizeof (struct riscv_private_data));
1216 1.8.2.1 perseant pd->gp = 0;
1217 1.8.2.1 perseant pd->print_addr = 0;
1218 1.8.2.1 perseant for (i = 0; i < (int) ARRAY_SIZE (pd->hi_addr); i++)
1219 1.8.2.1 perseant pd->hi_addr[i] = -1;
1220 1.8.2.1 perseant pd->to_print_addr = false;
1221 1.8.2.1 perseant pd->has_gp = false;
1222 1.8.2.1 perseant
1223 1.8.2.1 perseant for (i = 0; i < info->symtab_size; i++)
1224 1.8.2.1 perseant {
1225 1.8.2.1 perseant asymbol *sym = info->symtab[i];
1226 1.8.2.1 perseant if (strcmp (bfd_asymbol_name (sym), RISCV_GP_SYMBOL) == 0)
1227 1.8.2.1 perseant {
1228 1.8.2.1 perseant pd->gp = bfd_asymbol_value (sym);
1229 1.8.2.1 perseant pd->has_gp = true;
1230 1.8.2.1 perseant }
1231 1.8.2.1 perseant }
1232 1.8.2.1 perseant
1233 1.8.2.1 perseant info->private_data = pd;
1234 1.8.2.1 perseant return true;
1235 1.8.2.1 perseant }
1236 1.8.2.1 perseant
1237 1.1 matt int
1238 1.1 matt print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
1239 1.1 matt {
1240 1.8.2.1 perseant bfd_byte packet[RISCV_MAX_INSN_LEN];
1241 1.1 matt insn_t insn = 0;
1242 1.8 christos bfd_vma dump_size;
1243 1.1 matt int status;
1244 1.8 christos enum riscv_seg_mstate mstate;
1245 1.8.2.1 perseant int (*riscv_disassembler) (bfd_vma, insn_t, const bfd_byte *,
1246 1.8.2.1 perseant struct disassemble_info *);
1247 1.1 matt
1248 1.3 matt if (info->disassembler_options != NULL)
1249 1.3 matt {
1250 1.3 matt parse_riscv_dis_options (info->disassembler_options);
1251 1.3 matt /* Avoid repeatedly parsing the options. */
1252 1.3 matt info->disassembler_options = NULL;
1253 1.3 matt }
1254 1.3 matt else if (riscv_gpr_names == NULL)
1255 1.3 matt set_default_riscv_dis_options ();
1256 1.1 matt
1257 1.8.2.1 perseant if (info->private_data == NULL && !riscv_init_disasm_info (info))
1258 1.8.2.1 perseant return -1;
1259 1.8.2.1 perseant
1260 1.8 christos mstate = riscv_search_mapping_symbol (memaddr, info);
1261 1.8 christos /* Save the last mapping state. */
1262 1.8 christos last_map_state = mstate;
1263 1.8 christos
1264 1.8 christos /* Set the size to dump. */
1265 1.8 christos if (mstate == MAP_DATA
1266 1.8 christos && (info->flags & DISASSEMBLE_DATA) == 0)
1267 1.1 matt {
1268 1.8 christos dump_size = riscv_data_length (memaddr, info);
1269 1.8 christos info->bytes_per_chunk = dump_size;
1270 1.8 christos riscv_disassembler = riscv_disassemble_data;
1271 1.8 christos }
1272 1.8 christos else
1273 1.8 christos {
1274 1.8 christos /* Get the first 2-bytes to check the lenghth of instruction. */
1275 1.8 christos status = (*info->read_memory_func) (memaddr, packet, 2, info);
1276 1.1 matt if (status != 0)
1277 1.1 matt {
1278 1.1 matt (*info->memory_error_func) (status, memaddr, info);
1279 1.8.2.1 perseant return -1;
1280 1.1 matt }
1281 1.8 christos insn = (insn_t) bfd_getl16 (packet);
1282 1.8 christos dump_size = riscv_insn_length (insn);
1283 1.8 christos riscv_disassembler = riscv_disassemble_insn;
1284 1.8 christos }
1285 1.1 matt
1286 1.8 christos /* Fetch the instruction to dump. */
1287 1.8 christos status = (*info->read_memory_func) (memaddr, packet, dump_size, info);
1288 1.8 christos if (status != 0)
1289 1.8 christos {
1290 1.8 christos (*info->memory_error_func) (status, memaddr, info);
1291 1.8.2.1 perseant return -1;
1292 1.1 matt }
1293 1.8 christos insn = (insn_t) bfd_get_bits (packet, dump_size * 8, false);
1294 1.1 matt
1295 1.8.2.1 perseant return (*riscv_disassembler) (memaddr, insn, packet, info);
1296 1.8 christos }
1297 1.8 christos
1298 1.8 christos disassembler_ftype
1299 1.8 christos riscv_get_disassembler (bfd *abfd)
1300 1.8 christos {
1301 1.8 christos const char *default_arch = "rv64gc";
1302 1.8 christos
1303 1.8 christos if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
1304 1.8 christos {
1305 1.8 christos const char *sec_name = get_elf_backend_data (abfd)->obj_attrs_section;
1306 1.8 christos if (bfd_get_section_by_name (abfd, sec_name) != NULL)
1307 1.8 christos {
1308 1.8 christos obj_attribute *attr = elf_known_obj_attributes_proc (abfd);
1309 1.8 christos unsigned int Tag_a = Tag_RISCV_priv_spec;
1310 1.8 christos unsigned int Tag_b = Tag_RISCV_priv_spec_minor;
1311 1.8 christos unsigned int Tag_c = Tag_RISCV_priv_spec_revision;
1312 1.8 christos riscv_get_priv_spec_class_from_numbers (attr[Tag_a].i,
1313 1.8 christos attr[Tag_b].i,
1314 1.8 christos attr[Tag_c].i,
1315 1.8 christos &default_priv_spec);
1316 1.8 christos default_arch = attr[Tag_RISCV_arch].s;
1317 1.8 christos }
1318 1.8 christos }
1319 1.8 christos
1320 1.8 christos riscv_release_subset_list (&riscv_subsets);
1321 1.8 christos riscv_parse_subset (&riscv_rps_dis, default_arch);
1322 1.8 christos return print_insn_riscv;
1323 1.1 matt }
1324 1.1 matt
1325 1.7 christos /* Prevent use of the fake labels that are generated as part of the DWARF
1326 1.7 christos and for relaxable relocations in the assembler. */
1327 1.7 christos
1328 1.8 christos bool
1329 1.7 christos riscv_symbol_is_valid (asymbol * sym,
1330 1.7 christos struct disassemble_info * info ATTRIBUTE_UNUSED)
1331 1.7 christos {
1332 1.7 christos const char * name;
1333 1.7 christos
1334 1.7 christos if (sym == NULL)
1335 1.8 christos return false;
1336 1.7 christos
1337 1.7 christos name = bfd_asymbol_name (sym);
1338 1.7 christos
1339 1.8 christos return (strcmp (name, RISCV_FAKE_LABEL_NAME) != 0
1340 1.8 christos && !riscv_elf_is_mapping_symbols (name));
1341 1.8 christos }
1342 1.8 christos
1343 1.8 christos
1345 1.8 christos /* Indices into option argument vector for options accepting an argument.
1346 1.8 christos Use RISCV_OPTION_ARG_NONE for options accepting no argument. */
1347 1.8 christos
1348 1.8 christos typedef enum
1349 1.8 christos {
1350 1.8 christos RISCV_OPTION_ARG_NONE = -1,
1351 1.8 christos RISCV_OPTION_ARG_PRIV_SPEC,
1352 1.8 christos
1353 1.8 christos RISCV_OPTION_ARG_COUNT
1354 1.8 christos } riscv_option_arg_t;
1355 1.8 christos
1356 1.8 christos /* Valid RISCV disassembler options. */
1357 1.8 christos
1358 1.8 christos static struct
1359 1.8 christos {
1360 1.8 christos const char *name;
1361 1.8 christos const char *description;
1362 1.8 christos riscv_option_arg_t arg;
1363 1.8 christos } riscv_options[] =
1364 1.8 christos {
1365 1.8 christos { "numeric",
1366 1.8 christos N_("Print numeric register names, rather than ABI names."),
1367 1.8 christos RISCV_OPTION_ARG_NONE },
1368 1.8 christos { "no-aliases",
1369 1.8 christos N_("Disassemble only into canonical instructions."),
1370 1.8 christos RISCV_OPTION_ARG_NONE },
1371 1.8 christos { "priv-spec=",
1372 1.8 christos N_("Print the CSR according to the chosen privilege spec."),
1373 1.8 christos RISCV_OPTION_ARG_PRIV_SPEC }
1374 1.8 christos };
1375 1.8 christos
1376 1.8 christos /* Build the structure representing valid RISCV disassembler options.
1377 1.8 christos This is done dynamically for maintenance ease purpose; a static
1378 1.8 christos initializer would be unreadable. */
1379 1.8 christos
1380 1.8 christos const disasm_options_and_args_t *
1381 1.8 christos disassembler_options_riscv (void)
1382 1.8 christos {
1383 1.8 christos static disasm_options_and_args_t *opts_and_args;
1384 1.8 christos
1385 1.8 christos if (opts_and_args == NULL)
1386 1.8 christos {
1387 1.8 christos size_t num_options = ARRAY_SIZE (riscv_options);
1388 1.8 christos size_t num_args = RISCV_OPTION_ARG_COUNT;
1389 1.8 christos disasm_option_arg_t *args;
1390 1.8 christos disasm_options_t *opts;
1391 1.8 christos size_t i, priv_spec_count;
1392 1.8 christos
1393 1.8 christos args = XNEWVEC (disasm_option_arg_t, num_args + 1);
1394 1.8 christos
1395 1.8 christos args[RISCV_OPTION_ARG_PRIV_SPEC].name = "SPEC";
1396 1.8 christos priv_spec_count = PRIV_SPEC_CLASS_DRAFT - PRIV_SPEC_CLASS_NONE - 1;
1397 1.8 christos args[RISCV_OPTION_ARG_PRIV_SPEC].values
1398 1.8 christos = XNEWVEC (const char *, priv_spec_count + 1);
1399 1.8 christos for (i = 0; i < priv_spec_count; i++)
1400 1.8 christos args[RISCV_OPTION_ARG_PRIV_SPEC].values[i]
1401 1.8 christos = riscv_priv_specs[i].name;
1402 1.8 christos /* The array we return must be NULL terminated. */
1403 1.8 christos args[RISCV_OPTION_ARG_PRIV_SPEC].values[i] = NULL;
1404 1.8 christos
1405 1.8 christos /* The array we return must be NULL terminated. */
1406 1.8 christos args[num_args].name = NULL;
1407 1.8 christos args[num_args].values = NULL;
1408 1.8 christos
1409 1.8 christos opts_and_args = XNEW (disasm_options_and_args_t);
1410 1.8 christos opts_and_args->args = args;
1411 1.8 christos
1412 1.8 christos opts = &opts_and_args->options;
1413 1.8 christos opts->name = XNEWVEC (const char *, num_options + 1);
1414 1.8 christos opts->description = XNEWVEC (const char *, num_options + 1);
1415 1.8 christos opts->arg = XNEWVEC (const disasm_option_arg_t *, num_options + 1);
1416 1.8 christos for (i = 0; i < num_options; i++)
1417 1.8 christos {
1418 1.8 christos opts->name[i] = riscv_options[i].name;
1419 1.8 christos opts->description[i] = _(riscv_options[i].description);
1420 1.8 christos if (riscv_options[i].arg != RISCV_OPTION_ARG_NONE)
1421 1.8 christos opts->arg[i] = &args[riscv_options[i].arg];
1422 1.8 christos else
1423 1.8 christos opts->arg[i] = NULL;
1424 1.8 christos }
1425 1.8 christos /* The array we return must be NULL terminated. */
1426 1.8 christos opts->name[i] = NULL;
1427 1.8 christos opts->description[i] = NULL;
1428 1.8 christos opts->arg[i] = NULL;
1429 1.8 christos }
1430 1.8 christos
1431 1.7 christos return opts_and_args;
1432 1.7 christos }
1433 1.1 matt
1434 1.1 matt void
1435 1.1 matt print_riscv_disassembler_options (FILE *stream)
1436 1.8 christos {
1437 1.8 christos const disasm_options_and_args_t *opts_and_args;
1438 1.8 christos const disasm_option_arg_t *args;
1439 1.8 christos const disasm_options_t *opts;
1440 1.8 christos size_t max_len = 0;
1441 1.8 christos size_t i;
1442 1.8 christos size_t j;
1443 1.8 christos
1444 1.8 christos opts_and_args = disassembler_options_riscv ();
1445 1.8 christos opts = &opts_and_args->options;
1446 1.8 christos args = opts_and_args->args;
1447 1.1 matt
1448 1.8 christos fprintf (stream, _("\n\
1449 1.1 matt The following RISC-V specific disassembler options are supported for use\n\
1450 1.8 christos with the -M switch (multiple options should be separated by commas):\n"));
1451 1.8 christos fprintf (stream, "\n");
1452 1.8 christos
1453 1.8 christos /* Compute the length of the longest option name. */
1454 1.8 christos for (i = 0; opts->name[i] != NULL; i++)
1455 1.8 christos {
1456 1.8 christos size_t len = strlen (opts->name[i]);
1457 1.8 christos
1458 1.8 christos if (opts->arg[i] != NULL)
1459 1.8 christos len += strlen (opts->arg[i]->name);
1460 1.8 christos if (max_len < len)
1461 1.8 christos max_len = len;
1462 1.1 matt }
1463 1.8 christos
1464 1.8 christos for (i = 0, max_len++; opts->name[i] != NULL; i++)
1465 1.8 christos {
1466 1.8 christos fprintf (stream, " %s", opts->name[i]);
1467 1.8 christos if (opts->arg[i] != NULL)
1468 1.8 christos fprintf (stream, "%s", opts->arg[i]->name);
1469 1.8 christos if (opts->description[i] != NULL)
1470 1.8 christos {
1471 1.8 christos size_t len = strlen (opts->name[i]);
1472 1.8 christos
1473 1.8 christos if (opts->arg != NULL && opts->arg[i] != NULL)
1474 1.8 christos len += strlen (opts->arg[i]->name);
1475 1.8 christos fprintf (stream, "%*c %s", (int) (max_len - len), ' ',
1476 1.8 christos opts->description[i]);
1477 1.8 christos }
1478 1.8 christos fprintf (stream, "\n");
1479 1.1 matt }
1480 1.8 christos
1481 1.8 christos for (i = 0; args[i].name != NULL; i++)
1482 1.8.2.1 perseant {
1483 1.8.2.1 perseant if (args[i].values == NULL)
1484 1.8 christos continue;
1485 1.8 christos fprintf (stream, _("\n\
1486 1.8 christos For the options above, the following values are supported for \"%s\":\n "),
1487 1.8 christos args[i].name);
1488 1.8 christos for (j = 0; args[i].values[j] != NULL; j++)
1489 1.8 christos fprintf (stream, " %s", args[i].values[j]);
1490 1.8 christos fprintf (stream, _("\n"));
1491 1.1 matt }
1492 1.1 matt
1493 1.1 matt fprintf (stream, _("\n"));
1494 1.8.2.1 perseant }
1495 1.8.2.1 perseant
1496 1.8.2.1 perseant void disassemble_free_riscv (struct disassemble_info *info ATTRIBUTE_UNUSED)
1497 1.8.2.1 perseant {
1498 1.8.2.1 perseant riscv_release_subset_list (&riscv_subsets);
1499 }
1500