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