dc94c2b45129dc2f7d5db1fbf4eed70d9f296499
[platform/upstream/coreclr.git] / src / vm / eventpipe.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include "common.h"
6 #include "clrtypes.h"
7 #include "safemath.h"
8 #include "diagnosticsipc.h"
9 #include "eventpipe.h"
10 #include "eventpipebuffermanager.h"
11 #include "eventpipeconfiguration.h"
12 #include "eventpipesessionprovider.h"
13 #include "eventpipeevent.h"
14 #include "eventpipeeventsource.h"
15 #include "eventpipefile.h"
16 #include "eventpipeprovider.h"
17 #include "eventpipesession.h"
18 #include "eventpipejsonfile.h"
19 #include "eventtracebase.h"
20 #include "sampleprofiler.h"
21 #include "win32threadpool.h"
22
23 #ifdef FEATURE_PAL
24 #include "pal.h"
25 #endif // FEATURE_PAL
26
27 #ifdef FEATURE_PERFTRACING
28
29 CrstStatic EventPipe::s_configCrst;
30 bool EventPipe::s_tracingInitialized = false;
31 EventPipeConfiguration *EventPipe::s_pConfig = NULL;
32 EventPipeSession *EventPipe::s_pSession = NULL;
33 EventPipeBufferManager *EventPipe::s_pBufferManager = NULL;
34 EventPipeFile *EventPipe::s_pFile = NULL;
35 EventPipeEventSource *EventPipe::s_pEventSource = NULL;
36 LPCWSTR EventPipe::s_pCommandLine = NULL;
37 HANDLE EventPipe::s_fileSwitchTimerHandle = NULL;
38 ULONGLONG EventPipe::s_lastFlushSwitchTime = 0;
39
40 #ifdef FEATURE_PAL
41 // This function is auto-generated from /src/scripts/genEventPipe.py
42 extern "C" void InitProvidersAndEvents();
43 #else
44 void InitProvidersAndEvents();
45 #endif
46
47 EventPipeEventPayload::EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount)
48 {
49     CONTRACTL
50     {
51         NOTHROW;
52         GC_NOTRIGGER;
53         MODE_ANY;
54     }
55     CONTRACTL_END;
56
57     m_pData = NULL;
58     m_pEventData = pEventData;
59     m_eventDataCount = eventDataCount;
60     m_allocatedData = false;
61
62     S_UINT32 tmp_size = S_UINT32(0);
63     for (unsigned int i = 0; i < m_eventDataCount; i++)
64     {
65         tmp_size += S_UINT32(m_pEventData[i].Size);
66     }
67
68     if (tmp_size.IsOverflow())
69     {
70         // If there is an overflow, drop the data and create an empty payload
71         m_pEventData = NULL;
72         m_eventDataCount = 0;
73         m_size = 0;
74     }
75     else
76     {
77         m_size = tmp_size.Value();
78     }
79 }
80
81 EventPipeEventPayload::~EventPipeEventPayload()
82 {
83     CONTRACTL
84     {
85         NOTHROW;
86         GC_NOTRIGGER;
87         MODE_ANY;
88     }
89     CONTRACTL_END;
90
91     if (m_allocatedData && m_pData != NULL)
92     {
93         delete[] m_pData;
94         m_pData = NULL;
95     }
96 }
97
98 void EventPipeEventPayload::Flatten()
99 {
100     CONTRACTL
101     {
102         NOTHROW;
103         GC_NOTRIGGER;
104         MODE_ANY;
105     }
106     CONTRACTL_END;
107
108     if (m_size > 0)
109     {
110         if (!IsFlattened())
111         {
112             BYTE *tmp_pData = new (nothrow) BYTE[m_size];
113             if (tmp_pData != NULL)
114             {
115                 m_allocatedData = true;
116                 CopyData(tmp_pData);
117                 m_pData = tmp_pData;
118             }
119         }
120     }
121 }
122
123 void EventPipeEventPayload::CopyData(BYTE *pDst)
124 {
125     CONTRACTL
126     {
127         NOTHROW;
128         GC_NOTRIGGER;
129         MODE_ANY;
130     }
131     CONTRACTL_END;
132
133     if (m_size > 0)
134     {
135         if (IsFlattened())
136         {
137             memcpy(pDst, m_pData, m_size);
138         }
139
140         else if (m_pEventData != NULL)
141         {
142             unsigned int offset = 0;
143             for (unsigned int i = 0; i < m_eventDataCount; i++)
144             {
145                 memcpy(pDst + offset, (BYTE *)m_pEventData[i].Ptr, m_pEventData[i].Size);
146                 offset += m_pEventData[i].Size;
147             }
148         }
149     }
150 }
151
152 BYTE *EventPipeEventPayload::GetFlatData()
153 {
154     CONTRACTL
155     {
156         NOTHROW;
157         GC_NOTRIGGER;
158         MODE_ANY;
159     }
160     CONTRACTL_END;
161
162     if (!IsFlattened())
163     {
164         Flatten();
165     }
166     return m_pData;
167 }
168
169 void EventPipe::Initialize()
170 {
171     STANDARD_VM_CONTRACT;
172
173     s_tracingInitialized = s_configCrst.InitNoThrow(
174         CrstEventPipe,
175         (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN | CRST_HOST_BREAKABLE));
176
177     s_pConfig = new EventPipeConfiguration();
178     s_pConfig->Initialize();
179
180     s_pBufferManager = new EventPipeBufferManager();
181
182     s_pEventSource = new EventPipeEventSource();
183
184     // This calls into auto-generated code to initialize the runtime providers
185     // and events so that the EventPipe configuration lock isn't taken at runtime
186     InitProvidersAndEvents();
187 }
188
189 void EventPipe::Shutdown()
190 {
191     CONTRACTL
192     {
193         NOTHROW;
194         GC_TRIGGERS;
195         MODE_ANY;
196     }
197     CONTRACTL_END;
198
199     // Mark tracing as no longer initialized.
200     s_tracingInitialized = false;
201
202     // We are shutting down, so if disabling EventPipe throws, we need to move along anyway.
203     EX_TRY
204     {
205         Disable((EventPipeSessionID)s_pSession);
206     }
207     EX_CATCH {}
208     EX_END_CATCH(SwallowAllExceptions);
209
210     // Save pointers to the configuration and buffer manager.
211     EventPipeConfiguration *pConfig = s_pConfig;
212     EventPipeBufferManager *pBufferManager = s_pBufferManager;
213
214     // Set the static pointers to NULL so that the rest of the EventPipe knows that they are no longer available.
215     // Flush process write buffers to make sure other threads can see the change.
216     s_pConfig = NULL;
217     s_pBufferManager = NULL;
218     FlushProcessWriteBuffers();
219
220     // Free resources.
221     delete pConfig;
222     delete pBufferManager;
223     delete s_pEventSource;
224     s_pEventSource = NULL;
225
226     // On Windows, this is just a pointer to the return value from
227     // GetCommandLineW(), so don't attempt to free it.
228 #ifdef FEATURE_PAL
229     delete[] s_pCommandLine;
230     s_pCommandLine = NULL;
231 #endif
232 }
233
234 EventPipeSessionID EventPipe::Enable(
235     LPCWSTR strOutputPath,
236     uint32_t circularBufferSizeInMB,
237     uint64_t profilerSamplingRateInNanoseconds,
238     const EventPipeProviderConfiguration *pProviders,
239     uint32_t numProviders,
240     EventPipeSessionType sessionType,
241     IpcStream *const pStream)
242 {
243     CONTRACTL
244     {
245         THROWS;
246         GC_TRIGGERS;
247         MODE_ANY;
248         PRECONDITION(circularBufferSizeInMB > 0);
249         PRECONDITION(profilerSamplingRateInNanoseconds > 0);
250         PRECONDITION(numProviders > 0 && pProviders != nullptr);
251     }
252     CONTRACTL_END;
253
254     // Take the lock before enabling tracing.
255     CrstHolder _crst(GetLock());
256
257     // Create a new session.
258     SampleProfiler::SetSamplingRate(static_cast<unsigned long>(profilerSamplingRateInNanoseconds));
259     EventPipeSession *pSession = s_pConfig->CreateSession(
260         sessionType,
261         circularBufferSizeInMB,
262         pProviders,
263         numProviders);
264
265     EventPipeSessionID sessionId = Enable(strOutputPath, pSession, sessionType, pStream);
266     return sessionId;
267 }
268
269 EventPipeSessionID EventPipe::Enable(
270     LPCWSTR strOutputPath,
271     EventPipeSession *const pSession,
272     EventPipeSessionType sessionType,
273     IpcStream *const pStream)
274 {
275     CONTRACTL
276     {
277         THROWS;
278         GC_TRIGGERS;
279         MODE_ANY;
280         PRECONDITION(pSession != nullptr);
281         PRECONDITION(GetLock()->OwnedByCurrentThread());
282     }
283     CONTRACTL_END;
284
285     // If the state or arguments are invalid, bail here.
286     if (pSession == nullptr || !pSession->IsValid())
287         return 0;
288     if (sessionType == EventPipeSessionType::File && strOutputPath == nullptr)
289         return 0;
290     if (sessionType == EventPipeSessionType::IpcStream && pStream == nullptr)
291         return 0;
292
293     // If tracing is not initialized or is already enabled, bail here.
294     if (!s_tracingInitialized || s_pConfig == nullptr || s_pConfig->Enabled())
295         return 0;
296
297     // Enable the EventPipe EventSource.
298     s_pEventSource->Enable(pSession);
299
300     // Save the session.
301     s_pSession = pSession;
302     EventPipeSessionID sessionId = reinterpret_cast<EventPipeSessionID>(s_pSession);
303
304     // Create the event pipe file.
305     // A NULL output path means that we should not write the results to a file.
306     // This is used in the EventListener streaming case.
307     switch (sessionType)
308     {
309         case EventPipeSessionType::File:
310             if (strOutputPath != nullptr)
311                 s_pFile = new EventPipeFile(new FileStreamWriter(SString(strOutputPath)));
312             break;
313
314         case EventPipeSessionType::IpcStream:
315             s_pFile = new EventPipeFile(new IpcStreamWriter(sessionId, pStream));
316             CreateFlushTimerCallback();
317             break;
318
319         default:
320             s_pFile = nullptr;
321             break;
322     }
323
324     // Enable tracing.
325     s_pConfig->Enable(s_pSession);
326
327     // Enable the sample profiler
328     SampleProfiler::Enable();
329
330     // Return the session ID.
331     return sessionId;
332 }
333
334 void EventPipe::Disable(EventPipeSessionID id)
335 {
336     CONTRACTL
337     {
338         THROWS;
339         GC_TRIGGERS;
340         MODE_ANY;
341     }
342     CONTRACTL_END;
343
344     // Only perform the disable operation if the session ID
345     // matches the current active session.
346     if (id != (EventPipeSessionID)s_pSession)
347         return;
348
349     // Don't block GC during clean-up.
350     GCX_PREEMP();
351
352     // Take the lock before disabling tracing.
353     CrstHolder _crst(GetLock());
354
355     if (s_pConfig != NULL && s_pConfig->Enabled())
356     {
357         // Disable the profiler.
358         SampleProfiler::Disable();
359
360         // Log the process information event.
361         s_pEventSource->SendProcessInfo(s_pCommandLine);
362
363         // Log the runtime information event.
364         ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Normal);
365
366         // Disable tracing.
367         s_pConfig->Disable(s_pSession);
368
369         // Delete the session.
370         s_pConfig->DeleteSession(s_pSession);
371         s_pSession = NULL;
372
373         // Delete the file switch timer.
374         DeleteFlushTimerCallback();
375
376         // Flush all write buffers to make sure that all threads see the change.
377         FlushProcessWriteBuffers();
378
379         // Write to the file.
380         if (s_pFile != nullptr)
381         {
382             LARGE_INTEGER disableTimeStamp;
383             QueryPerformanceCounter(&disableTimeStamp);
384             s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
385
386             if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
387             {
388                 // Before closing the file, do rundown.
389                 const EventPipeProviderConfiguration RundownProviders[] = {
390                     {W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL},       // Public provider.
391                     {W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL} // Rundown provider.
392                 };
393
394                 // The circular buffer size doesn't matter because all events are written synchronously during rundown.
395                 s_pSession = s_pConfig->CreateSession(
396                     EventPipeSessionType::File,
397                     1 /* circularBufferSizeInMB */,
398                     RundownProviders,
399                     sizeof(RundownProviders) / sizeof(EventPipeProviderConfiguration));
400                 s_pConfig->EnableRundown(s_pSession);
401
402                 // Ask the runtime to emit rundown events.
403                 if (g_fEEStarted && !g_fEEShutDown)
404                     ETW::EnumerationLog::EndRundown();
405
406                 // Disable the event pipe now that rundown is complete.
407                 s_pConfig->Disable(s_pSession);
408
409                 // Delete the rundown session.
410                 s_pConfig->DeleteSession(s_pSession);
411                 s_pSession = NULL;
412             }
413
414             delete s_pFile;
415             s_pFile = nullptr;
416         }
417
418         // De-allocate buffers.
419         s_pBufferManager->DeAllocateBuffers();
420
421         // Delete deferred providers.
422         // Providers can't be deleted during tracing because they may be needed when serializing the file.
423         s_pConfig->DeleteDeferredProviders();
424     }
425 }
426
427 void EventPipe::CreateFlushTimerCallback()
428 {
429     CONTRACTL
430     {
431         THROWS;
432         GC_TRIGGERS;
433         MODE_ANY;
434         PRECONDITION(GetLock()->OwnedByCurrentThread());
435     }
436     CONTRACTL_END
437
438     if (s_pFile == nullptr)
439         return;
440
441     NewHolder<ThreadpoolMgr::TimerInfoContext> timerContextHolder = new (nothrow) ThreadpoolMgr::TimerInfoContext();
442     if (timerContextHolder == NULL)
443         return;
444
445     timerContextHolder->TimerId = 0;
446
447     // Initialize the last file switch time.
448     s_lastFlushSwitchTime = CLRGetTickCount64();
449
450     bool success = false;
451     _ASSERTE(s_fileSwitchTimerHandle == NULL);
452     EX_TRY
453     {
454         if (ThreadpoolMgr::CreateTimerQueueTimer(
455                 &s_fileSwitchTimerHandle,
456                 FlushTimer,
457                 timerContextHolder,
458                 100, // DueTime (msec)
459                 100, // Period (msec)
460                 0 /* flags */))
461         {
462             _ASSERTE(s_fileSwitchTimerHandle != NULL);
463             success = true;
464         }
465     }
466     EX_CATCH
467     {
468     }
469     EX_END_CATCH(RethrowTerminalExceptions);
470
471     if (!success)
472     {
473         _ASSERTE(s_fileSwitchTimerHandle == NULL);
474         return;
475     }
476
477     timerContextHolder.SuppressRelease(); // the timer context is automatically deleted by the timer infrastructure
478 }
479
480 void EventPipe::DeleteFlushTimerCallback()
481 {
482     CONTRACTL
483     {
484         THROWS;
485         GC_TRIGGERS;
486         MODE_ANY;
487         PRECONDITION(GetLock()->OwnedByCurrentThread());
488     }
489     CONTRACTL_END
490
491     if ((s_fileSwitchTimerHandle != NULL) && (ThreadpoolMgr::DeleteTimerQueueTimer(s_fileSwitchTimerHandle, NULL)))
492         s_fileSwitchTimerHandle = NULL;
493 }
494
495 void WINAPI EventPipe::FlushTimer(PVOID parameter, BOOLEAN timerFired)
496 {
497     CONTRACTL
498     {
499         THROWS;
500         GC_TRIGGERS;
501         MODE_ANY;
502         PRECONDITION(timerFired);
503     }
504     CONTRACTL_END;
505
506     // Take the lock control lock to make sure that tracing isn't disabled during this operation.
507     CrstHolder _crst(GetLock());
508
509     if (s_pSession == nullptr || s_pFile == nullptr)
510         return;
511
512     // Make sure that we should actually switch files.
513     if (!Enabled() || s_pSession->GetSessionType() != EventPipeSessionType::IpcStream)
514         return;
515
516     GCX_PREEMP();
517
518     if (CLRGetTickCount64() > (s_lastFlushSwitchTime + 100))
519     {
520         // Get the current time stamp.
521         // WriteAllBuffersToFile will use this to ensure that no events after
522         // the current timestamp are written into the file.
523         LARGE_INTEGER stopTimeStamp;
524         QueryPerformanceCounter(&stopTimeStamp);
525         s_pBufferManager->WriteAllBuffersToFile(s_pFile, stopTimeStamp);
526
527         s_lastFlushSwitchTime = CLRGetTickCount64();
528     }
529 }
530
531 EventPipeSession *EventPipe::GetSession(EventPipeSessionID id)
532 {
533     LIMITED_METHOD_CONTRACT;
534
535     EventPipeSession *pSession = NULL;
536     if ((EventPipeSessionID)s_pSession == id)
537     {
538         pSession = s_pSession;
539     }
540     return pSession;
541 }
542
543 bool EventPipe::Enabled()
544 {
545     LIMITED_METHOD_CONTRACT;
546
547     bool enabled = false;
548     if (s_pConfig != NULL)
549     {
550         enabled = s_pConfig->Enabled();
551     }
552
553     return enabled;
554 }
555
556 EventPipeProvider *EventPipe::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
557 {
558     CONTRACTL
559     {
560         THROWS;
561         GC_TRIGGERS;
562         MODE_ANY;
563     }
564     CONTRACTL_END;
565
566     EventPipeProvider *pProvider = NULL;
567     if (s_pConfig != NULL)
568     {
569         pProvider = s_pConfig->CreateProvider(providerName, pCallbackFunction, pCallbackData);
570     }
571
572     return pProvider;
573 }
574
575 EventPipeProvider *EventPipe::GetProvider(const SString &providerName)
576 {
577     CONTRACTL
578     {
579         THROWS;
580         GC_NOTRIGGER;
581         MODE_ANY;
582     }
583     CONTRACTL_END;
584
585     EventPipeProvider *pProvider = NULL;
586     if (s_pConfig != NULL)
587     {
588         pProvider = s_pConfig->GetProvider(providerName);
589     }
590
591     return pProvider;
592 }
593
594 void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
595 {
596     CONTRACTL
597     {
598         THROWS;
599         GC_TRIGGERS;
600         MODE_ANY;
601     }
602     CONTRACTL_END;
603
604     // Take the lock to make sure that we don't have a race
605     // between disabling tracing and deleting a provider
606     // where we hold a provider after tracing has been disabled.
607     CrstHolder _crst(GetLock());
608
609     if (pProvider != NULL)
610     {
611         if (Enabled())
612         {
613             // Save the provider until the end of the tracing session.
614             pProvider->SetDeleteDeferred();
615         }
616         else
617         {
618             // Delete the provider now.
619             if (s_pConfig != NULL)
620             {
621                 s_pConfig->DeleteProvider(pProvider);
622             }
623         }
624     }
625 }
626
627 void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
628 {
629     CONTRACTL
630     {
631         NOTHROW;
632         GC_NOTRIGGER;
633         MODE_ANY;
634     }
635     CONTRACTL_END;
636
637     EventPipeEventPayload payload(pData, length);
638     EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
639 }
640
641 void EventPipe::WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
642 {
643     CONTRACTL
644     {
645         NOTHROW;
646         GC_NOTRIGGER;
647         MODE_ANY;
648     }
649     CONTRACTL_END;
650
651     EventPipeEventPayload payload(pEventData, eventDataCount);
652     EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
653 }
654
655 void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
656 {
657     CONTRACTL
658     {
659         NOTHROW;
660         GC_NOTRIGGER;
661         MODE_ANY;
662     }
663     CONTRACTL_END;
664
665     // Exit early if the event is not enabled.
666     if (!event.IsEnabled())
667     {
668         return;
669     }
670
671     // Get the current thread;
672     Thread *pThread = GetThread();
673
674     if (s_pConfig == NULL)
675     {
676         // We can't procede without a configuration
677         return;
678     }
679     _ASSERTE(s_pSession != NULL);
680
681     // If the activity id isn't specified AND we are in a managed thread, pull it from the current thread.
682     // If pThread is NULL (we aren't in writing from a managed thread) then pActivityId can be NULL
683     if (pActivityId == NULL && pThread != NULL)
684     {
685         pActivityId = pThread->GetActivityId();
686     }
687
688     if (!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
689     {
690         s_pBufferManager->WriteEvent(pThread, *s_pSession, event, payload, pActivityId, pRelatedActivityId);
691     }
692     else if (s_pConfig->RundownEnabled())
693     {
694         // It is possible that some events that are enabled on rundown can be emitted from other threads.
695         // We're not interested in these events and they can cause corrupted trace files because rundown
696         // events are written synchronously and not under lock.
697         // If we encounter an event that did not originate on the thread that is doing rundown, ignore it.
698         if (pThread == NULL || !s_pConfig->IsRundownThread(pThread))
699         {
700             return;
701         }
702
703         BYTE *pData = payload.GetFlatData();
704         if (pData != NULL)
705         {
706             // Write synchronously to the file.
707             // We're under lock and blocking the disabling thread.
708             // This copy occurs here (rather than at file write) because
709             // A) The FastSerializer API would need to change if we waited
710             // B) It is unclear there is a benefit to multiple file write calls
711             //    as opposed a a buffer copy here
712             EventPipeEventInstance instance(
713                 *s_pSession,
714                 event,
715                 pThread->GetOSThreadId(),
716                 pData,
717                 payload.GetSize(),
718                 pActivityId,
719                 pRelatedActivityId);
720             instance.EnsureStack(*s_pSession);
721
722             if (s_pFile != NULL)
723             {
724                 // EventPipeFile::WriteEvent needs to allocate a metadata event
725                 // and can therefore throw. In this context we will silently
726                 // fail rather than disrupt the caller
727                 EX_TRY
728                 {
729                     s_pFile->WriteEvent(instance);
730                 }
731                 EX_CATCH {}
732                 EX_END_CATCH(SwallowAllExceptions);
733             }
734         }
735     }
736 }
737
738 void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length)
739 {
740     CONTRACTL
741     {
742         NOTHROW;
743         GC_TRIGGERS;
744         MODE_PREEMPTIVE;
745     }
746     CONTRACTL_END;
747
748     EventPipeEventPayload payload(pData, length);
749
750     // Write the event to the thread's buffer.
751     if (s_pBufferManager != NULL)
752     {
753         // Specify the sampling thread as the "current thread", so that we select the right buffer.
754         // Specify the target thread so that the event gets properly attributed.
755         s_pBufferManager->WriteEvent(pSamplingThread, *s_pSession, *pEvent, payload, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents);
756     }
757 }
758
759 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
760 {
761     CONTRACTL
762     {
763         NOTHROW;
764         GC_NOTRIGGER;
765         MODE_ANY;
766     }
767     CONTRACTL_END;
768
769     Thread *pThread = GetThread();
770     if (pThread != NULL)
771     {
772         return WalkManagedStackForThread(pThread, stackContents);
773     }
774
775     return false;
776 }
777
778 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
779 {
780     CONTRACTL
781     {
782         NOTHROW;
783         GC_NOTRIGGER;
784         MODE_ANY;
785         PRECONDITION(pThread != NULL);
786     }
787     CONTRACTL_END;
788
789     // Calling into StackWalkFrames in preemptive mode violates the host contract,
790     // but this contract is not used on CoreCLR.
791     CONTRACT_VIOLATION(HostViolation);
792
793     stackContents.Reset();
794
795     StackWalkAction swaRet = pThread->StackWalkFrames(
796         (PSTACKWALKFRAMESCALLBACK)&StackWalkCallback,
797         &stackContents,
798         ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES | ALLOW_INVALID_OBJECTS);
799
800     return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
801 }
802
803 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
804 {
805     CONTRACTL
806     {
807         NOTHROW;
808         GC_NOTRIGGER;
809         MODE_ANY;
810         PRECONDITION(pCf != NULL);
811         PRECONDITION(pData != NULL);
812     }
813     CONTRACTL_END;
814
815     // Get the IP.
816     UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
817     if (controlPC == 0)
818     {
819         if (pData->GetLength() == 0)
820         {
821             // This happens for pinvoke stubs on the top of the stack.
822             return SWA_CONTINUE;
823         }
824     }
825
826     _ASSERTE(controlPC != 0);
827
828     // Add the IP to the captured stack.
829     pData->Append(
830         controlPC,
831         pCf->GetFunction());
832
833     // Continue the stack walk.
834     return SWA_CONTINUE;
835 }
836
837 void EventPipe::SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv)
838 {
839     CONTRACTL
840     {
841         THROWS;
842         GC_TRIGGERS;
843         MODE_COOPERATIVE;
844         PRECONDITION(pwzAssemblyPath != NULL);
845         PRECONDITION(argc <= 0 || argv != NULL);
846     }
847     CONTRACTL_END;
848
849     // Get the command line.
850     LPCWSTR osCommandLine = GetCommandLineW();
851
852 #ifndef FEATURE_PAL
853     // On Windows, osCommandLine contains the executable and all arguments.
854     s_pCommandLine = osCommandLine;
855 #else
856     // On UNIX, the PAL doesn't have the command line arguments, so we must build the command line.
857     // osCommandLine contains the full path to the executable.
858     SString commandLine(osCommandLine);
859     commandLine.Append((WCHAR)' ');
860     commandLine.Append(pwzAssemblyPath);
861
862     for (int i = 0; i < argc; i++)
863     {
864         commandLine.Append((WCHAR)' ');
865         commandLine.Append(argv[i]);
866     }
867
868     // Allocate a new string for the command line.
869     SIZE_T commandLineLen = commandLine.GetCount();
870     WCHAR *pCommandLine = new WCHAR[commandLineLen + 1];
871     wcsncpy(pCommandLine, commandLine.GetUnicode(), commandLineLen);
872     pCommandLine[commandLineLen] = '\0';
873
874     s_pCommandLine = pCommandLine;
875 #endif
876 }
877
878 EventPipeEventInstance *EventPipe::GetNextEvent()
879 {
880     CONTRACTL
881     {
882         THROWS;
883         GC_TRIGGERS;
884         MODE_PREEMPTIVE;
885     }
886     CONTRACTL_END;
887
888     EventPipeEventInstance *pInstance = NULL;
889
890     // Only fetch the next event if a tracing session exists.
891     // The buffer manager is not disposed until the process is shutdown.
892     if (s_pSession != NULL)
893     {
894         pInstance = s_pBufferManager->GetNextEvent();
895     }
896
897     return pInstance;
898 }
899
900 #endif // FEATURE_PERFTRACING