Home | History | Annotate | Line # | Download | only in opcodes
riscv-dis.c revision 1.1.1.3
      1      1.1  christos /* RISC-V disassembler
      2  1.1.1.3  christos    Copyright (C) 2011-2020 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    Contributed by Andrew Waterman (andrew (at) sifive.com).
      5      1.1  christos    Based on MIPS target.
      6      1.1  christos 
      7      1.1  christos    This file is part of the GNU opcodes library.
      8      1.1  christos 
      9      1.1  christos    This library is free software; you can redistribute it and/or modify
     10      1.1  christos    it under the terms of the GNU General Public License as published by
     11      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     12      1.1  christos    any later version.
     13      1.1  christos 
     14      1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     15      1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     16      1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     17      1.1  christos    License for more details.
     18      1.1  christos 
     19      1.1  christos    You should have received a copy of the GNU General Public License
     20      1.1  christos    along with this program; see the file COPYING3. If not,
     21      1.1  christos    see <http://www.gnu.org/licenses/>.  */
     22      1.1  christos 
     23      1.1  christos #include "sysdep.h"
     24  1.1.1.2  christos #include "disassemble.h"
     25      1.1  christos #include "libiberty.h"
     26      1.1  christos #include "opcode/riscv.h"
     27      1.1  christos #include "opintl.h"
     28      1.1  christos #include "elf-bfd.h"
     29      1.1  christos #include "elf/riscv.h"
     30  1.1.1.3  christos #include "elfxx-riscv.h"
     31      1.1  christos 
     32  1.1.1.2  christos #include "bfd_stdint.h"
     33      1.1  christos #include <ctype.h>
     34      1.1  christos 
     35  1.1.1.3  christos static enum riscv_priv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
     36  1.1.1.3  christos 
     37      1.1  christos struct riscv_private_data
     38      1.1  christos {
     39      1.1  christos   bfd_vma gp;
     40      1.1  christos   bfd_vma print_addr;
     41      1.1  christos   bfd_vma hi_addr[OP_MASK_RD + 1];
     42      1.1  christos };
     43      1.1  christos 
     44      1.1  christos static const char * const *riscv_gpr_names;
     45      1.1  christos static const char * const *riscv_fpr_names;
     46      1.1  christos 
     47      1.1  christos /* Other options.  */
     48      1.1  christos static int no_aliases;	/* If set disassemble as most general inst.  */
     49      1.1  christos 
     50      1.1  christos static void
     51      1.1  christos set_default_riscv_dis_options (void)
     52      1.1  christos {
     53      1.1  christos   riscv_gpr_names = riscv_gpr_names_abi;
     54      1.1  christos   riscv_fpr_names = riscv_fpr_names_abi;
     55      1.1  christos   no_aliases = 0;
     56      1.1  christos }
     57      1.1  christos 
     58  1.1.1.3  christos static bfd_boolean
     59  1.1.1.3  christos parse_riscv_dis_option_without_args (const char *option)
     60      1.1  christos {
     61      1.1  christos   if (strcmp (option, "no-aliases") == 0)
     62      1.1  christos     no_aliases = 1;
     63      1.1  christos   else if (strcmp (option, "numeric") == 0)
     64      1.1  christos     {
     65      1.1  christos       riscv_gpr_names = riscv_gpr_names_numeric;
     66      1.1  christos       riscv_fpr_names = riscv_fpr_names_numeric;
     67      1.1  christos     }
     68      1.1  christos   else
     69  1.1.1.3  christos     return FALSE;
     70  1.1.1.3  christos   return TRUE;
     71  1.1.1.3  christos }
     72  1.1.1.3  christos 
     73  1.1.1.3  christos static void
     74  1.1.1.3  christos parse_riscv_dis_option (const char *option)
     75  1.1.1.3  christos {
     76  1.1.1.3  christos   char *equal, *value;
     77  1.1.1.3  christos 
     78  1.1.1.3  christos   if (parse_riscv_dis_option_without_args (option))
     79  1.1.1.3  christos     return;
     80  1.1.1.3  christos 
     81  1.1.1.3  christos   equal = strchr (option, '=');
     82  1.1.1.3  christos   if (equal == NULL)
     83  1.1.1.3  christos     {
     84  1.1.1.3  christos       /* The option without '=' should be defined above.  */
     85  1.1.1.3  christos       opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
     86  1.1.1.3  christos       return;
     87  1.1.1.3  christos     }
     88  1.1.1.3  christos   if (equal == option
     89  1.1.1.3  christos       || *(equal + 1) == '\0')
     90  1.1.1.3  christos     {
     91  1.1.1.3  christos       /* Invalid options with '=', no option name before '=',
     92  1.1.1.3  christos        and no value after '='.  */
     93  1.1.1.3  christos       opcodes_error_handler (_("unrecognized disassembler option with '=': %s"),
     94  1.1.1.3  christos                             option);
     95  1.1.1.3  christos       return;
     96  1.1.1.3  christos     }
     97  1.1.1.3  christos 
     98  1.1.1.3  christos   *equal = '\0';
     99  1.1.1.3  christos   value = equal + 1;
    100  1.1.1.3  christos   if (strcmp (option, "priv-spec") == 0)
    101  1.1.1.3  christos     {
    102  1.1.1.3  christos       if (!riscv_get_priv_spec_class (value, &default_priv_spec))
    103  1.1.1.3  christos        opcodes_error_handler (_("unknown privilege spec set by %s=%s"),
    104  1.1.1.3  christos                               option, value);
    105  1.1.1.3  christos     }
    106  1.1.1.3  christos   else
    107      1.1  christos     {
    108  1.1.1.2  christos       /* xgettext:c-format */
    109  1.1.1.2  christos       opcodes_error_handler (_("unrecognized disassembler option: %s"), option);
    110      1.1  christos     }
    111      1.1  christos }
    112      1.1  christos 
    113      1.1  christos static void
    114      1.1  christos parse_riscv_dis_options (const char *opts_in)
    115      1.1  christos {
    116      1.1  christos   char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
    117      1.1  christos 
    118      1.1  christos   set_default_riscv_dis_options ();
    119      1.1  christos 
    120      1.1  christos   for ( ; opt_end != NULL; opt = opt_end + 1)
    121      1.1  christos     {
    122      1.1  christos       if ((opt_end = strchr (opt, ',')) != NULL)
    123      1.1  christos 	*opt_end = 0;
    124      1.1  christos       parse_riscv_dis_option (opt);
    125      1.1  christos     }
    126      1.1  christos 
    127      1.1  christos   free (opts);
    128      1.1  christos }
    129      1.1  christos 
    130      1.1  christos /* Print one argument from an array.  */
    131      1.1  christos 
    132      1.1  christos static void
    133      1.1  christos arg_print (struct disassemble_info *info, unsigned long val,
    134      1.1  christos 	   const char* const* array, size_t size)
    135      1.1  christos {
    136      1.1  christos   const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
    137      1.1  christos   (*info->fprintf_func) (info->stream, "%s", s);
    138      1.1  christos }
    139      1.1  christos 
    140      1.1  christos static void
    141      1.1  christos maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset)
    142      1.1  christos {
    143      1.1  christos   if (pd->hi_addr[base_reg] != (bfd_vma)-1)
    144      1.1  christos     {
    145  1.1.1.2  christos       pd->print_addr = (base_reg != 0 ? pd->hi_addr[base_reg] : 0) + offset;
    146      1.1  christos       pd->hi_addr[base_reg] = -1;
    147      1.1  christos     }
    148      1.1  christos   else if (base_reg == X_GP && pd->gp != (bfd_vma)-1)
    149      1.1  christos     pd->print_addr = pd->gp + offset;
    150      1.1  christos   else if (base_reg == X_TP || base_reg == 0)
    151      1.1  christos     pd->print_addr = offset;
    152      1.1  christos }
    153      1.1  christos 
    154      1.1  christos /* Print insn arguments for 32/64-bit code.  */
    155      1.1  christos 
    156      1.1  christos static void
    157      1.1  christos print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
    158      1.1  christos {
    159      1.1  christos   struct riscv_private_data *pd = info->private_data;
    160      1.1  christos   int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
    161      1.1  christos   int rd = (l >> OP_SH_RD) & OP_MASK_RD;
    162      1.1  christos   fprintf_ftype print = info->fprintf_func;
    163      1.1  christos 
    164      1.1  christos   if (*d != '\0')
    165      1.1  christos     print (info->stream, "\t");
    166      1.1  christos 
    167      1.1  christos   for (; *d != '\0'; d++)
    168      1.1  christos     {
    169      1.1  christos       switch (*d)
    170      1.1  christos 	{
    171      1.1  christos 	case 'C': /* RVC */
    172      1.1  christos 	  switch (*++d)
    173      1.1  christos 	    {
    174      1.1  christos 	    case 's': /* RS1 x8-x15 */
    175      1.1  christos 	    case 'w': /* RS1 x8-x15 */
    176      1.1  christos 	      print (info->stream, "%s",
    177      1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
    178      1.1  christos 	      break;
    179      1.1  christos 	    case 't': /* RS2 x8-x15 */
    180      1.1  christos 	    case 'x': /* RS2 x8-x15 */
    181      1.1  christos 	      print (info->stream, "%s",
    182      1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
    183      1.1  christos 	      break;
    184      1.1  christos 	    case 'U': /* RS1, constrained to equal RD */
    185      1.1  christos 	      print (info->stream, "%s", riscv_gpr_names[rd]);
    186      1.1  christos 	      break;
    187      1.1  christos 	    case 'c': /* RS1, constrained to equal sp */
    188      1.1  christos 	      print (info->stream, "%s", riscv_gpr_names[X_SP]);
    189      1.1  christos 	      break;
    190      1.1  christos 	    case 'V': /* RS2 */
    191      1.1  christos 	      print (info->stream, "%s",
    192      1.1  christos 		     riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
    193      1.1  christos 	      break;
    194      1.1  christos 	    case 'i':
    195      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SIMM3 (l));
    196      1.1  christos 	      break;
    197  1.1.1.2  christos 	    case 'o':
    198      1.1  christos 	    case 'j':
    199      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_IMM (l));
    200      1.1  christos 	      break;
    201      1.1  christos 	    case 'k':
    202      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LW_IMM (l));
    203      1.1  christos 	      break;
    204      1.1  christos 	    case 'l':
    205      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LD_IMM (l));
    206      1.1  christos 	      break;
    207      1.1  christos 	    case 'm':
    208      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LWSP_IMM (l));
    209      1.1  christos 	      break;
    210      1.1  christos 	    case 'n':
    211      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
    212      1.1  christos 	      break;
    213      1.1  christos 	    case 'K':
    214      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_ADDI4SPN_IMM (l));
    215      1.1  christos 	      break;
    216      1.1  christos 	    case 'L':
    217      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_ADDI16SP_IMM (l));
    218      1.1  christos 	      break;
    219      1.1  christos 	    case 'M':
    220      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SWSP_IMM (l));
    221      1.1  christos 	      break;
    222      1.1  christos 	    case 'N':
    223      1.1  christos 	      print (info->stream, "%d", (int)EXTRACT_RVC_SDSP_IMM (l));
    224      1.1  christos 	      break;
    225      1.1  christos 	    case 'p':
    226      1.1  christos 	      info->target = EXTRACT_RVC_B_IMM (l) + pc;
    227      1.1  christos 	      (*info->print_address_func) (info->target, info);
    228      1.1  christos 	      break;
    229      1.1  christos 	    case 'a':
    230      1.1  christos 	      info->target = EXTRACT_RVC_J_IMM (l) + pc;
    231      1.1  christos 	      (*info->print_address_func) (info->target, info);
    232      1.1  christos 	      break;
    233      1.1  christos 	    case 'u':
    234      1.1  christos 	      print (info->stream, "0x%x",
    235      1.1  christos 		     (int)(EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
    236      1.1  christos 	      break;
    237      1.1  christos 	    case '>':
    238      1.1  christos 	      print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x3f);
    239      1.1  christos 	      break;
    240      1.1  christos 	    case '<':
    241      1.1  christos 	      print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x1f);
    242      1.1  christos 	      break;
    243      1.1  christos 	    case 'T': /* floating-point RS2 */
    244      1.1  christos 	      print (info->stream, "%s",
    245      1.1  christos 		     riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
    246      1.1  christos 	      break;
    247      1.1  christos 	    case 'D': /* floating-point RS2 x8-x15 */
    248      1.1  christos 	      print (info->stream, "%s",
    249      1.1  christos 		     riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
    250      1.1  christos 	      break;
    251      1.1  christos 	    }
    252      1.1  christos 	  break;
    253      1.1  christos 
    254      1.1  christos 	case ',':
    255      1.1  christos 	case '(':
    256      1.1  christos 	case ')':
    257      1.1  christos 	case '[':
    258      1.1  christos 	case ']':
    259      1.1  christos 	  print (info->stream, "%c", *d);
    260      1.1  christos 	  break;
    261      1.1  christos 
    262      1.1  christos 	case '0':
    263      1.1  christos 	  /* Only print constant 0 if it is the last argument */
    264      1.1  christos 	  if (!d[1])
    265      1.1  christos 	    print (info->stream, "0");
    266      1.1  christos 	  break;
    267      1.1  christos 
    268      1.1  christos 	case 'b':
    269      1.1  christos 	case 's':
    270  1.1.1.2  christos 	  if ((l & MASK_JALR) == MATCH_JALR)
    271  1.1.1.2  christos 	    maybe_print_address (pd, rs1, 0);
    272      1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[rs1]);
    273      1.1  christos 	  break;
    274      1.1  christos 
    275      1.1  christos 	case 't':
    276      1.1  christos 	  print (info->stream, "%s",
    277      1.1  christos 		 riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]);
    278      1.1  christos 	  break;
    279      1.1  christos 
    280      1.1  christos 	case 'u':
    281      1.1  christos 	  print (info->stream, "0x%x",
    282      1.1  christos 		 (unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
    283      1.1  christos 	  break;
    284      1.1  christos 
    285      1.1  christos 	case 'm':
    286      1.1  christos 	  arg_print (info, EXTRACT_OPERAND (RM, l),
    287      1.1  christos 		     riscv_rm, ARRAY_SIZE (riscv_rm));
    288      1.1  christos 	  break;
    289      1.1  christos 
    290      1.1  christos 	case 'P':
    291      1.1  christos 	  arg_print (info, EXTRACT_OPERAND (PRED, l),
    292      1.1  christos 		     riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
    293      1.1  christos 	  break;
    294      1.1  christos 
    295      1.1  christos 	case 'Q':
    296      1.1  christos 	  arg_print (info, EXTRACT_OPERAND (SUCC, l),
    297      1.1  christos 		     riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
    298      1.1  christos 	  break;
    299      1.1  christos 
    300      1.1  christos 	case 'o':
    301      1.1  christos 	  maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
    302      1.1  christos 	  /* Fall through.  */
    303      1.1  christos 	case 'j':
    304      1.1  christos 	  if (((l & MASK_ADDI) == MATCH_ADDI && rs1 != 0)
    305      1.1  christos 	      || (l & MASK_JALR) == MATCH_JALR)
    306      1.1  christos 	    maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
    307      1.1  christos 	  print (info->stream, "%d", (int)EXTRACT_ITYPE_IMM (l));
    308      1.1  christos 	  break;
    309      1.1  christos 
    310      1.1  christos 	case 'q':
    311      1.1  christos 	  maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l));
    312      1.1  christos 	  print (info->stream, "%d", (int)EXTRACT_STYPE_IMM (l));
    313      1.1  christos 	  break;
    314      1.1  christos 
    315      1.1  christos 	case 'a':
    316      1.1  christos 	  info->target = EXTRACT_UJTYPE_IMM (l) + pc;
    317      1.1  christos 	  (*info->print_address_func) (info->target, info);
    318      1.1  christos 	  break;
    319      1.1  christos 
    320      1.1  christos 	case 'p':
    321      1.1  christos 	  info->target = EXTRACT_SBTYPE_IMM (l) + pc;
    322      1.1  christos 	  (*info->print_address_func) (info->target, info);
    323      1.1  christos 	  break;
    324      1.1  christos 
    325      1.1  christos 	case 'd':
    326      1.1  christos 	  if ((l & MASK_AUIPC) == MATCH_AUIPC)
    327      1.1  christos 	    pd->hi_addr[rd] = pc + EXTRACT_UTYPE_IMM (l);
    328      1.1  christos 	  else if ((l & MASK_LUI) == MATCH_LUI)
    329      1.1  christos 	    pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l);
    330      1.1  christos 	  else if ((l & MASK_C_LUI) == MATCH_C_LUI)
    331      1.1  christos 	    pd->hi_addr[rd] = EXTRACT_RVC_LUI_IMM (l);
    332      1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[rd]);
    333      1.1  christos 	  break;
    334      1.1  christos 
    335      1.1  christos 	case 'z':
    336      1.1  christos 	  print (info->stream, "%s", riscv_gpr_names[0]);
    337      1.1  christos 	  break;
    338      1.1  christos 
    339      1.1  christos 	case '>':
    340      1.1  christos 	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMT, l));
    341      1.1  christos 	  break;
    342      1.1  christos 
    343      1.1  christos 	case '<':
    344      1.1  christos 	  print (info->stream, "0x%x", (int)EXTRACT_OPERAND (SHAMTW, l));
    345      1.1  christos 	  break;
    346      1.1  christos 
    347      1.1  christos 	case 'S':
    348      1.1  christos 	case 'U':
    349      1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[rs1]);
    350      1.1  christos 	  break;
    351      1.1  christos 
    352      1.1  christos 	case 'T':
    353      1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
    354      1.1  christos 	  break;
    355      1.1  christos 
    356      1.1  christos 	case 'D':
    357      1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[rd]);
    358      1.1  christos 	  break;
    359      1.1  christos 
    360      1.1  christos 	case 'R':
    361      1.1  christos 	  print (info->stream, "%s", riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
    362      1.1  christos 	  break;
    363      1.1  christos 
    364      1.1  christos 	case 'E':
    365      1.1  christos 	  {
    366  1.1.1.3  christos 	    static const char *riscv_csr_hash[4096];    /* Total 2^12 CSR.  */
    367  1.1.1.3  christos 	    static bfd_boolean init_csr = FALSE;
    368      1.1  christos 	    unsigned int csr = EXTRACT_OPERAND (CSR, l);
    369  1.1.1.3  christos 
    370  1.1.1.3  christos 	    if (!init_csr)
    371      1.1  christos 	      {
    372  1.1.1.3  christos 		unsigned int i;
    373  1.1.1.3  christos 		for (i = 0; i < 4096; i++)
    374  1.1.1.3  christos 		  riscv_csr_hash[i] = NULL;
    375  1.1.1.3  christos 
    376  1.1.1.3  christos 		/* Set to the newest privilege version.  */
    377  1.1.1.3  christos 		if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
    378  1.1.1.3  christos 		  default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1;
    379  1.1.1.3  christos 
    380  1.1.1.3  christos #define DECLARE_CSR(name, num, class, define_version, abort_version)	\
    381  1.1.1.3  christos 		if (riscv_csr_hash[num] == NULL 			\
    382  1.1.1.3  christos 		    && ((define_version == PRIV_SPEC_CLASS_NONE 	\
    383  1.1.1.3  christos 			 && abort_version == PRIV_SPEC_CLASS_NONE)	\
    384  1.1.1.3  christos 			|| (default_priv_spec >= define_version 	\
    385  1.1.1.3  christos 			    && default_priv_spec < abort_version)))	\
    386  1.1.1.3  christos 		  riscv_csr_hash[num] = #name;
    387  1.1.1.3  christos #define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \
    388  1.1.1.3  christos 		DECLARE_CSR (name, num, class, define_version, abort_version)
    389      1.1  christos #include "opcode/riscv-opc.h"
    390      1.1  christos #undef DECLARE_CSR
    391      1.1  christos 	      }
    392  1.1.1.3  christos 
    393  1.1.1.3  christos 	    if (riscv_csr_hash[csr] != NULL)
    394  1.1.1.3  christos 	      print (info->stream, "%s", riscv_csr_hash[csr]);
    395      1.1  christos 	    else
    396      1.1  christos 	      print (info->stream, "0x%x", csr);
    397      1.1  christos 	    break;
    398      1.1  christos 	  }
    399      1.1  christos 
    400      1.1  christos 	case 'Z':
    401      1.1  christos 	  print (info->stream, "%d", rs1);
    402      1.1  christos 	  break;
    403      1.1  christos 
    404      1.1  christos 	default:
    405      1.1  christos 	  /* xgettext:c-format */
    406      1.1  christos 	  print (info->stream, _("# internal error, undefined modifier (%c)"),
    407      1.1  christos 		 *d);
    408      1.1  christos 	  return;
    409      1.1  christos 	}
    410      1.1  christos     }
    411      1.1  christos }
    412      1.1  christos 
    413      1.1  christos /* Print the RISC-V instruction at address MEMADDR in debugged memory,
    414      1.1  christos    on using INFO.  Returns length of the instruction, in bytes.
    415      1.1  christos    BIGENDIAN must be 1 if this is big-endian code, 0 if
    416      1.1  christos    this is little-endian code.  */
    417      1.1  christos 
    418      1.1  christos static int
    419      1.1  christos riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
    420      1.1  christos {
    421      1.1  christos   const struct riscv_opcode *op;
    422      1.1  christos   static bfd_boolean init = 0;
    423      1.1  christos   static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
    424      1.1  christos   struct riscv_private_data *pd;
    425      1.1  christos   int insnlen;
    426      1.1  christos 
    427      1.1  christos #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : OP_MASK_OP))
    428      1.1  christos 
    429      1.1  christos   /* Build a hash table to shorten the search time.  */
    430      1.1  christos   if (! init)
    431      1.1  christos     {
    432      1.1  christos       for (op = riscv_opcodes; op->name; op++)
    433      1.1  christos 	if (!riscv_hash[OP_HASH_IDX (op->match)])
    434      1.1  christos 	  riscv_hash[OP_HASH_IDX (op->match)] = op;
    435      1.1  christos 
    436      1.1  christos       init = 1;
    437      1.1  christos     }
    438      1.1  christos 
    439      1.1  christos   if (info->private_data == NULL)
    440      1.1  christos     {
    441      1.1  christos       int i;
    442      1.1  christos 
    443      1.1  christos       pd = info->private_data = xcalloc (1, sizeof (struct riscv_private_data));
    444      1.1  christos       pd->gp = -1;
    445      1.1  christos       pd->print_addr = -1;
    446      1.1  christos       for (i = 0; i < (int)ARRAY_SIZE (pd->hi_addr); i++)
    447      1.1  christos 	pd->hi_addr[i] = -1;
    448      1.1  christos 
    449      1.1  christos       for (i = 0; i < info->symtab_size; i++)
    450      1.1  christos 	if (strcmp (bfd_asymbol_name (info->symtab[i]), RISCV_GP_SYMBOL) == 0)
    451      1.1  christos 	  pd->gp = bfd_asymbol_value (info->symtab[i]);
    452      1.1  christos     }
    453      1.1  christos   else
    454      1.1  christos     pd = info->private_data;
    455      1.1  christos 
    456      1.1  christos   insnlen = riscv_insn_length (word);
    457      1.1  christos 
    458  1.1.1.3  christos   /* RISC-V instructions are always little-endian.  */
    459  1.1.1.3  christos   info->endian_code = BFD_ENDIAN_LITTLE;
    460  1.1.1.3  christos 
    461      1.1  christos   info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
    462      1.1  christos   info->bytes_per_line = 8;
    463  1.1.1.3  christos   /* We don't support constant pools, so this must be code.  */
    464  1.1.1.3  christos   info->display_endian = info->endian_code;
    465      1.1  christos   info->insn_info_valid = 1;
    466      1.1  christos   info->branch_delay_insns = 0;
    467      1.1  christos   info->data_size = 0;
    468      1.1  christos   info->insn_type = dis_nonbranch;
    469      1.1  christos   info->target = 0;
    470      1.1  christos   info->target2 = 0;
    471      1.1  christos 
    472      1.1  christos   op = riscv_hash[OP_HASH_IDX (word)];
    473      1.1  christos   if (op != NULL)
    474      1.1  christos     {
    475  1.1.1.2  christos       unsigned xlen = 0;
    476      1.1  christos 
    477      1.1  christos       /* If XLEN is not known, get its value from the ELF class.  */
    478      1.1  christos       if (info->mach == bfd_mach_riscv64)
    479      1.1  christos 	xlen = 64;
    480      1.1  christos       else if (info->mach == bfd_mach_riscv32)
    481      1.1  christos 	xlen = 32;
    482      1.1  christos       else if (info->section != NULL)
    483      1.1  christos 	{
    484      1.1  christos 	  Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
    485      1.1  christos 	  xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
    486      1.1  christos 	}
    487      1.1  christos 
    488      1.1  christos       for (; op->name; op++)
    489      1.1  christos 	{
    490      1.1  christos 	  /* Does the opcode match?  */
    491      1.1  christos 	  if (! (op->match_func) (op, word))
    492      1.1  christos 	    continue;
    493      1.1  christos 	  /* Is this a pseudo-instruction and may we print it as such?  */
    494      1.1  christos 	  if (no_aliases && (op->pinfo & INSN_ALIAS))
    495      1.1  christos 	    continue;
    496      1.1  christos 	  /* Is this instruction restricted to a certain value of XLEN?  */
    497  1.1.1.2  christos 	  if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
    498      1.1  christos 	    continue;
    499      1.1  christos 
    500      1.1  christos 	  /* It's a match.  */
    501      1.1  christos 	  (*info->fprintf_func) (info->stream, "%s", op->name);
    502      1.1  christos 	  print_insn_args (op->args, word, memaddr, info);
    503      1.1  christos 
    504      1.1  christos 	  /* Try to disassemble multi-instruction addressing sequences.  */
    505      1.1  christos 	  if (pd->print_addr != (bfd_vma)-1)
    506      1.1  christos 	    {
    507      1.1  christos 	      info->target = pd->print_addr;
    508      1.1  christos 	      (*info->fprintf_func) (info->stream, " # ");
    509      1.1  christos 	      (*info->print_address_func) (info->target, info);
    510      1.1  christos 	      pd->print_addr = -1;
    511      1.1  christos 	    }
    512      1.1  christos 
    513  1.1.1.2  christos 	  /* Finish filling out insn_info fields.  */
    514  1.1.1.2  christos 	  switch (op->pinfo & INSN_TYPE)
    515  1.1.1.2  christos 	    {
    516  1.1.1.2  christos 	    case INSN_BRANCH:
    517  1.1.1.2  christos 	      info->insn_type = dis_branch;
    518  1.1.1.2  christos 	      break;
    519  1.1.1.2  christos 	    case INSN_CONDBRANCH:
    520  1.1.1.2  christos 	      info->insn_type = dis_condbranch;
    521  1.1.1.2  christos 	      break;
    522  1.1.1.2  christos 	    case INSN_JSR:
    523  1.1.1.2  christos 	      info->insn_type = dis_jsr;
    524  1.1.1.2  christos 	      break;
    525  1.1.1.2  christos 	    case INSN_DREF:
    526  1.1.1.2  christos 	      info->insn_type = dis_dref;
    527  1.1.1.2  christos 	      break;
    528  1.1.1.2  christos 	    default:
    529  1.1.1.2  christos 	      break;
    530  1.1.1.2  christos 	    }
    531  1.1.1.2  christos 
    532  1.1.1.2  christos 	  if (op->pinfo & INSN_DATA_SIZE)
    533  1.1.1.2  christos 	    {
    534  1.1.1.2  christos 	      int size = ((op->pinfo & INSN_DATA_SIZE)
    535  1.1.1.2  christos 			  >> INSN_DATA_SIZE_SHIFT);
    536  1.1.1.2  christos 	      info->data_size = 1 << (size - 1);
    537  1.1.1.2  christos 	    }
    538  1.1.1.2  christos 
    539      1.1  christos 	  return insnlen;
    540      1.1  christos 	}
    541      1.1  christos     }
    542      1.1  christos 
    543      1.1  christos   /* We did not find a match, so just print the instruction bits.  */
    544      1.1  christos   info->insn_type = dis_noninsn;
    545      1.1  christos   (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long)word);
    546      1.1  christos   return insnlen;
    547      1.1  christos }
    548      1.1  christos 
    549      1.1  christos int
    550      1.1  christos print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
    551      1.1  christos {
    552      1.1  christos   bfd_byte packet[2];
    553      1.1  christos   insn_t insn = 0;
    554      1.1  christos   bfd_vma n;
    555      1.1  christos   int status;
    556      1.1  christos 
    557      1.1  christos   if (info->disassembler_options != NULL)
    558      1.1  christos     {
    559      1.1  christos       parse_riscv_dis_options (info->disassembler_options);
    560      1.1  christos       /* Avoid repeatedly parsing the options.  */
    561      1.1  christos       info->disassembler_options = NULL;
    562      1.1  christos     }
    563      1.1  christos   else if (riscv_gpr_names == NULL)
    564      1.1  christos     set_default_riscv_dis_options ();
    565      1.1  christos 
    566      1.1  christos   /* Instructions are a sequence of 2-byte packets in little-endian order.  */
    567      1.1  christos   for (n = 0; n < sizeof (insn) && n < riscv_insn_length (insn); n += 2)
    568      1.1  christos     {
    569      1.1  christos       status = (*info->read_memory_func) (memaddr + n, packet, 2, info);
    570      1.1  christos       if (status != 0)
    571      1.1  christos 	{
    572      1.1  christos 	  /* Don't fail just because we fell off the end.  */
    573      1.1  christos 	  if (n > 0)
    574      1.1  christos 	    break;
    575      1.1  christos 	  (*info->memory_error_func) (status, memaddr, info);
    576      1.1  christos 	  return status;
    577      1.1  christos 	}
    578      1.1  christos 
    579      1.1  christos       insn |= ((insn_t) bfd_getl16 (packet)) << (8 * n);
    580      1.1  christos     }
    581      1.1  christos 
    582      1.1  christos   return riscv_disassemble_insn (memaddr, insn, info);
    583      1.1  christos }
    584      1.1  christos 
    585  1.1.1.2  christos /* Prevent use of the fake labels that are generated as part of the DWARF
    586  1.1.1.2  christos    and for relaxable relocations in the assembler.  */
    587  1.1.1.2  christos 
    588  1.1.1.2  christos bfd_boolean
    589  1.1.1.2  christos riscv_symbol_is_valid (asymbol * sym,
    590  1.1.1.2  christos                        struct disassemble_info * info ATTRIBUTE_UNUSED)
    591  1.1.1.2  christos {
    592  1.1.1.2  christos   const char * name;
    593  1.1.1.2  christos 
    594  1.1.1.2  christos   if (sym == NULL)
    595  1.1.1.2  christos     return FALSE;
    596  1.1.1.2  christos 
    597  1.1.1.2  christos   name = bfd_asymbol_name (sym);
    598  1.1.1.2  christos 
    599  1.1.1.2  christos   return (strcmp (name, RISCV_FAKE_LABEL_NAME) != 0);
    600  1.1.1.2  christos }
    601  1.1.1.2  christos 
    602      1.1  christos void
    603      1.1  christos print_riscv_disassembler_options (FILE *stream)
    604      1.1  christos {
    605      1.1  christos   fprintf (stream, _("\n\
    606      1.1  christos The following RISC-V-specific disassembler options are supported for use\n\
    607      1.1  christos with the -M switch (multiple options should be separated by commas):\n"));
    608      1.1  christos 
    609      1.1  christos   fprintf (stream, _("\n\
    610  1.1.1.3  christos   numeric         Print numeric register names, rather than ABI names.\n"));
    611  1.1.1.3  christos 
    612  1.1.1.3  christos   fprintf (stream, _("\n\
    613  1.1.1.3  christos   no-aliases      Disassemble only into canonical instructions, rather\n\
    614  1.1.1.3  christos                   than into pseudoinstructions.\n"));
    615      1.1  christos 
    616      1.1  christos   fprintf (stream, _("\n\
    617  1.1.1.3  christos   priv-spec=PRIV  Print the CSR according to the chosen privilege spec\n\
    618  1.1.1.3  christos                   (1.9, 1.9.1, 1.10, 1.11).\n"));
    619      1.1  christos 
    620      1.1  christos   fprintf (stream, _("\n"));
    621      1.1  christos }
    622