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