diff --git a/src/gc/env/etmdummy.h b/src/gc/env/etmdummy.h
index 983bba67b323..937a6265f915 100644
--- a/src/gc/env/etmdummy.h
+++ b/src/gc/env/etmdummy.h
@@ -169,6 +169,7 @@
#define FireEtwDebugIPCEventEnd() 0
#define FireEtwDebugExceptionProcessingStart() 0
#define FireEtwDebugExceptionProcessingEnd() 0
+#define FireEtwCodeSymbols(ModuleId, TotalChunks, ChunkNumber, ChunkLength, Chunk, ClrInstanceID) 0
#define FireEtwCLRStackWalkDCStart(ClrInstanceID, Reserved1, Reserved2, FrameCount, Stack) 0
#define FireEtwMethodDCStart(MethodID, ModuleID, MethodStartAddress, MethodSize, MethodToken, MethodFlags) 0
#define FireEtwMethodDCStart_V1(MethodID, ModuleID, MethodStartAddress, MethodSize, MethodToken, MethodFlags, ClrInstanceID) 0
diff --git a/src/inc/eventtracebase.h b/src/inc/eventtracebase.h
index 9a6b218d3f6f..768a774f42dc 100644
--- a/src/inc/eventtracebase.h
+++ b/src/inc/eventtracebase.h
@@ -730,6 +730,22 @@ namespace ETW
static VOID RuntimeInformation(INT32 type);
#else
static VOID RuntimeInformation(INT32 type) {};
+#endif // FEATURE_EVENT_TRACE
+ };
+
+ class CodeSymbolLog
+ {
+ public:
+#ifdef FEATURE_EVENT_TRACE
+ static VOID EmitCodeSymbols(Module* pModule);
+ static HRESULT GetInMemorySymbolsLength(Module* pModule, DWORD* pCountSymbolBytes);
+ static HRESULT ReadInMemorySymbols(Module* pmodule, DWORD symbolsReadOffset, BYTE* pSymbolBytes,
+ DWORD countSymbolBytes, DWORD* pCountSymbolBytesRead);
+#else
+ static VOID EmitCodeSymbols(Module* pModule) {}
+ static HRESULT GetInMemorySymbolsLength(Module* pModule, DWORD* pCountSymbolBytes) { return S_OK; }
+ static HRESULT ReadInMemorySymbols(Module* pmodule, DWORD symbolsReadOffset, BYTE* pSymbolBytes,
+ DWORD countSymbolBytes, DWORD* pCountSymbolBytesRead) { return S_OK; }
#endif // FEATURE_EVENT_TRACE
};
};
diff --git a/src/pal/prebuilt/inc/clretwall.h b/src/pal/prebuilt/inc/clretwall.h
index 865fccf866d1..a3df060dc504 100644
--- a/src/pal/prebuilt/inc/clretwall.h
+++ b/src/pal/prebuilt/inc/clretwall.h
@@ -218,7 +218,7 @@ Routine Description:
#endif
#endif // MCGEN_DISABLE_PROVIDER_CODE_GENERATION
//+
-// Provider Microsoft-Windows-DotNETRuntime Event Count 166
+// Provider Microsoft-Windows-DotNETRuntime Event Count 167
//+
EXTERN_C __declspec(selectany) const GUID MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER = {0xe13c0d23, 0xccbc, 0x4e12, {0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4}};
@@ -371,6 +371,8 @@ EXTERN_C __declspec(selectany) const GUID ThreadId = {0x641994c5, 0x16f2, 0x4123
EXTERN_C __declspec(selectany) const GUID DebugIPCEventId = {0xec2f3703, 0x8321, 0x4301, {0xbd, 0x51, 0x2c, 0xb9, 0xa0, 0x9f, 0x31, 0xb1}};
#define CLR_EXCEPTION_PROCESSING_TASK 0x1a
EXTERN_C __declspec(selectany) const GUID DebugExceptionProcessingId = {0xc4412198, 0xef03, 0x47f1, {0x9b, 0xd1, 0x11, 0xc6, 0x63, 0x7a, 0x20, 0x62}};
+#define CLR_CODE_SYMBOLS_TASK 0x1e
+EXTERN_C __declspec(selectany) const GUID CodeSymbolsId = {0x53aedf69, 0x2049, 0x4f7d, {0x93, 0x45, 0xd3, 0x01, 0x8b, 0x5c, 0x4d, 0x80}};
//
// Keyword
//
@@ -403,6 +405,7 @@ EXTERN_C __declspec(selectany) const GUID DebugExceptionProcessingId = {0xc44121
#define CLR_THREADTRANSFER_KEYWORD 0x80000000
#define CLR_DEBUGGER_KEYWORD 0x100000000
#define CLR_MONITORING_KEYWORD 0x200000000
+#define CLR_CODESYMBOLS_KEYWORD 0x400000000
//
// Event Descriptors
@@ -739,6 +742,8 @@ EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR DebugExceptionProcessingSt
#define DebugExceptionProcessingStart_value 0xf2
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR DebugExceptionProcessingEnd = {0xf3, 0x0, 0x0, 0x4, 0x2, 0x1a, 0x100000000};
#define DebugExceptionProcessingEnd_value 0xf3
+EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR CodeSymbols = {0x104, 0x0, 0x0, 0x5, 0x1, 0x1e, 0x400000000};
+#define CodeSymbols_value 0x104
//
// Note on Generate Code from Manifest Windows Vista and above
@@ -768,9 +773,9 @@ EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR DebugExceptionProcessingEn
//
EXTERN_C __declspec(selectany) DECLSPEC_CACHEALIGN ULONG Microsoft_Windows_DotNETRuntimeEnableBits[1];
-EXTERN_C __declspec(selectany) const ULONGLONG Microsoft_Windows_DotNETRuntimeKeywords[31] = {0x1, 0x1, 0x10001, 0x80000, 0x100000, 0x200000, 0x400000, 0x2, 0x2000000, 0x10000, 0x10000, 0x80010000, 0x80010000, 0x0, 0x200008000, 0x8000, 0x4000, 0x40000000, 0x800, 0x10800, 0x2000, 0x30, 0x10, 0x1000, 0x20000, 0x8, 0x20000008, 0x20000000, 0x400, 0x400, 0x100000000};
-EXTERN_C __declspec(selectany) const UCHAR Microsoft_Windows_DotNETRuntimeLevels[31] = {4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 2, 4, 4, 0, 4, 4, 4, 4, 5, 5, 5, 4, 4, 4, 5, 4, 4};
-EXTERN_C __declspec(selectany) MCGEN_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context = {0, 0, 0, 0, 0, 0, 0, 0, 31, Microsoft_Windows_DotNETRuntimeEnableBits, Microsoft_Windows_DotNETRuntimeKeywords, Microsoft_Windows_DotNETRuntimeLevels};
+EXTERN_C __declspec(selectany) const ULONGLONG Microsoft_Windows_DotNETRuntimeKeywords[32] = {0x1, 0x1, 0x10001, 0x80000, 0x100000, 0x200000, 0x400000, 0x2, 0x2000000, 0x10000, 0x10000, 0x80010000, 0x80010000, 0x0, 0x200008000, 0x8000, 0x4000, 0x40000000, 0x800, 0x10800, 0x2000, 0x30, 0x10, 0x1000, 0x20000, 0x8, 0x20000008, 0x20000000, 0x400, 0x400, 0x100000000, 0x400000000};
+EXTERN_C __declspec(selectany) const UCHAR Microsoft_Windows_DotNETRuntimeLevels[32] = {4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 2, 4, 4, 0, 4, 4, 4, 4, 5, 5, 5, 4, 4, 4, 5, 4, 4, 5};
+EXTERN_C __declspec(selectany) MCGEN_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context = {0, 0, 0, 0, 0, 0, 0, 0, 32, Microsoft_Windows_DotNETRuntimeEnableBits, Microsoft_Windows_DotNETRuntimeKeywords, Microsoft_Windows_DotNETRuntimeLevels};
EXTERN_C __declspec(selectany) REGHANDLE Microsoft_Windows_DotNETRuntimeHandle = (REGHANDLE)0;
@@ -3191,6 +3196,20 @@ Routine Description:
CoTemplateEventDescriptor(Microsoft_Windows_DotNETRuntimeHandle, &DebugExceptionProcessingEnd)\
: ERROR_SUCCESS\
+//
+// Enablement check macro for CodeSymbols
+//
+
+#define EventEnabledCodeSymbols() ((Microsoft_Windows_DotNETRuntimeEnableBits[0] & 0x80000000) != 0)
+
+//
+// Event Macro for CodeSymbols
+//
+#define FireEtwCodeSymbols(ModuleId, TotalChunks, ChunkNumber, ChunkLength, Chunk, ClrInstanceID)\
+ EventEnabledCodeSymbols() ?\
+ CoTemplate_xhhqbh(Microsoft_Windows_DotNETRuntimeHandle, &CodeSymbols, ModuleId, TotalChunks, ChunkNumber, ChunkLength, Chunk, ClrInstanceID)\
+ : ERROR_SUCCESS\
+
#endif // MCGEN_DISABLE_PROVIDER_CODE_GENERATION
//+
@@ -10909,6 +10928,54 @@ MCGEN_CALLOUT(RegHandle,
}
#endif
+//
+//Template from manifest : CodeSymbols
+//
+#ifndef CoTemplate_xhhqbh_def
+#define CoTemplate_xhhqbh_def
+ETW_INLINE
+ULONG
+CoTemplate_xhhqbh(
+ _In_ REGHANDLE RegHandle,
+ _In_ PCEVENT_DESCRIPTOR Descriptor,
+ _In_ unsigned __int64 _Arg0,
+ _In_ const unsigned short _Arg1,
+ _In_ const unsigned short _Arg2,
+ _In_ const unsigned int _Arg3,
+ _In_reads_(_Arg3) const BYTE* _Arg4,
+ _In_ const unsigned short _Arg5
+ )
+{
+#define ARGUMENT_COUNT_xhhqbh 6
+ ULONG Error = ERROR_SUCCESS;
+
+ EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_xhhqbh];
+
+ EventDataDescCreate(&EventData[0], &_Arg0, sizeof(unsigned __int64) );
+
+ EventDataDescCreate(&EventData[1], &_Arg1, sizeof(const unsigned short) );
+
+ EventDataDescCreate(&EventData[2], &_Arg2, sizeof(const unsigned short) );
+
+ EventDataDescCreate(&EventData[3], &_Arg3, sizeof(const unsigned int) );
+
+ EventDataDescCreate(&EventData[4], _Arg4, (ULONG)sizeof(char)*_Arg3);
+
+ EventDataDescCreate(&EventData[5], &_Arg5, sizeof(const unsigned short) );
+
+ Error = EventWrite(RegHandle, Descriptor, ARGUMENT_COUNT_xhhqbh, EventData);
+
+#ifdef MCGEN_CALLOUT
+MCGEN_CALLOUT(RegHandle,
+ Descriptor,
+ ARGUMENT_COUNT_xhhqbh,
+ EventData);
+#endif
+
+ return Error;
+}
+#endif
+
//
//Template from manifest : StressLog
//
@@ -12438,6 +12505,7 @@ MCGEN_CALLOUT(RegHandle,
#define MSG_RuntimePublisher_ThreadTransferKeywordMessage 0x10000020L
#define MSG_RuntimePublisher_DebuggerKeywordMessage 0x10000021L
#define MSG_RuntimePublisher_MonitoringKeywordMessage 0x10000022L
+#define MSG_RuntimePublisher_CodeSymbolsKeywordMessage 0x10000023L
#define MSG_RundownPublisher_LoaderKeywordMessage 0x11000004L
#define MSG_RundownPublisher_JitKeywordMessage 0x11000005L
#define MSG_RundownPublisher_NGenKeywordMessage 0x11000006L
@@ -12725,6 +12793,7 @@ MCGEN_CALLOUT(RegHandle,
#define MSG_RuntimePublisher_ExceptionCatchTaskMessage 0x7000001BL
#define MSG_RuntimePublisher_ExceptionFinallyTaskMessage 0x7000001CL
#define MSG_RuntimePublisher_ExceptionFilterTaskMessage 0x7000001DL
+#define MSG_RuntimePublisher_CodeSymbolsTaskMessage 0x7000001EL
#define MSG_RundownPublisher_MethodTaskMessage 0x71000001L
#define MSG_RundownPublisher_LoaderTaskMessage 0x71000002L
#define MSG_RundownPublisher_StackTaskMessage 0x7100000BL
@@ -12848,6 +12917,7 @@ MCGEN_CALLOUT(RegHandle,
#define MSG_RuntimePublisher_GCMarkWithTypeEventMessage 0xB00000CAL
#define MSG_RuntimePublisher_ExceptionExceptionHandlingEventMessage 0xB00000FAL
#define MSG_RuntimePublisher_ExceptionExceptionHandlingNoneEventMessage 0xB00000FBL
+#define MSG_RuntimePublisher_CodeSymbolsEventMessage 0xB0000104L
#define MSG_RuntimePublisher_GCStart_V1EventMessage 0xB0010001L
#define MSG_RuntimePublisher_GCEnd_V1EventMessage 0xB0010002L
#define MSG_RuntimePublisher_GCRestartEEEnd_V1EventMessage 0xB0010003L
diff --git a/src/pal/prebuilt/inc/etmdummy.h b/src/pal/prebuilt/inc/etmdummy.h
index 983bba67b323..937a6265f915 100644
--- a/src/pal/prebuilt/inc/etmdummy.h
+++ b/src/pal/prebuilt/inc/etmdummy.h
@@ -169,6 +169,7 @@
#define FireEtwDebugIPCEventEnd() 0
#define FireEtwDebugExceptionProcessingStart() 0
#define FireEtwDebugExceptionProcessingEnd() 0
+#define FireEtwCodeSymbols(ModuleId, TotalChunks, ChunkNumber, ChunkLength, Chunk, ClrInstanceID) 0
#define FireEtwCLRStackWalkDCStart(ClrInstanceID, Reserved1, Reserved2, FrameCount, Stack) 0
#define FireEtwMethodDCStart(MethodID, ModuleID, MethodStartAddress, MethodSize, MethodToken, MethodFlags) 0
#define FireEtwMethodDCStart_V1(MethodID, ModuleID, MethodStartAddress, MethodSize, MethodToken, MethodFlags, ClrInstanceID) 0
diff --git a/src/vm/ClrEtwAll.man b/src/vm/ClrEtwAll.man
index 71b73468781c..ed9b25cd53a9 100644
--- a/src/vm/ClrEtwAll.man
+++ b/src/vm/ClrEtwAll.man
@@ -73,6 +73,8 @@
message="$(string.RuntimePublisher.DebuggerKeywordMessage)" symbol="CLR_DEBUGGER_KEYWORD" />
+
@@ -362,7 +364,13 @@
-
+
+
+
+
+
@@ -2249,6 +2257,25 @@
+
+
+
+
+
+
+
+
+
+ %1
+ %2
+ %3
+ %4
+ %5
+ %6
+
+
+
+
@@ -3121,6 +3148,12 @@
keywords="DebuggerKeyword" opcode="win:Stop"
task="DebugExceptionProcessing"
symbol="DebugExceptionProcessingEnd" />
+
+
+
@@ -6262,6 +6295,7 @@
+
@@ -6416,6 +6450,7 @@
+
@@ -6689,6 +6724,7 @@
+
diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp
index d3d5bb870081..698e032217ca 100644
--- a/src/vm/ceeload.cpp
+++ b/src/vm/ceeload.cpp
@@ -4467,8 +4467,7 @@ void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms)
&cbWritten);
IfFailThrow(HRESULT_FROM_WIN32(dwError));
- // Don't eager load the diasymreader
-
+ ETW::CodeSymbolLog::EmitCodeSymbols(this);
// Tell the debugger that symbols have been loaded for this
// module. We iterate through all domains which contain this
// module's assembly, and send a debugger notify for each one.
diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp
index 0cb474e2f87f..5b33792d3537 100644
--- a/src/vm/compile.cpp
+++ b/src/vm/compile.cpp
@@ -1875,6 +1875,8 @@ BOOL CEEPreloader::DoesMethodNeedRestoringBeforePrestubIsRun(
BOOL CEECompileInfo::IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle)
{
+ WRAPPER_NO_CONTRACT;
+
MethodDesc * pMethod = GetMethod(handle);
return pMethod->HasNativeCallableAttribute();
}
diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp
index 13c704f4c0cb..ecedc325207d 100644
--- a/src/vm/eventtrace.cpp
+++ b/src/vm/eventtrace.cpp
@@ -4978,6 +4978,248 @@ VOID ETW::InfoLog::RuntimeInformation(INT32 type)
} EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
}
+/* Fires ETW events every time a pdb is dynamically loaded.
+*
+* The ETW events correspond to sending parts of the pdb in roughly
+* 64K sized chunks in order. Additional information sent is as follows:
+* ModuleID, TotalChunks, Size of Current Chunk, Chunk Number, CLRInstanceID
+*
+* Note: The current implementation does not support reflection.emit.
+* The method will silently return without firing an event.
+*/
+
+VOID ETW::CodeSymbolLog::EmitCodeSymbols(Module* pModule)
+{
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+
+ EX_TRY {
+ if (ETW_TRACING_CATEGORY_ENABLED(
+ MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
+ TRACE_LEVEL_VERBOSE,
+ CLR_CODESYMBOLS_KEYWORD))
+ {
+ if (pModule != NULL)
+ {
+ UINT16 clrInstanceID = GetClrInstanceId();
+ UINT64 moduleID = (ModuleID)pModule;
+ DWORD length = 0;
+ // We silently exit if pdb is of length 0 instead of sending an event with no pdb bytes
+ if (CodeSymbolLog::GetInMemorySymbolsLength(pModule, &length) == S_OK && length > 0)
+ {
+ // The maximum data size allowed is 64K - (Size of the Event_Header)
+ // Since the actual size of user data can only be determined at runtime
+ // we simplify the header size value to be 1000 bytes as a conservative
+ // estmate.
+ static const DWORD maxDataSize = 63000;
+
+ ldiv_t qr = ldiv(length, maxDataSize);
+
+ // We do not allow pdbs of size greater than 2GB for now,
+ // so totalChunks should fit in 16 bits.
+ if (qr.quot < UINT16_MAX)
+ {
+ // If there are trailing bits in the last chunk, then increment totalChunks by 1
+ UINT16 totalChunks = (UINT16)(qr.quot + ((qr.rem != 0) ? 1 : 0));
+ NewArrayHolder chunk(new BYTE[maxDataSize]);
+ DWORD offset = 0;
+ for (UINT16 chunkNum = 0; offset < length; chunkNum++)
+ {
+ DWORD lengthRead = 0;
+ // We expect ReadInMemorySymbols to always return maxDataSize sized chunks
+ // Or it is the last chunk and it is less than maxDataSize.
+ CodeSymbolLog::ReadInMemorySymbols(pModule, offset, chunk, maxDataSize, &lengthRead);
+
+ _ASSERTE(lengthRead == maxDataSize || // Either we are in the first to (n-1)th chunk
+ (lengthRead < maxDataSize && chunkNum + 1 == totalChunks)); // Or we are in the last chunk
+
+ FireEtwCodeSymbols(moduleID, totalChunks, chunkNum, lengthRead, chunk, clrInstanceID);
+ offset += lengthRead;
+ }
+ }
+ }
+ }
+ }
+ } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
+}
+
+/* Returns the length of an in-memory symbol stream
+*
+* If the module has in-memory symbols the length of the stream will
+* be placed in pCountSymbolBytes. If the module doesn't have in-memory
+* symbols, *pCountSymbolBytes = 0
+*
+* Returns S_OK if the length could be determined (even if it is 0)
+*
+* Note: The current implementation does not support reflection.emit.
+* CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case.
+*
+* //IMPORTANT NOTE: The desktop code outside the Project K branch
+* contains copies of this function in the clr\src\vm\proftoeeinterfaceimpl.cpp
+* file of the desktop version corresponding to the profiler version
+* of this feature. Anytime that feature/code is ported to Project K
+* the code below should be appropriately merged so as to avoid
+* duplication.
+*/
+
+HRESULT ETW::CodeSymbolLog::GetInMemorySymbolsLength(
+ Module* pModule,
+ DWORD* pCountSymbolBytes)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ if (pCountSymbolBytes == NULL)
+ {
+ return E_INVALIDARG;
+ }
+ *pCountSymbolBytes = 0;
+
+ if (pModule == NULL)
+ {
+ return E_INVALIDARG;
+ }
+ if (pModule->IsBeingUnloaded())
+ {
+ return CORPROF_E_DATAINCOMPLETE;
+ }
+
+ //This method would work fine on reflection.emit, but there would be no way to know
+ //if some other thread was changing the size of the symbols before this method returned.
+ //Adding events or locks to detect/prevent changes would make the scenario workable
+ if (pModule->IsReflection())
+ {
+ return COR_PRF_MODULE_DYNAMIC;
+ }
+
+ CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
+ if (pStream == NULL)
+ {
+ return S_OK;
+ }
+
+ STATSTG SizeData = { 0 };
+ hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ if (SizeData.cbSize.u.HighPart > 0)
+ {
+ return COR_E_OVERFLOW;
+ }
+ *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
+
+ return S_OK;
+}
+
+/* Reads bytes from an in-memory symbol stream
+*
+* This function attempts to read countSymbolBytes of data starting at offset
+* symbolsReadOffset within the in-memory stream. The data will be copied into
+* pSymbolBytes which is expected to have countSymbolBytes of space available.
+* pCountSymbolsBytesRead contains the actual number of bytes read which
+* may be less than countSymbolBytes if the end of the stream is reached.
+*
+* Returns S_OK if a non-zero number of bytes were read.
+*
+* Note: The current implementation does not support reflection.emit.
+* CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case.
+*
+* //IMPORTANT NOTE: The desktop code outside the Project K branch
+* contains copies of this function in the clr\src\vm\proftoeeinterfaceimpl.cpp
+* file of the desktop version corresponding to the profiler version
+* of this feature. Anytime that feature/code is ported to Project K
+* the code below should be appropriately merged so as to avoid
+* duplication.
+
+*/
+
+HRESULT ETW::CodeSymbolLog::ReadInMemorySymbols(
+ Module* pModule,
+ DWORD symbolsReadOffset,
+ BYTE* pSymbolBytes,
+ DWORD countSymbolBytes,
+ DWORD* pCountSymbolBytesRead)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ if (pSymbolBytes == NULL)
+ {
+ return E_INVALIDARG;
+ }
+ if (pCountSymbolBytesRead == NULL)
+ {
+ return E_INVALIDARG;
+ }
+ *pCountSymbolBytesRead = 0;
+
+ if (pModule == NULL)
+ {
+ return E_INVALIDARG;
+ }
+ if (pModule->IsBeingUnloaded())
+ {
+ return CORPROF_E_DATAINCOMPLETE;
+ }
+
+ //This method would work fine on reflection.emit, but there would be no way to know
+ //if some other thread was changing the size of the symbols before this method returned.
+ //Adding events or locks to detect/prevent changes would make the scenario workable
+ if (pModule->IsReflection())
+ {
+ return COR_PRF_MODULE_DYNAMIC;
+ }
+
+ CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
+ if (pStream == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ STATSTG SizeData = { 0 };
+ hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ if (SizeData.cbSize.u.HighPart > 0)
+ {
+ return COR_E_OVERFLOW;
+ }
+ DWORD streamSize = SizeData.cbSize.u.LowPart;
+ if (symbolsReadOffset >= streamSize)
+ {
+ return E_INVALIDARG;
+ }
+
+ *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
+ memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
+
+ return S_OK;
+}
+
/*******************************************************/
/* This is called by the runtime when a method is jitted completely */
/*******************************************************/
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index fae4cce8f825..ba0c8ba73159 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -2568,6 +2568,8 @@ bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
/*IN*/ CORINFO_CLASS_HANDLE structHnd,
/*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
{
+ LIMITED_METHOD_CONTRACT;
+
return false;
}