summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/binder/inc/applicationcontext.hpp8
-rw-r--r--src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.cs39
-rw-r--r--src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.csproj12
-rw-r--r--src/debug/ee/debugger.inl17
-rw-r--r--src/jit/emitarm.cpp94
-rw-r--r--src/pal/src/exception/seh-unwind.cpp2
-rw-r--r--src/vm/arm/armsinglestepper.cpp15
-rw-r--r--src/vm/eventpipebuffer.cpp20
-rw-r--r--src/vm/eventpipebuffer.h15
-rw-r--r--src/vm/eventpipeeventinstance.cpp1
11 files changed, 210 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore
index c3d1f56b52..75353416b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -178,6 +178,7 @@ node_modules/
.atom-build.json
tags
TAGS
+cscope.*
# RIA/Silverlight projects
Generated_Code/
diff --git a/src/binder/inc/applicationcontext.hpp b/src/binder/inc/applicationcontext.hpp
index 9c8926207c..2f95fe68dd 100644
--- a/src/binder/inc/applicationcontext.hpp
+++ b/src/binder/inc/applicationcontext.hpp
@@ -71,8 +71,12 @@ namespace BINDER_SPACE
key = e.m_wszSimpleName;
return key;
}
- static count_t Hash(const key_t &str) { return HashiString(str); }
- static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (_wcsicmp(lhs, rhs) == 0); }
+ static count_t Hash(const key_t &str)
+ {
+ SString ssKey(SString::Literal, str);
+ return ssKey.HashCaseInsensitive();
+ }
+ static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (SString::_wcsicmp(lhs, rhs) == 0); }
void OnDestructPerEntryCleanupAction(const SimpleNameToFileNameMapEntry & e)
{
diff --git a/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.cs b/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.cs
new file mode 100644
index 0000000000..65f0ea68c0
--- /dev/null
+++ b/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+public class Program
+{
+ [DllImport("libc", EntryPoint = "setlocale")]
+ public static extern IntPtr setlocale(int category, [MarshalAs(UnmanagedType.LPStr)] string locale);
+
+ public static int Main()
+ {
+ Assembly a1 = Assembly.GetExecutingAssembly();
+
+ // In case of Turkish locale:
+ // towupper 'i' -> \x0130 (instead of 'I')
+ // towlower 'I' -> \x0131 (instead of 'i')
+ const string TRLocale = "tr_TR.UTF-8";
+ IntPtr res = setlocale(6 /*LC_ALL*/, TRLocale);
+ if (TRLocale != Marshal.PtrToStringAnsi(res))
+ {
+ Console.WriteLine("Failed! " + TRLocale + " locale was not found in system!");
+ return -1;
+ }
+
+ Assembly a2 = Assembly.Load("Ii");
+
+ if (a1 != a2)
+ {
+ Console.WriteLine("Failed!");
+ return -2;
+ }
+
+ Console.WriteLine("Passed!");
+ return 100;
+ }
+}
diff --git a/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.csproj b/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.csproj
new file mode 100644
index 0000000000..d1d1441426
--- /dev/null
+++ b/src/coreclr/tests/src/Loader/binding/assemblies/assemblybugs/37910/Ii.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>1</CLRTestPriority>
+ <!-- Test unsupported outside of linux -->
+ <CLRTestTargetUnsupported Condition="'$(TargetOS)' != 'Linux'">true</CLRTestTargetUnsupported>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Ii.cs" />
+ </ItemGroup>
+</Project>
diff --git a/src/debug/ee/debugger.inl b/src/debug/ee/debugger.inl
index 612aacd609..c7aea02d6e 100644
--- a/src/debug/ee/debugger.inl
+++ b/src/debug/ee/debugger.inl
@@ -242,9 +242,24 @@ inline void FuncEvalFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
pRD->SetEcxLocation(&(pDE->m_context.Ecx));
pRD->SetEaxLocation(&(pDE->m_context.Eax));
pRD->SetEbpLocation(&(pDE->m_context.Ebp));
- pRD->SP = (DWORD)GetSP(&pDE->m_context);
pRD->PCTAddr = GetReturnAddressPtr();
+
+#ifdef WIN64EXCEPTIONS
+
+ pRD->IsCallerContextValid = FALSE;
+ pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
+
+ pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);
+ pRD->pCurrentContext->Esp = (DWORD)GetSP(&pDE->m_context);
+
+ SyncRegDisplayToCurrentContext(pRD);
+
+#else // WIN64EXCEPTIONS
+
pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr);
+ pRD->SP = (DWORD)GetSP(&pDE->m_context);
+
+#endif // WIN64EXCEPTIONS
#elif defined(_TARGET_AMD64_)
pRD->IsCallerContextValid = FALSE;
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/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index 2b7c9360a6..d25a3a857f 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -310,7 +310,7 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
// Check if the frame we have unwound to is a frame that caused
// synchronous signal, like a hardware exception and record it
// in the context flags.
- if (unw_is_signal_frame(&cursor) > 0)
+ if ((st != 0) && (unw_is_signal_frame(&cursor) > 0))
{
context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
#if defined(_ARM_) || defined(_ARM64_) || defined(_X86_)
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
diff --git a/src/vm/eventpipebuffer.cpp b/src/vm/eventpipebuffer.cpp
index 16398714cd..e7489cd0cd 100644
--- a/src/vm/eventpipebuffer.cpp
+++ b/src/vm/eventpipebuffer.cpp
@@ -22,8 +22,8 @@ EventPipeBuffer::EventPipeBuffer(unsigned int bufferSize)
m_pBuffer = new BYTE[bufferSize];
memset(m_pBuffer, 0, bufferSize);
- m_pCurrent = m_pBuffer;
m_pLimit = m_pBuffer + bufferSize;
+ m_pCurrent = GetNextAlignedAddress(m_pBuffer);
m_mostRecentTimeStamp.QuadPart = 0;
m_pLastPoppedEvent = NULL;
@@ -55,6 +55,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, Eve
GC_NOTRIGGER;
MODE_ANY;
PRECONDITION(pThread != NULL);
+ PRECONDITION(((size_t)m_pCurrent % AlignmentSize) == 0);
}
CONTRACTL_END;
@@ -110,7 +111,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, Eve
if(success)
{
// Advance the current pointer past the event.
- m_pCurrent += eventSize;
+ m_pCurrent = GetNextAlignedAddress(m_pCurrent + eventSize);
}
return success;
@@ -134,7 +135,7 @@ void EventPipeBuffer::Clear()
CONTRACTL_END;
memset(m_pBuffer, 0, (size_t)(m_pLimit - m_pBuffer));
- m_pCurrent = m_pBuffer;
+ m_pCurrent = GetNextAlignedAddress(m_pBuffer);
m_mostRecentTimeStamp.QuadPart = 0;
m_pLastPoppedEvent = NULL;
}
@@ -154,9 +155,10 @@ EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent,
if(pEvent == NULL)
{
// If this buffer contains an event, select it.
- if(m_pCurrent > m_pBuffer)
+ BYTE *pFirstAlignedInstance = GetNextAlignedAddress(m_pBuffer);
+ if(m_pCurrent > pFirstAlignedInstance)
{
- pNextInstance = (EventPipeEventInstance*)m_pBuffer;
+ pNextInstance = (EventPipeEventInstance*)pFirstAlignedInstance;
}
else
{
@@ -174,7 +176,7 @@ EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent,
// We have a pointer within the bounds of the buffer.
// Find the next event by skipping the current event with it's data payload immediately after the instance.
- pNextInstance = (EventPipeEventInstance *)(pEvent->GetData() + pEvent->GetDataLength());
+ pNextInstance = (EventPipeEventInstance *)GetNextAlignedAddress(const_cast<BYTE *>(pEvent->GetData() + pEvent->GetDataLength()));
// Check to see if we've reached the end of the written portion of the buffer.
if((BYTE*)pNextInstance >= m_pCurrent)
@@ -245,14 +247,14 @@ bool EventPipeBuffer::EnsureConsistency()
CONTRACTL_END;
// Check to see if the buffer is empty.
- if(m_pBuffer == m_pCurrent)
+ if(GetNextAlignedAddress(m_pBuffer) == m_pCurrent)
{
// Make sure that the buffer size is greater than zero.
_ASSERTE(m_pBuffer != m_pLimit);
}
// Validate the contents of the filled portion of the buffer.
- BYTE *ptr = m_pBuffer;
+ BYTE *ptr = GetNextAlignedAddress(m_pBuffer);
while(ptr < m_pCurrent)
{
// Validate the event.
@@ -263,7 +265,7 @@ bool EventPipeBuffer::EnsureConsistency()
_ASSERTE((pInstance->GetData() != NULL && pInstance->GetDataLength() > 0) || (pInstance->GetData() == NULL && pInstance->GetDataLength() == 0));
// Skip the event.
- ptr += sizeof(*pInstance) + pInstance->GetDataLength();
+ ptr = GetNextAlignedAddress(ptr + sizeof(*pInstance) + pInstance->GetDataLength());
}
// When we're done walking the filled portion of the buffer,
diff --git a/src/vm/eventpipebuffer.h b/src/vm/eventpipebuffer.h
index 7d6287d93d..7b20883f73 100644
--- a/src/vm/eventpipebuffer.h
+++ b/src/vm/eventpipebuffer.h
@@ -20,6 +20,10 @@ class EventPipeBuffer
private:
+ // Instances of EventPipeEventInstance in the buffer must be 8-byte aligned.
+ // It is OK for the data payloads to be unaligned because they are opaque blobs that are copied via memcpy.
+ const size_t AlignmentSize = 8;
+
// A pointer to the actual buffer.
BYTE *m_pBuffer;
@@ -72,6 +76,17 @@ private:
m_pNextBuffer = pBuffer;
}
+ FORCEINLINE BYTE* GetNextAlignedAddress(BYTE *pAddress)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_pBuffer <= pAddress && m_pLimit > pAddress);
+
+ pAddress = (BYTE*)ALIGN_UP(pAddress, AlignmentSize);
+
+ _ASSERTE((size_t)pAddress % AlignmentSize == 0);
+ return pAddress;
+ }
+
public:
EventPipeBuffer(unsigned int bufferSize);
diff --git a/src/vm/eventpipeeventinstance.cpp b/src/vm/eventpipeeventinstance.cpp
index 023b9b2aa9..1424dbc94c 100644
--- a/src/vm/eventpipeeventinstance.cpp
+++ b/src/vm/eventpipeeventinstance.cpp
@@ -54,6 +54,7 @@ EventPipeEventInstance::EventPipeEventInstance(
m_pData = pData;
m_dataLength = length;
QueryPerformanceCounter(&m_timeStamp);
+ _ASSERTE(m_timeStamp.QuadPart > 0);
if(event.NeedStack() && !session.RundownEnabled())
{