diff options
Diffstat (limited to 'packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch')
-rw-r--r-- | packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch b/packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch new file mode 100644 index 0000000000..b3408486cf --- /dev/null +++ b/packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch @@ -0,0 +1,449 @@ +From 4ff1199914c652c52740a7f414c20e7eaedf5389 Mon Sep 17 00:00:00 2001 +From: Kirill Frolov <k.frolov@samsung.com> +Date: Wed, 22 May 2019 17:05:06 +0300 +Subject: [PATCH] Fixed ARM single stepper: added "ADD Rn, PC" command + emulation (#24271) + +This change fixes bug #24164: pull request #11366 adds generation of +commands which use PC-relative addressing. But ArmSingleStepper doesn't +implements support for "ADD Rn, PC" command, so when we try to debug +managed code, generated JIT can't be single stepped correctly. + +Detailed changes description: + +1) added "ADD Rn, PC" command emulation to ArmSingleStepper; +2) asserts added to JIT code generator, which prevents using of CPU +instructions, which address PC (R15) register with except of only "ADD +Rn, PC" instruction (asserts generated only in Debug builds). + +Normally PC register shouldn't be used in arithmetic commands almost in +all cases. + +Change-Id: I76b8f973aa7a8231835c9983dff879e8592eda98 +--- + src/jit/emitarm.cpp | 95 ++++++++++++++++++++++++++++++++++++++++- + src/vm/arm/armsinglestepper.cpp | 15 +++++++ + 2 files changed, 109 insertions(+), 1 deletion(-) + +diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp +index 2b8eb25..3e73599 100644 +--- a/src/jit/emitarm.cpp ++++ b/src/jit/emitarm.cpp +@@ -1671,6 +1671,7 @@ void emitter::emitIns_R_I( + { + case INS_add: + case INS_sub: ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + if ((reg == REG_SP) && insDoesNotSetFlags(flags) && ((imm & 0x01fc) == imm)) + { + fmt = IF_T1_F; +@@ -1699,6 +1700,7 @@ void emitter::emitIns_R_I( + break; + + case INS_adc: ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + emitIns_R_R_I(ins, attr, reg, reg, imm, flags); + return; + +@@ -1808,6 +1810,7 @@ void emitter::emitIns_R_I( + case INS_lsl: + case INS_lsr: + // use the Reg, Reg, Imm encoding ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + emitIns_R_R_I(ins, attr, reg, reg, imm, flags); + return; + +@@ -1871,6 +1874,7 @@ void emitter::emitIns_R_I( + break; + + case INS_cmp: ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + assert(!EA_IS_CNS_RELOC(attr)); + assert(insSetsFlags(flags)); + sf = INS_FLAGS_SET; +@@ -1905,6 +1909,7 @@ void emitter::emitIns_R_I( + case INS_cmn: + case INS_tst: + case INS_teq: ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + assert(insSetsFlags(flags)); + sf = INS_FLAGS_SET; + if (isModImmConst(imm)) +@@ -1986,6 +1991,9 @@ void emitter::emitIns_R_R( + switch (ins) + { + case INS_add: ++ // VM debugging single stepper doesn't support PC register with this instruction. ++ // (but reg2 might be PC for ADD Rn, PC instruction) ++ assert(reg1 != REG_PC); + if (insDoesNotSetFlags(flags)) + { + fmt = IF_T1_D0; +@@ -1995,6 +2003,8 @@ void emitter::emitIns_R_R( + __fallthrough; + + case INS_sub: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + // Use the Thumb-1 reg,reg,reg encoding + emitIns_R_R_R(ins, attr, reg1, reg1, reg2, flags); + return; +@@ -2021,6 +2031,8 @@ void emitter::emitIns_R_R( + break; + + case INS_cmp: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insSetsFlags(flags)); + sf = INS_FLAGS_SET; + if (isLowRegister(reg1) && isLowRegister(reg2)) +@@ -2034,6 +2046,7 @@ void emitter::emitIns_R_R( + break; + + case INS_vmov_f2i: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + assert(isGeneralRegister(reg1)); + assert(isFloatReg(reg2)); + fmt = IF_T2_VMOVS; +@@ -2041,6 +2054,7 @@ void emitter::emitIns_R_R( + break; + + case INS_vmov_i2f: ++ assert(reg2 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. + assert(isFloatReg(reg1)); + assert(isGeneralRegister(reg2)); + fmt = IF_T2_VMOVS; +@@ -2071,6 +2085,8 @@ void emitter::emitIns_R_R( + goto VCVT_COMMON; + + case INS_vmov: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(reg1 != reg2); + __fallthrough; + +@@ -2099,6 +2115,8 @@ void emitter::emitIns_R_R( + case INS_vmul: + case INS_vsub: + case INS_vdiv: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + emitIns_R_R_R(ins, attr, reg1, reg1, reg2); + return; + +@@ -2122,6 +2140,8 @@ void emitter::emitIns_R_R( + case INS_eor: + case INS_orr: + case INS_sbc: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + if (insSetsFlags(flags) && isLowRegister(reg1) && isLowRegister(reg2)) + { + fmt = IF_T1_E; +@@ -2135,6 +2155,8 @@ void emitter::emitIns_R_R( + // the same static field load which got cse'd. + // there's no reason why this assert would be true in general + // assert(reg1 != reg2); ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + // Use the Thumb-2 three register encoding + emitIns_R_R_R_I(ins, attr, reg1, reg1, reg2, 0, flags); + return; +@@ -2147,6 +2169,8 @@ void emitter::emitIns_R_R( + // arithmetic right shift were the same local variable + // there's no reason why this assert would be true in general + // assert(reg1 != reg2); ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + if (insSetsFlags(flags) && isLowRegister(reg1) && isLowRegister(reg2)) + { + fmt = IF_T1_E; +@@ -2163,7 +2187,8 @@ void emitter::emitIns_R_R( + case INS_mul: + // We will prefer the T2 encoding, unless (flags == INS_FLAGS_SET) + // The thumb-1 instruction executes much slower as it must always set the flags +- // ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + if (insMustSetFlags(flags) && isLowRegister(reg1) && isLowRegister(reg2)) + { + fmt = IF_T1_E; +@@ -2180,6 +2205,8 @@ void emitter::emitIns_R_R( + case INS_mvn: + case INS_cmn: + case INS_tst: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + if (insSetsFlags(flags) && isLowRegister(reg1) && isLowRegister(reg2)) + { + fmt = IF_T1_E; +@@ -2202,6 +2229,8 @@ void emitter::emitIns_R_R( + case INS_uxth: + assert(size == EA_2BYTE); + EXTEND_COMMON: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insDoesNotSetFlags(flags)); + if (isLowRegister(reg1) && isLowRegister(reg2)) + { +@@ -2231,6 +2260,8 @@ void emitter::emitIns_R_R( + break; + + case INS_clz: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insDoesNotSetFlags(flags)); + fmt = IF_T2_C10; + sf = INS_FLAGS_NOT_SET; +@@ -2295,6 +2326,8 @@ void emitter::emitIns_R_I_I( + { + case INS_bfc: + { ++ assert(reg != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ + int lsb = imm1; + int msb = lsb + imm2 - 1; + +@@ -2355,6 +2388,8 @@ void emitter::emitIns_R_R_I(instruction ins, + switch (ins) + { + case INS_add: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + + // Can we possibly encode the immediate 'imm' using a Thumb-1 encoding? +@@ -2376,6 +2411,8 @@ void emitter::emitIns_R_R_I(instruction ins, + __fallthrough; + + case INS_sub: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + + // Is it just a mov? +@@ -2456,6 +2493,8 @@ void emitter::emitIns_R_R_I(instruction ins, + case INS_bic: + case INS_orr: + case INS_orn: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + if (isModImmConst(imm)) + { +@@ -2486,6 +2525,8 @@ void emitter::emitIns_R_R_I(instruction ins, + break; + + case INS_rsb: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + if (imm == 0 && isLowRegister(reg1) && isLowRegister(reg2) && insSetsFlags(flags)) + { +@@ -2498,6 +2539,8 @@ void emitter::emitIns_R_R_I(instruction ins, + case INS_adc: + case INS_eor: + case INS_sbc: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + if (isModImmConst(imm)) + { +@@ -2531,6 +2574,8 @@ void emitter::emitIns_R_R_I(instruction ins, + break; + + case INS_mvn: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert((imm >= 0) && (imm <= 31)); // required for encoding + assert(!insOptAnyInc(opt)); + if (imm == 0) +@@ -2555,6 +2600,8 @@ void emitter::emitIns_R_R_I(instruction ins, + case INS_cmn: + case INS_teq: + case INS_tst: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insSetsFlags(flags)); + assert((imm >= 0) && (imm <= 31)); // required for encoding + assert(!insOptAnyInc(opt)); +@@ -2589,6 +2636,8 @@ void emitter::emitIns_R_R_I(instruction ins, + case INS_asr: + case INS_lsl: + case INS_lsr: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + + // On ARM, the immediate shift count of LSL and ROR must be between 1 and 31. For LSR and ASR, it is between +@@ -2631,6 +2680,8 @@ void emitter::emitIns_R_R_I(instruction ins, + case INS_uxth: + assert(size == EA_2BYTE); + EXTEND_COMMON: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(insOptsNone(opt)); + assert(insDoesNotSetFlags(flags)); + assert((imm & 0x018) == imm); // required for encoding +@@ -2877,6 +2928,9 @@ void emitter::emitIns_R_R_R(instruction ins, + + case INS_sub: + assert(reg3 != REG_SP); ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC || ins == INS_add); // allow ADD Rn, PC instruction in T2 encoding + + if (isLowRegister(reg1) && isLowRegister(reg2) && isLowRegister(reg3) && insSetsFlags(flags)) + { +@@ -2911,6 +2965,9 @@ void emitter::emitIns_R_R_R(instruction ins, + case INS_eor: + case INS_orr: + case INS_sbc: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); + if (reg1 == reg2) + { + // Try to encode as a Thumb-1 instruction +@@ -2920,6 +2977,9 @@ void emitter::emitIns_R_R_R(instruction ins, + __fallthrough; + + case INS_orn: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); + // Use the Thumb-2 three register encoding, with imm=0 + emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0, flags); + return; +@@ -2927,6 +2987,9 @@ void emitter::emitIns_R_R_R(instruction ins, + case INS_asr: + case INS_lsl: + case INS_lsr: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); + if (reg1 == reg2 && insSetsFlags(flags) && isLowRegister(reg1) && isLowRegister(reg3)) + { + // Use the Thumb-1 regdest,reg encoding +@@ -2936,6 +2999,9 @@ void emitter::emitIns_R_R_R(instruction ins, + __fallthrough; + + case INS_ror: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); + fmt = IF_T2_C4; + sf = insMustSetFlags(flags); + break; +@@ -2943,6 +3009,11 @@ void emitter::emitIns_R_R_R(instruction ins, + case INS_mul: + if (insMustSetFlags(flags)) + { ++ assert(reg1 != ++ REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); ++ + if ((reg1 == reg2) && isLowRegister(reg1)) + { + // Use the Thumb-1 regdest,reg encoding +@@ -2964,6 +3035,10 @@ void emitter::emitIns_R_R_R(instruction ins, + + case INS_sdiv: + case INS_udiv: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); ++ + assert(insDoesNotSetFlags(flags)); + fmt = IF_T2_C5; + sf = INS_FLAGS_NOT_SET; +@@ -3022,6 +3097,8 @@ void emitter::emitIns_R_R_R(instruction ins, + break; + + case INS_vmov_i2d: ++ assert(reg2 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg3 != REG_PC); + assert(isDoubleReg(reg1)); + assert(isGeneralRegister(reg2)); + assert(isGeneralRegister(reg3)); +@@ -3030,6 +3107,8 @@ void emitter::emitIns_R_R_R(instruction ins, + break; + + case INS_vmov_d2i: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); + assert(isGeneralRegister(reg1)); + assert(isGeneralRegister(reg2)); + assert(isDoubleReg(reg3)); +@@ -3096,6 +3175,9 @@ void emitter::emitIns_R_R_I_I(instruction ins, + switch (ins) + { + case INS_bfi: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ + assert(insDoesNotSetFlags(flags)); + imm = (lsb << 5) | msb; + +@@ -3105,6 +3187,9 @@ void emitter::emitIns_R_R_I_I(instruction ins, + + case INS_sbfx: + case INS_ubfx: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ + assert(insDoesNotSetFlags(flags)); + imm = (lsb << 5) | (width - 1); + +@@ -3189,6 +3274,9 @@ void emitter::emitIns_R_R_R_I(instruction ins, + case INS_orn: + case INS_orr: + case INS_sbc: ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); + assert((imm >= 0) && (imm <= 31)); // required for encoding + assert(!insOptAnyInc(opt)); + if (imm == 0) +@@ -3339,6 +3427,11 @@ void emitter::emitIns_R_R_R_R( + } + assert((fmt == IF_T2_F1) || (fmt == IF_T2_F2)); + ++ assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. ++ assert(reg2 != REG_PC); ++ assert(reg3 != REG_PC); ++ assert(reg4 != REG_PC); ++ + instrDesc* id = emitNewInstr(attr); + insSize isz = emitInsSize(fmt); + +diff --git a/src/vm/arm/armsinglestepper.cpp b/src/vm/arm/armsinglestepper.cpp +index e000959..72b0925 100644 +--- a/src/vm/arm/armsinglestepper.cpp ++++ b/src/vm/arm/armsinglestepper.cpp +@@ -1043,6 +1043,21 @@ bool ArmSingleStepper::TryEmulate(T_CONTEXT *pCtx, WORD opcode1, WORD opcode2, b + + fEmulated = true; + } ++ else if ((opcode1 & 0xff00) == 0x4400) ++ { ++ // A8.8.6 ADD (register, Thumb) : T2 ++ DWORD Rm = BitExtract(opcode1, 6, 3); ++ ++ // We should only emulate this instruction if Pc is used ++ if (Rm == 15) ++ fEmulated = true; ++ ++ if (execute) ++ { ++ DWORD Rd = BitExtract(opcode1, 2, 0) | BitExtract(opcode1, 7, 7) << 3; ++ SetReg(pCtx, Rd, GetReg(pCtx, Rm) + GetReg(pCtx, Rd)); ++ } ++ } + else if (((opcode1 & 0xf000) == 0xd000) && ((opcode1 & 0x0f00) != 0x0e00)) + { + // B : T1 +-- +2.7.4 + |