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