summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/debug/ee/wks/wks.nativeproj1
-rw-r--r--src/dlls/mscoree/CMakeLists.txt4
-rw-r--r--src/dlls/mscoree/unixinterface.cpp26
-rw-r--r--src/gc/env/gcenv.os.h4
-rw-r--r--src/gc/sample/gcenv.windows.cpp22
-rw-r--r--src/inc/corexcep.h2
-rw-r--r--src/jit/assertionprop.cpp125
-rw-r--r--src/jit/compiler.h14
-rw-r--r--src/jit/compiler.hpp3
-rwxr-xr-xsrc/jit/ee_il_dll.cpp1
-rw-r--r--src/jit/importer.cpp18
-rw-r--r--src/mscorlib/ref/mscorlib.cs39
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs12
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs8
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs4
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs26
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs4
-rw-r--r--src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs2
-rw-r--r--src/mscorlib/src/System/Exception.cs2
-rw-r--r--src/pal/inc/pal.h2
-rw-r--r--src/pal/src/arch/i386/asmconstants.h6
-rw-r--r--src/pal/src/arch/i386/context2.S22
-rw-r--r--src/pal/src/debug/debug.cpp6
-rw-r--r--src/pal/src/exception/machexception.cpp6
-rw-r--r--src/pal/src/exception/signal.cpp14
-rw-r--r--src/pal/src/include/pal/context.h78
-rw-r--r--src/pal/src/include/pal/virtual.h6
-rw-r--r--src/pal/src/map/virtual.cpp251
-rw-r--r--src/pal/src/thread/context.cpp52
-rw-r--r--src/pal/src/thread/thread.cpp5
-rw-r--r--src/vm/CMakeLists.txt8
-rw-r--r--src/vm/gcenv.os.cpp9
-rw-r--r--src/vm/gdbjit.cpp1003
-rw-r--r--src/vm/gdbjit.h107
-rw-r--r--src/vm/gdbjithelpers.h31
-rw-r--r--src/vm/util.cpp17
36 files changed, 1740 insertions, 200 deletions
diff --git a/src/debug/ee/wks/wks.nativeproj b/src/debug/ee/wks/wks.nativeproj
index 8d89ac45cc..304c591485 100644
--- a/src/debug/ee/wks/wks.nativeproj
+++ b/src/debug/ee/wks/wks.nativeproj
@@ -34,6 +34,7 @@
<PreprocessAssembleArm Condition="'$(BuildArchitecture)' == 'arm'" Include="..\arm\dbghelpers.asm" />
<PreprocessAssembleArm Condition="'$(BuildArchitecture)' == 'arm64'" Include="..\arm64\dbghelpers.asm" />
<AssembleArm Condition="'$(BuildArchitecture)' == 'arm'" Include="$(IntermediateOutputDirectory)\dbghelpers.i" />
+ <AssembleArm64 Condition="'$(BuildArchitecture)' == 'arm64'" Include="$(IntermediateOutputDirectory)\dbghelpers.i" />
<Assemble386 Condition="'$(BuildArchitecture)' == 'i386'" Include="..\i386\dbghelpers.asm" />
<AssembleAmd64 Condition="'$(BuildArchitecture)' == 'amd64'" Include="..\amd64\dbghelpers.asm" />
</ItemGroup>
diff --git a/src/dlls/mscoree/CMakeLists.txt b/src/dlls/mscoree/CMakeLists.txt
index 7af76fbe6b..6a157e4105 100644
--- a/src/dlls/mscoree/CMakeLists.txt
+++ b/src/dlls/mscoree/CMakeLists.txt
@@ -1,5 +1,9 @@
include_directories("../../inc")
+if(FEATURE_GDBJIT)
+ add_definitions(-DFEATURE_GDBJIT)
+endif(FEATURE_GDBJIT)
+
set(CLR_SOURCES
mscoree.cpp
unixinterface.cpp
diff --git a/src/dlls/mscoree/unixinterface.cpp b/src/dlls/mscoree/unixinterface.cpp
index be345b3ca1..897924c90c 100644
--- a/src/dlls/mscoree/unixinterface.cpp
+++ b/src/dlls/mscoree/unixinterface.cpp
@@ -15,6 +15,9 @@
#include <utilcode.h>
#include <corhost.h>
#include <configuration.h>
+#ifdef FEATURE_GDBJIT
+#include "../../vm/gdbjithelpers.h"
+#endif // FEATURE_GDBJIT
typedef int (STDMETHODCALLTYPE *HostMain)(
const int argc,
@@ -137,6 +140,11 @@ static void ConvertConfigPropertiesToUnicode(
extern "C" LPCWSTR g_CLRJITPath;
#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+#ifdef FEATURE_GDBJIT
+GetInfoForMethodDelegate getInfoForMethodDelegate = NULL;
+extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**);
+#endif //FEATURE_GDBJIT
+
//
// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
//
@@ -238,8 +246,24 @@ int coreclr_initialize(
{
host.SuppressRelease();
*hostHandle = host;
- }
+#ifdef FEATURE_GDBJIT
+ hr = coreclr_create_delegate(*hostHandle,
+ *domainId,
+ "System.Diagnostics.Debug.SymbolReader",
+ "System.Diagnostics.Debug.SymbolReader.SymbolReader",
+ "GetInfoForMethod",
+ (void**)&getInfoForMethodDelegate);
+
+ if (!SUCCEEDED(hr))
+ {
+ fprintf(stderr,
+ "Can't create delegate for 'System.Diagnostics.Debug.SymbolReader.SymbolReader.GetInfoForMethod' "
+ "method - status: 0x%08x\n", hr);
+ }
+ hr = S_OK; // We don't need to fail if we can't create delegate
+#endif
+ }
return hr;
}
diff --git a/src/gc/env/gcenv.os.h b/src/gc/env/gcenv.os.h
index 0cdc7a4d16..bb0153f117 100644
--- a/src/gc/env/gcenv.os.h
+++ b/src/gc/env/gcenv.os.h
@@ -240,9 +240,9 @@ public:
// specified, it returns amount of actual physical memory.
static uint64_t GetPhysicalMemoryLimit();
- // Get global memory status
+ // Get memory status
// Parameters:
- // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
+ // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
// that is in use (0 indicates no memory use and 100 indicates full memory use).
// available_physical - The amount of physical memory currently available, in bytes.
// available_page_file - The maximum amount of memory the current process can commit, in bytes.
diff --git a/src/gc/sample/gcenv.windows.cpp b/src/gc/sample/gcenv.windows.cpp
index e35af6b6a0..76187f2185 100644
--- a/src/gc/sample/gcenv.windows.cpp
+++ b/src/gc/sample/gcenv.windows.cpp
@@ -13,8 +13,6 @@
#include "gcenv.h"
#include "gc.h"
-static LARGE_INTEGER performanceFrequency;
-
MethodTable * g_pFreeObjectMethodTable;
int32_t g_TrapReturningThreads;
@@ -23,12 +21,14 @@ bool g_fFinalizerRunOnShutDown;
GCSystemInfo g_SystemInfo;
+static LARGE_INTEGER g_performanceFrequency;
+
// Initialize the interface implementation
// Return:
// true if it has succeeded, false if it has failed
bool GCToOSInterface::Initialize()
{
- if (!::QueryPerformanceFrequency(&performanceFrequency))
+ if (!::QueryPerformanceFrequency(&g_performanceFrequency))
{
return false;
}
@@ -310,9 +310,12 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit()
return memStatus.ullTotalPhys;
}
-// Get global memory status
+// Get memory status
// Parameters:
-// ms - pointer to the structure that will be filled in with the memory status
+// memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
+// that is in use (0 indicates no memory use and 100 indicates full memory use).
+// available_physical - The amount of physical memory currently available, in bytes.
+// available_page_file - The maximum amount of memory the current process can commit, in bytes.
void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
MEMORYSTATUSEX memStatus;
@@ -356,14 +359,7 @@ int64_t GCToOSInterface::QueryPerformanceCounter()
// The counter frequency
int64_t GCToOSInterface::QueryPerformanceFrequency()
{
- LARGE_INTEGER frequency;
- if (!::QueryPerformanceFrequency(&frequency))
- {
- _ASSERTE(!"Fatal Error - cannot query performance counter.");
- abort();
- }
-
- return frequency.QuadPart;
+ return g_performanceFrequency.QuadPart;
}
// Get a time stamp with a low precision
diff --git a/src/inc/corexcep.h b/src/inc/corexcep.h
index d842545038..f1bed3e77b 100644
--- a/src/inc/corexcep.h
+++ b/src/inc/corexcep.h
@@ -14,7 +14,7 @@
// All COM+ exceptions are expressed as a RaiseException with this exception
// code. If you change this value, you must also change
-// bcl\src\system\Exception.cs's _COMPlusExceptionCode value.
+// mscorlib\src\system\Exception.cs's _COMPlusExceptionCode value.
#define EXCEPTION_MSVC 0xe06d7363 // 0xe0000000 | 'msc'
diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp
index 1ac1cd285f..781e46068b 100644
--- a/src/jit/assertionprop.cpp
+++ b/src/jit/assertionprop.cpp
@@ -754,12 +754,13 @@ Compiler::AssertionDsc * Compiler::optGetAssertion(AssertionIndex assertIndex)
{
assert(NO_ASSERTION_INDEX == 0);
noway_assert(assertIndex != NO_ASSERTION_INDEX);
+ noway_assert(assertIndex <= optAssertionCount);
+ AssertionDsc* assertion = &optAssertionTabPrivate[assertIndex - 1];
+#ifdef DEBUG
+ optDebugCheckAssertion(assertion);
+#endif
- if (assertIndex > optMaxAssertionCount)
- {
- return nullptr;
- }
- return &optAssertionTabPrivate[assertIndex - 1];
+ return assertion;
}
/*****************************************************************************
@@ -1488,6 +1489,63 @@ Compiler::AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
}
#ifdef DEBUG
+void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
+{
+ assert(assertion->assertionKind < OAK_COUNT);
+ assert(assertion->op1.kind < O1K_COUNT);
+ assert(assertion->op2.kind < O2K_COUNT);
+ // It would be good to check that op1.vn and op2.vn are valid value numbers.
+
+ switch(assertion->op1.kind)
+ {
+ case O1K_LCLVAR:
+ case O1K_EXACT_TYPE:
+ case O1K_SUBTYPE:
+ assert(assertion->op1.lcl.lclNum < lvaCount);
+ assert(optLocalAssertionProp ||
+ ((assertion->op1.lcl.ssaNum - SsaConfig::UNINIT_SSA_NUM) < lvaTable[assertion->op1.lcl.lclNum].lvNumSsaNames));
+ break;
+ case O1K_ARR_BND:
+ // It would be good to check that bnd.vnIdx and bnd.vnLen are valid value numbers.
+ break;
+ case O1K_ARRLEN_OPER_BND:
+ case O1K_ARRLEN_LOOP_BND:
+ case O1K_CONSTANT_LOOP_BND:
+ assert(!optLocalAssertionProp);
+ break;
+ default:
+ break;
+ }
+ switch (assertion->op2.kind)
+ {
+ case O2K_IND_CNS_INT:
+ case O2K_CONST_INT:
+ {
+ // The only flags that can be set are those in the GTF_ICON_HDL_MASK, or bit 0, which is
+ // used to indicate a long constant.
+ assert((assertion->op2.u1.iconFlags & ~(GTF_ICON_HDL_MASK|1)) == 0);
+ switch (assertion->op1.kind)
+ {
+ case O1K_EXACT_TYPE:
+ case O1K_SUBTYPE:
+ assert(assertion->op2.u1.iconFlags != 0);
+ break;
+ case O1K_LCLVAR:
+ case O1K_ARR_BND:
+ assert(lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF || assertion->op2.u1.iconVal == 0);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ // for all other 'assertion->op2.kind' values we don't check anything
+ break;
+ }
+}
+
/*****************************************************************************
*
* Verify that assertion prop related assumptions are valid. If "index"
@@ -1502,33 +1560,7 @@ void Compiler::optDebugCheckAssertions(AssertionIndex index)
for (AssertionIndex ind = start; ind <= end; ++ind)
{
AssertionDsc* assertion = optGetAssertion(ind);
- switch (assertion->op2.kind)
- {
- case O2K_IND_CNS_INT:
- case O2K_CONST_INT:
- {
- switch (assertion->op1.kind)
- {
- case O1K_EXACT_TYPE:
- case O1K_SUBTYPE:
- assert(assertion->op2.u1.iconFlags != 0);
- break;
- case O1K_ARRLEN_OPER_BND:
- case O1K_ARRLEN_LOOP_BND:
- case O1K_CONSTANT_LOOP_BND:
- assert(!optLocalAssertionProp);
- break;
- default:
- assert(lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF || assertion->op2.u1.iconVal == 0);
- break;
- }
- }
- break;
-
- default:
- // for all other 'assertion->op2.kind' values we don't check anything
- break;
- }
+ optDebugCheckAssertion(assertion);
}
}
#endif
@@ -4282,6 +4314,18 @@ ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
{
ASSERT_TP* jumpDestOut = fgAllocateTypeForEachBlk<ASSERT_TP>();
+ // The local assertion gen phase may have created unreachable blocks.
+ // They will never be visited in the dataflow propagation phase, so they need to
+ // be initialized correctly. This means that instead of setting their sets to
+ // apFull (i.e. all possible bits set), we need to set the bits only for valid
+ // assertions (note that at this point we are not creating any new assertions).
+ // Also note that assertion indices start from 1.
+ ASSERT_TP apValidFull = optNewEmptyAssertSet();
+ for (int i = 1; i <= optAssertionCount; i++)
+ {
+ BitVecOps::AddElemD(apTraits, apValidFull, i-1);
+ }
+
// Initially estimate the OUT sets to everything except killed expressions
// Also set the IN sets to 1, so that we can perform the intersection.
// Also, zero-out the flags for handler blocks, as we could be in the
@@ -4290,11 +4334,16 @@ ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
// edges.
for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
{
- block->bbAssertionIn = bbIsHandlerBeg(block) ? optNewEmptyAssertSet() : optNewFullAssertSet();
+ block->bbAssertionIn = optNewEmptyAssertSet();
+ if (!bbIsHandlerBeg(block))
+ {
+ BitVecOps::Assign(apTraits, block->bbAssertionIn, apValidFull);
+ }
block->bbAssertionGen = optNewEmptyAssertSet();
- block->bbAssertionOut = optNewFullAssertSet();
+ block->bbAssertionOut = optNewEmptyAssertSet();
+ BitVecOps::Assign(apTraits, block->bbAssertionOut, apValidFull);
jumpDestOut[block->bbNum] = optNewEmptyAssertSet();
- BitVecOps::Assign(apTraits, jumpDestOut[block->bbNum], apFull);
+ BitVecOps::Assign(apTraits, jumpDestOut[block->bbNum], apValidFull);
}
// Compute the data flow values for all tracked expressions
// IN and OUT never change for the initial basic block B1
@@ -4817,9 +4866,9 @@ void Compiler::optAssertionPropMain()
// and thus we must morph, set order, re-link
for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
{
- JITDUMP("Propagating %s assertions for BB%02d, stmt %08X, tree %08X, tree -> %d\n",
- BitVecOps::ToString(apTraits, assertions),
- block->bbNum, dspPtr(stmt), dspPtr(tree), tree->GetAssertion());
+ JITDUMP("Propagating %s assertions for BB%02d, stmt [%06d], tree [%06d], tree -> %d\n",
+ BitVecOps::ToString(apTraits, assertions),
+ block->bbNum, dspTreeID(stmt), dspTreeID(tree), tree->GetAssertion());
GenTreePtr newTree = optAssertionProp(assertions, tree, stmt);
if (newTree)
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 3eb2fdcb83..e3a4b519c7 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -5560,7 +5560,8 @@ public:
OAK_EQUAL,
OAK_NOT_EQUAL,
OAK_SUBRANGE,
- OAK_NO_THROW };
+ OAK_NO_THROW,
+ OAK_COUNT };
enum optOp1Kind { O1K_INVALID,
O1K_LCLVAR,
@@ -5569,7 +5570,8 @@ public:
O1K_ARRLEN_LOOP_BND,
O1K_CONSTANT_LOOP_BND,
O1K_EXACT_TYPE,
- O1K_SUBTYPE };
+ O1K_SUBTYPE,
+ O1K_COUNT };
enum optOp2Kind { O2K_INVALID,
O2K_LCLVAR_COPY,
@@ -5578,7 +5580,8 @@ public:
O2K_CONST_LONG,
O2K_CONST_DOUBLE,
O2K_ARR_LEN,
- O2K_SUBRANGE };
+ O2K_SUBRANGE,
+ O2K_COUNT };
struct AssertionDsc
{
optAssertionKind assertionKind;
@@ -5754,6 +5757,10 @@ public:
case O2K_INVALID:
// we will return false
break;
+
+ default:
+ assert(!"Unexpected value for op2.kind in AssertionDsc.");
+ break;
}
return false;
}
@@ -5892,6 +5899,7 @@ public :
#ifdef DEBUG
void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex=0);
+ void optDebugCheckAssertion(AssertionDsc* assertion);
void optDebugCheckAssertions(AssertionIndex AssertionIndex);
#endif
void optAddCopies();
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index b6127e72ed..1ff7b53348 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -3474,8 +3474,9 @@ void Compiler::optAssertionReset(AssertionIndex limit)
while (optAssertionCount > limit)
{
- AssertionIndex index = optAssertionCount--;
+ AssertionIndex index = optAssertionCount;
AssertionDsc* curAssertion = optGetAssertion(index);
+ optAssertionCount--;
unsigned lclNum = curAssertion->op1.lcl.lclNum;
assert(lclNum < lvaTableCnt);
BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp
index c726856b9b..ff42443c25 100755
--- a/src/jit/ee_il_dll.cpp
+++ b/src/jit/ee_il_dll.cpp
@@ -23,6 +23,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#if !defined(PLATFORM_UNIX)
#include <io.h> // For _dup, _setmode
#include <fcntl.h> // For _O_TEXT
+#include <errno.h> // For EINVAL
#endif
/*****************************************************************************/
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 98f8183b7a..aa63b8f812 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -6830,7 +6830,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
//-------------------------------------------------------------------------
// The "this" pointer
- if (!(mflags & CORINFO_FLG_STATIC) || opcode == CEE_NEWOBJ)
+ if (!(mflags & CORINFO_FLG_STATIC) && !((opcode == CEE_NEWOBJ) && (newobjThis == nullptr)))
{
GenTreePtr obj;
@@ -11736,10 +11736,18 @@ DO_LDFTN:
// At present this can only be String
else if (clsFlags & CORINFO_FLG_VAROBJSIZE)
{
- // This is the case for variable-sized objects that are not
- // arrays. In this case, call the constructor with a null 'this'
- // pointer
- newObjThisPtr = gtNewIconNode(0, TYP_REF);
+ if (eeGetEEInfo()->targetAbi == CORINFO_CORERT_ABI)
+ {
+ // The dummy argument does not exist in CoreRT
+ newObjThisPtr = nullptr;
+ }
+ else
+ {
+ // This is the case for variable-sized objects that are not
+ // arrays. In this case, call the constructor with a null 'this'
+ // pointer
+ newObjThisPtr = gtNewIconNode(0, TYP_REF);
+ }
/* Remember that this basic block contains 'new' of an object */
block->bbFlags |= BBF_HAS_NEWOBJ;
diff --git a/src/mscorlib/ref/mscorlib.cs b/src/mscorlib/ref/mscorlib.cs
index 965e727ee9..f44978ea25 100644
--- a/src/mscorlib/ref/mscorlib.cs
+++ b/src/mscorlib/ref/mscorlib.cs
@@ -171,13 +171,14 @@ namespace System
public ArithmeticException(string message, System.Exception innerException) { }
}
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
- public abstract partial class Array : System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable
+ public abstract partial class Array : System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.ICloneable
{
internal Array() { }
public bool IsFixedSize { get { return default(bool); } }
public bool IsReadOnly { get { return default(bool); } }
public bool IsSynchronized { get { return default(bool); } }
public int Length { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]get { return default(int); } }
+ public long LongLength { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]get { return default(long); } }
public int Rank { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]get { return default(int); } }
public object SyncRoot { get { return default(object); } }
int System.Collections.ICollection.Count { get { return default(int); } }
@@ -207,20 +208,28 @@ namespace System
[System.Security.SecuritySafeCriticalAttribute]
public static void ConstrainedCopy(System.Array sourceArray, int sourceIndex, System.Array destinationArray, int destinationIndex, int length) { }
-
+ public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, System.Converter<TInput, TOutput> converter) { return default(TOutput[]); }
+
[System.Security.SecuritySafeCriticalAttribute]
public static void Copy(System.Array sourceArray, System.Array destinationArray, int length) { }
-
+ public static void Copy(System.Array sourceArray, System.Array destinationArray, long length) { }
[System.Security.SecuritySafeCriticalAttribute]
public static void Copy(System.Array sourceArray, int sourceIndex, System.Array destinationArray, int destinationIndex, int length) { }
+ public static void Copy(System.Array sourceArray, long sourceIndex, System.Array destinationArray, long destinationIndex, long length) { }
public void CopyTo(System.Array array, int index) { }
+ public void CopyTo(System.Array array, long index) { }
[System.Security.SecuritySafeCriticalAttribute]
public static System.Array CreateInstance(System.Type elementType, int length) { return default(System.Array); }
[System.Security.SecuritySafeCriticalAttribute]
+ public static System.Array CreateInstance(System.Type elementType, int length1, int length2) { return default(System.Array); }
+ [System.Security.SecuritySafeCriticalAttribute]
+ public static System.Array CreateInstance(System.Type elementType, int length1, int length2, int length3) { return default(System.Array); }
+ [System.Security.SecuritySafeCriticalAttribute]
public static System.Array CreateInstance(System.Type elementType, params int[] lengths) { return default(System.Array); }
[System.Security.SecuritySafeCriticalAttribute]
public static System.Array CreateInstance(System.Type elementType, int[] lengths, int[] lowerBounds) { return default(System.Array); }
-
+ public static System.Array CreateInstance(System.Type elementType, params long[] lengths) { return default(System.Array); }
+
public static T[] Empty<T>() { return default(T[]); }
public static bool Exists<T>(T[] array, System.Predicate<T> match) { return default(bool); }
public static T Find<T>(T[] array, System.Predicate<T> match) { return default(T); }
@@ -236,6 +245,7 @@ namespace System
public System.Collections.IEnumerator GetEnumerator() { return default(System.Collections.IEnumerator); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)][System.Security.SecuritySafeCriticalAttribute]
public int GetLength(int dimension) { return default(int); }
+ public long GetLongLength(int dimension) { return default(long); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
[System.Security.SecuritySafeCriticalAttribute]
public int GetLowerBound(int dimension) { return default(int); }
@@ -245,8 +255,16 @@ namespace System
[System.Security.SecuritySafeCriticalAttribute]
public object GetValue(int index) { return default(object); }
[System.Security.SecuritySafeCriticalAttribute]
+ public object GetValue(int index1, int index2) { return default(object); }
+ [System.Security.SecuritySafeCriticalAttribute]
+ public object GetValue(int index1, int index2, int index3) { return default(object); }
+ [System.Security.SecuritySafeCriticalAttribute]
public object GetValue(params int[] indices) { return default(object); }
-
+ public object GetValue(long index) { return default(object); }
+ public object GetValue(long index1, long index2) { return default(object); }
+ public object GetValue(long index1, long index2, long index3) { return default(object); }
+ public object GetValue(params long[] indices) { return default(object); }
+
public static int IndexOf(System.Array array, object value) { return default(int); }
public static int IndexOf(System.Array array, object value, int startIndex) { return default(int); }
@@ -278,8 +296,16 @@ namespace System
[System.Security.SecuritySafeCriticalAttribute]
public void SetValue(object value, int index) { }
[System.Security.SecuritySafeCriticalAttribute]
+ public void SetValue(object value, int index1, int index2) { }
+ [System.Security.SecuritySafeCriticalAttribute]
+ public void SetValue(object value, int index1, int index2, int index3) { }
+ [System.Security.SecuritySafeCriticalAttribute]
public void SetValue(object value, params int[] indices) { }
-
+ public void SetValue(object value, long index) { }
+ public void SetValue(object value, long index1, long index2) { }
+ public void SetValue(object value, long index1, long index2, long index3) { }
+ public void SetValue(object value, params long[] indices) { }
+
public static void Sort(System.Array array) { }
public static void Sort(System.Array keys, System.Array items) { }
@@ -4227,6 +4253,7 @@ namespace System.Collections.Generic
public int BinarySearch(int index, int count, T item, System.Collections.Generic.IComparer<T> comparer) { return default(int); }
public void Clear() { }
public bool Contains(T item) { return default(bool); }
+ public List<TOutput> ConvertAll<TOutput>(System.Converter<T,TOutput> converter) { throw null; }
public void CopyTo(T[] array) { }
public void CopyTo(T[] array, int arrayIndex) { }
public void CopyTo(int index, T[] array, int arrayIndex, int count) { }
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs
index cad47eeb5b..b1f946464e 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventCounter.cs
@@ -1,4 +1,8 @@
-using System;
+// 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.Collections;
using System.Collections.Generic;
using System.Threading;
@@ -26,12 +30,12 @@ namespace System.Diagnostics.Tracing
{
if (name == null)
{
- throw new ArgumentNullException("name");
+ throw new ArgumentNullException(nameof(name));
}
if (eventSource == null)
{
- throw new ArgumentNullException("eventSource");
+ throw new ArgumentNullException(nameof(eventSource));
}
InitializeBuffer();
@@ -281,7 +285,7 @@ namespace System.Diagnostics.Tracing
else if (eventSourceIndex >= EventCounterGroup.s_eventCounterGroups.Length)
{
EventCounterGroup[] newEventCounterGroups = new EventCounterGroup[eventSourceIndex + 1];
- Array.Copy(EventCounterGroup.s_eventCounterGroups, newEventCounterGroups, EventCounterGroup.s_eventCounterGroups.Length);
+ Array.Copy(EventCounterGroup.s_eventCounterGroups, 0, newEventCounterGroups, 0, EventCounterGroup.s_eventCounterGroups.Length);
EventCounterGroup.s_eventCounterGroups = newEventCounterGroups;
}
}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs
index 4361bdefd7..11b6e6bac2 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventDescriptor.cs
@@ -73,12 +73,12 @@ namespace System.Diagnostics.Tracing
{
if (id < 0)
{
- throw new ArgumentOutOfRangeException("id", Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (id > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException("id", Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+ throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
}
m_traceloggingId = 0;
@@ -91,12 +91,12 @@ namespace System.Diagnostics.Tracing
if (task < 0)
{
- throw new ArgumentOutOfRangeException("task", Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (task > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException("task", Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+ throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
}
m_task = (ushort)task;
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs
index 2b0807f4ee..6ea8d98d92 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventProvider.cs
@@ -89,7 +89,7 @@ namespace System.Diagnostics.Tracing
private static WriteEventErrorCode s_returnCode; // The last return code
private const int s_basicTypeAllocationBufferSize = 16;
- private const int s_etwMaxNumberArguments = 64;
+ private const int s_etwMaxNumberArguments = 128;
private const int s_etwAPIMaxRefObjCount = 8;
private const int s_maxEventDataDescriptors = 128;
private const int s_traceEventMaximumSize = 65482;
@@ -560,7 +560,7 @@ namespace System.Diagnostics.Tracing
dataStart = 0;
if (filterData == null)
{
-#if !ES_BUILD_PCL && !FEATURE_PAL
+#if (!ES_BUILD_PCL && !PROJECTN && !FEATURE_PAL)
string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey;
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs
index 5e025b0966..ce6b9899ec 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource.cs
@@ -404,7 +404,7 @@ namespace System.Diagnostics.Tracing
public static Guid GetGuid(Type eventSourceType)
{
if (eventSourceType == null)
- throw new ArgumentNullException("eventSourceType");
+ throw new ArgumentNullException(nameof(eventSourceType));
Contract.EndContractBlock();
EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute));
@@ -429,7 +429,7 @@ namespace System.Diagnostics.Tracing
if (name == null)
{
- throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), "eventSourceType");
+ throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), nameof(eventSourceType));
}
return GenerateGuidFromName(name.ToUpperInvariant()); // Make it case insensitive.
}
@@ -472,7 +472,7 @@ namespace System.Diagnostics.Tracing
public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest, EventManifestOptions flags)
{
if (eventSourceType == null)
- throw new ArgumentNullException("eventSourceType");
+ throw new ArgumentNullException(nameof(eventSourceType));
Contract.EndContractBlock();
byte[] manifestBytes = EventSource.CreateManifestAndDescriptors(eventSourceType, assemblyPathToIncludeInManifest, null, flags);
@@ -511,12 +511,12 @@ namespace System.Diagnostics.Tracing
public static void SendCommand(EventSource eventSource, EventCommand command, IDictionary<string, string> commandArguments)
{
if (eventSource == null)
- throw new ArgumentNullException("eventSource");
+ throw new ArgumentNullException(nameof(eventSource));
// User-defined EventCommands should not conflict with the reserved commands.
if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), "command");
+ throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), nameof(command));
}
eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments);
@@ -1451,7 +1451,7 @@ namespace System.Diagnostics.Tracing
m_traits = traits;
if (m_traits != null && m_traits.Length % 2 != 0)
{
- throw new ArgumentException(Resources.GetResourceString("TraitEven"), "traits");
+ throw new ArgumentException(Resources.GetResourceString("TraitEven"), nameof(traits));
}
if (eventSourceGuid == Guid.Empty)
@@ -1543,7 +1543,7 @@ namespace System.Diagnostics.Tracing
private static string GetName(Type eventSourceType, EventManifestOptions flags)
{
if (eventSourceType == null)
- throw new ArgumentNullException("eventSourceType");
+ throw new ArgumentNullException(nameof(eventSourceType));
Contract.EndContractBlock();
EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute), flags);
@@ -3672,7 +3672,7 @@ namespace System.Diagnostics.Tracing
if (eventData == null || eventData.Length <= eventAttribute.EventId)
{
EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)];
- Array.Copy(eventData, newValues, eventData.Length);
+ Array.Copy(eventData, 0, newValues, 0, eventData.Length);
eventData = newValues;
}
@@ -3711,7 +3711,7 @@ namespace System.Diagnostics.Tracing
if (eventData.Length - idx > 2) // allow one wasted slot.
{
EventMetadata[] newValues = new EventMetadata[idx + 1];
- Array.Copy(eventData, newValues, newValues.Length);
+ Array.Copy(eventData, 0, newValues, 0, newValues.Length);
eventData = newValues;
}
}
@@ -3994,7 +3994,7 @@ namespace System.Diagnostics.Tracing
EventSourceSettings.EtwSelfDescribingEventFormat;
if ((settings & evtFormatMask) == evtFormatMask)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), "settings");
+ throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), nameof(settings));
}
// If you did not explicitly ask for manifest, you get self-describing.
@@ -4351,7 +4351,7 @@ namespace System.Diagnostics.Tracing
{
if (eventSource == null)
{
- throw new ArgumentNullException("eventSource");
+ throw new ArgumentNullException(nameof(eventSource));
}
Contract.EndContractBlock();
@@ -4366,7 +4366,7 @@ namespace System.Diagnostics.Tracing
{
if (eventSource == null)
{
- throw new ArgumentNullException("eventSource");
+ throw new ArgumentNullException(nameof(eventSource));
}
Contract.EndContractBlock();
@@ -6000,7 +6000,7 @@ namespace System.Diagnostics.Tracing
internal bool m_activityFilteringEnabled; // does THIS EventSource have activity filtering turned on for this listener?
#endif // FEATURE_ACTIVITYSAMPLING
- // Only guarenteed to exist after a InsureInit()
+ // Only guaranteed to exist after a InsureInit()
internal EventDispatcher m_Next; // These form a linked list in code:EventSource.m_Dispatchers
// Of all listeners for that eventSource.
}
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs
index b8512bf906..00bd0b7caa 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventSource_CoreCLR.cs
@@ -178,12 +178,12 @@ namespace System.Diagnostics.Tracing
else if ((type.IsArray || type.IsPointer) && type.GetElementType() == typeof(byte))
return "win:Binary";
- ManifestError(Environment.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name), true);
+ ManifestError(Resources.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name), true);
return string.Empty;
}
}
}
-
+
internal partial class EventProvider
{
[System.Security.SecurityCritical]
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs b/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs
index b213cb9dfb..e090c4f106 100644
--- a/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs
+++ b/src/mscorlib/src/System/Diagnostics/Eventing/StubEnvironment.cs
@@ -226,7 +226,7 @@ namespace Microsoft.Reflection
public static bool IsGenericType(this Type type) { return type.IsConstructedGenericType; }
public static Type BaseType(this Type type) { return type.GetTypeInfo().BaseType; }
public static Assembly Assembly(this Type type) { return type.GetTypeInfo().Assembly; }
- public static IEnumerable<PropertyInfo> GetProperties(this Type type) { return type.GetTypeInfo().DeclaredProperties; }
+ public static IEnumerable<PropertyInfo> GetProperties(this Type type) { return type.GetRuntimeProperties(); }
public static MethodInfo GetGetMethod(this PropertyInfo propInfo) { return propInfo.GetMethod; }
public static Type[] GetGenericArguments(this Type type) { return type.GenericTypeArguments; }
diff --git a/src/mscorlib/src/System/Exception.cs b/src/mscorlib/src/System/Exception.cs
index f35f7c5690..434b753165 100644
--- a/src/mscorlib/src/System/Exception.cs
+++ b/src/mscorlib/src/System/Exception.cs
@@ -891,7 +891,7 @@ namespace System {
private SafeSerializationManager _safeSerializationManager;
#endif // FEATURE_SERIALIZATION
- // See clr\src\vm\excep.h's EXCEPTION_COMPLUS definition:
+ // See src\inc\corexcep.h's EXCEPTION_COMPLUS definition:
private const int _COMPlusExceptionCode = unchecked((int)0xe0434352); // Win32 exception code for COM+ exceptions
// InternalToString is called by the runtime to get the exception text
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
index fe29112b07..e086717510 100644
--- a/src/pal/inc/pal.h
+++ b/src/pal/inc/pal.h
@@ -2570,6 +2570,8 @@ typedef struct _CONTEXT {
#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
+#define CONTEXT_XSTATE (CONTEXT_AMD64 | 0x40L)
+
#define CONTEXT_EXCEPTION_ACTIVE 0x8000000
#define CONTEXT_SERVICE_ACTIVE 0x10000000
#define CONTEXT_EXCEPTION_REQUEST 0x40000000
diff --git a/src/pal/src/arch/i386/asmconstants.h b/src/pal/src/arch/i386/asmconstants.h
index 8ec73b4bad..182c1191e4 100644
--- a/src/pal/src/arch/i386/asmconstants.h
+++ b/src/pal/src/arch/i386/asmconstants.h
@@ -14,6 +14,8 @@
#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+#define CONTEXT_XSTATE 64
+
#define CONTEXT_ContextFlags 6*8
#define CONTEXT_SegCs CONTEXT_ContextFlags+8
#define CONTEXT_SegDs CONTEXT_SegCs+2
@@ -47,7 +49,7 @@
#define CONTEXT_Rip CONTEXT_R15+8
#define CONTEXT_FltSave CONTEXT_Rip+8
#define FLOATING_SAVE_AREA_SIZE 4*8+24*16+96
-#define CONTEXT_Xmm0 CONTEXT_FltSave+FLOATING_SAVE_AREA_SIZE // was 10*16
+#define CONTEXT_Xmm0 CONTEXT_FltSave+10*16
#define CONTEXT_Xmm1 CONTEXT_Xmm0+16
#define CONTEXT_Xmm2 CONTEXT_Xmm1+16
#define CONTEXT_Xmm3 CONTEXT_Xmm2+16
@@ -63,7 +65,7 @@
#define CONTEXT_Xmm13 CONTEXT_Xmm12+16
#define CONTEXT_Xmm14 CONTEXT_Xmm13+16
#define CONTEXT_Xmm15 CONTEXT_Xmm14+16
-#define CONTEXT_VectorRegister CONTEXT_Xmm15+16
+#define CONTEXT_VectorRegister CONTEXT_FltSave+FLOATING_SAVE_AREA_SIZE
#define CONTEXT_VectorControl CONTEXT_VectorRegister+16*26
#define CONTEXT_DebugControl CONTEXT_VectorControl+8
#define CONTEXT_LastBranchToRip CONTEXT_DebugControl+8
diff --git a/src/pal/src/arch/i386/context2.S b/src/pal/src/arch/i386/context2.S
index 6320446a51..0e93e81a55 100644
--- a/src/pal/src/arch/i386/context2.S
+++ b/src/pal/src/arch/i386/context2.S
@@ -126,6 +126,28 @@ LOCAL_LABEL(Done_Restore_CONTEXT_DEBUG_REGISTERS):
fxrstor [rdi + CONTEXT_FltSave]
LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT):
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_XSTATE
+ je LOCAL_LABEL(Done_Restore_CONTEXT_XSTATE)
+
+ // Restore the extended state (for now, this is just the upper halves of YMM registers)
+ vinsertf128 ymm0, ymm0, xmmword ptr [rdi + (CONTEXT_VectorRegister + 0 * 16)], 1
+ vinsertf128 ymm1, ymm1, xmmword ptr [rdi + (CONTEXT_VectorRegister + 1 * 16)], 1
+ vinsertf128 ymm2, ymm2, xmmword ptr [rdi + (CONTEXT_VectorRegister + 2 * 16)], 1
+ vinsertf128 ymm3, ymm3, xmmword ptr [rdi + (CONTEXT_VectorRegister + 3 * 16)], 1
+ vinsertf128 ymm4, ymm4, xmmword ptr [rdi + (CONTEXT_VectorRegister + 4 * 16)], 1
+ vinsertf128 ymm5, ymm5, xmmword ptr [rdi + (CONTEXT_VectorRegister + 5 * 16)], 1
+ vinsertf128 ymm6, ymm6, xmmword ptr [rdi + (CONTEXT_VectorRegister + 6 * 16)], 1
+ vinsertf128 ymm7, ymm7, xmmword ptr [rdi + (CONTEXT_VectorRegister + 7 * 16)], 1
+ vinsertf128 ymm8, ymm8, xmmword ptr [rdi + (CONTEXT_VectorRegister + 8 * 16)], 1
+ vinsertf128 ymm9, ymm9, xmmword ptr [rdi + (CONTEXT_VectorRegister + 9 * 16)], 1
+ vinsertf128 ymm10, ymm10, xmmword ptr [rdi + (CONTEXT_VectorRegister + 10 * 16)], 1
+ vinsertf128 ymm11, ymm11, xmmword ptr [rdi + (CONTEXT_VectorRegister + 11 * 16)], 1
+ vinsertf128 ymm12, ymm12, xmmword ptr [rdi + (CONTEXT_VectorRegister + 12 * 16)], 1
+ vinsertf128 ymm13, ymm13, xmmword ptr [rdi + (CONTEXT_VectorRegister + 13 * 16)], 1
+ vinsertf128 ymm14, ymm14, xmmword ptr [rdi + (CONTEXT_VectorRegister + 14 * 16)], 1
+ vinsertf128 ymm15, ymm15, xmmword ptr [rdi + (CONTEXT_VectorRegister + 15 * 16)], 1
+LOCAL_LABEL(Done_Restore_CONTEXT_XSTATE):
+
test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_CONTROL
je LOCAL_LABEL(Done_Restore_CONTEXT_CONTROL)
diff --git a/src/pal/src/debug/debug.cpp b/src/pal/src/debug/debug.cpp
index 86ea9f98e4..b3ce4b1ff9 100644
--- a/src/pal/src/debug/debug.cpp
+++ b/src/pal/src/debug/debug.cpp
@@ -25,12 +25,14 @@ Revision History:
#undef _FILE_OFFSET_BITS
#endif
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(DEBUG); // some headers have code with asserts, so do this first
+
#include "pal/thread.hpp"
#include "pal/procobj.hpp"
#include "pal/file.hpp"
#include "pal/palinternal.h"
-#include "pal/dbgmsg.h"
#include "pal/process.h"
#include "pal/context.h"
#include "pal/debug.h"
@@ -66,8 +68,6 @@ Revision History:
using namespace CorUnix;
-SET_DEFAULT_DEBUG_CHANNEL(DEBUG);
-
extern "C" void DBG_DebugBreak_End();
#if HAVE_PROCFS_CTL
diff --git a/src/pal/src/exception/machexception.cpp b/src/pal/src/exception/machexception.cpp
index a483509f07..af1dc89fb5 100644
--- a/src/pal/src/exception/machexception.cpp
+++ b/src/pal/src/exception/machexception.cpp
@@ -14,12 +14,14 @@ Abstract:
--*/
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
#include "pal/thread.hpp"
#include "pal/seh.hpp"
#include "pal/palinternal.h"
#if HAVE_MACH_EXCEPTIONS
#include "machexception.h"
-#include "pal/dbgmsg.h"
#include "pal/critsect.h"
#include "pal/debug.h"
#include "pal/init.h"
@@ -42,8 +44,6 @@ Abstract:
using namespace CorUnix;
-SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
-
// The port we use to handle exceptions and to set the thread context
mach_port_t s_ExceptionPort;
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index 8dd75ac185..c2c217993a 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -18,6 +18,9 @@ Abstract:
--*/
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
#include "pal/corunix.hpp"
#include "pal/handleapi.hpp"
#include "pal/thread.hpp"
@@ -27,7 +30,6 @@ Abstract:
#include "pal/palinternal.h"
#if !HAVE_MACH_EXCEPTIONS
-#include "pal/dbgmsg.h"
#include "pal/init.h"
#include "pal/process.h"
#include "pal/debug.h"
@@ -43,8 +45,6 @@ Abstract:
using namespace CorUnix;
-SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
-
#ifdef SIGRTMIN
#define INJECT_ACTIVATION_SIGNAL SIGRTMIN
#endif
@@ -611,10 +611,16 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
// which is required for restoring context
RtlCaptureContext(contextRecord);
+ ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
+
+#if defined(_AMD64_)
+ contextFlags |= CONTEXT_XSTATE;
+#endif
+
// Fill context record with required information. from pal.h:
// On non-Win32 platforms, the CONTEXT pointer in the
// PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
- CONTEXTFromNativeContext(ucontext, contextRecord, CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
+ CONTEXTFromNativeContext(ucontext, contextRecord, contextFlags);
/* Unmask signal so we can receive it again */
sigemptyset(&signal_set);
diff --git a/src/pal/src/include/pal/context.h b/src/pal/src/include/pal/context.h
index 6f1b3fe734..5e378942fb 100644
--- a/src/pal/src/include/pal/context.h
+++ b/src/pal/src/include/pal/context.h
@@ -121,19 +121,71 @@ typedef ucontext_t native_context_t;
#define MCREG_R14(mc) ((mc).gregs[REG_R14])
#define MCREG_R15(mc) ((mc).gregs[REG_R15])
-#define FPREG_Xmm(uc, index) *(M128A*)&((uc)->uc_mcontext.fpregs->_xmm[index])
-
-#define FPREG_St(uc, index) *(M128A*)&((uc)->uc_mcontext.fpregs->_st[index])
-
-#define FPREG_ControlWord(uc) ((uc)->uc_mcontext.fpregs->cwd)
-#define FPREG_StatusWord(uc) ((uc)->uc_mcontext.fpregs->swd)
-#define FPREG_TagWord(uc) ((uc)->uc_mcontext.fpregs->ftw)
-#define FPREG_ErrorOffset(uc) *(DWORD*)&((uc)->uc_mcontext.fpregs->rip)
-#define FPREG_ErrorSelector(uc) *(((WORD*)&((uc)->uc_mcontext.fpregs->rip)) + 2)
-#define FPREG_DataOffset(uc) *(DWORD*)&((uc)->uc_mcontext.fpregs->rdp)
-#define FPREG_DataSelector(uc) *(((WORD*)&((uc)->uc_mcontext.fpregs->rdp)) + 2)
-#define FPREG_MxCsr(uc) ((uc)->uc_mcontext.fpregs->mxcsr)
-#define FPREG_MxCsr_Mask(uc) ((uc)->uc_mcontext.fpregs->mxcr_mask)
+#define FPREG_Fpstate(uc) ((uc)->uc_mcontext.fpregs)
+#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_xmm[index])
+
+#define FPREG_St(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_st[index])
+
+#define FPREG_ControlWord(uc) (FPREG_Fpstate(uc)->cwd)
+#define FPREG_StatusWord(uc) (FPREG_Fpstate(uc)->swd)
+#define FPREG_TagWord(uc) (FPREG_Fpstate(uc)->ftw)
+#define FPREG_ErrorOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rip)
+#define FPREG_ErrorSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rip)) + 2)
+#define FPREG_DataOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rdp)
+#define FPREG_DataSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rdp)) + 2)
+#define FPREG_MxCsr(uc) (FPREG_Fpstate(uc)->mxcsr)
+#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcr_mask)
+
+/////////////////////
+// Extended state
+
+inline _fpx_sw_bytes *FPREG_FpxSwBytes(const ucontext_t *uc)
+{
+ // Bytes 464..511 in the FXSAVE format are available for software to use for any purpose. In this case, they are used to
+ // indicate information about extended state.
+ _ASSERTE(reinterpret_cast<UINT8 *>(&FPREG_Fpstate(uc)->padding[12]) - reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) == 464);
+
+ _ASSERTE(FPREG_Fpstate(uc) != nullptr);
+
+ return reinterpret_cast<_fpx_sw_bytes *>(&FPREG_Fpstate(uc)->padding[12]);
+}
+
+inline UINT32 FPREG_ExtendedSize(const ucontext_t *uc)
+{
+ _ASSERTE(FPREG_FpxSwBytes(uc)->magic1 == FP_XSTATE_MAGIC1);
+ return FPREG_FpxSwBytes(uc)->extended_size;
+}
+
+inline bool FPREG_HasExtendedState(const ucontext_t *uc)
+{
+ // See comments in /usr/include/x86_64-linux-gnu/asm/sigcontext.h for info on how to detect if extended state is present
+ static_assert_no_msg(FP_XSTATE_MAGIC2_SIZE == sizeof(UINT32));
+
+ if (FPREG_FpxSwBytes(uc)->magic1 != FP_XSTATE_MAGIC1)
+ {
+ return false;
+ }
+
+ UINT32 extendedSize = FPREG_ExtendedSize(uc);
+ if (extendedSize < sizeof(_xstate))
+ {
+ return false;
+ }
+
+ _ASSERTE(extendedSize >= FP_XSTATE_MAGIC2_SIZE);
+ return *reinterpret_cast<UINT32 *>(reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) + (extendedSize - FP_XSTATE_MAGIC2_SIZE))
+ == FP_XSTATE_MAGIC2;
+}
+
+inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
+{
+ static_assert_no_msg(sizeof(reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space) == 16 * 16);
+ _ASSERTE(FPREG_HasExtendedState(uc));
+
+ return reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space;
+}
+
+/////////////////////
#else // BIT64
diff --git a/src/pal/src/include/pal/virtual.h b/src/pal/src/include/pal/virtual.h
index 028d83f0f1..a4e225281e 100644
--- a/src/pal/src/include/pal/virtual.h
+++ b/src/pal/src/include/pal/virtual.h
@@ -28,10 +28,10 @@ extern "C"
typedef struct _CMI {
struct _CMI * pNext; /* Link to the next entry. */
- struct _CMI * pLast; /* Link to the previous entry. */
+ struct _CMI * pPrevious; /* Link to the previous entry. */
- UINT_PTR startBoundary; /* Starting location of the region. */
- SIZE_T memSize; /* Size of the entire region.. */
+ UINT_PTR startBoundary; /* Starting location of the region. */
+ SIZE_T memSize; /* Size of the entire region.. */
DWORD accessProtection; /* Initial allocation access protection. */
DWORD allocationType; /* Initial allocation type. */
diff --git a/src/pal/src/map/virtual.cpp b/src/pal/src/map/virtual.cpp
index c3891494fd..e68ab7849f 100644
--- a/src/pal/src/map/virtual.cpp
+++ b/src/pal/src/map/virtual.cpp
@@ -8,7 +8,7 @@
Module Name:
- virtual.c
+ virtual.cpp
Abstract:
@@ -70,9 +70,80 @@ static LPVOID ReserveVirtualMemory(
// A memory allocator that allocates memory from a pre-reserved region
-// of virtual memory that is located near the coreclr library.
+// of virtual memory that is located near the CoreCLR library.
static ExecutableMemoryAllocator g_executableMemoryAllocator;
+//
+//
+// Virtual Memory Logging
+//
+// We maintain a lightweight in-memory circular buffer recording virtual
+// memory operations so that we can better diagnose failures and crashes
+// caused by one of these operations mishandling memory in some way.
+//
+//
+namespace VirtualMemoryLogging
+{
+ // Specifies the operation being logged
+ enum class VirtualOperation
+ {
+ Allocate = 0x10,
+ Reserve = 0x20,
+ Commit = 0x30,
+ Decommit = 0x40,
+ Release = 0x50,
+ };
+
+ // Indicates that the attempted operation has failed
+ const DWORD FailedOperationMarker = 0x80000000;
+
+ // An entry in the in-memory log
+ struct LogRecord
+ {
+ LONG RecordId;
+ DWORD Operation;
+ LPVOID CurrentThread;
+ LPVOID RequestedAddress;
+ LPVOID ReturnedAddress;
+ SIZE_T Size;
+ DWORD AllocationType;
+ DWORD Protect;
+ };
+
+ // Maximum number of records in the in-memory log
+ const LONG MaxRecords = 128;
+
+ // Buffer used to store the logged data
+ volatile LogRecord logRecords[MaxRecords];
+
+ // Current record number. Use (recordNumber % MaxRecords) to determine
+ // the current position in the circular buffer.
+ volatile LONG recordNumber = 0;
+
+ // Record an entry in the in-memory log
+ void LogVaOperation(
+ IN VirtualOperation operation,
+ IN LPVOID requestedAddress,
+ IN SIZE_T size,
+ IN DWORD flAllocationType,
+ IN DWORD flProtect,
+ IN LPVOID returnedAddress,
+ IN BOOL result)
+ {
+ LONG i = InterlockedIncrement(&recordNumber) - 1;
+ LogRecord* curRec = (LogRecord*)&logRecords[i % MaxRecords];
+
+ curRec->RecordId = i;
+ curRec->CurrentThread = (LPVOID)pthread_self();
+ curRec->RequestedAddress = requestedAddress;
+ curRec->ReturnedAddress = returnedAddress;
+ curRec->Size = size;
+ curRec->AllocationType = flAllocationType;
+ curRec->Protect = flProtect;
+ curRec->Operation = static_cast<DWORD>(operation) | (result ? 0 : FailedOperationMarker);
+ }
+}
+
/*++
Function:
VIRTUALInitialize()
@@ -88,7 +159,7 @@ extern "C"
BOOL
VIRTUALInitialize(bool initializeExecutableMemoryAllocator)
{
- TRACE( "Initializing the Virtual Critical Sections. \n" );
+ TRACE("Initializing the Virtual Critical Sections. \n");
InternalInitializeCriticalSection(&virtual_critsec);
@@ -226,7 +297,7 @@ static INT VIRTUALGetAllocationType( SIZE_T Index, CONST PCMI pInformation )
* IN BYTE* pBitArray - A pointer the array to be manipulated.
*
* Returns TRUE on success, FALSE otherwise.
- * Turn on/off memory staus bits.
+ * Turn on/off memory status bits.
*
*/
static BOOL VIRTUALSetPageBits ( UINT nStatus, SIZE_T nStartingBit,
@@ -445,20 +516,20 @@ static BOOL VIRTUALReleaseMemory( PCMI pMemoryToBeReleased )
pVirtualMemory = pMemoryToBeReleased->pNext;
if ( pMemoryToBeReleased->pNext )
{
- pMemoryToBeReleased->pNext->pLast = NULL;
+ pMemoryToBeReleased->pNext->pPrevious = NULL;
}
}
else /* Could be anywhere in the list. */
{
/* Delete the entry from the linked list. */
- if ( pMemoryToBeReleased->pLast )
+ if ( pMemoryToBeReleased->pPrevious )
{
- pMemoryToBeReleased->pLast->pNext = pMemoryToBeReleased->pNext;
+ pMemoryToBeReleased->pPrevious->pNext = pMemoryToBeReleased->pNext;
}
if ( pMemoryToBeReleased->pNext )
{
- pMemoryToBeReleased->pNext->pLast = pMemoryToBeReleased->pLast;
+ pMemoryToBeReleased->pNext->pPrevious = pMemoryToBeReleased->pPrevious;
}
}
@@ -594,7 +665,7 @@ static void VIRTUALDisplayList( void )
DBGOUT( "\t accessProtection %d \n", p->accessProtection );
DBGOUT( "\t allocationType %d \n", p->allocationType );
DBGOUT( "\t pNext %p \n", p->pNext );
- DBGOUT( "\t pLast %p \n", p->pLast );
+ DBGOUT( "\t pLast %p \n", p->pPrevious );
count++;
p = p->pNext;
@@ -604,6 +675,30 @@ static void VIRTUALDisplayList( void )
}
#endif
+#ifdef DEBUG
+void VerifyRightEntry(PCMI pEntry)
+{
+ volatile PCMI pRight = pEntry->pNext;
+ SIZE_T endAddress;
+ if (pRight != nullptr)
+ {
+ endAddress = ((SIZE_T)pEntry->startBoundary) + pEntry->memSize;
+ _ASSERTE(endAddress <= (SIZE_T)pRight->startBoundary);
+ }
+}
+
+void VerifyLeftEntry(PCMI pEntry)
+{
+ volatile PCMI pLeft = pEntry->pPrevious;
+ SIZE_T endAddress;
+ if (pLeft != NULL)
+ {
+ endAddress = ((SIZE_T)pLeft->startBoundary) + pLeft->memSize;
+ _ASSERTE(endAddress <= (SIZE_T)pEntry->startBoundary);
+ }
+}
+#endif // DEBUG
+
/****
* VIRTUALStoreAllocationInfo()
*
@@ -611,107 +706,106 @@ static void VIRTUALDisplayList( void )
* NOTE: The caller must own the critical section.
*/
static BOOL VIRTUALStoreAllocationInfo(
- IN UINT_PTR startBoundary, /* Start of the region. */
- IN SIZE_T memSize, /* Size of the region. */
+ IN UINT_PTR startBoundary, /* Start of the region. */
+ IN SIZE_T memSize, /* Size of the region. */
IN DWORD flAllocationType, /* Allocation Types. */
IN DWORD flProtection ) /* Protections flags on the memory. */
{
- PCMI pNewEntry = NULL;
- PCMI pMemInfo = NULL;
- BOOL bRetVal = TRUE;
+ PCMI pNewEntry = nullptr;
+ PCMI pMemInfo = nullptr;
SIZE_T nBufferSize = 0;
- if ( ( memSize & VIRTUAL_PAGE_MASK ) != 0 )
+ if ((memSize & VIRTUAL_PAGE_MASK) != 0)
{
- ERROR( "The memory size was not in multiples of the page size. \n" );
- bRetVal = FALSE;
- goto done;
+ ERROR("The memory size was not a multiple of the page size. \n");
+ return FALSE;
}
-
- if ( !(pNewEntry = ( PCMI )InternalMalloc( sizeof( *pNewEntry )) ) )
+
+ if (!(pNewEntry = (PCMI)InternalMalloc(sizeof(*pNewEntry))))
{
ERROR( "Unable to allocate memory for the structure.\n");
- bRetVal = FALSE;
- goto done;
+ return FALSE;
}
-
+
pNewEntry->startBoundary = startBoundary;
pNewEntry->memSize = memSize;
pNewEntry->allocationType = flAllocationType;
pNewEntry->accessProtection = flProtection;
-
+
nBufferSize = memSize / VIRTUAL_PAGE_SIZE / CHAR_BIT;
- if ( ( memSize / VIRTUAL_PAGE_SIZE ) % CHAR_BIT != 0 )
+ if ((memSize / VIRTUAL_PAGE_SIZE) % CHAR_BIT != 0)
{
nBufferSize++;
}
-
- pNewEntry->pAllocState = (BYTE*)InternalMalloc( nBufferSize );
- pNewEntry->pProtectionState = (BYTE*)InternalMalloc( (memSize / VIRTUAL_PAGE_SIZE) );
+
+ pNewEntry->pAllocState = (BYTE*)InternalMalloc(nBufferSize);
+ pNewEntry->pProtectionState = (BYTE*)InternalMalloc((memSize / VIRTUAL_PAGE_SIZE));
if (pNewEntry->pAllocState && pNewEntry->pProtectionState)
{
/* Set the intial allocation state, and initial allocation protection. */
- VIRTUALSetAllocState( MEM_RESERVE, 0, nBufferSize * CHAR_BIT, pNewEntry );
- memset( pNewEntry->pProtectionState,
- VIRTUALConvertWinFlags( flProtection ),
- memSize / VIRTUAL_PAGE_SIZE );
+ VIRTUALSetAllocState(MEM_RESERVE, 0, nBufferSize * CHAR_BIT, pNewEntry);
+ memset(pNewEntry->pProtectionState,
+ VIRTUALConvertWinFlags(flProtection),
+ memSize / VIRTUAL_PAGE_SIZE);
}
else
{
ERROR( "Unable to allocate memory for the structure.\n");
- bRetVal = FALSE;
- if (pNewEntry->pProtectionState) InternalFree( pNewEntry->pProtectionState );
- pNewEntry->pProtectionState = NULL;
+ if (pNewEntry->pProtectionState) InternalFree(pNewEntry->pProtectionState);
+ pNewEntry->pProtectionState = nullptr;
- if (pNewEntry->pAllocState) InternalFree( pNewEntry->pAllocState );
- pNewEntry->pAllocState = NULL;
+ if (pNewEntry->pAllocState) InternalFree(pNewEntry->pAllocState);
+ pNewEntry->pAllocState = nullptr;
- InternalFree( pNewEntry );
- pNewEntry = NULL;
-
- goto done;
+ InternalFree(pNewEntry);
+ pNewEntry = nullptr;
+
+ return FALSE;
}
pMemInfo = pVirtualMemory;
- if ( pMemInfo && pMemInfo->startBoundary < startBoundary )
+ if (pMemInfo && pMemInfo->startBoundary < startBoundary)
{
/* Look for the correct insert point */
- TRACE( "Looking for the correct insert location.\n");
- while ( pMemInfo->pNext && ( pMemInfo->pNext->startBoundary < startBoundary ) )
+ TRACE("Looking for the correct insert location.\n");
+ while (pMemInfo->pNext && (pMemInfo->pNext->startBoundary < startBoundary))
{
pMemInfo = pMemInfo->pNext;
}
-
+
pNewEntry->pNext = pMemInfo->pNext;
- pNewEntry->pLast = pMemInfo;
-
- if ( pNewEntry->pNext )
+ pNewEntry->pPrevious = pMemInfo;
+
+ if (pNewEntry->pNext)
{
- pNewEntry->pNext->pLast = pNewEntry;
+ pNewEntry->pNext->pPrevious = pNewEntry;
}
-
+
pMemInfo->pNext = pNewEntry;
}
else
{
- TRACE( "Inserting a new element into the linked list\n" );
/* This is the first entry in the list. */
pNewEntry->pNext = pMemInfo;
- pNewEntry->pLast = NULL;
-
- if ( pNewEntry->pNext )
+ pNewEntry->pPrevious = nullptr;
+
+ if (pNewEntry->pNext)
{
- pNewEntry->pNext->pLast = pNewEntry;
+ pNewEntry->pNext->pPrevious = pNewEntry;
}
-
+
pVirtualMemory = pNewEntry ;
}
-done:
- TRACE( "Exiting StoreAllocationInformation. \n" );
- return bRetVal;
+
+#ifdef DEBUG
+ VerifyRightEntry(pNewEntry);
+ VerifyLeftEntry(pNewEntry);
+#endif // DEBUG
+
+ return TRUE;
}
/******
@@ -778,6 +872,15 @@ static LPVOID VIRTUALReserveMemory(
}
}
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Reserve,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ pRetVal,
+ pRetVal != NULL);
+
InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
return pRetVal;
}
@@ -1058,6 +1161,16 @@ error:
}
done:
+
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Commit,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ pRetVal,
+ pRetVal != NULL);
+
return pRetVal;
}
@@ -1117,6 +1230,15 @@ VirtualAlloc(
WARN( "Ignoring the allocation flag MEM_TOP_DOWN.\n" );
}
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Allocate,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ NULL,
+ TRUE);
+
if ( flAllocationType & MEM_RESERVE )
{
InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
@@ -1325,6 +1447,17 @@ VirtualFree(
}
VirtualFreeExit:
+
+ LogVaOperation(
+ (dwFreeType & MEM_DECOMMIT) ? VirtualMemoryLogging::VirtualOperation::Decommit
+ : VirtualMemoryLogging::VirtualOperation::Release,
+ lpAddress,
+ dwSize,
+ dwFreeType,
+ 0,
+ NULL,
+ bRetVal);
+
InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
LOGEXIT( "VirtualFree returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
PERF_EXIT(VirtualFree);
diff --git a/src/pal/src/thread/context.cpp b/src/pal/src/thread/context.cpp
index 025bb978c6..9aaf105d74 100644
--- a/src/pal/src/thread/context.cpp
+++ b/src/pal/src/thread/context.cpp
@@ -19,8 +19,10 @@ Abstract:
--*/
-#include "pal/palinternal.h"
#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
#include "pal/context.h"
#include "pal/debug.h"
#include "pal/thread.hpp"
@@ -29,8 +31,6 @@ Abstract:
#include <errno.h>
#include <unistd.h>
-SET_DEFAULT_DEBUG_CHANNEL(THREAD);
-
extern PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode;
// in context2.S
@@ -465,6 +465,15 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native)
}
#endif
}
+
+ // TODO: Enable for all Unix systems
+#if defined(_AMD64_) && defined(__linux__)
+ if ((lpContext->ContextFlags & CONTEXT_XSTATE) != 0)
+ {
+ _ASSERTE(FPREG_HasExtendedState(native));
+ memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16);
+ }
+#endif // _AMD64_
}
/*++
@@ -513,16 +522,19 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
if (native->uc_mcontext.__fpregs == nullptr)
#endif
{
- // Reset the CONTEXT_FLOATING_POINT bit(s) so it's clear that the floating point
- // data in the CONTEXT is not valid. Since CONTEXT_FLOATING_POINT is defined as
- // the architecture bit(s) OR'd with one or more other bits, we first get the bits
- // that are unique to CONTEXT_FLOATING_POINT by resetting the architecture bits.
- // We determine what those are by inverting the union of CONTEXT_CONTROL and
- // CONTEXT_INTEGER, both of which should also have the architecture bit(s) set.
+ // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's
+ // clear that the floating point and extended state data in the CONTEXT is not
+ // valid. Since these flags are defined as the architecture bit(s) OR'd with one
+ // or more other bits, we first get the bits that are unique to each by resetting
+ // the architecture bits. We determine what those are by inverting the union of
+ // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the
+ // architecture bit(s) set.
const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
- lpContext->ContextFlags &= ~floatingPointFlags;
+ const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
+
+ lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags);
- // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT
+ // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE
return;
}
#endif
@@ -551,6 +563,24 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
}
#endif
}
+
+ // TODO: Enable for all Unix systems
+#if defined(_AMD64_) && defined(__linux__)
+ if ((contextFlags & CONTEXT_XSTATE) != 0)
+ {
+ if (FPREG_HasExtendedState(native))
+ {
+ memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16);
+ }
+ else
+ {
+ // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in
+ // the CONTEXT is not valid.
+ const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
+ lpContext->ContextFlags &= ~xstateFlags;
+ }
+ }
+#endif // _AMD64_
}
/*++
diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp
index 159c451224..d6f6f9c47a 100644
--- a/src/pal/src/thread/thread.cpp
+++ b/src/pal/src/thread/thread.cpp
@@ -18,6 +18,9 @@ Abstract:
--*/
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
+
#include "pal/corunix.hpp"
#include "pal/context.h"
#include "pal/thread.hpp"
@@ -29,7 +32,6 @@ Abstract:
#include "procprivate.hpp"
#include "pal/process.h"
#include "pal/module.h"
-#include "pal/dbgmsg.h"
#include "pal/environ.h"
#include "pal/init.h"
@@ -74,7 +76,6 @@ using namespace CorUnix;
/* ------------------- Definitions ------------------------------*/
-SET_DEFAULT_DEBUG_CHANNEL(THREAD);
// The default stack size of a newly created thread (currently 256KB)
// when the dwStackSize parameter of PAL_CreateThread()
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index 89a6437da1..66fc6432af 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -27,6 +27,13 @@ if(CLR_CMAKE_PLATFORM_UNIX)
add_compile_options(-fPIC)
endif(CLR_CMAKE_PLATFORM_UNIX)
+if(FEATURE_GDBJIT)
+ set(VM_SOURCES_GDBJIT
+ gdbjit.cpp
+ )
+ add_definitions(-DFEATURE_GDBJIT)
+endif(FEATURE_GDBJIT)
+
set(VM_SOURCES_DAC_AND_WKS_COMMON
appdomain.cpp
array.cpp
@@ -109,6 +116,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
virtualcallstub.cpp
win32threadpool.cpp
zapsig.cpp
+ ${VM_SOURCES_GDBJIT}
)
if(FEATURE_READYTORUN)
diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp
index 1972b23ea7..73b21a7a0b 100644
--- a/src/vm/gcenv.os.cpp
+++ b/src/vm/gcenv.os.cpp
@@ -534,9 +534,14 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit()
return memStatus.ullTotalPhys;
}
-// Get global memory status
+// Get memory status
// Parameters:
-// ms - pointer to the structure that will be filled in with the memory status
+// memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
+// that is in use (0 indicates no memory use and 100 indicates full memory use).
+// available_physical - The amount of physical memory currently available, in bytes.
+// available_page_file - The maximum amount of memory the current process can commit, in bytes.
+// Remarks:
+// Any parameter can be null.
void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp
new file mode 100644
index 0000000000..435dec4da3
--- /dev/null
+++ b/src/vm/gdbjit.cpp
@@ -0,0 +1,1003 @@
+// 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.
+//*****************************************************************************
+// File: gdbjit.cpp
+//
+
+//
+// NotifyGdb implementation.
+//
+//*****************************************************************************
+
+#include "common.h"
+#include "gdbjit.h"
+#include "gdbjithelpers.h"
+
+struct DebuggerILToNativeMap
+{
+ ULONG ilOffset;
+ ULONG nativeStartOffset;
+ ULONG nativeEndOffset;
+ ICorDebugInfo::SourceTypes source;
+};
+BYTE* DebugInfoStoreNew(void * pData, size_t cBytes)
+{
+ return new (nothrow) BYTE[cBytes];
+}
+
+/* Get IL to native offsets map */
+HRESULT
+GetMethodNativeMap(MethodDesc* methodDesc,
+ ULONG32* numMap,
+ DebuggerILToNativeMap** map)
+{
+ // Use the DebugInfoStore to get IL->Native maps.
+ // It doesn't matter whether we're jitted, ngenned etc.
+
+ DebugInfoRequest request;
+ TADDR nativeCodeStartAddr = PCODEToPINSTR(methodDesc->GetNativeCode());
+ request.InitFromStartingAddr(methodDesc, nativeCodeStartAddr);
+
+ // Bounds info.
+ ULONG32 countMapCopy;
+ NewHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
+
+ BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
+ DebugInfoStoreNew,
+ NULL, // allocator
+ &countMapCopy,
+ &mapCopy,
+ NULL,
+ NULL);
+
+ if (!success)
+ {
+ return E_FAIL;
+ }
+
+ // Need to convert map formats.
+ *numMap = countMapCopy;
+
+ *map = new (nothrow) DebuggerILToNativeMap[countMapCopy];
+ if (!*map)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ ULONG32 i;
+ for (i = 0; i < *numMap; i++)
+ {
+ (*map)[i].ilOffset = mapCopy[i].ilOffset;
+ (*map)[i].nativeStartOffset = mapCopy[i].nativeOffset;
+ if (i > 0)
+ {
+ (*map)[i - 1].nativeEndOffset = (*map)[i].nativeStartOffset;
+ }
+ (*map)[i].source = mapCopy[i].source;
+ }
+ if (*numMap >= 1)
+ {
+ (*map)[i - 1].nativeEndOffset = 0;
+ }
+ return S_OK;
+}
+
+/* Get mapping of IL offsets to source line numbers */
+HRESULT
+GetDebugInfoFromPDB(MethodDesc* MethodDescPtr, SymbolsInfo** symInfo, unsigned int &symInfoLen)
+{
+ DebuggerILToNativeMap* map = NULL;
+
+ ULONG32 numMap;
+
+ if (!getInfoForMethodDelegate)
+ return E_FAIL;
+
+ if (GetMethodNativeMap(MethodDescPtr, &numMap, &map) != S_OK)
+ return E_FAIL;
+
+ const Module* mod = MethodDescPtr->GetMethodTable()->GetModule();
+ SString modName = mod->GetFile()->GetPath();
+ StackScratchBuffer scratch;
+ const char* szModName = modName.GetUTF8(scratch);
+
+ MethodDebugInfo* methodDebugInfo = new (nothrow) MethodDebugInfo();
+ if (methodDebugInfo == nullptr)
+ return E_OUTOFMEMORY;
+ methodDebugInfo->points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numMap);
+ if (methodDebugInfo->points == nullptr)
+ return E_OUTOFMEMORY;
+ methodDebugInfo->size = numMap;
+
+ if (!getInfoForMethodDelegate(szModName, MethodDescPtr->GetMemberDef(), *methodDebugInfo))
+ return E_FAIL;
+
+ symInfoLen = methodDebugInfo->size;
+ *symInfo = new (nothrow) SymbolsInfo[symInfoLen];
+ if (*symInfo == nullptr)
+ return E_FAIL;
+
+ for (ULONG32 i = 0; i < symInfoLen; i++)
+ {
+ for (ULONG32 j = 0; j < numMap; j++)
+ {
+ if (methodDebugInfo->points[i].ilOffset == map[j].ilOffset)
+ {
+ SymbolsInfo& s = (*symInfo)[i];
+ const SequencePointInfo& sp = methodDebugInfo->points[i];
+
+ s.nativeOffset = map[j].nativeStartOffset;
+ s.ilOffset = map[j].ilOffset;
+ s.fileIndex = 0;
+ //wcscpy(s.fileName, sp.fileName);
+ int len = WideCharToMultiByte(CP_UTF8, 0, sp.fileName, -1, s.fileName, sizeof(s.fileName), NULL, NULL);
+ s.fileName[len] = 0;
+ s.lineNumber = sp.lineNumber;
+ }
+ }
+ }
+
+ CoTaskMemFree(methodDebugInfo->points);
+ return S_OK;
+}
+
+// GDB JIT interface
+typedef enum
+{
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ UINT64 symfile_size;
+};
+
+struct jit_descriptor
+{
+ UINT32 version;
+ /* This type should be jit_actions_t, but we use uint32_t
+ to be explicit about the bitwidth. */
+ UINT32 action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+// GDB puts a breakpoint in this function.
+// To prevent from inlining we add noinline attribute and inline assembler statement.
+extern "C"
+void __attribute__((noinline)) __jit_debug_register_code() { __asm__(""); };
+
+/* Make sure to specify the version statically, because the
+ debugger may check the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+// END of GDB JIT interface
+
+/* Predefined section names */
+const char* SectionNames[] = {
+ "", ".text", ".shstrtab", ".debug_str", ".debug_abbrev", ".debug_info",
+ ".debug_pubnames", ".debug_pubtypes", ".debug_line", ""
+};
+
+const int SectionNamesCount = sizeof(SectionNames) / sizeof(SectionNames[0]);
+
+/* Static data for section headers */
+struct SectionHeader {
+ uint32_t m_type;
+ uint64_t m_flags;
+} Sections[] = {
+ {SHT_NULL, 0},
+ {SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR},
+ {SHT_STRTAB, 0},
+ {SHT_PROGBITS, SHF_MERGE | SHF_STRINGS },
+ {SHT_PROGBITS, 0},
+ {SHT_PROGBITS, 0},
+ {SHT_PROGBITS, 0},
+ {SHT_PROGBITS, 0},
+ {SHT_PROGBITS, 0}
+};
+
+/* Static data for .debug_str section */
+const char* DebugStrings[] = {
+ "CoreCLR", "" /* module name */, "" /* module path */, "" /* method name */, "int"
+};
+
+const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]);
+
+/* Static data for .debug_abbrev */
+const unsigned char AbbrevTable[] = {
+ 1, DW_TAG_compile_unit, DW_CHILDREN_yes,
+ DW_AT_producer, DW_FORM_strp, DW_AT_language, DW_FORM_data2, DW_AT_name, DW_FORM_strp,
+ DW_AT_stmt_list, DW_FORM_sec_offset, 0, 0,
+ 2, DW_TAG_subprogram, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_strp, DW_AT_decl_file, DW_FORM_data1, DW_AT_decl_line, DW_FORM_data1,
+ DW_AT_type, DW_FORM_ref4, DW_AT_external, DW_FORM_flag_present, 0, 0,
+ 3, DW_TAG_base_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_strp, DW_AT_encoding, DW_FORM_data1, DW_AT_byte_size, DW_FORM_data1,0, 0,
+ 0
+};
+
+const int AbbrevTableSize = sizeof(AbbrevTable);
+
+/* Static data for .debug_line, including header */
+#define DWARF_LINE_BASE (-5)
+#define DWARF_LINE_RANGE 14
+#define DWARF_OPCODE_BASE 13
+
+DwarfLineNumHeader LineNumHeader = {
+ 0, 2, 0, 1, 1, DWARF_LINE_BASE, DWARF_LINE_RANGE, DWARF_OPCODE_BASE, {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}
+};
+
+/* Static data for .debug_info */
+struct __attribute__((packed)) DebugInfo
+{
+ uint8_t m_cu_abbrev;
+ uint32_t m_prod_off;
+ uint16_t m_lang;
+ uint32_t m_cu_name;
+ uint32_t m_line_num;
+
+ uint8_t m_sub_abbrev;
+ uint32_t m_sub_name;
+ uint8_t m_file, m_line;
+ uint32_t m_sub_type;
+
+ uint8_t m_type_abbrev;
+ uint32_t m_type_name;
+ uint8_t m_encoding;
+ uint8_t m_byte_size;
+} debugInfo = {
+ 1, 0, DW_LANG_C89, 0, 0,
+ 2, 0, 1, 1, 37,
+ 3, 0, DW_ATE_signed, 4
+};
+
+/* Create ELF/DWARF debug info for jitted method */
+void NotifyGdb::MethodCompiled(MethodDesc* MethodDescPtr)
+{
+ PCODE pCode = MethodDescPtr->GetNativeCode();
+
+ if (pCode == NULL)
+ return;
+ unsigned int symInfoLen = 0;
+ NewArrayHolder<SymbolsInfo> symInfo = nullptr;
+
+ /* Get method name & size of jitted code */
+ LPCUTF8 methodName = MethodDescPtr->GetName();
+ EECodeInfo codeInfo(pCode);
+ TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
+
+#ifdef _TARGET_ARM_
+ pCode &= ~1; // clear thumb flag for debug info
+#endif
+
+ /* Get module name */
+ const Module* mod = MethodDescPtr->GetMethodTable()->GetModule();
+ SString modName = mod->GetFile()->GetPath();
+ StackScratchBuffer scratch;
+ const char* szModName = modName.GetUTF8(scratch);
+ const char *szModulePath, *szModuleFile;
+
+ SplitPathname(szModName, szModulePath, szModuleFile);
+
+ /* Get debug info for method from portable PDB */
+ HRESULT hr = GetDebugInfoFromPDB(MethodDescPtr, &symInfo, symInfoLen);
+ if (FAILED(hr) || symInfoLen == 0)
+ {
+ return;
+ }
+
+ MemBuf elfHeader, sectHeaders, sectStr, dbgInfo, dbgAbbrev, dbgPubname, dbgPubType, dbgLine, dbgStr, elfFile;
+
+ /* Build .debug_abbrev section */
+ if (!BuildDebugAbbrev(dbgAbbrev))
+ {
+ return;
+ }
+
+ /* Build .debug_line section */
+ if (!BuildLineTable(dbgLine, pCode, symInfo, symInfoLen))
+ {
+ return;
+ }
+
+ DebugStrings[1] = szModuleFile;
+ DebugStrings[3] = methodName;
+
+ /* Build .debug_str section */
+ if (!BuildDebugStrings(dbgStr))
+ {
+ return;
+ }
+
+ /* Build .debug_info section */
+ if (!BuildDebugInfo(dbgInfo))
+ {
+ return;
+ }
+
+ /* Build .debug_pubname section */
+ if (!BuildDebugPub(dbgPubname, methodName, dbgInfo.MemSize, 26))
+ {
+ return;
+ }
+
+ /* Build debug_pubtype section */
+ if (!BuildDebugPub(dbgPubType, "int", dbgInfo.MemSize, 37))
+ {
+ return;
+ }
+
+ /* Build section names section */
+ if (!BuildSectionNameTable(sectStr))
+ {
+ return;
+ }
+
+ /* Build section headers table */
+ if (!BuildSectionTable(sectHeaders))
+ {
+ return;
+ }
+
+ /* Patch section offsets & sizes */
+ long offset = sizeof(Elf_Ehdr);
+ Elf_Shdr* pShdr = reinterpret_cast<Elf_Shdr*>(sectHeaders.MemPtr.GetValue());
+ ++pShdr; // .text
+ pShdr->sh_addr = pCode;
+ pShdr->sh_size = codeSize;
+ ++pShdr; // .shstrtab
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = sectStr.MemSize;
+ offset += sectStr.MemSize;
+ ++pShdr; // .debug_str
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgStr.MemSize;
+ offset += dbgStr.MemSize;
+ ++pShdr; // .debug_abbrev
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgAbbrev.MemSize;
+ offset += dbgAbbrev.MemSize;
+ ++pShdr; // .debug_info
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgInfo.MemSize;
+ offset += dbgInfo.MemSize;
+ ++pShdr; // .debug_pubnames
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgPubname.MemSize;
+ offset += dbgPubname.MemSize;
+ ++pShdr; // .debug_pubtypes
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgPubType.MemSize;
+ offset += dbgPubType.MemSize;
+ ++pShdr; // .debug_line
+ pShdr->sh_offset = offset;
+ pShdr->sh_size = dbgLine.MemSize;
+ offset += dbgLine.MemSize;
+
+ /* Build ELF header */
+ if (!BuildELFHeader(elfHeader))
+ {
+ return;
+ }
+ Elf_Ehdr* header = reinterpret_cast<Elf_Ehdr*>(elfHeader.MemPtr.GetValue());
+#ifdef _TARGET_ARM_
+ header->e_flags = EF_ARM_EABI_VER5;
+#ifdef ARM_SOFTFP
+ header->e_flags |= EF_ARM_SOFT_FLOAT;
+#else
+ header->e_flags |= EF_ARM_VFP_FLOAT;
+#endif
+#endif
+ header->e_shoff = offset;
+ header->e_shentsize = sizeof(Elf_Shdr);
+ header->e_shnum = SectionNamesCount - 1;
+ header->e_shstrndx = 2;
+
+ /* Build ELF image in memory */
+ elfFile.MemSize = elfHeader.MemSize + sectStr.MemSize + dbgStr.MemSize + dbgAbbrev.MemSize
+ + dbgInfo.MemSize + dbgPubname.MemSize + dbgPubType.MemSize + dbgLine.MemSize + sectHeaders.MemSize;
+ elfFile.MemPtr = new (nothrow) char[elfFile.MemSize];
+ if (elfFile.MemPtr == nullptr)
+ {
+ return;
+ }
+
+ /* Copy section data */
+ offset = 0;
+ memcpy(elfFile.MemPtr, elfHeader.MemPtr, elfHeader.MemSize);
+ offset += elfHeader.MemSize;
+ memcpy(elfFile.MemPtr + offset, sectStr.MemPtr, sectStr.MemSize);
+ offset += sectStr.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgStr.MemPtr, dbgStr.MemSize);
+ offset += dbgStr.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgAbbrev.MemPtr, dbgAbbrev.MemSize);
+ offset += dbgAbbrev.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgInfo.MemPtr, dbgInfo.MemSize);
+ offset += dbgInfo.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgPubname.MemPtr, dbgPubname.MemSize);
+ offset += dbgPubname.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgPubType.MemPtr, dbgPubType.MemSize);
+ offset += dbgPubType.MemSize;
+ memcpy(elfFile.MemPtr + offset, dbgLine.MemPtr, dbgLine.MemSize);
+ offset += dbgLine.MemSize;
+ memcpy(elfFile.MemPtr + offset, sectHeaders.MemPtr, sectHeaders.MemSize);
+
+ /* Create GDB JIT structures */
+ jit_code_entry* jit_symbols = new (nothrow) jit_code_entry;
+
+ if (jit_symbols == nullptr)
+ {
+ return;
+ }
+
+ /* Fill the new entry */
+ jit_symbols->next_entry = jit_symbols->prev_entry = 0;
+ jit_symbols->symfile_addr = elfFile.MemPtr;
+ jit_symbols->symfile_size = elfFile.MemSize;
+
+ /* Link into list */
+ jit_code_entry *head = __jit_debug_descriptor.first_entry;
+ __jit_debug_descriptor.first_entry = jit_symbols;
+ if (head != 0)
+ {
+ jit_symbols->next_entry = head;
+ head->prev_entry = jit_symbols;
+ }
+
+ /* Notify the debugger */
+ __jit_debug_descriptor.relevant_entry = jit_symbols;
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_register_code();
+
+}
+
+void NotifyGdb::MethodDropped(MethodDesc* MethodDescPtr)
+{
+ PCODE pCode = MethodDescPtr->GetNativeCode();
+
+ if (pCode == NULL)
+ return;
+
+ /* Find relevant entry */
+ for (jit_code_entry* jit_symbols = __jit_debug_descriptor.first_entry; jit_symbols != 0; jit_symbols = jit_symbols->next_entry)
+ {
+ const char* ptr = jit_symbols->symfile_addr;
+ uint64_t size = jit_symbols->symfile_size;
+
+ const Elf_Ehdr* pEhdr = reinterpret_cast<const Elf_Ehdr*>(ptr);
+ const Elf_Shdr* pShdr = reinterpret_cast<const Elf_Shdr*>(ptr + pEhdr->e_shoff);
+ ++pShdr; // bump to .text section
+ if (pShdr->sh_addr == pCode)
+ {
+ /* Notify the debugger */
+ __jit_debug_descriptor.relevant_entry = jit_symbols;
+ __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+ __jit_debug_register_code();
+
+ /* Free memory */
+ delete[] ptr;
+
+ /* Unlink from list */
+ if (jit_symbols->prev_entry == 0)
+ __jit_debug_descriptor.first_entry = jit_symbols->next_entry;
+ else
+ jit_symbols->prev_entry->next_entry = jit_symbols->next_entry;
+ delete jit_symbols;
+ break;
+ }
+ }
+}
+
+/* Build the DWARF .debug_line section */
+bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines)
+{
+ MemBuf fileTable, lineProg;
+
+ /* Build file table */
+ if (!BuildFileTable(fileTable, lines, nlines))
+ return false;
+ /* Build line info program */
+ if (!BuildLineProg(lineProg, startAddr, lines, nlines))
+ {
+ return false;
+ }
+
+ buf.MemSize = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize + lineProg.MemSize;
+ buf.MemPtr = new (nothrow) char[buf.MemSize];
+
+ if (buf.MemPtr == nullptr)
+ {
+ return false;
+ }
+
+ /* Fill the line info header */
+ DwarfLineNumHeader* header = reinterpret_cast<DwarfLineNumHeader*>(buf.MemPtr.GetValue());
+ memcpy(buf.MemPtr, &LineNumHeader, sizeof(DwarfLineNumHeader));
+ header->m_length = buf.MemSize - sizeof(uint32_t);
+ header->m_hdr_length = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize - 2 * sizeof(uint32_t) - sizeof(uint16_t);
+ buf.MemPtr[sizeof(DwarfLineNumHeader)] = 0; // this is for missing directory table
+ /* copy file table */
+ memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1, fileTable.MemPtr, fileTable.MemSize);
+ /* copy line program */
+ memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
+
+ return true;
+}
+
+/* Buid the source files table for DWARF source line info */
+bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines)
+{
+ const char** files = nullptr;
+ unsigned nfiles = 0;
+
+ /* GetValue file names and replace them with indices in file table */
+ files = new (nothrow) const char*[nlines];
+ if (files == nullptr)
+ return false;
+ for (unsigned i = 0; i < nlines; ++i)
+ {
+ const char *filePath, *fileName;
+ SplitPathname(lines[i].fileName, filePath, fileName);
+
+ /* if this isn't first then we already added file, so adjust index */
+ lines[i].fileIndex = (nfiles) ? (nfiles - 1) : (nfiles);
+
+ bool found = false;
+ for (int j = 0; j < nfiles; ++j)
+ {
+ if (strcmp(fileName, files[j]) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ /* add new source file */
+ if (!found)
+ {
+ files[nfiles++] = fileName;
+ }
+ }
+
+ /* build file table */
+ unsigned totalSize = 0;
+
+ for (unsigned i = 0; i < nfiles; ++i)
+ {
+ totalSize += strlen(files[i]) + 1 + 3;
+ }
+ totalSize += 1;
+
+ buf.MemSize = totalSize;
+ buf.MemPtr = new (nothrow) char[buf.MemSize];
+
+ if (buf.MemPtr == nullptr)
+ {
+ delete[] files;
+ return false;
+ }
+
+ /* copy collected file names */
+ char *ptr = buf.MemPtr;
+ for (unsigned i = 0; i < nfiles; ++i)
+ {
+ strcpy(ptr, files[i]);
+ ptr += strlen(files[i]) + 1;
+ // three LEB128 entries which we don't care
+ *ptr++ = 0;
+ *ptr++ = 0;
+ *ptr++ = 0;
+ }
+ // final zero byte
+ *ptr = 0;
+
+ delete[] files;
+ return true;
+}
+
+/* Command to set absolute address */
+void NotifyGdb::IssueSetAddress(char*& ptr, PCODE addr)
+{
+ *ptr++ = 0;
+ *ptr++ = ADDRESS_SIZE + 1;
+ *ptr++ = DW_LNE_set_address;
+ *reinterpret_cast<PCODE*>(ptr) = addr;
+ ptr += ADDRESS_SIZE;
+}
+
+/* End of line program */
+void NotifyGdb::IssueEndOfSequence(char*& ptr)
+{
+ *ptr++ = 0;
+ *ptr++ = 1;
+ *ptr++ = DW_LNE_end_sequence;
+}
+
+/* Command w/o parameters */
+void NotifyGdb::IssueSimpleCommand(char*& ptr, uint8_t command)
+{
+ *ptr++ = command;
+}
+
+/* Command with one LEB128 parameter */
+void NotifyGdb::IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_size)
+{
+ *ptr++ = command;
+ while (param_size-- > 0)
+ {
+ *ptr++ = *param++;
+ }
+}
+
+/* Special command moves address, line number and issue one row to source line matrix */
+void NotifyGdb::IssueSpecialCommand(char*& ptr, int8_t line_shift, uint8_t addr_shift)
+{
+ *ptr++ = (line_shift - DWARF_LINE_BASE) + addr_shift * DWARF_LINE_RANGE + DWARF_OPCODE_BASE;
+}
+
+/* Check to see if given shifts are fit into one byte command */
+bool NotifyGdb::FitIntoSpecialOpcode(int8_t line_shift, uint8_t addr_shift)
+{
+ unsigned opcode = (line_shift - DWARF_LINE_BASE) + addr_shift * DWARF_LINE_RANGE + DWARF_OPCODE_BASE;
+
+ return opcode < 255;
+}
+
+/* Build program for DWARF source line section */
+bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines)
+{
+ static char cnv_buf[16];
+
+ /* reserve memory assuming worst case: one extended and one special command for each line */
+ buf.MemSize = nlines * ( 4 + ADDRESS_SIZE) + 4;
+ buf.MemPtr = new (nothrow) char[buf.MemSize];
+ char* ptr = buf.MemPtr;
+
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ /* set absolute start address */
+ IssueSetAddress(ptr, startAddr);
+ IssueSimpleCommand(ptr, DW_LNS_set_prologue_end);
+
+ int prevLine = 1, prevAddr = 0, prevFile = 0;
+
+ for (int i = 0; i < nlines; ++i)
+ {
+ /* different source file */
+ if (lines[i].fileIndex != prevFile)
+ {
+ int len = Leb128Encode(static_cast<uint32_t>(lines[i].fileIndex+1), cnv_buf, sizeof(cnv_buf));
+ IssueParamCommand(ptr, DW_LNS_set_file, cnv_buf, len);
+ prevFile = lines[i].fileIndex;
+ }
+ /* too big line number shift */
+ if (lines[i].lineNumber - prevLine > (DWARF_LINE_BASE + DWARF_LINE_RANGE - 1))
+ {
+ int len = Leb128Encode(static_cast<int32_t>(lines[i].lineNumber - prevLine), cnv_buf, sizeof(cnv_buf));
+ IssueParamCommand(ptr, DW_LNS_advance_line, cnv_buf, len);
+ prevLine = lines[i].lineNumber;
+ }
+ /* first try special opcode */
+ if (FitIntoSpecialOpcode(lines[i].lineNumber - prevLine, lines[i].nativeOffset - prevAddr))
+ IssueSpecialCommand(ptr, lines[i].lineNumber - prevLine, lines[i].nativeOffset - prevAddr);
+ else
+ {
+ IssueSetAddress(ptr, startAddr + lines[i].nativeOffset);
+ IssueSpecialCommand(ptr, lines[i].lineNumber - prevLine, 0);
+ }
+
+ prevLine = lines[i].lineNumber;
+ prevAddr = lines[i].nativeOffset;
+ }
+
+ IssueEndOfSequence(ptr);
+
+ buf.MemSize = ptr - buf.MemPtr;
+ return true;
+}
+
+/* Build the DWARF .debug_str section */
+bool NotifyGdb::BuildDebugStrings(MemBuf& buf)
+{
+ uint32_t totalLength = 0;
+
+ /* calculate total section size */
+ for (int i = 0; i < DebugStringCount; ++i)
+ {
+ totalLength += strlen(DebugStrings[i]) + 1;
+ }
+
+ buf.MemSize = totalLength;
+ buf.MemPtr = new (nothrow) char[totalLength];
+
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ /* copy strings */
+ char* bufPtr = buf.MemPtr;
+ for (int i = 0; i < DebugStringCount; ++i)
+ {
+ strcpy(bufPtr, DebugStrings[i]);
+ bufPtr += strlen(DebugStrings[i]) + 1;
+ }
+
+ return true;
+}
+
+/* Build the DWARF .debug_abbrev section */
+bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
+{
+ buf.MemPtr = new (nothrow) char[AbbrevTableSize];
+ buf.MemSize = AbbrevTableSize;
+
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ memcpy(buf.MemPtr, AbbrevTable, AbbrevTableSize);
+ return true;
+}
+
+/* Build tge DWARF .debug_info section */
+bool NotifyGdb::BuildDebugInfo(MemBuf& buf)
+{
+ buf.MemSize = sizeof(DwarfCompUnit) + sizeof(DebugInfo) + 1;
+ buf.MemPtr = new (nothrow) char[buf.MemSize];
+
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ /* Compile uint header */
+ DwarfCompUnit* cu = reinterpret_cast<DwarfCompUnit*>(buf.MemPtr.GetValue());
+ cu->m_length = buf.MemSize - sizeof(uint32_t);
+ cu->m_version = 4;
+ cu->m_abbrev_offset = 0;
+ cu->m_addr_size = ADDRESS_SIZE;
+
+ /* copy debug information */
+ DebugInfo* di = reinterpret_cast<DebugInfo*>(buf.MemPtr + sizeof(DwarfCompUnit));
+ memcpy(buf.MemPtr + sizeof(DwarfCompUnit), &debugInfo, sizeof(DebugInfo));
+ di->m_prod_off = 0;
+ di->m_cu_name = strlen(DebugStrings[0]) + 1;
+ di->m_sub_name = strlen(DebugStrings[0]) + 1 + strlen(DebugStrings[1]) + 1 + strlen(DebugStrings[2]) + 1;
+ di->m_type_name = strlen(DebugStrings[0]) + 1 + strlen(DebugStrings[1]) + 1 + strlen(DebugStrings[2]) + 1 + strlen(DebugStrings[3]) + 1;
+
+ /* zero end marker */
+ buf.MemPtr[buf.MemSize-1] = 0;
+ return true;
+}
+
+/* Build the DWARF lookup section */
+bool NotifyGdb::BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t die_offset)
+{
+ uint32_t length = sizeof(DwarfPubHeader) + sizeof(uint32_t) + strlen(name) + 1 + sizeof(uint32_t);
+
+ buf.MemSize = length;
+ buf.MemPtr = new (nothrow) char[buf.MemSize];
+
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ DwarfPubHeader* header = reinterpret_cast<DwarfPubHeader*>(buf.MemPtr.GetValue());
+ header->m_length = length - sizeof(uint32_t);
+ header->m_version = 2;
+ header->m_debug_info_off = 0;
+ header->m_debug_info_len = size;
+ *reinterpret_cast<uint32_t*>(buf.MemPtr + sizeof(DwarfPubHeader)) = die_offset;
+ strcpy(buf.MemPtr + sizeof(DwarfPubHeader) + sizeof(uint32_t), name);
+ *reinterpret_cast<uint32_t*>(buf.MemPtr + length - sizeof(uint32_t)) = 0;
+
+ return true;
+}
+
+/* Build ELF string section */
+bool NotifyGdb::BuildSectionNameTable(MemBuf& buf)
+{
+ uint32_t totalLength = 0;
+
+ /* calculate total size */
+ for (int i = 0; i < SectionNamesCount; ++i)
+ {
+ totalLength += strlen(SectionNames[i]) + 1;
+ }
+
+ buf.MemSize = totalLength;
+ buf.MemPtr = new (nothrow) char[totalLength];
+ if (buf.MemPtr == nullptr)
+ return false;
+
+ /* copy strings */
+ char* bufPtr = buf.MemPtr;
+ for (int i = 0; i < SectionNamesCount; ++i)
+ {
+ strcpy(bufPtr, SectionNames[i]);
+ bufPtr += strlen(SectionNames[i]) + 1;
+ }
+
+ return true;
+}
+
+/* Build the ELF section headers table */
+bool NotifyGdb::BuildSectionTable(MemBuf& buf)
+{
+ Elf_Shdr* sectionHeaders = new (nothrow) Elf_Shdr[SectionNamesCount - 1];
+ Elf_Shdr* pSh = sectionHeaders;
+
+ if (sectionHeaders == nullptr)
+ {
+ return false;
+ }
+
+ /* NULL entry */
+ pSh->sh_name = 0;
+ pSh->sh_type = SHT_NULL;
+ pSh->sh_flags = 0;
+ pSh->sh_addr = 0;
+ pSh->sh_offset = 0;
+ pSh->sh_size = 0;
+ pSh->sh_link = SHN_UNDEF;
+ pSh->sh_info = 0;
+ pSh->sh_addralign = 0;
+ pSh->sh_entsize = 0;
+
+ ++pSh;
+ /* fill section header data */
+ uint32_t sectNameOffset = 1;
+ for (int i = 1; i < SectionNamesCount - 1; ++i, ++pSh)
+ {
+ pSh->sh_name = sectNameOffset;
+ sectNameOffset += strlen(SectionNames[i]) + 1;
+ pSh->sh_type = Sections[i].m_type;
+ pSh->sh_flags = Sections[i].m_flags;
+ pSh->sh_addr = 0;
+ pSh->sh_offset = 0;
+ pSh->sh_size = 0;
+ pSh->sh_link = SHN_UNDEF;
+ pSh->sh_info = 0;
+ pSh->sh_addralign = 1;
+ pSh->sh_entsize = 0;
+ }
+
+ buf.MemPtr = reinterpret_cast<char*>(sectionHeaders);
+ buf.MemSize = sizeof(Elf_Shdr) * (SectionNamesCount - 1);
+ return true;
+}
+
+/* Build the ELF header */
+bool NotifyGdb::BuildELFHeader(MemBuf& buf)
+{
+ Elf_Ehdr* header = new (nothrow) Elf_Ehdr;
+ buf.MemPtr = reinterpret_cast<char*>(header);
+ buf.MemSize = sizeof(Elf_Ehdr);
+
+ if (header == nullptr)
+ return false;
+
+ return true;
+
+}
+
+/* Split full path name into directory & file anmes */
+void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const char*& fileName)
+{
+ char* pSlash = strrchr(path, '/');
+
+ if (pSlash != nullptr)
+ {
+ *pSlash = 0;
+ fileName = ++pSlash;
+ pathName = path;
+ }
+ else
+ {
+ fileName = path;
+ pathName = nullptr;
+ }
+}
+
+/* LEB128 for 32-bit unsigned integer */
+int NotifyGdb::Leb128Encode(uint32_t num, char* buf, int size)
+{
+ int i = 0;
+
+ do
+ {
+ uint8_t byte = num & 0x7F;
+ if (i >= size)
+ break;
+ num >>= 7;
+ if (num != 0)
+ byte |= 0x80;
+ buf[i++] = byte;
+ }
+ while (num != 0);
+
+ return i;
+}
+
+/* LEB128 for 32-bit signed integer */
+int NotifyGdb::Leb128Encode(int32_t num, char* buf, int size)
+{
+ int i = 0;
+ bool hasMore = true, isNegative = num < 0;
+
+ while (hasMore && i < size)
+ {
+ uint8_t byte = num & 0x7F;
+ num >>= 7;
+
+ if ((num == 0 && (byte & 0x40) == 0) || (num == -1 && (byte & 0x40) == 0x40))
+ hasMore = false;
+ else
+ byte |= 0x80;
+ buf[i++] = byte;
+ }
+
+ return i;
+}
+
+/* ELF 32bit header */
+Elf32_Ehdr::Elf32_Ehdr()
+{
+ e_ident[EI_MAG0] = ElfMagic[0];
+ e_ident[EI_MAG1] = ElfMagic[1];
+ e_ident[EI_MAG2] = ElfMagic[2];
+ e_ident[EI_MAG3] = ElfMagic[3];
+ e_ident[EI_CLASS] = ELFCLASS32;
+ e_ident[EI_DATA] = ELFDATA2LSB;
+ e_ident[EI_VERSION] = EV_CURRENT;
+ e_ident[EI_OSABI] = ELFOSABI_NONE;
+ e_ident[EI_ABIVERSION] = 0;
+ for (int i = EI_PAD; i < EI_NIDENT; ++i)
+ e_ident[i] = 0;
+
+ e_type = ET_REL;
+#if defined(_TARGET_X86_)
+ e_machine = EM_386;
+#elif defined(_TARGET_ARM_)
+ e_machine = EM_ARM;
+#endif
+ e_flags = 0;
+ e_version = 1;
+ e_entry = 0;
+ e_phoff = 0;
+ e_ehsize = sizeof(Elf32_Ehdr);
+ e_phentsize = 0;
+ e_phnum = 0;
+}
+
+/* ELF 64bit header */
+Elf64_Ehdr::Elf64_Ehdr()
+{
+ e_ident[EI_MAG0] = ElfMagic[0];
+ e_ident[EI_MAG1] = ElfMagic[1];
+ e_ident[EI_MAG2] = ElfMagic[2];
+ e_ident[EI_MAG3] = ElfMagic[3];
+ e_ident[EI_CLASS] = ELFCLASS64;
+ e_ident[EI_DATA] = ELFDATA2LSB;
+ e_ident[EI_VERSION] = EV_CURRENT;
+ e_ident[EI_OSABI] = ELFOSABI_NONE;
+ e_ident[EI_ABIVERSION] = 0;
+ for (int i = EI_PAD; i < EI_NIDENT; ++i)
+ e_ident[i] = 0;
+
+ e_type = ET_REL;
+#if defined(_TARGET_AMD64_)
+ e_machine = EM_X86_64;
+#elif defined(_TARGET_ARM64_)
+ e_machine = EM_AARCH64;
+#endif
+ e_flags = 0;
+ e_version = 1;
+ e_entry = 0;
+ e_phoff = 0;
+ e_ehsize = sizeof(Elf64_Ehdr);
+ e_phentsize = 0;
+ e_phnum = 0;
+}
diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h
new file mode 100644
index 0000000000..5c7f24b34c
--- /dev/null
+++ b/src/vm/gdbjit.h
@@ -0,0 +1,107 @@
+// 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.
+//*****************************************************************************
+// File: gdbjit.h
+//
+
+//
+// Header file for GDB JIT interface implemenation.
+//
+//*****************************************************************************
+
+
+#ifndef __GDBJIT_H__
+#define __GDBJIT_H__
+
+#include <stdint.h>
+#include "method.hpp"
+#include "../inc/llvm/ELF.h"
+#include "../inc/llvm/Dwarf.h"
+
+#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
+ typedef Elf32_Ehdr Elf_Ehdr;
+ typedef Elf32_Shdr Elf_Shdr;
+#define ADDRESS_SIZE 4
+#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+ typedef Elf64_Ehdr Elf_Ehdr;
+ typedef Elf64_Shdr Elf_Shdr;
+#define ADDRESS_SIZE 8
+#else
+#error "Target is not supported"
+#endif
+
+struct __attribute__((packed)) DwarfCompUnit
+{
+ uint32_t m_length;
+ uint16_t m_version;
+ uint32_t m_abbrev_offset;
+ uint8_t m_addr_size;
+};
+
+struct __attribute__((packed)) DwarfPubHeader
+{
+ uint32_t m_length;
+ uint16_t m_version;
+ uint32_t m_debug_info_off;
+ uint32_t m_debug_info_len;
+};
+
+#define DW_LNS_MAX DW_LNS_set_isa
+
+struct __attribute__((packed)) DwarfLineNumHeader
+{
+ uint32_t m_length;
+ uint16_t m_version;
+ uint32_t m_hdr_length;
+ uint8_t m_min_instr_len;
+ uint8_t m_def_is_stmt;
+ int8_t m_line_base;
+ uint8_t m_line_range;
+ uint8_t m_opcode_base;
+ uint8_t m_std_num_arg[DW_LNS_MAX];
+};
+
+struct SymbolsInfo
+{
+ int lineNumber, ilOffset, nativeOffset, fileIndex;
+ char fileName[2*MAX_PATH_FNAME];
+};
+
+
+class NotifyGdb
+{
+public:
+ static void MethodCompiled(MethodDesc* MethodDescPtr);
+ static void MethodDropped(MethodDesc* MethodDescPtr);
+private:
+ struct MemBuf
+ {
+ NewArrayHolder<char> MemPtr;
+ unsigned MemSize;
+ MemBuf() : MemPtr(0), MemSize(0)
+ {}
+ };
+
+ static bool BuildELFHeader(MemBuf& buf);
+ static bool BuildSectionNameTable(MemBuf& buf);
+ static bool BuildSectionTable(MemBuf& buf);
+ static bool BuildDebugStrings(MemBuf& buf);
+ static bool BuildDebugAbbrev(MemBuf& buf);
+ static bool BuildDebugInfo(MemBuf& buf);
+ static bool BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t dieOffset);
+ static bool BuildLineTable(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines);
+ static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines);
+ static bool BuildLineProg(MemBuf& buf, PCODE startAddr, SymbolsInfo* lines, unsigned nlines);
+ static bool FitIntoSpecialOpcode(int8_t line_shift, uint8_t addr_shift);
+ static void IssueSetAddress(char*& ptr, PCODE addr);
+ static void IssueEndOfSequence(char*& ptr);
+ static void IssueSimpleCommand(char*& ptr, uint8_t command);
+ static void IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_len);
+ static void IssueSpecialCommand(char*& ptr, int8_t line_shift, uint8_t addr_shift);
+ static void SplitPathname(const char* path, const char*& pathName, const char*& fileName);
+ static int Leb128Encode(uint32_t num, char* buf, int size);
+ static int Leb128Encode(int32_t num, char* buf, int size);
+};
+
+#endif // #ifndef __GDBJIT_H__
diff --git a/src/vm/gdbjithelpers.h b/src/vm/gdbjithelpers.h
new file mode 100644
index 0000000000..1fa5d4674e
--- /dev/null
+++ b/src/vm/gdbjithelpers.h
@@ -0,0 +1,31 @@
+// 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.
+//*****************************************************************************
+// File: gdbjithelpers.h
+//
+//
+// Helper file with managed delegate for GDB JIT interface implemenation.
+//
+//*****************************************************************************
+
+
+#ifndef __GDBJITHELPERS_H__
+#define __GDBJITHELPERS_H__
+
+struct SequencePointInfo
+{
+ int lineNumber, ilOffset;
+ char16_t* fileName;
+};
+
+struct MethodDebugInfo
+{
+ SequencePointInfo* points;
+ int size;
+};
+
+typedef int (*GetInfoForMethodDelegate)(const char*, unsigned int, MethodDebugInfo& methodDebugInfo);
+extern GetInfoForMethodDelegate getInfoForMethodDelegate;
+
+#endif // !__GDBJITHELPERS_H__
diff --git a/src/vm/util.cpp b/src/vm/util.cpp
index f7185c744f..e0f09e3ae0 100644
--- a/src/vm/util.cpp
+++ b/src/vm/util.cpp
@@ -3399,6 +3399,11 @@ void InitializeClrNotifications()
#pragma optimize("", off)
#endif // _MSC_VER
+#if defined(FEATURE_GDBJIT)
+#include "gdbjit.h"
+__declspec(thread) bool tls_isSymReaderInProgress = false;
+#endif // FEATURE_GDBJIT
+
// called from the runtime
void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr)
{
@@ -3410,7 +3415,14 @@ void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr)
MODE_PREEMPTIVE;
}
CONTRACTL_END;
-
+#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
+ if(!tls_isSymReaderInProgress)
+ {
+ tls_isSymReaderInProgress = true;
+ NotifyGdb::MethodCompiled(MethodDescPtr);
+ tls_isSymReaderInProgress = false;
+ }
+#endif
TADDR Args[2] = { JIT_NOTIFICATION, (TADDR) MethodDescPtr };
DACNotifyExceptionHelper(Args, 2);
}
@@ -3426,6 +3438,9 @@ void DACNotify::DoJITDiscardNotification(MethodDesc *MethodDescPtr)
}
CONTRACTL_END;
+#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
+ NotifyGdb::MethodDropped(MethodDescPtr);
+#endif
TADDR Args[2] = { JIT_DISCARD_NOTIFICATION, (TADDR) MethodDescPtr };
DACNotifyExceptionHelper(Args, 2);
}