summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Frolov <k.frolov@samsung.com>2019-05-22 17:05:06 +0300
committer이형주/Common Platform Lab(SR)/Staff Engineer/삼성전자 <leee.lee@samsung.com>2019-10-31 07:20:16 +0900
commitacfc7408960548202d6ac9dc8898b1d5c9b9dea8 (patch)
treedf190c4859d0fd9a449e6cae2a74dadc13d66fd2
parent2fde2771a894da22715a46656578bc7d1dcbd6ce (diff)
downloadcoreclr-acfc7408960548202d6ac9dc8898b1d5c9b9dea8.tar.gz
coreclr-acfc7408960548202d6ac9dc8898b1d5c9b9dea8.tar.bz2
coreclr-acfc7408960548202d6ac9dc8898b1d5c9b9dea8.zip
Fixed ARM single stepper: added "ADD Rn, PC" command emulation (#24271)submit/tizen_5.0_base/20191030.234851
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.
-rw-r--r--src/jit/emitarm.cpp94
-rw-r--r--src/vm/arm/armsinglestepper.cpp15
2 files changed, 108 insertions, 1 deletions
diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp
index e5c98f9469..9c779eff59 100644
--- a/src/jit/emitarm.cpp
+++ b/src/jit/emitarm.cpp
@@ -1684,6 +1684,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;
@@ -1712,6 +1713,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;
@@ -1821,6 +1823,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;
@@ -1884,6 +1887,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;
@@ -1918,6 +1922,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))
@@ -1999,6 +2004,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;
@@ -2008,6 +2016,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;
@@ -2034,6 +2044,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))
@@ -2047,6 +2059,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;
@@ -2054,6 +2067,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;
@@ -2084,6 +2098,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;
@@ -2112,6 +2128,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;
@@ -2135,6 +2153,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;
@@ -2148,6 +2168,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;
@@ -2160,6 +2182,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;
@@ -2176,7 +2200,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;
@@ -2193,6 +2218,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;
@@ -2215,6 +2242,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))
{
@@ -2244,6 +2273,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;
@@ -2308,6 +2339,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;
@@ -2368,6 +2401,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?
@@ -2389,6 +2424,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?
@@ -2479,6 +2516,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))
{
@@ -2509,6 +2548,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))
{
@@ -2521,6 +2562,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))
{
@@ -2554,6 +2597,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)
@@ -2578,6 +2623,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));
@@ -2612,6 +2659,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
@@ -2654,6 +2703,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
@@ -2900,6 +2951,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))
{
@@ -2934,6 +2988,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
@@ -2943,6 +3000,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;
@@ -2950,6 +3010,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
@@ -2959,6 +3022,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;
@@ -2966,6 +3032,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
@@ -2990,6 +3061,9 @@ void emitter::emitIns_R_R_R(instruction ins,
case INS_udiv:
#endif // !USE_HELPERS_FOR_INT_DIV
+ 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;
@@ -3048,6 +3122,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));
@@ -3056,6 +3132,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));
@@ -3122,6 +3200,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;
@@ -3131,6 +3212,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);
@@ -3215,6 +3299,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)
@@ -3365,6 +3452,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 bfe88244f8..525e3bcf2b 100644
--- a/src/vm/arm/armsinglestepper.cpp
+++ b/src/vm/arm/armsinglestepper.cpp
@@ -1051,6 +1051,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