diff options
Diffstat (limited to 'opcodes/riscv-dis.c')
-rw-r--r-- | opcodes/riscv-dis.c | 439 |
1 files changed, 266 insertions, 173 deletions
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index 367004d..9c3158a 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -37,25 +37,8 @@ disassemble_info::fprintf_func which is for unstyled output. */ #define fprintf_func please_use_fprintf_styled_func_instead -/* Current XLEN for the disassembler. */ -static unsigned xlen = 0; - -/* Default ISA specification version (constant as of now). */ -static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1; - -/* 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 = -{ - &riscv_subsets, /* subset_list. */ - opcodes_error_handler,/* error_handler. */ - &xlen, /* xlen. */ - &default_isa_spec, /* isa_spec. */ - false, /* check_unknown_prefixed_ext. */ -}; +/* The earliest privilege spec supported by disassembler. */ +#define PRIV_SPEC_EARLIEST PRIV_SPEC_CLASS_1P10 struct riscv_private_data { @@ -64,50 +47,61 @@ struct riscv_private_data bfd_vma hi_addr[OP_MASK_RD + 1]; bool to_print_addr; bool has_gp; + /* Current XLEN for the disassembler. */ + unsigned xlen; + /* Default ISA specification version. */ + enum riscv_spec_class default_isa_spec; + /* Default privileged specification. */ + enum riscv_spec_class default_priv_spec; + /* Used for architecture parser. */ + riscv_parse_subset_t riscv_rps_dis; + /* Default architecture string for the object file. It will be changed once + elf architecture attribute exits. This is used for mapping symbol $x. */ + const char* default_arch; + /* Used for mapping symbols. */ + int last_map_symbol; + bfd_vma last_stop_offset; + bfd_vma last_map_symbol_boundary; + enum riscv_seg_mstate last_map_state; + asection *last_map_section; + /* Register names as used by the disassembler. */ + const char (*riscv_gpr_names)[NRC]; + const char (*riscv_fpr_names)[NRC]; + /* If set, disassemble as most general instruction. */ + bool no_aliases; + /* If set, disassemble without checking architecture string, just like what + we did at the beginning. */ + bool all_ext; }; -/* Used for mapping symbols. */ -static int last_map_symbol = -1; -static bfd_vma last_stop_offset = 0; -static bfd_vma last_map_symbol_boundary = 0; -static enum riscv_seg_mstate last_map_state = MAP_NONE; -static asection *last_map_section = NULL; - -/* Register names as used by the disassembler. */ -static const char (*riscv_gpr_names)[NRC]; -static const char (*riscv_fpr_names)[NRC]; - -/* If set, disassemble as most general instruction. */ -static bool no_aliases = false; - -/* If set, disassemble without checking architectire string, just like what - we did at the beginning. */ -static bool all_ext = false; - /* Set default RISC-V disassembler options. */ static void -set_default_riscv_dis_options (void) +set_default_riscv_dis_options (struct disassemble_info *info) { - riscv_gpr_names = riscv_gpr_names_abi; - riscv_fpr_names = riscv_fpr_names_abi; - no_aliases = false; + struct riscv_private_data *pd = info->private_data; + pd->riscv_gpr_names = riscv_gpr_names_abi; + pd->riscv_fpr_names = riscv_fpr_names_abi; + pd->no_aliases = false; + pd->all_ext = false; } /* Parse RISC-V disassembler option (without arguments). */ static bool -parse_riscv_dis_option_without_args (const char *option) +parse_riscv_dis_option_without_args (const char *option, + struct disassemble_info *info) { + struct riscv_private_data *pd = info->private_data; if (strcmp (option, "no-aliases") == 0) - no_aliases = true; + pd->no_aliases = true; else if (strcmp (option, "numeric") == 0) { - riscv_gpr_names = riscv_gpr_names_numeric; - riscv_fpr_names = riscv_fpr_names_numeric; + pd->riscv_gpr_names = riscv_gpr_names_numeric; + pd->riscv_fpr_names = riscv_fpr_names_numeric; } else if (strcmp (option, "max") == 0) - all_ext = true; + pd->all_ext = true; else return false; return true; @@ -116,11 +110,11 @@ parse_riscv_dis_option_without_args (const char *option) /* Parse RISC-V disassembler option (possibly with arguments). */ static void -parse_riscv_dis_option (const char *option) +parse_riscv_dis_option (const char *option, struct disassemble_info *info) { char *equal, *value; - if (parse_riscv_dis_option_without_args (option)) + if (parse_riscv_dis_option_without_args (option, info)) return; equal = strchr (option, '='); @@ -144,18 +138,19 @@ parse_riscv_dis_option (const char *option) value = equal + 1; if (strcmp (option, "priv-spec") == 0) { + struct riscv_private_data *pd = info->private_data; enum riscv_spec_class priv_spec = PRIV_SPEC_CLASS_NONE; const char *name = NULL; RISCV_GET_PRIV_SPEC_CLASS (value, priv_spec); - if (priv_spec == PRIV_SPEC_CLASS_NONE) + if (priv_spec < PRIV_SPEC_EARLIEST) opcodes_error_handler (_("unknown privileged spec set by %s=%s"), option, value); - else if (default_priv_spec == PRIV_SPEC_CLASS_NONE) - default_priv_spec = priv_spec; - else if (default_priv_spec != priv_spec) + else if (pd->default_priv_spec == PRIV_SPEC_CLASS_NONE) + pd->default_priv_spec = priv_spec; + else if (pd->default_priv_spec != priv_spec) { - RISCV_GET_PRIV_SPEC_NAME (name, default_priv_spec); + RISCV_GET_PRIV_SPEC_NAME (name, pd->default_priv_spec); opcodes_error_handler (_("mis-matched privilege spec set by %s=%s, " "the elf privilege attribute is %s"), option, value, name); @@ -171,17 +166,17 @@ parse_riscv_dis_option (const char *option) /* Parse RISC-V disassembler options. */ static void -parse_riscv_dis_options (const char *opts_in) +parse_riscv_dis_options (const char *opts_in, struct disassemble_info *info) { char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts; - set_default_riscv_dis_options (); + set_default_riscv_dis_options (info); for ( ; opt_end != NULL; opt = opt_end + 1) { if ((opt_end = strchr (opt, ',')) != NULL) *opt_end = 0; - parse_riscv_dis_option (opt); + parse_riscv_dis_option (opt, info); } free (opts); @@ -221,7 +216,7 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset, pd->print_addr = (bfd_vma)(int32_t) pd->print_addr; /* Fit into a 32-bit value on RV32. */ - if (xlen == 32) + if (pd->xlen == 32) pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr; } @@ -230,60 +225,61 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset, static void print_reg_list (disassemble_info *info, insn_t l) { - bool numeric = riscv_gpr_names == riscv_gpr_names_numeric; + struct riscv_private_data *pd = info->private_data; + bool numeric = pd->riscv_gpr_names == riscv_gpr_names_numeric; unsigned reg_list = (int)EXTRACT_OPERAND (REG_LIST, l); unsigned r_start = numeric ? X_S2 : X_S0; info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_RA]); + "%s", pd->riscv_gpr_names[X_RA]); if (reg_list == 5) { info->fprintf_styled_func (info->stream, dis_style_text, ","); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_S0]); + "%s", pd->riscv_gpr_names[X_S0]); } else if (reg_list == 6 || (numeric && reg_list > 6)) { info->fprintf_styled_func (info->stream, dis_style_text, ","); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_S0]); + "%s", pd->riscv_gpr_names[X_S0]); info->fprintf_styled_func (info->stream, dis_style_text, "-"); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_S1]); + "%s", pd->riscv_gpr_names[X_S1]); } if (reg_list == 15) { info->fprintf_styled_func (info->stream, dis_style_text, ","); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[r_start]); + "%s", pd->riscv_gpr_names[r_start]); info->fprintf_styled_func (info->stream, dis_style_text, "-"); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_S11]); + "%s", pd->riscv_gpr_names[X_S11]); } else if (reg_list == 7 && numeric) { info->fprintf_styled_func (info->stream, dis_style_text, ","); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[X_S2]); + "%s", pd->riscv_gpr_names[X_S2]); } else if (reg_list > 6) { info->fprintf_styled_func (info->stream, dis_style_text, ","); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[r_start]); + "%s", pd->riscv_gpr_names[r_start]); info->fprintf_styled_func (info->stream, dis_style_text, "-"); info->fprintf_styled_func (info->stream, dis_style_register, - "%s", riscv_gpr_names[reg_list + 11]); + "%s", pd->riscv_gpr_names[reg_list + 11]); } } /* Get Zcmp sp adjustment immediate. */ static int -riscv_get_spimm (insn_t l) +riscv_get_spimm (insn_t l, int xlen) { - int spimm = riscv_get_sp_base(l, *riscv_rps_dis.xlen); + int spimm = riscv_get_sp_base(l, xlen); spimm += EXTRACT_ZCMP_SPIMM (l); if (((l ^ MATCH_CM_PUSH) & MASK_CM_PUSH) == 0) spimm *= -1; @@ -326,24 +322,24 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info case 's': /* RS1 x8-x15. */ case 'w': /* RS1 x8-x15. */ print (info->stream, dis_style_register, "%s", - riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]); + pd->riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]); break; case 't': /* RS2 x8-x15. */ case 'x': /* RS2 x8-x15. */ print (info->stream, dis_style_register, "%s", - riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]); + pd->riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]); break; case 'U': /* RS1, constrained to equal RD. */ print (info->stream, dis_style_register, - "%s", riscv_gpr_names[rd]); + "%s", pd->riscv_gpr_names[rd]); break; case 'c': /* RS1, constrained to equal sp. */ print (info->stream, dis_style_register, "%s", - riscv_gpr_names[X_SP]); + pd->riscv_gpr_names[X_SP]); break; case 'V': /* RS2 */ print (info->stream, dis_style_register, "%s", - riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]); + pd->riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]); break; case 'o': case 'j': @@ -409,11 +405,11 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info break; case 'T': /* Floating-point RS2. */ print (info->stream, dis_style_register, "%s", - riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]); + pd->riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]); break; case 'D': /* Floating-point RS2 x8-x15. */ print (info->stream, dis_style_register, "%s", - riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]); + pd->riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]); break; } break; @@ -429,7 +425,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info case 'e': if (!EXTRACT_OPERAND (VWD, l)) print (info->stream, dis_style_register, "%s", - riscv_gpr_names[0]); + pd->riscv_gpr_names[0]); else print (info->stream, dis_style_register, "%s", riscv_vecr_names_numeric[EXTRACT_OPERAND (VD, l)]); @@ -517,15 +513,21 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info print (info->stream, dis_style_immediate, "0"); break; + case 'r': + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[EXTRACT_OPERAND (RS3, l)]); + break; + case 's': if ((l & MASK_JALR) == MATCH_JALR) maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l), 0); - print (info->stream, dis_style_register, "%s", riscv_gpr_names[rs1]); + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[rs1]); break; case 't': print (info->stream, dis_style_register, "%s", - riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]); + pd->riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]); break; case 'u': @@ -585,7 +587,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l); else if ((l & MASK_C_LUI) == MATCH_C_LUI) pd->hi_addr[rd] = EXTRACT_CITYPE_LUI_IMM (l); - print (info->stream, dis_style_register, "%s", riscv_gpr_names[rd]); + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[rd]); break; case 'y': @@ -594,7 +597,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info break; case 'z': - print (info->stream, dis_style_register, "%s", riscv_gpr_names[0]); + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[0]); break; case '>': @@ -609,21 +613,23 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info case 'S': case 'U': - print (info->stream, dis_style_register, "%s", riscv_fpr_names[rs1]); + print (info->stream, dis_style_register, "%s", + pd->riscv_fpr_names[rs1]); break; case 'T': print (info->stream, dis_style_register, "%s", - riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]); + pd->riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]); break; case 'D': - print (info->stream, dis_style_register, "%s", riscv_fpr_names[rd]); + print (info->stream, dis_style_register, "%s", + pd->riscv_fpr_names[rd]); break; case 'R': print (info->stream, dis_style_register, "%s", - riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]); + pd->riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]); break; case 'E': @@ -639,15 +645,15 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info riscv_csr_hash[i] = NULL; /* Set to the newest privileged version. */ - if (default_priv_spec == PRIV_SPEC_CLASS_NONE) - default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; + if (pd->default_priv_spec == PRIV_SPEC_CLASS_NONE) + pd->default_priv_spec = PRIV_SPEC_CLASS_DRAFT - 1; #define DECLARE_CSR(name, num, class, define_version, abort_version) \ if (riscv_csr_hash[num] == NULL \ && ((define_version == PRIV_SPEC_CLASS_NONE \ && abort_version == PRIV_SPEC_CLASS_NONE) \ - || (default_priv_spec >= define_version \ - && default_priv_spec < abort_version))) \ + || (pd->default_priv_spec >= define_version \ + && pd->default_priv_spec < abort_version))) \ riscv_csr_hash[num] = #name; #define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \ DECLARE_CSR (name, num, class, define_version, abort_version) @@ -656,7 +662,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info } if (riscv_csr_hash[csr] != NULL) - if (riscv_subset_supports (&riscv_rps_dis, "xtheadvector") + if (riscv_subset_supports (&pd->riscv_rps_dis, "xtheadvector") && (csr == CSR_VSTART || csr == CSR_VXSAT || csr == CSR_VXRM @@ -716,11 +722,11 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info { case '1': print (info->stream, dis_style_register, "%s", - riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG1, l))]); + pd->riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG1, l))]); break; case '2': print (info->stream, dis_style_register, "%s", - riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG2, l))]); + pd->riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG2, l))]); break; case 'b': print (info->stream, dis_style_immediate, "%d", @@ -735,7 +741,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info break; case 'p': print (info->stream, dis_style_immediate, "%d", - riscv_get_spimm (l)); + riscv_get_spimm (l, pd->xlen)); break; case 'i': case 'I': @@ -880,6 +886,37 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info break; } break; + case 'm': /* Vendor-specific (MIPS) operands. */ + switch (*++oparg) + { + case '@': + print (info->stream, dis_style_register, "0x%x", + (unsigned) EXTRACT_OPERAND (MIPS_HINT, l)); + break; + case '#': + print (info->stream, dis_style_register, "0x%x", + (unsigned) EXTRACT_OPERAND (MIPS_IMM9, l)); + break; + case '$': + print (info->stream, dis_style_immediate, "%d", + (unsigned)EXTRACT_MIPS_LDP_IMM (l)); + break; + case '%': + print (info->stream, dis_style_immediate, "%d", + (unsigned)EXTRACT_MIPS_LWP_IMM (l)); + break; + case '^': + print (info->stream, dis_style_immediate, "%d", + (unsigned)EXTRACT_MIPS_SDP_IMM (l)); + break; + case '&': + print (info->stream, dis_style_immediate, "%d", + (unsigned)EXTRACT_MIPS_SWP_IMM (l)); + break; + default: + goto undefined_modifier; + } + break; default: goto undefined_modifier; } @@ -947,21 +984,21 @@ riscv_disassemble_insn (bfd_vma memaddr, { /* If XLEN is not known, get its value from the ELF class. */ if (info->mach == bfd_mach_riscv64) - xlen = 64; + pd->xlen = 64; else if (info->mach == bfd_mach_riscv32) - xlen = 32; + pd->xlen = 32; else if (info->section != NULL) { Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner); - xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32; + pd->xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32; } /* If arch has the Zfinx extension, replace FPR with GPR. */ - if (riscv_subset_supports (&riscv_rps_dis, "zfinx")) - riscv_fpr_names = riscv_gpr_names; + if (riscv_subset_supports (&pd->riscv_rps_dis, "zfinx")) + pd->riscv_fpr_names = pd->riscv_gpr_names; else - riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi ? - riscv_fpr_names_abi : riscv_fpr_names_numeric; + pd->riscv_fpr_names = pd->riscv_gpr_names == riscv_gpr_names_abi ? + riscv_fpr_names_abi : riscv_fpr_names_numeric; for (; op->name; op++) { @@ -972,14 +1009,16 @@ riscv_disassemble_insn (bfd_vma memaddr, if (! (op->match_func) (op, word)) continue; /* Is this a pseudo-instruction and may we print it as such? */ - if (no_aliases && (op->pinfo & INSN_ALIAS)) + if (pd->no_aliases && (op->pinfo & INSN_ALIAS)) continue; /* Is this instruction restricted to a certain value of XLEN? */ - if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen)) + if ((op->xlen_requirement != 0) + && (op->xlen_requirement != pd->xlen)) continue; /* Is this instruction supported by the current architecture? */ - if (!all_ext - && !riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class)) + if (!pd->all_ext + && !riscv_multi_subset_supports (&pd->riscv_rps_dis, + op->insn_class)) continue; /* It's a match. */ @@ -1052,6 +1091,23 @@ riscv_disassemble_insn (bfd_vma memaddr, return insnlen; } +/* Decide if we need to parse the architecture string again, also record the + string into the current subset list. */ + +static void +riscv_dis_parse_subset (struct disassemble_info *info, const char *arch_new) +{ + struct riscv_private_data *pd = info->private_data; + const char *arch_subset_list = pd->riscv_rps_dis.subset_list->arch_str; + if (arch_subset_list == NULL || strcmp (arch_subset_list, arch_new) != 0) + { + riscv_release_subset_list (pd->riscv_rps_dis.subset_list); + riscv_parse_subset (&pd->riscv_rps_dis, arch_new); + riscv_arch_str (pd->xlen, pd->riscv_rps_dis.subset_list, + true/* update */); + } +} + /* If we find the suitable mapping symbol update the STATE. Otherwise, do nothing. */ @@ -1060,6 +1116,7 @@ riscv_update_map_state (int n, enum riscv_seg_mstate *state, struct disassemble_info *info) { + struct riscv_private_data *pd = info->private_data; const char *name; /* If the symbol is in a different section, ignore it. */ @@ -1068,14 +1125,16 @@ riscv_update_map_state (int n, return; name = bfd_asymbol_name(info->symtab[n]); - if (strcmp (name, "$x") == 0) - *state = MAP_INSN; - else if (strcmp (name, "$d") == 0) + if (strcmp (name, "$d") == 0) *state = MAP_DATA; + else if (strcmp (name, "$x") == 0) + { + *state = MAP_INSN; + riscv_dis_parse_subset (info, pd->default_arch); + } else if (strncmp (name, "$xrv", 4) == 0) { *state = MAP_INSN; - riscv_release_subset_list (&riscv_subsets); /* ISA mapping string may be numbered, suffixed with '.n'. Do not consider this as part of the ISA string. */ @@ -1086,11 +1145,11 @@ riscv_update_map_state (int n, char *name_substr = xmalloc (suffix_index + 1); strncpy (name_substr, name, suffix_index); name_substr[suffix_index] = '\0'; - riscv_parse_subset (&riscv_rps_dis, name_substr + 2); + riscv_dis_parse_subset (info, name_substr + 2); free (name_substr); } else - riscv_parse_subset (&riscv_rps_dis, name + 2); + riscv_dis_parse_subset (info, name + 2); } } @@ -1119,6 +1178,7 @@ static enum riscv_seg_mstate riscv_search_mapping_symbol (bfd_vma memaddr, struct disassemble_info *info) { + struct riscv_private_data *pd = info->private_data; enum riscv_seg_mstate mstate; bool from_last_map_symbol; bool found = false; @@ -1127,11 +1187,11 @@ riscv_search_mapping_symbol (bfd_vma memaddr, /* Return the last map state if the address is still within the range of the last mapping symbol. */ - if (last_map_section == info->section - && (memaddr < last_map_symbol_boundary)) - return last_map_state; + if (pd->last_map_section == info->section + && (memaddr < pd->last_map_symbol_boundary)) + return pd->last_map_state; - last_map_section = info->section; + pd->last_map_section = info->section; /* Decide whether to print the data or instruction by default, in case we can not find the corresponding mapping symbols. */ @@ -1147,17 +1207,17 @@ riscv_search_mapping_symbol (bfd_vma memaddr, /* Reset the last_map_symbol if we start to dump a new section. */ if (memaddr <= 0) - last_map_symbol = -1; + pd->last_map_symbol = -1; /* If the last stop offset is different from the current one, then don't use the last_map_symbol to search. We usually reset the info->stop_offset when handling a new section. */ - from_last_map_symbol = (last_map_symbol >= 0 - && info->stop_offset == last_stop_offset); + from_last_map_symbol = (pd->last_map_symbol >= 0 + && info->stop_offset == pd->last_stop_offset); /* Start scanning from wherever we finished last time, or the start of the function. */ - n = from_last_map_symbol ? last_map_symbol : info->symtab_pos + 1; + n = from_last_map_symbol ? pd->last_map_symbol : info->symtab_pos + 1; /* Find the suitable mapping symbol to dump. */ for (; n < info->symtab_size; n++) @@ -1182,7 +1242,7 @@ riscv_search_mapping_symbol (bfd_vma memaddr, can pick up a text mapping symbol of a preceeding section. */ if (!found) { - n = from_last_map_symbol ? last_map_symbol : info->symtab_pos; + n = from_last_map_symbol ? pd->last_map_symbol : info->symtab_pos; for (; n >= 0; n--) { @@ -1221,7 +1281,7 @@ riscv_search_mapping_symbol (bfd_vma memaddr, /* The next mapping symbol has been found, and it represents the boundary of this mapping symbol. */ found_next = true; - last_map_symbol_boundary = addr; + pd->last_map_symbol_boundary = addr; break; } } @@ -1229,12 +1289,13 @@ riscv_search_mapping_symbol (bfd_vma memaddr, /* No further mapping symbol has been found, indicating that the boundary of the current mapping symbol is the end of this section. */ if (!found_next) - last_map_symbol_boundary = info->section->vma + info->section->size; + pd->last_map_symbol_boundary = info->section->vma + + info->section->size; } /* Save the information for next use. */ - last_map_symbol = symbol; - last_stop_offset = info->stop_offset; + pd->last_map_symbol = symbol; + pd->last_stop_offset = info->stop_offset; return mstate; } @@ -1245,17 +1306,18 @@ static bfd_vma riscv_data_length (bfd_vma memaddr, disassemble_info *info) { + struct riscv_private_data *pd = info->private_data; bfd_vma length; bool found = false; length = 4; if (info->symtab_size != 0 && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour - && last_map_symbol >= 0) + && pd->last_map_symbol >= 0) { int n; enum riscv_seg_mstate m = MAP_NONE; - for (n = last_map_symbol + 1; n < info->symtab_size; n++) + for (n = pd->last_map_symbol + 1; n < info->symtab_size; n++) { bfd_vma addr = bfd_asymbol_value (info->symtab[n]); if (addr > memaddr @@ -1289,6 +1351,7 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED, disassemble_info *info) { info->display_endian = info->endian; + int i; switch (info->bytes_per_chunk) { @@ -1308,14 +1371,6 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED, (*info->fprintf_styled_func) (info->stream, dis_style_immediate, "0x%04x", (unsigned) data); break; - case 3: - info->bytes_per_line = 7; - (*info->fprintf_styled_func) - (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%06x", (unsigned) data); - break; case 4: info->bytes_per_line = 8; (*info->fprintf_styled_func) @@ -1335,7 +1390,22 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED, (unsigned long long) data); break; default: - abort (); + /* Arbitrary data so just print the bits in the shape of an .<N>byte + directive. */ + info->bytes_per_line = info->bytes_per_chunk; + (*info->fprintf_styled_func) + (info->stream, dis_style_assembler_directive, ".%dbyte", info->bytes_per_chunk); + (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t"); + (*info->fprintf_styled_func) (info->stream, dis_style_immediate, "0x"); + for (i = info->bytes_per_line; i > 0;) + { + i--; + data = bfd_get_bits (packet + i, 8, false); + (*info->fprintf_styled_func) + (info->stream, dis_style_immediate, "%02x", + (unsigned) data); + } + break; } return info->bytes_per_chunk; } @@ -1344,7 +1414,6 @@ static bool riscv_init_disasm_info (struct disassemble_info *info) { int i; - struct riscv_private_data *pd = xcalloc (1, sizeof (struct riscv_private_data)); pd->gp = 0; @@ -1352,8 +1421,8 @@ riscv_init_disasm_info (struct disassemble_info *info) 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; + pd->has_gp = false; for (i = 0; i < info->symtab_size; i++) { asymbol *sym = info->symtab[i]; @@ -1364,7 +1433,50 @@ riscv_init_disasm_info (struct disassemble_info *info) } } + pd->xlen = 0; + pd->default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1; + pd->default_priv_spec = PRIV_SPEC_CLASS_NONE; + + pd->riscv_rps_dis.subset_list = xcalloc (1, sizeof (riscv_parse_subset_t)); + pd->riscv_rps_dis.error_handler = opcodes_error_handler; + pd->riscv_rps_dis.xlen = &pd->xlen; + pd->riscv_rps_dis.isa_spec = &pd->default_isa_spec; + pd->riscv_rps_dis.check_unknown_prefixed_ext = false; + pd->default_arch = "rv64gc"; + if (info->section != NULL) + { + bfd *abfd = info->section->owner; + if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + const char *sec_name = + get_elf_backend_data (abfd)->obj_attrs_section; + if (bfd_get_section_by_name (abfd, sec_name) != NULL) + { + obj_attribute *attr = elf_known_obj_attributes_proc (abfd); + unsigned int Tag_a = Tag_RISCV_priv_spec; + unsigned int Tag_b = Tag_RISCV_priv_spec_minor; + unsigned int Tag_c = Tag_RISCV_priv_spec_revision; + riscv_get_priv_spec_class_from_numbers (attr[Tag_a].i, + attr[Tag_b].i, + attr[Tag_c].i, + &pd->default_priv_spec); + pd->default_arch = attr[Tag_RISCV_arch].s; + } + } + } + + pd->last_map_symbol = -1; + pd->last_stop_offset = 0; + pd->last_map_symbol_boundary = 0; + pd->last_map_state = MAP_NONE; + pd->last_map_section = NULL; + pd->riscv_gpr_names = NULL; + pd->riscv_fpr_names = NULL; + pd->no_aliases = false; + pd->all_ext = false; + info->private_data = pd; + riscv_dis_parse_subset (info, pd->default_arch); return true; } @@ -1398,21 +1510,21 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info) int (*riscv_disassembler) (bfd_vma, insn_t, const bfd_byte *, struct disassemble_info *); + if (info->private_data == NULL && !riscv_init_disasm_info (info)) + return -1; + if (info->disassembler_options != NULL) { - parse_riscv_dis_options (info->disassembler_options); + parse_riscv_dis_options (info->disassembler_options, info); /* Avoid repeatedly parsing the options. */ info->disassembler_options = NULL; } - else if (riscv_gpr_names == NULL) - set_default_riscv_dis_options (); - - if (info->private_data == NULL && !riscv_init_disasm_info (info)) - return -1; + else if (((struct riscv_private_data *) info->private_data)->riscv_gpr_names == NULL) + set_default_riscv_dis_options (info); mstate = riscv_search_mapping_symbol (memaddr, info); /* Save the last mapping state. */ - last_map_state = mstate; + ((struct riscv_private_data *) info->private_data)->last_map_state = mstate; /* Set the size to dump. */ if (mstate == MAP_DATA @@ -1466,33 +1578,6 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info) return (*riscv_disassembler) (memaddr, insn, packet, info); } -disassembler_ftype -riscv_get_disassembler (bfd *abfd) -{ - const char *default_arch = "rv64gc"; - - if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - const char *sec_name = get_elf_backend_data (abfd)->obj_attrs_section; - if (bfd_get_section_by_name (abfd, sec_name) != NULL) - { - obj_attribute *attr = elf_known_obj_attributes_proc (abfd); - unsigned int Tag_a = Tag_RISCV_priv_spec; - unsigned int Tag_b = Tag_RISCV_priv_spec_minor; - unsigned int Tag_c = Tag_RISCV_priv_spec_revision; - riscv_get_priv_spec_class_from_numbers (attr[Tag_a].i, - attr[Tag_b].i, - attr[Tag_c].i, - &default_priv_spec); - default_arch = attr[Tag_RISCV_arch].s; - } - } - - riscv_release_subset_list (&riscv_subsets); - riscv_parse_subset (&riscv_rps_dis, default_arch); - return print_insn_riscv; -} - /* Prevent use of the fake labels that are generated as part of the DWARF and for relaxable relocations in the assembler. */ @@ -1532,6 +1617,9 @@ static struct riscv_option_arg_t arg; } riscv_options[] = { + { "max", + N_("Disassemble without checking architecture string."), + RISCV_OPTION_ARG_NONE }, { "numeric", N_("Print numeric register names, rather than ABI names."), RISCV_OPTION_ARG_NONE }, @@ -1563,12 +1651,12 @@ disassembler_options_riscv (void) args = XNEWVEC (disasm_option_arg_t, num_args + 1); args[RISCV_OPTION_ARG_PRIV_SPEC].name = "SPEC"; - priv_spec_count = PRIV_SPEC_CLASS_DRAFT - PRIV_SPEC_CLASS_NONE - 1; + priv_spec_count = PRIV_SPEC_CLASS_DRAFT - PRIV_SPEC_EARLIEST; args[RISCV_OPTION_ARG_PRIV_SPEC].values = XNEWVEC (const char *, priv_spec_count + 1); for (i = 0; i < priv_spec_count; i++) args[RISCV_OPTION_ARG_PRIV_SPEC].values[i] - = riscv_priv_specs[i].name; + = riscv_priv_specs[PRIV_SPEC_EARLIEST - PRIV_SPEC_CLASS_NONE - 1 + i].name; /* The array we return must be NULL terminated. */ args[RISCV_OPTION_ARG_PRIV_SPEC].values[i] = NULL; @@ -1665,5 +1753,10 @@ with the -M switch (multiple options should be separated by commas):\n")); void disassemble_free_riscv (struct disassemble_info *info ATTRIBUTE_UNUSED) { - riscv_release_subset_list (&riscv_subsets); + struct riscv_private_data *pd = info->private_data; + if (pd) + { + riscv_release_subset_list (pd->riscv_rps_dis.subset_list); + free (pd->riscv_rps_dis.subset_list); + } } |