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