summaryrefslogtreecommitdiff
path: root/packaging/0001-Fixed-ARM-single-stepper-added-ADD-Rn-PC-command-emu.patch
blob: b3408486cfa89e66a9cc526dc185b78cef95ec0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
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