From 46e136c952e0242308db2682ba2ec4020cdcd006 Mon Sep 17 00:00:00 2001 From: Amaury de la Vieuville Date: Sat, 8 Jun 2013 13:38:52 +0000 Subject: [PATCH] ARM: fix CPS decoding when ambiguous with QADD Handle the case when the disassembler table can't tell the difference between some encodings of QADD and CPS. Add some necessary safe guards in CPS decoding as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183610 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrInfo.td | 2 ++ .../ARM/Disassembler/ARMDisassembler.cpp | 32 +++++++++++++++++++ .../ARM/basic-arm-instructions.txt | 4 +++ test/MC/Disassembler/ARM/invalid-CPS-arm.txt | 9 ++++++ 4 files changed, 47 insertions(+) create mode 100644 test/MC/Disassembler/ARM/invalid-CPS-arm.txt diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 2ea01f9378b..310c3819d9c 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -3279,9 +3279,11 @@ class AAI op27_20, bits<8> op11_4, string opc, // Saturating add/subtract +let DecoderMethod = "DecodeQADDInstruction" in def QADD : AAI<0b00010000, 0b00000101, "qadd", [(set GPRnopc:$Rd, (int_arm_qadd GPRnopc:$Rm, GPRnopc:$Rn))], (ins GPRnopc:$Rm, GPRnopc:$Rn), "\t$Rd, $Rm, $Rn">; + def QSUB : AAI<0b00010010, 0b00000101, "qsub", [(set GPRnopc:$Rd, (int_arm_qsub GPRnopc:$Rm, GPRnopc:$Rn))], (ins GPRnopc:$Rm, GPRnopc:$Rn), "\t$Rd, $Rm, $Rn">; diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 0b93f910547..bb0fc9b371e 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -359,6 +359,8 @@ static DecodeStatus DecodeThumbAddSPReg(MCInst &Inst, uint16_t Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeThumbCPS(MCInst &Inst, uint16_t Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeQADDInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeThumbBLXOffset(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeT2AddrModeImm12(MCInst &Inst, unsigned Val, @@ -1733,6 +1735,29 @@ static DecodeStatus DecodeRFEInstruction(MCInst &Inst, unsigned Insn, return S; } +static DecodeStatus DecodeQADDInstruction(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned Rd = fieldFromInstruction(Insn, 12, 4); + unsigned Rm = fieldFromInstruction(Insn, 0, 4); + unsigned Rn = fieldFromInstruction(Insn, 16, 4); + unsigned pred = fieldFromInstruction(Insn, 28, 4); + + if (pred == 0xF) + return DecodeCPSInstruction(Inst, Insn, Address, Decoder); + + if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rd, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rm, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodeGPRnopcRegisterClass(Inst, Rn, Address, Decoder))) + return MCDisassembler::Fail; + if (!Check(S, DecodePredicateOperand(Inst, pred, Address, Decoder))) + return MCDisassembler::Fail; + return S; +} + static DecodeStatus DecodeMemMultipleWritebackInstruction(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { @@ -1827,6 +1852,13 @@ static DecodeStatus DecodeCPSInstruction(MCInst &Inst, unsigned Insn, DecodeStatus S = MCDisassembler::Success; + // This decoder is called from multiple location that do not check + // the full encoding is valid before they do. + if (fieldFromInstruction(Insn, 5, 1) != 0 || + fieldFromInstruction(Insn, 16, 1) != 0 || + fieldFromInstruction(Insn, 20, 8) != 0x10) + return MCDisassembler::Fail; + // imod == '01' --> UNPREDICTABLE // NOTE: Even though this is technically UNPREDICTABLE, we choose to // return failure here. The '01' imod value is unprintable, so there's diff --git a/test/MC/Disassembler/ARM/basic-arm-instructions.txt b/test/MC/Disassembler/ARM/basic-arm-instructions.txt index 92cfe6862ed..ae4172b0705 100644 --- a/test/MC/Disassembler/ARM/basic-arm-instructions.txt +++ b/test/MC/Disassembler/ARM/basic-arm-instructions.txt @@ -454,10 +454,14 @@ # CHECK: cpsie aif # CHECK: cps #15 # CHECK: cpsid if, #10 +# CHECK: cpsid af, #17 +# CHECK: cpsie f, #26 0xc0 0x01 0x08 0xf1 0x0f 0x00 0x02 0xf1 0xca 0x00 0x0e 0xf1 +0x51 0x01 0x0e 0xf1 +0x5a 0x00 0x0a 0xf1 #------------------------------------------------------------------------------ diff --git a/test/MC/Disassembler/ARM/invalid-CPS-arm.txt b/test/MC/Disassembler/ARM/invalid-CPS-arm.txt new file mode 100644 index 00000000000..e447eb68dd9 --- /dev/null +++ b/test/MC/Disassembler/ARM/invalid-CPS-arm.txt @@ -0,0 +1,9 @@ +# CPS: various encodings that are ambiguous with other instructions + +# RUN: echo "0x9f 0xff 0x4e 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s +# RUN: echo "0x80 0x80 0x2c 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s +# RUN: echo "0xce 0x3f 0x28 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s +# RUN: echo "0x80 0x00 0x20 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s +# RUN: echo "0xa0 0x00 0x00 0xf1" | llvm-mc -triple=armv7 -disassemble 2>&1 | FileCheck %s + +# CHECK: invalid instruction encoding