summaryrefslogtreecommitdiff
path: root/packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch
diff options
context:
space:
mode:
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.patch449
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
+