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