From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7922) id E0BB43858D20; Wed, 17 Apr 2024 10:21:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E0BB43858D20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1713349281; bh=YVsaRjuMuU2Iyz4by4goCQK+44DCcL/kJYiGA2QkBwg=; h=From:To:Subject:Date:From; b=VrXV7SHM6yWlEeLt3wfYSBSr7hc3ESYiNd6Fq0mmjlAwC+A0fGXBPJiYPxHBaMOck vmrcGeWJjtc6UJac1PnoEIlfWbkM44aeMeQwKSgNr8X3+Op4nLEeBVZbZ5VZBGsf+v C5dD5cGUaLXuIm1mq2LbDPN82cVFO+zEjHmF4cc8= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Victor Do Nascimento To: binutils-cvs@sourceware.org Subject: [binutils-gdb] aarch64: Remove asserts from operand qualifier decoders [PR31595] X-Act-Checkin: binutils-gdb X-Git-Author: Victor Do Nascimento X-Git-Refname: refs/heads/master X-Git-Oldrev: 75d277b1f506dcfbedfee3bef078dfe2b484958b X-Git-Newrev: 5b1c70bfe0d8f84dc28237d6150b7b9d57c791a8 Message-Id: <20240417102121.E0BB43858D20@sourceware.org> Date: Wed, 17 Apr 2024 10:21:21 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D5b1c70bfe0d8= f84dc28237d6150b7b9d57c791a8 commit 5b1c70bfe0d8f84dc28237d6150b7b9d57c791a8 Author: Victor Do Nascimento Date: Tue Apr 16 11:49:15 2024 +0100 aarch64: Remove asserts from operand qualifier decoders [PR31595] =20 Given that the disassembler should never abort when decoding (potentially random) data, assertion statements in the `get_*reg_qualifier_from_value' function family prove problematic. =20 Consider the random 32-bit word W, encoded in a data segment and encountered on execution of `objdump -D '. =20 If: =20 (W & ~opcode_mask) =3D=3D valid instruction =20 Then before `print_insn_aarch64_word' has a chance to report the instruction as potentially undefined, an attempt will be made to have the qualifiers for the instruction's register operands (if any) decoded. If the relevant bits do not map onto a valid qualifier for the matched instruction-like word, an abort will be triggered and the execution of objdump aborted. =20 As this scenario is perfectly feasible and, in light of the fact that objdump must successfully decode all sections of a given object file, it is not appropriate to assert in this family of functions. =20 Therefore, we add a new pseudo-qualifier `AARCH64_OPND_QLF_ERR' for handling invalid qualifier-associated values and re-purpose the assertion conditions in qualifier-retrieving functions to be the predicate guarding the returning of the calculated qualifier type. If the predicate fails, we return this new qualifier and allow the caller to handle the error as appropriate. =20 As these functions are called either from within `aarch64_extract_operand' or `do_special_decoding', both of which are expected to return non-zero values, it suffices that callers return zero upon encountering `AARCH64_OPND_QLF_ERR'. =20 Ar present the error presented in the hypothetical scenario has been encountered in `get_sreg_qualifier_from_value', but the change is made to the whole family to keep the interface consistent. =20 Bug: https://sourceware.org/PR31595 Diff: --- binutils/testsuite/binutils-all/aarch64/illegal.d | 1 + binutils/testsuite/binutils-all/aarch64/illegal.s | 3 + include/opcode/aarch64.h | 3 + opcodes/aarch64-dis.c | 98 ++++++++++++++++++-= ---- 4 files changed, 87 insertions(+), 18 deletions(-) diff --git a/binutils/testsuite/binutils-all/aarch64/illegal.d b/binutils/t= estsuite/binutils-all/aarch64/illegal.d index 4b90a1d9f39..b69318aec85 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: =20 0+000 <.*>: [ ]+0:[ ]+68ea18cc[ ]+.inst[ ]+0x68ea18cc ; undefined +[ ]+4:[ ]+9dc39839[ ]+.inst[ ]+0x9dc39839 ; undefined #pass =20 diff --git a/binutils/testsuite/binutils-all/aarch64/illegal.s b/binutils/t= estsuite/binutils-all/aarch64/illegal.s index 216cbe6f265..43668c6db55 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 als= o the address reg .inst 0x68ea18cc =20 + # 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 2fca9528c20..e8fe93ef127 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, }; =0C /* Instruction class. */ diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 96f42ae862a..b70e6da9eb7 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 =3D AARCH64_OPND_QLF_W + value; - assert (value <=3D 0x1 - && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value); - return qualifier; + if (value <=3D 0x1 + && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value) + return qualifier; + return AARCH64_OPND_QLF_ERR; } =20 /* Given VALUE, return qualifier for a vector register. This does not sup= port @@ -237,9 +238,10 @@ get_vreg_qualifier_from_value (aarch64_insn value) if (qualifier >=3D AARCH64_OPND_QLF_V_2H) qualifier +=3D 1; =20 - assert (value <=3D 0x8 - && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value); - return qualifier; + if (value <=3D 0x8 + && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value) + return qualifier; + return AARCH64_OPND_QLF_ERR; } =20 /* 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 =3D AARCH64_OPND_QLF_S_B + value; =20 - assert (value <=3D 0x4 - && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value); - return qualifier; + if (value <=3D 0x4 + && aarch64_get_qualifier_standard_value (qualifier) =3D=3D value) + return qualifier; + return AARCH64_OPND_QLF_ERR; } =20 /* 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 =3D=3D 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 =3D=3D 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; } =20 /* Operand extractors. */ @@ -355,6 +362,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch= 64_opnd_info *info, aarch64_insn value =3D extract_field (FLD_imm4_11, code, 0); /* Depend on AARCH64_OPND_Ed to determine the qualifier. */ info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; shift =3D get_logsz (aarch64_get_qualifier_esize (info->qualifier)); info->reglane.index =3D value >> shift; } @@ -374,6 +383,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch= 64_opnd_info *info, if (pos > 3) return false; info->qualifier =3D get_sreg_qualifier_from_value (pos); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; info->reglane.index =3D (unsigned) (value >> 1); } } @@ -381,6 +392,8 @@ aarch64_ext_reglane (const aarch64_operand *self, aarch= 64_opnd_info *info, { /* Need information in other operand(s) to help decoding. */ info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D 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, aarch= 64_opnd_info *info, =20 /* Need information in other operand(s) to help decoding. */ info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D 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 =3D get_vreg_qualifier_from_value ((pos << 1) | (int) Q); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return false; } else - info->qualifier =3D get_sreg_qualifier_from_value (pos); + { + info->qualifier =3D get_sreg_qualifier_from_value (pos); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; + } =20 if (info->type =3D=3D AARCH64_OPND_IMM_VLSR) /* immh @@ -773,6 +794,8 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand= *self ATTRIBUTE_UNUSED, =20 /* cmode */ info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D 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 =3D get_sreg_qualifier_from_value (value); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; } =20 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 =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; =20 /* Rn */ info->addr.base_regno =3D 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 =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; =20 /* Rn */ info->addr.base_regno =3D 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 =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D 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 =3D aarch64_get_qualifier_esize (info->qualifier); @@ -1172,6 +1203,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, a= arch64_opnd_info *info, { aarch64_insn imm; info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; =20 /* Rn */ info->addr.base_regno =3D 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 =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; shift =3D get_logsz (aarch64_get_qualifier_esize (info->qualifier)); /* Rn */ info->addr.base_regno =3D 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; =20 info->qualifier =3D get_expected_qualifier (inst, info->idx); + if (info->qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; /* Rn */ info->addr.base_regno =3D extract_field (self->fields[0], code, 0); /* simm10 */ @@ -2467,6 +2504,8 @@ decode_sizeq (aarch64_inst *inst) if (mask =3D=3D 0x7) { inst->operands[idx].qualifier =3D get_vreg_qualifier_from_value (val= ue); + if (inst->operands[idx].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; return 1; } =20 @@ -2649,6 +2688,8 @@ do_special_decoding (aarch64_inst *inst) idx =3D select_operand_for_sf_field_coding (inst->opcode); value =3D extract_field (FLD_sf, inst->value, 0); inst->operands[idx].qualifier =3D get_greg_qualifier_from_value (val= ue); + if (inst->operands[idx].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; if ((inst->opcode->flags & F_N) && extract_field (FLD_N, inst->value, 0) !=3D value) return 0; @@ -2659,6 +2700,8 @@ do_special_decoding (aarch64_inst *inst) idx =3D select_operand_for_sf_field_coding (inst->opcode); value =3D extract_field (FLD_lse_sz, inst->value, 0); inst->operands[idx].qualifier =3D get_greg_qualifier_from_value (val= ue); + if (inst->operands[idx].qualifier =3D=3D 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 =3D=3D AARCH64_OPND_CLASS_INT_REG) - inst->operands[i].qualifier =3D get_greg_qualifier_from_value (value = & 1); + { + inst->operands[i].qualifier =3D get_greg_qualifier_from_value (valu= e & 1); + if (inst->operands[i].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; + } else if (aarch64_operands[inst->operands[i].type].op_class =3D=3D AARCH64_OPND_CLASS_FP_REG) { value +=3D (extract_field (FLD_opc1, inst->value, 0) << 2); inst->operands[i].qualifier =3D get_sreg_qualifier_from_value (valu= e); + if (inst->operands[i].qualifier =3D=3D 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 =3D=3D 0x3) - inst->operands[idx].qualifier =3D get_sreg_qualifier_from_value (value); + { + inst->operands[idx].qualifier =3D get_sreg_qualifier_from_value (value); + if (inst->operands[idx].qualifier =3D=3D 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 =3D (unsigned) extract_field (FLD_Q, inst->value, inst->opcode->ma= sk); inst->operands[0].qualifier =3D get_vreg_qualifier_from_value ((num << 1) | Q); + if (inst->operands[0].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; + } =20 if ((inst->opcode->flags & F_OPD_SIZE) && inst->opcode->iclass =3D=3D sv= e2_urqvs) @@ -2753,7 +2809,11 @@ do_special_decoding (aarch64_inst *inst) inst->opcode->mask); inst->operands[0].qualifier =3D get_vreg_qualifier_from_value (1 + (size << 1)); + if (inst->operands[0].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; inst->operands[2].qualifier =3D get_sreg_qualifier_from_value (size); + if (inst->operands[2].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; } =20 if (inst->opcode->flags & F_GPRSIZE_IN_Q) @@ -2772,6 +2832,8 @@ do_special_decoding (aarch64_inst *inst) assert (idx =3D=3D 0 || idx =3D=3D 1); value =3D extract_field (FLD_Q, inst->value, 0); inst->operands[idx].qualifier =3D get_greg_qualifier_from_value (val= ue); + if (inst->operands[idx].qualifier =3D=3D AARCH64_OPND_QLF_ERR) + return 0; } =20 if (inst->opcode->flags & F_LDS_SIZE)