From 39b1ec64c8a771c736dda297c1a4f601b052767d Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Thu, 8 Oct 2015 18:28:37 -0700 Subject: [PATCH 1/2] Code changes for firing etw events when a pdb is dynamically loaded. This corresponds to the following user story: 1200238. As a profiler developer, I want to access PDB content for dynamic assemblies in the ETW event stream, so that I can show my users source for their callstack frames. The main function in eventtrace.cpp, EmitCodeSymbols, divides the pdb stream into appropriate chunks and transmits them as events in order. There are helper functions which have been taken from the corresponding code in Desktop (Netfxdev1) to provide a dynamically loaded pdb through the profiler authored by Noah. The test uses EventToSymbols, which is based on TraceEventParser to turn on the CodeSymbols and ModuleLoad keywords and listens for events that send out pdb chunks. It then concatenates the chunks to create the pdb on disk. The BigPdb.cs program loads a dll and pdb dynamically, which triggers the events by the runtime. Once the pdb is recreated, it is compared with the original to make sure there are no differences and if not, the test is declared as passed. The test also uses an EventSource event to transmit a unique cookie to make sure the pdb created corresponds to the process under test, in case there are mulitple instances of the test running. [tfs-changeset: 1535373] --- src/gc/env/etmdummy.h | 1 + src/inc/eventtracebase.h | 16 ++ src/pal/prebuilt/inc/clretwall.h | 78 +++++++++- src/pal/prebuilt/inc/etmdummy.h | 1 + src/vm/ClrEtwAll.man | 38 ++++- src/vm/ceeload.cpp | 3 +- src/vm/eventtrace.cpp | 242 +++++++++++++++++++++++++++++++ 7 files changed, 372 insertions(+), 7 deletions(-) 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 @@ + + @@ -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/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 */ /*******************************************************/ From 250782557977bec590ae0a0a83de01ba3b3d6ec3 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Fri, 9 Oct 2015 08:38:34 -0700 Subject: [PATCH 2/2] Fix contracts so scanRuntime@x86chk task succeeds [tfs-changeset: 1535699] --- src/vm/compile.cpp | 2 ++ src/vm/jitinterface.cpp | 2 ++ 2 files changed, 4 insertions(+) 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/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; }