#include <stdint.h>
#include <ctype.h>
+/* Current XLEN for the disassembler. */
+unsigned xlen = 0;
+
+/* Default ISA specification version (constant as of now). */
static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
-static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
-unsigned xlen = 0;
+/* Default privileged specification
+ (as specified by the ELF attributes or the `priv-spec' option). */
+static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
static riscv_subset_list_t riscv_subsets;
static riscv_parse_subset_t riscv_rps_dis =
bfd_vma gp;
bfd_vma print_addr;
bfd_vma hi_addr[OP_MASK_RD + 1];
+ bool to_print_addr;
+ bool has_gp;
};
/* Used for mapping symbols. */
static bfd_vma last_stop_offset = 0;
enum riscv_seg_mstate last_map_state;
+/* Register names as used by the disassembler. */
static const char * const *riscv_gpr_names;
static const char * const *riscv_fpr_names;
/* If set, disassemble as most general instruction. */
static int no_aliases;
+
+/* Set default RISC-V disassembler options. */
+
static void
set_default_riscv_dis_options (void)
{
no_aliases = 0;
}
+/* Parse RISC-V disassembler option (without arguments). */
+
static bool
parse_riscv_dis_option_without_args (const char *option)
{
return true;
}
+/* Parse RISC-V disassembler option (possibly with arguments). */
+
static void
parse_riscv_dis_option (const char *option)
{
}
}
+/* Parse RISC-V disassembler options. */
+
static void
parse_riscv_dis_options (const char *opts_in)
{
(*info->fprintf_styled_func) (info->stream, dis_style_text, "%s", s);
}
+/* If we need to print an address, set its value and state. */
+
static void
maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
int wide)
pd->print_addr = (base_reg != 0 ? pd->hi_addr[base_reg] : 0) + offset;
pd->hi_addr[base_reg] = -1;
}
- else if (base_reg == X_GP && pd->gp != (bfd_vma)-1)
+ else if (base_reg == X_GP && pd->has_gp)
pd->print_addr = pd->gp + offset;
else if (base_reg == X_TP || base_reg == 0)
pd->print_addr = offset;
else
return; /* Don't print the address. */
+ pd->to_print_addr = true;
/* Sign-extend a 32-bit value to a 64-bit value. */
if (wide)
break;
case 'u':
print (info->stream, dis_style_immediate, "0x%x",
- (int)(EXTRACT_CITYPE_IMM (l) & (RISCV_BIGIMM_REACH-1)));
+ (unsigned)(EXTRACT_CITYPE_IMM (l) & (RISCV_BIGIMM_REACH-1)));
break;
case '>':
print (info->stream, dis_style_immediate, "0x%x",
- (int)EXTRACT_CITYPE_IMM (l) & 0x3f);
+ (unsigned)EXTRACT_CITYPE_IMM (l) & 0x3f);
break;
case '<':
print (info->stream, dis_style_immediate, "0x%x",
- (int)EXTRACT_CITYPE_IMM (l) & 0x1f);
+ (unsigned)EXTRACT_CITYPE_IMM (l) & 0x1f);
break;
case 'T': /* Floating-point RS2. */
print (info->stream, dis_style_register, "%s",
(int)EXTRACT_RVV_OFFSET (l));
break;
case 'm':
- if (! EXTRACT_OPERAND (VMASK, l))
- print (info->stream, dis_style_register, ",%s",
- riscv_vecm_names_numeric[0]);
+ if (!EXTRACT_OPERAND (VMASK, l))
+ {
+ print (info->stream, dis_style_text, ",");
+ print (info->stream, dis_style_register, "%s",
+ riscv_vecm_names_numeric[0]);
+ }
break;
}
break;
print (info->stream, dis_style_immediate, "0");
break;
- case 'b':
case 's':
if ((l & MASK_JALR) == MATCH_JALR)
maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 0);
break;
case 'y':
- print (info->stream, dis_style_text, "0x%x",
- (int)EXTRACT_OPERAND (BS, l));
+ print (info->stream, dis_style_immediate, "0x%x",
+ (unsigned)EXTRACT_OPERAND (BS, l));
break;
case 'z':
case '>':
print (info->stream, dis_style_immediate, "0x%x",
- (int)EXTRACT_OPERAND (SHAMT, l));
+ (unsigned)EXTRACT_OPERAND (SHAMT, l));
break;
case '<':
print (info->stream, dis_style_immediate, "0x%x",
- (int)EXTRACT_OPERAND (SHAMTW, l));
+ (unsigned)EXTRACT_OPERAND (SHAMTW, l));
break;
case 'S':
}
if (riscv_csr_hash[csr] != NULL)
- print (info->stream, dis_style_text, "%s", riscv_csr_hash[csr]);
+ print (info->stream, dis_style_register, "%s",
+ riscv_csr_hash[csr]);
else
- print (info->stream, dis_style_text, "0x%x", csr);
+ print (info->stream, dis_style_immediate, "0x%x", csr);
break;
}
case 'Y':
- print (info->stream, dis_style_text, "0x%x",
- (int) EXTRACT_OPERAND (RNUM, l));
+ print (info->stream, dis_style_immediate, "0x%x",
+ (unsigned) EXTRACT_OPERAND (RNUM, l));
break;
case 'Z':
- print (info->stream, dis_style_text, "%d", rs1);
+ print (info->stream, dis_style_immediate, "%d", rs1);
break;
+ case 'X': /* Integer immediate. */
+ {
+ size_t n;
+ size_t s;
+ bool sign;
+
+ switch (*++oparg)
+ {
+ case 'l': /* Literal. */
+ oparg++;
+ while (*oparg && *oparg != ',')
+ {
+ print (info->stream, dis_style_immediate, "%c", *oparg);
+ oparg++;
+ }
+ oparg--;
+ break;
+ case 's': /* 'XsN@S' ... N-bit signed immediate at bit S. */
+ sign = true;
+ goto print_imm;
+ case 'u': /* 'XuN@S' ... N-bit unsigned immediate at bit S. */
+ sign = false;
+ goto print_imm;
+ print_imm:
+ n = strtol (oparg + 1, (char **)&oparg, 10);
+ if (*oparg != '@')
+ goto undefined_modifier;
+ s = strtol (oparg + 1, (char **)&oparg, 10);
+ oparg--;
+
+ if (!sign)
+ print (info->stream, dis_style_immediate, "%lu",
+ (unsigned long)EXTRACT_U_IMM (n, s, l));
+ else
+ print (info->stream, dis_style_immediate, "%li",
+ (signed long)EXTRACT_S_IMM (n, s, l));
+ break;
+ default:
+ goto undefined_modifier;
+ }
+ }
+ break;
default:
+ undefined_modifier:
/* xgettext:c-format */
print (info->stream, dis_style_text,
_("# internal error, undefined modifier (%c)"),
int i;
pd = info->private_data = xcalloc (1, sizeof (struct riscv_private_data));
- pd->gp = -1;
- pd->print_addr = -1;
+ pd->gp = 0;
+ pd->print_addr = 0;
for (i = 0; i < (int)ARRAY_SIZE (pd->hi_addr); i++)
pd->hi_addr[i] = -1;
+ pd->to_print_addr = false;
+ pd->has_gp = false;
for (i = 0; i < info->symtab_size; i++)
if (strcmp (bfd_asymbol_name (info->symtab[i]), RISCV_GP_SYMBOL) == 0)
- pd->gp = bfd_asymbol_value (info->symtab[i]);
+ {
+ pd->gp = bfd_asymbol_value (info->symtab[i]);
+ pd->has_gp = true;
+ }
}
else
pd = info->private_data;
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
}
- /* If arch has ZFINX flags, use gpr for disassemble. */
- if(riscv_subset_supports (&riscv_rps_dis, "zfinx"))
+ /* If arch has the Zfinx extension, replace FPR with GPR. */
+ if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
riscv_fpr_names = riscv_gpr_names;
for (; op->name; op++)
/* Is this instruction restricted to a certain value of XLEN? */
if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
continue;
-
+ /* Is this instruction supported by the current architecture? */
if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
continue;
print_insn_args (op->args, word, memaddr, info);
/* Try to disassemble multi-instruction addressing sequences. */
- if (pd->print_addr != (bfd_vma)-1)
+ if (pd->to_print_addr)
{
info->target = pd->print_addr;
(*info->fprintf_styled_func)
(info->stream, dis_style_comment_start, " # ");
(*info->print_address_func) (info->target, info);
- pd->print_addr = -1;
+ pd->to_print_addr = false;
}
/* Finish filling out insn_info fields. */
case 4:
case 8:
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".%dbyte\t", insnlen);
+ (info->stream, dis_style_assembler_directive, ".%dbyte", insnlen);
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
(*info->fprintf_styled_func) (info->stream, dis_style_immediate,
"0x%llx", (unsigned long long) word);
break;
{
int i;
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".byte\t");
+ (info->stream, dis_style_assembler_directive, ".byte");
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
for (i = 0; i < insnlen; ++i)
{
if (i > 0)
case 1:
info->bytes_per_line = 6;
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".byte\t");
- (*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, "0x%02llx",
- (unsigned long long) data);
+ (info->stream, dis_style_assembler_directive, ".byte");
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+ (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+ "0x%02x", (unsigned)data);
break;
case 2:
info->bytes_per_line = 8;
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".short\t");
+ (info->stream, dis_style_assembler_directive, ".short");
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
(*info->fprintf_styled_func)
- (info->stream, dis_style_immediate, "0x%04llx",
- (unsigned long long) data);
+ (info->stream, dis_style_immediate, "0x%04x", (unsigned) data);
break;
case 4:
info->bytes_per_line = 8;
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".word\t");
+ (info->stream, dis_style_assembler_directive, ".word");
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
(*info->fprintf_styled_func)
- (info->stream, dis_style_immediate, "0x%08llx",
- (unsigned long long) data);
+ (info->stream, dis_style_immediate, "0x%08lx",
+ (unsigned long) data);
break;
case 8:
info->bytes_per_line = 8;
(*info->fprintf_styled_func)
- (info->stream, dis_style_assembler_directive, ".dword\t");
+ (info->stream, dis_style_assembler_directive, ".dword");
+ (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
(*info->fprintf_styled_func)
(info->stream, dis_style_immediate, "0x%016llx",
(unsigned long long) data);
int
print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
{
- bfd_byte packet[8];
+ bfd_byte packet[RISCV_MAX_INSN_LEN];
insn_t insn = 0;
bfd_vma dump_size;
int status;
for (i = 0; args[i].name != NULL; i++)
{
+ if (args[i].values == NULL)
+ continue;
fprintf (stream, _("\n\
For the options above, the following values are supported for \"%s\":\n "),
args[i].name);