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