Home | History | Annotate | Line # | Download | only in opcodes
riscv-dis.c revision 1.1.1.1
      1      1.1      matt /* RISC-V disassembler
      2  1.1.1.1  christos    Copyright (C) 2011-2018 Free Software Foundation, Inc.
      3      1.1      matt 
      4  1.1.1.1  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.1.1.1  christos    along with this program; see the file COPYING3. If not,
     21  1.1.1.1  christos    see <http://www.gnu.org/licenses/>.  */
     22      1.1      matt 
     23      1.1      matt #include "sysdep.h"
     24  1.1.1.1  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.1      matt 
     31      1.1      matt #include <stdint.h>
     32  1.1.1.1  christos #include <ctype.h>
     33      1.1      matt 
     34      1.1      matt struct riscv_private_data
     35      1.1      matt {
     36      1.1      matt   bfd_vma gp;
     37      1.1      matt   bfd_vma print_addr;
     38      1.1      matt   bfd_vma hi_addr[OP_MASK_RD + 1];
     39      1.1      matt };
     40      1.1      matt 
     41      1.1      matt static const char * const *riscv_gpr_names;
     42      1.1      matt static const char * const *riscv_fpr_names;
     43      1.1      matt 
     44  1.1.1.1  christos /* Other options.  */
     45      1.1      matt static int no_aliases;	/* If set disassemble as most general inst.  */
     46      1.1      matt 
     47      1.1      matt static void
     48  1.1.1.1  christos set_default_riscv_dis_options (void)
     49      1.1      matt {
     50      1.1      matt   riscv_gpr_names = riscv_gpr_names_abi;
     51      1.1      matt   riscv_fpr_names = riscv_fpr_names_abi;
     52      1.1      matt   no_aliases = 0;
     53      1.1      matt }
     54      1.1      matt 
     55      1.1      matt static void
     56  1.1.1.1  christos parse_riscv_dis_option (const char *option)
     57      1.1      matt {
     58  1.1.1.1  christos   if (strcmp (option, "no-aliases") == 0)
     59  1.1.1.1  christos     no_aliases = 1;
     60  1.1.1.1  christos   else if (strcmp (option, "numeric") == 0)
     61      1.1      matt     {
     62  1.1.1.1  christos       riscv_gpr_names = riscv_gpr_names_numeric;
     63  1.1.1.1  christos       riscv_fpr_names = riscv_fpr_names_numeric;
     64      1.1      matt     }
     65  1.1.1.1  christos   else
     66      1.1      matt     {
     67  1.1.1.1  christos       /* Invalid option.  */
     68  1.1.1.1  christos       fprintf (stderr, _("Unrecognized disassembler option: %s\n"), option);
     69      1.1      matt     }
     70      1.1      matt }
     71      1.1      matt 
     72      1.1      matt static void
     73  1.1.1.1  christos parse_riscv_dis_options (const char *opts_in)
     74      1.1      matt {
     75  1.1.1.1  christos   char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
     76      1.1      matt 
     77  1.1.1.1  christos   set_default_riscv_dis_options ();
     78      1.1      matt 
     79  1.1.1.1  christos   for ( ; opt_end != NULL; opt = opt_end + 1)
     80      1.1      matt     {
     81  1.1.1.1  christos       if ((opt_end = strchr (opt, ',')) != NULL)
     82  1.1.1.1  christos 	*opt_end = 0;
     83  1.1.1.1  christos       parse_riscv_dis_option (opt);
     84      1.1      matt     }
     85  1.1.1.1  christos 
     86  1.1.1.1  christos   free (opts);
     87      1.1      matt }
     88      1.1      matt 
     89  1.1.1.1  christos /* Print one argument from an array.  */
     90      1.1      matt 
     91      1.1      matt static void
     92      1.1      matt arg_print (struct disassemble_info *info, unsigned long val,
     93      1.1      matt 	   const char* const* array, size_t size)
     94      1.1      matt {
     95      1.1      matt   const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
     96      1.1      matt   (*info->fprintf_func) (info->stream, "%s", s);
     97      1.1      matt }
     98      1.1      matt 
     99      1.1      matt static void
    100      1.1      matt maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset)
    101      1.1      matt {
    102      1.1      matt   if (pd->hi_addr[base_reg] != (bfd_vma)-1)
    103      1.1      matt     {
    104  1.1.1.1  christos       pd->print_addr = (base_reg != 0 ? pd->hi_addr[base_reg] : 0) + offset;
    105      1.1      matt       pd->hi_addr[base_reg] = -1;
    106      1.1      matt     }
    107  1.1.1.1  christos   else if (base_reg == X_GP && pd->gp != (bfd_vma)-1)
    108      1.1      matt     pd->print_addr = pd->gp + offset;
    109  1.1.1.1  christos   else if (base_reg == X_TP || base_reg == 0)
    110      1.1      matt     pd->print_addr = offset;
    111      1.1      matt }
    112      1.1      matt 
    113      1.1      matt /* Print insn arguments for 32/64-bit code.  */
    114      1.1      matt 
    115      1.1      matt static void
    116      1.1      matt print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
    117      1.1      matt {
    118      1.1      matt   struct riscv_private_data *pd = info->private_data;
    119      1.1      matt   int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
    120      1.1      matt   int rd = (l >> OP_SH_RD) & OP_MASK_RD;
    121  1.1.1.1  christos   fprintf_ftype print = info->fprintf_func;
    122      1.1      matt 
    123      1.1      matt   if (*d != '\0')
    124  1.1.1.1  christos     print (info->stream, "\t");
    125      1.1      matt 
    126      1.1      matt   for (; *d != '\0'; d++)
    127      1.1      matt     {
    128      1.1      matt       switch (*d)
    129      1.1      matt 	{
    130  1.1.1.1  christos 	case 'C': /* RVC */
    131  1.1.1.1  christos 	  switch (*++d)
    132  1.1.1.1  christos 	    {
    133  1.1.1.1  christos 	    case 's': /* RS1 x8-x15 */
    134  1.1.1.1  christos 	    case 'w': /* RS1 x8-x15 */
    135  1.1.1.1  christos 	      print (info->stream, "%s",
    136  1.1.1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
    137  1.1.1.1  christos 	      break;
    138  1.1.1.1  christos 	    case 't': /* RS2 x8-x15 */
    139  1.1.1.1  christos 	    case 'x': /* RS2 x8-x15 */
    140  1.1.1.1  christos 	      print (info->stream, "%s",
    141  1.1.1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
    142  1.1.1.1  christos 	      break;
    143  1.1.1.1  christos 	    case 'U': /* RS1, constrained to equal RD */
    144  1.1.1.1  christos 	      print (info->stream, "%s", riscv_gpr_names[rd]);
    145  1.1.1.1  christos 	      break;
    146  1.1.1.1  christos 	    case 'c': /* RS1, constrained to equal sp */
    147  1.1.1.1  christos 	      print (info->stream, "%s", riscv_gpr_names[X_SP]);
    148  1.1.1.1  christos 	      break;
    149  1.1.1.1  christos 	    case 'V': /* RS2 */
    150  1.1.1.1  christos 	      print (info->stream, "%s",
    151  1.1.1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
    152  1.1.1.1  christos 	      break;
    153  1.1.1.1  christos 	    case 'i':
    154  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SIMM3 (l));
    155  1.1.1.1  christos 	      break;
    156  1.1.1.1  christos 	    case 'o':
    157  1.1.1.1  christos 	    case 'j':
    158  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_IMM (l));
    159  1.1.1.1  christos 	      break;
    160  1.1.1.1  christos 	    case 'k':
    161  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LW_IMM (l));
    162  1.1.1.1  christos 	      break;
    163  1.1.1.1  christos 	    case 'l':
    164  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LD_IMM (l));
    165  1.1.1.1  christos 	      break;
    166  1.1.1.1  christos 	    case 'm':
    167  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LWSP_IMM (l));
    168  1.1.1.1  christos 	      break;
    169  1.1.1.1  christos 	    case 'n':
    170  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
    171  1.1.1.1  christos 	      break;
    172  1.1.1.1  christos 	    case 'K':
    173  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_ADDI4SPN_IMM (l));
    174  1.1.1.1  christos 	      break;
    175  1.1.1.1  christos 	    case 'L':
    176  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_ADDI16SP_IMM (l));
    177  1.1.1.1  christos 	      break;
    178  1.1.1.1  christos 	    case 'M':
    179  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SWSP_IMM (l));
    180  1.1.1.1  christos 	      break;
    181  1.1.1.1  christos 	    case 'N':
    182  1.1.1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SDSP_IMM (l));
    183  1.1.1.1  christos 	      break;
    184  1.1.1.1  christos 	    case 'p':
    185  1.1.1.1  christos 	      info->target = EXTRACT_RVC_B_IMM (l) + pc;
    186  1.1.1.1  christos 	      (*info->print_address_func) (info->target, info);
    187  1.1.1.1  christos 	      break;
    188  1.1.1.1  christos 	    case 'a':
    189  1.1.1.1  christos 	      info->target = EXTRACT_RVC_J_IMM (l) + pc;
    190  1.1.1.1  christos 	      (*info->print_address_func) (info->target, info);
    191  1.1.1.1  christos 	      break;
    192  1.1.1.1  christos 	    case 'u':
    193  1.1.1.1  christos 	      print (info->stream, "0x%x",
    194  1.1.1.1  christos 		     (int)(EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
    195  1.1.1.1  christos 	      break;
    196  1.1.1.1  christos 	    case '>':
    197  1.1.1.1  christos 	      print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x3f);
    198  1.1.1.1  christos 	      break;
    199  1.1.1.1  christos 	    case '<':
    200  1.1.1.1  christos 	      print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x1f);
    201  1.1.1.1  christos 	      break;
    202  1.1.1.1  christos 	    case 'T': /* floating-point RS2 */
    203  1.1.1.1  christos 	      print (info->stream, "%s",
    204  1.1.1.1  christos 		     riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
    205  1.1.1.1  christos 	      break;
    206  1.1.1.1  christos 	    case 'D': /* floating-point RS2 x8-x15 */
    207  1.1.1.1  christos 	      print (info->stream, "%s",
    208  1.1.1.1  christos 		     riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
    209  1.1.1.1  christos 	      break;
    210  1.1.1.1  christos 	    }
    211  1.1.1.1  christos 	  break;
    212      1.1      matt 
    213      1.1      matt 	case ',':
    214      1.1      matt 	case '(':
    215      1.1      matt 	case ')':
    216      1.1      matt 	case '[':
    217      1.1      matt 	case ']':
    218  1.1.1.1  christos 	  print (info->stream, "%c", *d);
    219      1.1      matt 	  break;
    220      1.1      matt 
    221      1.1      matt 	case '0':
    222  1.1.1.1  christos 	  /* Only print constant 0 if it is the last argument */
    223  1.1.1.1  christos 	  if (!d[1])
    224  1.1.1.1  christos 	    print (info->stream, "0");
    225      1.1      matt 	  break;
    226      1.1      matt 
    227      1.1      matt 	case 'b':
    228      1.1      matt 	case 's':
    229  1.1.1.1  christos 	  if ((l & MASK_JALR) == MATCH_JALR)
    230  1.1.1.1  christos 	    maybe_print_address (pd, rs1, 0);
    231  1.1.1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[rs1]);
    232      1.1      matt 	  break;
    233      1.1      matt 
    234      1.1      matt 	case 't':
    235  1.1.1.1  christos 	  print (info->stream, "%s",
    236  1.1.1.1  christos 		 riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]);
    237      1.1      matt 	  break;
    238      1.1      matt 
    239      1.1      matt 	case 'u':
    240  1.1.1.1  christos 	  print (info->stream, "0x%x",
    241  1.1.1.1  christos 		 (unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
    242      1.1      matt 	  break;
    243      1.1      matt 
    244      1.1      matt 	case 'm':
    245  1.1.1.1  christos 	  arg_print (info, EXTRACT_OPERAND (RM, l),
    246  1.1.1.1  christos 		     riscv_rm, ARRAY_SIZE (riscv_rm));
    247      1.1      matt 	  break;
    248      1.1      matt 
    249      1.1      matt 	case 'P':
    250  1.1.1.1  christos 	  arg_print (info, EXTRACT_OPERAND (PRED, l),
    251  1.1.1.1  christos 		     riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
    252      1.1      matt 	  break;
    253      1.1      matt 
    254      1.1      matt 	case 'Q':
    255  1.1.1.1  christos 	  arg_print (info, EXTRACT_OPERAND (SUCC, l),
    256  1.1.1.1  christos 		     riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
    257      1.1      matt 	  break;
    258      1.1      matt 
    259      1.1      matt 	case 'o':
    260      1.1      matt 	  maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
    261  1.1.1.1  christos 	  /* Fall through.  */
    262      1.1      matt 	case 'j':
    263  1.1.1.1  christos 	  if (((l & MASK_ADDI) == MATCH_ADDI && rs1 != 0)
    264  1.1.1.1  christos 	      || (l & MASK_JALR) == MATCH_JALR)
    265      1.1      matt 	    maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
    266  1.1.1.1  christos 	  print (info->stream, "%d", (int)EXTRACT_ITYPE_IMM (l));
    267      1.1      matt 	  break;
    268      1.1      matt 
    269      1.1      matt 	case 'q':
    270      1.1      matt 	  maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l));
    271  1.1.1.1  christos 	  print (info->stream, "%d", (int)EXTRACT_STYPE_IMM (l));
    272      1.1      matt 	  break;
    273      1.1      matt 
    274      1.1      matt 	case 'a':
    275      1.1      matt 	  info->target = EXTRACT_UJTYPE_IMM (l) + pc;
    276      1.1      matt 	  (*info->print_address_func) (info->target, info);
    277      1.1      matt 	  break;
    278      1.1      matt 
    279      1.1      matt 	case 'p':
    280      1.1      matt 	  info->target = EXTRACT_SBTYPE_IMM (l) + pc;
    281      1.1      matt 	  (*info->print_address_func) (info->target, info);
    282      1.1      matt 	  break;
    283      1.1      matt 
    284      1.1      matt 	case 'd':
    285      1.1      matt 	  if ((l & MASK_AUIPC) == MATCH_AUIPC)
    286  1.1.1.1  christos 	    pd->hi_addr[rd] = pc + EXTRACT_UTYPE_IMM (l);
    287      1.1      matt 	  else if ((l & MASK_LUI) == MATCH_LUI)
    288  1.1.1.1  christos 	    pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l);
    289  1.1.1.1  christos 	  else if ((l & MASK_C_LUI) == MATCH_C_LUI)
    290  1.1.1.1  christos 	    pd->hi_addr[rd] = EXTRACT_RVC_LUI_IMM (l);
    291  1.1.1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[rd]);
    292      1.1      matt 	  break;
    293      1.1      matt 
    294      1.1      matt 	case 'z':
    295  1.1.1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[0]);
    296      1.1      matt 	  break;
    297      1.1      matt 
    298      1.1      matt 	case '>':
    299  1.1.1.1  christos 	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMT, l));
    300      1.1      matt 	  break;
    301      1.1      matt 
    302      1.1      matt 	case '<':
    303  1.1.1.1  christos 	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMTW, l));
    304      1.1      matt 	  break;
    305      1.1      matt 
    306      1.1      matt 	case 'S':
    307      1.1      matt 	case 'U':
    308  1.1.1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[rs1]);
    309      1.1      matt 	  break;
    310      1.1      matt 
    311      1.1      matt 	case 'T':
    312  1.1.1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
    313      1.1      matt 	  break;
    314      1.1      matt 
    315      1.1      matt 	case 'D':
    316  1.1.1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[rd]);
    317      1.1      matt 	  break;
    318      1.1      matt 
    319      1.1      matt 	case 'R':
    320  1.1.1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
    321      1.1      matt 	  break;
    322      1.1      matt 
    323      1.1      matt 	case 'E':
    324      1.1      matt 	  {
    325  1.1.1.1  christos 	    const char* csr_name = NULL;
    326  1.1.1.1  christos 	    unsigned int csr = EXTRACT_OPERAND (CSR, l);
    327  1.1.1.1  christos 	    switch (csr)
    328      1.1      matt 	      {
    329  1.1.1.1  christos #define DECLARE_CSR(name, num) case num: csr_name = #name; break;
    330  1.1.1.1  christos #include "opcode/riscv-opc.h"
    331  1.1.1.1  christos #undef DECLARE_CSR
    332      1.1      matt 	      }
    333  1.1.1.1  christos 	    if (csr_name)
    334  1.1.1.1  christos 	      print (info->stream, "%s", csr_name);
    335  1.1.1.1  christos 	    else
    336  1.1.1.1  christos 	      print (info->stream, "0x%x", csr);
    337      1.1      matt 	    break;
    338      1.1      matt 	  }
    339      1.1      matt 
    340      1.1      matt 	case 'Z':
    341  1.1.1.1  christos 	  print (info->stream, "%d", rs1);
    342      1.1      matt 	  break;
    343      1.1      matt 
    344      1.1      matt 	default:
    345      1.1      matt 	  /* xgettext:c-format */
    346  1.1.1.1  christos 	  print (info->stream, _("# internal error, undefined modifier (%c)"),
    347  1.1.1.1  christos 		 *d);
    348      1.1      matt 	  return;
    349      1.1      matt 	}
    350      1.1      matt     }
    351      1.1      matt }
    352      1.1      matt 
    353      1.1      matt /* Print the RISC-V instruction at address MEMADDR in debugged memory,
    354      1.1      matt    on using INFO.  Returns length of the instruction, in bytes.
    355      1.1      matt    BIGENDIAN must be 1 if this is big-endian code, 0 if
    356      1.1      matt    this is little-endian code.  */
    357      1.1      matt 
    358      1.1      matt static int
    359      1.1      matt riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
    360      1.1      matt {
    361      1.1      matt   const struct riscv_opcode *op;
    362      1.1      matt   static bfd_boolean init = 0;
    363      1.1      matt   static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
    364      1.1      matt   struct riscv_private_data *pd;
    365      1.1      matt   int insnlen;
    366      1.1      matt 
    367  1.1.1.1  christos #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : OP_MASK_OP))
    368  1.1.1.1  christos 
    369      1.1      matt   /* Build a hash table to shorten the search time.  */
    370      1.1      matt   if (! init)
    371      1.1      matt     {
    372  1.1.1.1  christos       for (op = riscv_opcodes; op->name; op++)
    373  1.1.1.1  christos 	if (!riscv_hash[OP_HASH_IDX (op->match)])
    374  1.1.1.1  christos 	  riscv_hash[OP_HASH_IDX (op->match)] = op;
    375      1.1      matt 
    376      1.1      matt       init = 1;
    377      1.1      matt     }
    378      1.1      matt 
    379      1.1      matt   if (info->private_data == NULL)
    380      1.1      matt     {
    381      1.1      matt       int i;
    382      1.1      matt 
    383  1.1.1.1  christos       pd = info->private_data = xcalloc (1, sizeof (struct riscv_private_data));
    384      1.1      matt       pd->gp = -1;
    385      1.1      matt       pd->print_addr = -1;
    386  1.1.1.1  christos       for (i = 0; i < (int)ARRAY_SIZE (pd->hi_addr); i++)
    387      1.1      matt 	pd->hi_addr[i] = -1;
    388      1.1      matt 
    389      1.1      matt       for (i = 0; i < info->symtab_size; i++)
    390  1.1.1.1  christos 	if (strcmp (bfd_asymbol_name (info->symtab[i]), RISCV_GP_SYMBOL) == 0)
    391      1.1      matt 	  pd->gp = bfd_asymbol_value (info->symtab[i]);
    392      1.1      matt     }
    393      1.1      matt   else
    394      1.1      matt     pd = info->private_data;
    395      1.1      matt 
    396      1.1      matt   insnlen = riscv_insn_length (word);
    397      1.1      matt 
    398      1.1      matt   info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
    399      1.1      matt   info->bytes_per_line = 8;
    400      1.1      matt   info->display_endian = info->endian;
    401      1.1      matt   info->insn_info_valid = 1;
    402      1.1      matt   info->branch_delay_insns = 0;
    403      1.1      matt   info->data_size = 0;
    404      1.1      matt   info->insn_type = dis_nonbranch;
    405      1.1      matt   info->target = 0;
    406      1.1      matt   info->target2 = 0;
    407      1.1      matt 
    408  1.1.1.1  christos   op = riscv_hash[OP_HASH_IDX (word)];
    409      1.1      matt   if (op != NULL)
    410      1.1      matt     {
    411  1.1.1.1  christos       int xlen = 0;
    412  1.1.1.1  christos 
    413  1.1.1.1  christos       /* If XLEN is not known, get its value from the ELF class.  */
    414  1.1.1.1  christos       if (info->mach == bfd_mach_riscv64)
    415  1.1.1.1  christos 	xlen = 64;
    416  1.1.1.1  christos       else if (info->mach == bfd_mach_riscv32)
    417  1.1.1.1  christos 	xlen = 32;
    418  1.1.1.1  christos       else if (info->section != NULL)
    419  1.1.1.1  christos 	{
    420  1.1.1.1  christos 	  Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
    421  1.1.1.1  christos 	  xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
    422  1.1.1.1  christos 	}
    423  1.1.1.1  christos 
    424  1.1.1.1  christos       for (; op->name; op++)
    425      1.1      matt 	{
    426  1.1.1.1  christos 	  /* Does the opcode match?  */
    427  1.1.1.1  christos 	  if (! (op->match_func) (op, word))
    428  1.1.1.1  christos 	    continue;
    429  1.1.1.1  christos 	  /* Is this a pseudo-instruction and may we print it as such?  */
    430  1.1.1.1  christos 	  if (no_aliases && (op->pinfo & INSN_ALIAS))
    431  1.1.1.1  christos 	    continue;
    432  1.1.1.1  christos 	  /* Is this instruction restricted to a certain value of XLEN?  */
    433  1.1.1.1  christos 	  if (isdigit (op->subset[0]) && atoi (op->subset) != xlen)
    434  1.1.1.1  christos 	    continue;
    435  1.1.1.1  christos 
    436  1.1.1.1  christos 	  /* It's a match.  */
    437  1.1.1.1  christos 	  (*info->fprintf_func) (info->stream, "%s", op->name);
    438  1.1.1.1  christos 	  print_insn_args (op->args, word, memaddr, info);
    439  1.1.1.1  christos 
    440  1.1.1.1  christos 	  /* Try to disassemble multi-instruction addressing sequences.  */
    441  1.1.1.1  christos 	  if (pd->print_addr != (bfd_vma)-1)
    442      1.1      matt 	    {
    443  1.1.1.1  christos 	      info->target = pd->print_addr;
    444  1.1.1.1  christos 	      (*info->fprintf_func) (info->stream, " # ");
    445  1.1.1.1  christos 	      (*info->print_address_func) (info->target, info);
    446  1.1.1.1  christos 	      pd->print_addr = -1;
    447      1.1      matt 	    }
    448  1.1.1.1  christos 
    449  1.1.1.1  christos 	  return insnlen;
    450      1.1      matt 	}
    451      1.1      matt     }
    452      1.1      matt 
    453  1.1.1.1  christos   /* We did not find a match, so just print the instruction bits.  */
    454      1.1      matt   info->insn_type = dis_noninsn;
    455      1.1      matt   (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long)word);
    456      1.1      matt   return insnlen;
    457      1.1      matt }
    458      1.1      matt 
    459      1.1      matt int
    460      1.1      matt print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
    461      1.1      matt {
    462  1.1.1.1  christos   bfd_byte packet[2];
    463      1.1      matt   insn_t insn = 0;
    464      1.1      matt   bfd_vma n;
    465      1.1      matt   int status;
    466      1.1      matt 
    467  1.1.1.1  christos   if (info->disassembler_options != NULL)
    468  1.1.1.1  christos     {
    469  1.1.1.1  christos       parse_riscv_dis_options (info->disassembler_options);
    470  1.1.1.1  christos       /* Avoid repeatedly parsing the options.  */
    471  1.1.1.1  christos       info->disassembler_options = NULL;
    472  1.1.1.1  christos     }
    473  1.1.1.1  christos   else if (riscv_gpr_names == NULL)
    474  1.1.1.1  christos     set_default_riscv_dis_options ();
    475      1.1      matt 
    476      1.1      matt   /* Instructions are a sequence of 2-byte packets in little-endian order.  */
    477  1.1.1.1  christos   for (n = 0; n < sizeof (insn) && n < riscv_insn_length (insn); n += 2)
    478      1.1      matt     {
    479  1.1.1.1  christos       status = (*info->read_memory_func) (memaddr + n, packet, 2, info);
    480      1.1      matt       if (status != 0)
    481      1.1      matt 	{
    482  1.1.1.1  christos 	  /* Don't fail just because we fell off the end.  */
    483  1.1.1.1  christos 	  if (n > 0)
    484      1.1      matt 	    break;
    485      1.1      matt 	  (*info->memory_error_func) (status, memaddr, info);
    486      1.1      matt 	  return status;
    487      1.1      matt 	}
    488      1.1      matt 
    489  1.1.1.1  christos       insn |= ((insn_t) bfd_getl16 (packet)) << (8 * n);
    490      1.1      matt     }
    491      1.1      matt 
    492      1.1      matt   return riscv_disassemble_insn (memaddr, insn, info);
    493      1.1      matt }
    494      1.1      matt 
    495      1.1      matt void
    496      1.1      matt print_riscv_disassembler_options (FILE *stream)
    497      1.1      matt {
    498      1.1      matt   fprintf (stream, _("\n\
    499      1.1      matt The following RISC-V-specific disassembler options are supported for use\n\
    500      1.1      matt with the -M switch (multiple options should be separated by commas):\n"));
    501      1.1      matt 
    502      1.1      matt   fprintf (stream, _("\n\
    503  1.1.1.1  christos   numeric       Print numeric register names, rather than ABI names.\n"));
    504      1.1      matt 
    505      1.1      matt   fprintf (stream, _("\n\
    506  1.1.1.1  christos   no-aliases    Disassemble only into canonical instructions, rather\n\
    507  1.1.1.1  christos                 than into pseudoinstructions.\n"));
    508      1.1      matt 
    509      1.1      matt   fprintf (stream, _("\n"));
    510      1.1      matt }
    511