aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binutils/testsuite/binutils-all/aarch64/illegal.d1
-rw-r--r--binutils/testsuite/binutils-all/aarch64/illegal.s3
-rw-r--r--include/opcode/aarch64.h3
-rw-r--r--opcodes/aarch64-dis.c98
4 files changed, 87 insertions, 18 deletions
diff --git a/binutils/testsuite/binutils-all/aarch64/illegal.d b/binutils/testsuite/binutils-all/aarch64/illegal.d
index 4b90a1d..b69318a 100644
--- a/binutils/testsuite/binutils-all/aarch64/illegal.d
+++ b/binutils/testsuite/binutils-all/aarch64/illegal.d
@@ -8,5 +8,6 @@ Disassembly of section \.text:
0+000 <.*>:
[ ]+0:[ ]+68ea18cc[ ]+.inst[ ]+0x68ea18cc ; undefined
+[ ]+4:[ ]+9dc39839[ ]+.inst[ ]+0x9dc39839 ; undefined
#pass
diff --git a/binutils/testsuite/binutils-all/aarch64/illegal.s b/binutils/testsuite/binutils-all/aarch64/illegal.s
index 216cbe6..43668c6 100644
--- a/binutils/testsuite/binutils-all/aarch64/illegal.s
+++ b/binutils/testsuite/binutils-all/aarch64/illegal.s
@@ -4,4 +4,7 @@
# ldpsw x12, x6, [x6],#-8 ; illegal because one of the dest regs is also the address reg
.inst 0x68ea18cc
+ # illegal, resembles the opcode `ldapur' with invalid qualifier bits
+ .inst 0x9dc39839
+
# FIXME: Add more illegal instructions here.
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 2fca952..e8fe93e 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -894,6 +894,9 @@ enum aarch64_opnd_qualifier
/* Special qualifier helping retrieve qualifier information during the
decoding time (currently not in use). */
AARCH64_OPND_QLF_RETRIEVE,
+
+ /* Special qualifier used for indicating error in qualifier retrieval. */
+ AARCH64_OPND_QLF_ERR,
};
/* Instruction class. */
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 96f42ae..b70e6da 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -219,9 +219,10 @@ static inline enum aarch64_opnd_qualifier
get_greg_qualifier_from_value (aarch64_insn value)
{
enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_W + value;
- assert (value <= 0x1
- && aarch64_get_qualifier_standard_value (qualifier) == value);
- return qualifier;
+ if (value <= 0x1
+ && aarch64_get_qualifier_standard_value (qualifier) == value)
+ return qualifier;
+ return AARCH64_OPND_QLF_ERR;
}
/* Given VALUE, return qualifier for a vector register. This does not support
@@ -237,9 +238,10 @@ get_vreg_qualifier_from_value (aarch64_insn value)
if (qualifier >= AARCH64_OPND_QLF_V_2H)
qualifier += 1;
- assert (value <= 0x8
- && aarch64_get_qualifier_standard_value (qualifier) == value);
- return qualifier;
+ if (value <= 0x8
+ && aarch64_get_qualifier_standard_value (qualifier) == value)
+ return qualifier;
+ return AARCH64_OPND_QLF_ERR;
}
/* Given VALUE, return qualifier for an FP or AdvSIMD scalar register. */
@@ -248,9 +250,10 @@ get_sreg_qualifier_from_value (aarch64_insn value)
{
enum aarch64_opnd_qualifier qualifier = AARCH64_OPND_QLF_S_B + value;
- assert (value <= 0x4
- && aarch64_get_qualifier_standard_value (qualifier) == value);
- return qualifier;
+ if (value <= 0x4
+ && aarch64_get_qualifier_standard_value (qualifier) == value)
+ return qualifier;
+ return AARCH64_OPND_QLF_ERR;
}
/* Given the instruction in *INST which is probably half way through the
@@ -263,13 +266,17 @@ get_expected_qualifier (const aarch64_inst *inst, int i)
{
aarch64_opnd_qualifier_seq_t qualifiers;
/* Should not be called if the qualifier is known. */
- assert (inst->operands[i].qualifier == AARCH64_OPND_QLF_NIL);
- int invalid_count;
- if (aarch64_find_best_match (inst, inst->opcode->qualifiers_list,
- i, qualifiers, &invalid_count))
- return qualifiers[i];
+ if (inst->operands[i].qualifier == AARCH64_OPND_QLF_NIL)
+ {
+ int invalid_count;
+ if (aarch64_find_best_match (inst, inst->opcode->qualifiers_list,
+ i, qualifiers, &invalid_count))
+ return qualifiers[i];
+ else
+ return AARCH64_OPND_QLF_NIL;
+ }
else
- return AARCH64_OPND_QLF_NIL;
+ return AARCH64_OPND_QLF_ERR;
}
/* Operand extractors. */
@@ -355,6 +362,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
aarch64_insn value = extract_field (FLD_imm4_11, code, 0);
/* Depend on AARCH64_OPND_Ed to determine the qualifier. */
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier));
info->reglane.index = value >> shift;
}
@@ -374,6 +383,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
if (pos > 3)
return false;
info->qualifier = get_sreg_qualifier_from_value (pos);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
info->reglane.index = (unsigned) (value >> 1);
}
}
@@ -381,6 +392,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
{
/* Need information in other operand(s) to help decoding. */
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
switch (info->qualifier)
{
case AARCH64_OPND_QLF_S_4B:
@@ -405,6 +418,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch64_opnd_info *info,
/* Need information in other operand(s) to help decoding. */
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
switch (info->qualifier)
{
case AARCH64_OPND_QLF_S_H:
@@ -644,9 +659,15 @@ aarch64_ext_advsimd_imm_shift (const aarch64_operand *self ATTRIBUTE_UNUSED,
1xxx 1 2D */
info->qualifier =
get_vreg_qualifier_from_value ((pos << 1) | (int) Q);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return false;
}
else
- info->qualifier = get_sreg_qualifier_from_value (pos);
+ {
+ info->qualifier = get_sreg_qualifier_from_value (pos);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
+ }
if (info->type == AARCH64_OPND_IMM_VLSR)
/* immh <shift>
@@ -773,6 +794,8 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED,
/* cmode */
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
switch (info->qualifier)
{
case AARCH64_OPND_QLF_NIL:
@@ -1014,6 +1037,8 @@ aarch64_ext_ft (const aarch64_operand *self ATTRIBUTE_UNUSED,
if (value > 0x4)
return false;
info->qualifier = get_sreg_qualifier_from_value (value);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
}
return true;
@@ -1086,6 +1111,8 @@ aarch64_ext_rcpc3_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
/* Rn */
info->addr.base_regno = extract_field (self->fields[0], code, 0);
@@ -1105,6 +1132,8 @@ aarch64_ext_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
/* Rn */
info->addr.base_regno = extract_field (self->fields[0], code, 0);
@@ -1154,6 +1183,8 @@ aarch64_ext_addr_regoff (const aarch64_operand *self ATTRIBUTE_UNUSED,
/* Need information in other operand(s) to help achieve the decoding
from 'S' field. */
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
/* Get the size of the data element that is accessed, which may be
different from that of the source register size, e.g. in strb/ldrb. */
size = aarch64_get_qualifier_esize (info->qualifier);
@@ -1172,6 +1203,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info,
{
aarch64_insn imm;
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
/* Rn */
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
@@ -1210,6 +1243,8 @@ aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info,
{
int shift;
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
shift = get_logsz (aarch64_get_qualifier_esize (info->qualifier));
/* Rn */
info->addr.base_regno = extract_field (self->fields[0], code, 0);
@@ -1228,6 +1263,8 @@ aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
aarch64_insn imm;
info->qualifier = get_expected_qualifier (inst, info->idx);
+ if (info->qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
/* Rn */
info->addr.base_regno = extract_field (self->fields[0], code, 0);
/* simm10 */
@@ -2467,6 +2504,8 @@ decode_sizeq (aarch64_inst *inst)
if (mask == 0x7)
{
inst->operands[idx].qualifier = get_vreg_qualifier_from_value (value);
+ if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
return 1;
}
@@ -2649,6 +2688,8 @@ do_special_decoding (aarch64_inst *inst)
idx = select_operand_for_sf_field_coding (inst->opcode);
value = extract_field (FLD_sf, inst->value, 0);
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
+ if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
if ((inst->opcode->flags & F_N)
&& extract_field (FLD_N, inst->value, 0) != value)
return 0;
@@ -2659,6 +2700,8 @@ do_special_decoding (aarch64_inst *inst)
idx = select_operand_for_sf_field_coding (inst->opcode);
value = extract_field (FLD_lse_sz, inst->value, 0);
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
+ if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
}
/* rcpc3 'size' field. */
if (inst->opcode->flags & F_RCPC3_SIZE)
@@ -2670,12 +2713,18 @@ do_special_decoding (aarch64_inst *inst)
{
if (aarch64_operands[inst->operands[i].type].op_class
== AARCH64_OPND_CLASS_INT_REG)
- inst->operands[i].qualifier = get_greg_qualifier_from_value (value & 1);
+ {
+ inst->operands[i].qualifier = get_greg_qualifier_from_value (value & 1);
+ if (inst->operands[i].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
+ }
else if (aarch64_operands[inst->operands[i].type].op_class
== AARCH64_OPND_CLASS_FP_REG)
{
value += (extract_field (FLD_opc1, inst->value, 0) << 2);
inst->operands[i].qualifier = get_sreg_qualifier_from_value (value);
+ if (inst->operands[i].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
}
}
}
@@ -2709,7 +2758,11 @@ do_special_decoding (aarch64_inst *inst)
/* For most related instruciton, the 'size' field is fully available for
operand encoding. */
if (mask == 0x3)
- inst->operands[idx].qualifier = get_sreg_qualifier_from_value (value);
+ {
+ inst->operands[idx].qualifier = get_sreg_qualifier_from_value (value);
+ if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
+ }
else
{
get_operand_possible_qualifiers (idx, inst->opcode->qualifiers_list,
@@ -2744,6 +2797,9 @@ do_special_decoding (aarch64_inst *inst)
Q = (unsigned) extract_field (FLD_Q, inst->value, inst->opcode->mask);
inst->operands[0].qualifier =
get_vreg_qualifier_from_value ((num << 1) | Q);
+ if (inst->operands[0].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
+
}
if ((inst->opcode->flags & F_OPD_SIZE) && inst->opcode->iclass == sve2_urqvs)
@@ -2753,7 +2809,11 @@ do_special_decoding (aarch64_inst *inst)
inst->opcode->mask);
inst->operands[0].qualifier
= get_vreg_qualifier_from_value (1 + (size << 1));
+ if (inst->operands[0].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
inst->operands[2].qualifier = get_sreg_qualifier_from_value (size);
+ if (inst->operands[2].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
}
if (inst->opcode->flags & F_GPRSIZE_IN_Q)
@@ -2772,6 +2832,8 @@ do_special_decoding (aarch64_inst *inst)
assert (idx == 0 || idx == 1);
value = extract_field (FLD_Q, inst->value, 0);
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
+ if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
}
if (inst->opcode->flags & F_LDS_SIZE)