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