diff --git a/src/TraceEvent/EventSources/ProcessMetadataEventSource.cs b/src/TraceEvent/EventSources/ProcessMetadataEventSource.cs
new file mode 100644
index 000000000..9c74acf97
--- /dev/null
+++ b/src/TraceEvent/EventSources/ProcessMetadataEventSource.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Diagnostics.Tracing;
+
+namespace Microsoft.Diagnostics.Tracing
+{
+ [EventSource(Name = "ProcessMetadataEventSource")]
+ public sealed class ProcessMetadataEventSource : EventSource
+ {
+ public class Tasks
+ {
+ public const EventTask Process = (EventTask)1;
+ public const EventTask Thread = (EventTask)2;
+ public const EventTask Module = (EventTask)3;
+ }
+
+ [Event(1, Opcode = EventOpcode.Start, Task = Tasks.Process)]
+ public void ProcessStart(long ProcessId, long ParentProcessId, string Executable, string CommandLine)
+ {
+ this.WriteEvent(1, ProcessId, ParentProcessId, Executable, CommandLine);
+ }
+
+ [Event(2, Opcode = EventOpcode.Stop, Task = Tasks.Process)]
+ public void ProcessExit(long ProcessId, long ParentProcessId, int ExitCode, string Executable, string CommandLine)
+ {
+ this.WriteEvent(2, ProcessId, ParentProcessId, ExitCode, Executable, CommandLine);
+ }
+
+ [Event(3, Opcode = EventOpcode.Start, Task = Tasks.Thread)]
+ public void ThreadCreate(long ProcessId, long ThreadId, ulong StackBaseAddress, string ThreadName)
+ {
+ this.WriteEvent(3, ProcessId, ThreadId, StackBaseAddress, ThreadName);
+ }
+
+ [Event(4, Opcode = EventOpcode.Stop, Task = Tasks.Thread)]
+ public void ThreadDestroy(long ProcessId, long ThreadId, ulong StackBaseAddress, string ThreadName)
+ {
+ this.WriteEvent(4, ProcessId, ThreadId, StackBaseAddress, ThreadName);
+ }
+
+ [Event(5, Opcode = EventOpcode.Start, Task = Tasks.Module)]
+ public void ModuleLoad(long ProcessId, ulong LoadAddress, long ModuleSize, Guid DebugGuid, int DebugAge, string ModuleFilePath, string DebugModuleFileName)
+ {
+ this.WriteEvent(5, ProcessId, LoadAddress, ModuleSize, DebugGuid, DebugAge, ModuleFilePath, DebugModuleFileName);
+ }
+
+ [Event(6, Opcode = EventOpcode.Stop, Task = Tasks.Module)]
+ public void ModuleUnload(long ProcessId, long LoadAddress, long ModuleSize, string ModuleFilePath)
+ {
+ this.WriteEvent(6, ProcessId, LoadAddress, ModuleSize, ModuleFilePath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/TraceEvent/Parsers/ProcessMetadataTraceEventParser.cs b/src/TraceEvent/Parsers/ProcessMetadataTraceEventParser.cs
new file mode 100644
index 000000000..4c7c5d062
--- /dev/null
+++ b/src/TraceEvent/Parsers/ProcessMetadataTraceEventParser.cs
@@ -0,0 +1,683 @@
+//
+using System;
+using System.Diagnostics;
+using System.Diagnostics.Tracing;
+using System.Text;
+using Microsoft.Diagnostics.Tracing;
+using Address = System.UInt64;
+
+#pragma warning disable 1591 // disable warnings on XML comments not being present
+
+// This code was automatically generated by the TraceParserGen tool, which converts
+// an ETW event manifest into strongly typed C# classes.
+namespace Microsoft.Diagnostics.Tracing.Parsers
+{
+ using Microsoft.Diagnostics.Tracing.Parsers.ProcessMetadataEventSource;
+
+ [System.CodeDom.Compiler.GeneratedCode("traceparsergen", "2.0")]
+ public sealed class ProcessMetadataEventSourceTraceEventParser : TraceEventParser
+ {
+ public static string ProviderName = "ProcessMetadataEventSource";
+ public static Guid ProviderGuid = new Guid(unchecked((int)0xa0aec25c), unchecked((short)0xe018), unchecked((short)0x5ee2), 0x59, 0x94, 0xb2, 0x88, 0x6f, 0xdb, 0x33, 0x3d);
+
+ public enum Keywords : long
+ {
+ Session3 = 0x100000000000,
+ Session2 = 0x200000000000,
+ Session1 = 0x400000000000,
+ Session0 = 0x800000000000,
+ };
+
+ public ProcessMetadataEventSourceTraceEventParser(TraceEventSource source) : base(source) { }
+
+ public event Action EventSourceMessage
+ {
+ add
+ {
+ RegisterTemplate(new EventSourceMessageArgsTraceData(value, 0, 65534, "EventSourceMessage", Guid.Empty, 0, "", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 0, Guid.Empty);
+ }
+ }
+ public event Action ModuleStart
+ {
+ add
+ {
+ RegisterTemplate(new ModuleLoadArgsTraceData(value, 5, 3, "Module", Guid.Empty, 1, "Start", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 5, Guid.Empty);
+ }
+ }
+ public event Action ModuleStop
+ {
+ add
+ {
+ RegisterTemplate(new ModuleUnloadArgsTraceData(value, 6, 3, "Module", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 6, Guid.Empty);
+ }
+ }
+ public event Action ProcessStart
+ {
+ add
+ {
+ RegisterTemplate(new ProcessStartArgsTraceData(value, 1, 1, "Process", Guid.Empty, 1, "Start", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 1, Guid.Empty);
+ }
+ }
+ public event Action ProcessStop
+ {
+ add
+ {
+ RegisterTemplate(new ProcessExitArgsTraceData(value, 2, 1, "Process", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 2, Guid.Empty);
+ }
+ }
+ public event Action ThreadStart
+ {
+ add
+ {
+ RegisterTemplate(new ThreadCreateArgsTraceData(value, 3, 2, "Thread", Guid.Empty, 1, "Start", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 3, Guid.Empty);
+ }
+ }
+ public event Action ThreadStop
+ {
+ add
+ {
+ RegisterTemplate(new ThreadDestroyArgsTraceData(value, 4, 2, "Thread", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName));
+ }
+ remove
+ {
+ source.UnregisterEventTemplate(value, 4, Guid.Empty);
+ }
+ }
+
+ #region private
+ protected override string GetProviderName() { return ProviderName; }
+
+ static private EventSourceMessageArgsTraceData EventSourceMessageTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new EventSourceMessageArgsTraceData(action, 0, 65534, "EventSourceMessage", Guid.Empty, 0, "", ProviderGuid, ProviderName);
+ }
+ static private ModuleLoadArgsTraceData ModuleStartTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ModuleLoadArgsTraceData(action, 5, 3, "Module", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ }
+ static private ModuleUnloadArgsTraceData ModuleStopTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ModuleUnloadArgsTraceData(action, 6, 3, "Module", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ }
+ static private ProcessStartArgsTraceData ProcessStartTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ProcessStartArgsTraceData(action, 1, 1, "Process", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ }
+ static private ProcessExitArgsTraceData ProcessStopTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ProcessExitArgsTraceData(action, 2, 1, "Process", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ }
+ static private ThreadCreateArgsTraceData ThreadStartTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ThreadCreateArgsTraceData(action, 3, 2, "Thread", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ }
+ static private ThreadDestroyArgsTraceData ThreadStopTemplate(Action action)
+ { // action, eventid, taskid, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName
+ return new ThreadDestroyArgsTraceData(action, 4, 2, "Thread", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ }
+
+ static private volatile TraceEvent[] s_templates;
+ protected internal override void EnumerateTemplates(Func eventsToObserve, Action callback)
+ {
+ if (s_templates == null)
+ {
+ var templates = new TraceEvent[7];
+ templates[0] = new EventSourceMessageArgsTraceData(null, 0, 65534, "EventSourceMessage", Guid.Empty, 0, "", ProviderGuid, ProviderName);
+ templates[1] = new ProcessStartArgsTraceData(null, 1, 1, "Process", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ templates[2] = new ProcessExitArgsTraceData(null, 2, 1, "Process", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ templates[3] = new ThreadCreateArgsTraceData(null, 3, 2, "Thread", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ templates[4] = new ThreadDestroyArgsTraceData(null, 4, 2, "Thread", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ templates[5] = new ModuleLoadArgsTraceData(null, 5, 3, "Module", Guid.Empty, 1, "Start", ProviderGuid, ProviderName);
+ templates[6] = new ModuleUnloadArgsTraceData(null, 6, 3, "Module", Guid.Empty, 2, "Stop", ProviderGuid, ProviderName);
+ s_templates = templates;
+ }
+ foreach (var template in s_templates)
+ if (eventsToObserve == null || eventsToObserve(template.ProviderName, template.EventName) == EventFilterResponse.AcceptEvent)
+ callback(template);
+ }
+
+ private void RegisterTemplate(TraceEvent template)
+ {
+ Debug.Assert(template.ProviderGuid == MicrosoftAntimalwareEngineTraceEventParser.ProviderGuid);
+ source.RegisterEventTemplate(template);
+ }
+
+ #endregion
+ }
+}
+
+namespace Microsoft.Diagnostics.Tracing.Parsers.ProcessMetadataEventSource
+{
+ public sealed class EventSourceMessageArgsTraceData : TraceEvent
+ {
+ public string message { get { return GetUnicodeStringAt(0); } }
+
+ #region Private
+ internal EventSourceMessageArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(0)));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(0)));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "message", message);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "message" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return message;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ModuleLoadArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long LoadAddress { get { return GetInt64At(8); } }
+ public long ModuleSize { get { return GetInt64At(16); } }
+ public Guid DebugGuid { get { return GetGuidAt(24); } }
+ public int DebugAge { get { return GetInt32At(40); } }
+ public string ModuleFilePath { get { return GetUnicodeStringAt(44); } }
+ public string DebugModuleFileName { get { return GetUnicodeStringAt(SkipUnicodeString(44)); } }
+
+ #region Private
+ internal ModuleLoadArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(SkipUnicodeString(44))));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(SkipUnicodeString(44))));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "LoadAddress", LoadAddress);
+ XmlAttrib(sb, "ModuleSize", ModuleSize);
+ XmlAttrib(sb, "DebugGuid", DebugGuid);
+ XmlAttrib(sb, "DebugAge", DebugAge);
+ XmlAttrib(sb, "ModuleFilePath", ModuleFilePath);
+ XmlAttrib(sb, "DebugModuleFileName", DebugModuleFileName);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "LoadAddress", "ModuleSize", "DebugGuid", "DebugAge", "ModuleFilePath", "DebugModuleFileName" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return LoadAddress;
+ case 2:
+ return ModuleSize;
+ case 3:
+ return DebugGuid;
+ case 4:
+ return DebugAge;
+ case 5:
+ return ModuleFilePath;
+ case 6:
+ return DebugModuleFileName;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ModuleUnloadArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long LoadAddress { get { return GetInt64At(8); } }
+ public long ModuleSize { get { return GetInt64At(16); } }
+ public string ModuleFilePath { get { return GetUnicodeStringAt(24); } }
+
+ #region Private
+ internal ModuleUnloadArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(24)));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(24)));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "LoadAddress", LoadAddress);
+ XmlAttrib(sb, "ModuleSize", ModuleSize);
+ XmlAttrib(sb, "ModuleFilePath", ModuleFilePath);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "LoadAddress", "ModuleSize", "ModuleFilePath" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return LoadAddress;
+ case 2:
+ return ModuleSize;
+ case 3:
+ return ModuleFilePath;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ProcessStartArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long ParentProcessId { get { return GetInt64At(8); } }
+ public string Executable { get { return GetUnicodeStringAt(16); } }
+ public string CommandLine { get { return GetUnicodeStringAt(SkipUnicodeString(16)); } }
+
+ #region Private
+ internal ProcessStartArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(SkipUnicodeString(16))));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(SkipUnicodeString(16))));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "ParentProcessId", ParentProcessId);
+ XmlAttrib(sb, "Executable", Executable);
+ XmlAttrib(sb, "CommandLine", CommandLine);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "ParentProcessId", "Executable", "CommandLine" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return ParentProcessId;
+ case 2:
+ return Executable;
+ case 3:
+ return CommandLine;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ProcessExitArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long ParentProcessId { get { return GetInt64At(8); } }
+ public int ExitCode { get { return GetInt32At(16); } }
+ public string Executable { get { return GetUnicodeStringAt(20); } }
+ public string CommandLine { get { return GetUnicodeStringAt(SkipUnicodeString(20)); } }
+
+ #region Private
+ internal ProcessExitArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(SkipUnicodeString(20))));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(SkipUnicodeString(20))));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "ParentProcessId", ParentProcessId);
+ XmlAttrib(sb, "ExitCode", ExitCode);
+ XmlAttrib(sb, "Executable", Executable);
+ XmlAttrib(sb, "CommandLine", CommandLine);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "ParentProcessId", "ExitCode", "Executable", "CommandLine" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return ParentProcessId;
+ case 2:
+ return ExitCode;
+ case 3:
+ return Executable;
+ case 4:
+ return CommandLine;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ThreadCreateArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long ThreadId { get { return GetInt64At(8); } }
+ public long StackBaseAddress { get { return GetInt64At(16); } }
+ public string ThreadName { get { return GetUnicodeStringAt(24); } }
+
+ #region Private
+ internal ThreadCreateArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(24)));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(24)));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "ThreadId", ThreadId);
+ XmlAttrib(sb, "StackBaseAddress", StackBaseAddress);
+ XmlAttrib(sb, "ThreadName", ThreadName);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "ThreadId", "StackBaseAddress", "ThreadName" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return ThreadId;
+ case 2:
+ return StackBaseAddress;
+ case 3:
+ return ThreadName;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+ public sealed class ThreadDestroyArgsTraceData : TraceEvent
+ {
+ public long ProcessId { get { return GetInt64At(0); } }
+ public long ThreadId { get { return GetInt64At(8); } }
+ public long StackBaseAddress { get { return GetInt64At(16); } }
+ public string ThreadName { get { return GetUnicodeStringAt(24); } }
+
+ #region Private
+ internal ThreadDestroyArgsTraceData(Action action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
+ : base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
+ {
+ Action = action;
+ }
+ protected internal override void Dispatch()
+ {
+ Action(this);
+ }
+ protected internal override void Validate()
+ {
+ Debug.Assert(!(Version == 0 && EventDataLength != SkipUnicodeString(24)));
+ Debug.Assert(!(Version > 0 && EventDataLength < SkipUnicodeString(24)));
+ }
+ protected internal override Delegate Target
+ {
+ get { return Action; }
+ set { Action = (Action)value; }
+ }
+ public override StringBuilder ToXml(StringBuilder sb)
+ {
+ Prefix(sb);
+ XmlAttrib(sb, "ProcessId", ProcessId);
+ XmlAttrib(sb, "ThreadId", ThreadId);
+ XmlAttrib(sb, "StackBaseAddress", StackBaseAddress);
+ XmlAttrib(sb, "ThreadName", ThreadName);
+ sb.Append("/>");
+ return sb;
+ }
+
+ public override string[] PayloadNames
+ {
+ get
+ {
+ if (payloadNames == null)
+ payloadNames = new string[] { "ProcessId", "ThreadId", "StackBaseAddress", "ThreadName" };
+ return payloadNames;
+ }
+ }
+
+ public override object PayloadValue(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return ProcessId;
+ case 1:
+ return ThreadId;
+ case 2:
+ return StackBaseAddress;
+ case 3:
+ return ThreadName;
+ default:
+ Debug.Assert(false, "Bad field index");
+ return null;
+ }
+ }
+
+ public static ulong GetKeywords() { return 0; }
+ public static string GetProviderName() { return "ProcessMetadataEventSource"; }
+ public static Guid GetProviderGuid() { return new Guid("a0aec25c-e018-5ee2-5994-b2886fdb333d"); }
+ private event Action Action;
+ #endregion
+ }
+}
diff --git a/src/TraceEvent/TraceEvent.cs b/src/TraceEvent/TraceEvent.cs
index 157fa0b53..8dffd7c94 100644
--- a/src/TraceEvent/TraceEvent.cs
+++ b/src/TraceEvent/TraceEvent.cs
@@ -194,6 +194,23 @@ public KernelTraceEventParser Kernel
}
}
+ ///
+ /// For convenience, we provide a property returns a ProcessMetadataTraceEventParser that knows
+ /// how to parse all the Process Metadata events into callbacks.
+ ///
+ public ProcessMetadataEventSourceTraceEventParser ProcessMetadata
+ {
+ get
+ {
+ if (_ProcessMetadata == null)
+ {
+ _ProcessMetadata = new ProcessMetadataEventSourceTraceEventParser(this);
+ }
+
+ return _ProcessMetadata;
+ }
+ }
+
#if !NOT_WINDOWS && !NO_DYNAMIC_TRACEEVENTPARSER
///
/// For convenience, we provide a property returns a DynamicTraceEventParser that knows
@@ -422,6 +439,7 @@ string ITraceParserServices.ProviderNameForGuid(Guid taskOrProviderGuid)
internal /*protected*/ bool useClassicETW;
internal /*protected*/ ClrTraceEventParser _CLR;
internal /*protected*/ KernelTraceEventParser _Kernel;
+ internal /*protected*/ ProcessMetadataEventSourceTraceEventParser _ProcessMetadata;
#if !NOT_WINDOWS && !NO_DYNAMIC_TRACEEVENTPARSER
internal /*protected*/ DynamicTraceEventParser _Dynamic;
internal /*protected*/ RegisteredTraceEventParser _Registered;
diff --git a/src/TraceEvent/TraceLog.cs b/src/TraceEvent/TraceLog.cs
index d6586c568..c59a27a73 100644
--- a/src/TraceEvent/TraceLog.cs
+++ b/src/TraceEvent/TraceLog.cs
@@ -30,6 +30,7 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Diagnostics.Tracing.Parsers.ProcessMetadataEventSource;
using Address = System.UInt64;
@@ -899,6 +900,7 @@ internal static void CreateFromTraceEventSource(TraceEventDispatcher source, str
var dynamicParser = source.Dynamic;
var clrParser = source.Clr;
var kernelParser = source.Kernel;
+ var processMetadataParser = source.ProcessMetadata;
// Get all the users data from the original source. Note that this happens by reference, which means
// that even though we have not built up the state yet (since we have not scanned the data yet), it will
@@ -1135,13 +1137,13 @@ private unsafe void SetupCallbacks(TraceEventDispatcher rawEvents)
// Process level events.
kernelParser.ProcessStartGroup += delegate (ProcessTraceData data)
{
- processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC, data.Opcode == TraceEventOpcode.Start).ProcessStart(data);
+ processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC, data.Opcode == TraceEventOpcode.Start).ProcessStart(data, data.CommandLine, data.ImageFileName, data.ParentID);
// Don't filter them out (not that many, useful for finding command line)
};
kernelParser.ProcessEndGroup += delegate (ProcessTraceData data)
{
- processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).ProcessEnd(data);
+ processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).ProcessEnd(data, data.CommandLine, data.ImageFileName, data.ParentID, data.ExitStatus);
// Don't filter them out (not that many, useful for finding command line)
};
// Thread level events
@@ -1234,7 +1236,7 @@ private unsafe void SetupCallbacks(TraceEventDispatcher rawEvents)
}
}
- var moduleFile = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).LoadedModules.ImageLoadOrUnload(data, isLoad, fileName);
+ var moduleFile = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).LoadedModules.ImageLoadOrUnload(data, data.ImageBase, data.ImageSize, isLoad, fileName);
// TODO review: is using the timestamp the best way to make the association
if (lastDbgData != null && data.TimeStampQPC == lastDbgData.TimeStampQPC)
{
@@ -1786,6 +1788,95 @@ private unsafe void SetupCallbacks(TraceEventDispatcher rawEvents)
sampleProfileInterval100ns = data.OldInterval;
}
};
+
+ var processMetadataParser = rawEvents.ProcessMetadata;
+
+ processMetadataParser.ProcessStart += delegate(ProcessStartArgsTraceData data)
+ {
+ Processes.GetOrCreateProcess((int)data.ProcessId, data.TimeStampQPC, isProcessStartEvent: true).ProcessStart(data, data.CommandLine, data.Executable, (int)data.ParentProcessId);
+ };
+
+ processMetadataParser.ProcessStop += delegate (ProcessExitArgsTraceData data)
+ {
+ Processes.GetOrCreateProcess((int)data.ProcessId, data.TimeStampQPC).ProcessEnd(data, data.CommandLine, data.Executable, (int)data.ParentProcessId, data.ExitCode);
+ };
+
+ processMetadataParser.ThreadStart += delegate (ThreadCreateArgsTraceData data)
+ {
+ TraceProcess process = processes.GetOrCreateProcess((int)data.ProcessId, data.TimeStampQPC);
+ thread = Threads.GetOrCreateThread((int)data.ThreadId, data.TimeStampQPC, process, data.Opcode == TraceEventOpcode.Start || data.Opcode == TraceEventOpcode.DataCollectionStart);
+ thread.startTimeQPC = data.TimeStampQPC;
+ thread.userStackBase = (Address)data.StackBaseAddress;
+ if (data.Opcode == TraceEventOpcode.DataCollectionStart)
+ {
+ bookKeepingEvent = true;
+ thread.startTimeQPC = sessionStartTimeQPC;
+ }
+ else if (data.Opcode == TraceEventOpcode.Start)
+ {
+ var threadProc = thread.Process;
+ if (!threadProc.anyThreads)
+ {
+ // We saw a real process start (not a DCStart or a non at all)
+ if (sessionStartTimeQPC < threadProc.startTimeQPC && threadProc.startTimeQPC < data.TimeStampQPC)
+ {
+ thread.threadInfo = "Startup Thread";
+ }
+
+ threadProc.anyThreads = true;
+ }
+ }
+ };
+
+ processMetadataParser.ThreadStop += delegate (ThreadDestroyArgsTraceData data)
+ {
+ TraceProcess process = processes.GetOrCreateProcess((int)data.ProcessId, data.TimeStampQPC);
+ thread = Threads.GetOrCreateThread((int)data.ThreadId, data.TimeStampQPC, process);
+ if (thread.process == null)
+ {
+ thread.process = process;
+ }
+
+ if (data.ThreadName.Length > 0)
+ {
+ CategorizeThread(data, data.ThreadName);
+ }
+
+ Debug.Assert(thread.process == process, "Different events disagree on the process object!");
+ DebugWarn(thread.endTimeQPC == long.MaxValue || thread.ThreadID == 0, "Thread end on a terminated thread " + data.ThreadId + " that ended at " + QPCTimeToRelMSec(thread.endTimeQPC), data);
+ DebugWarn(thread.Process.endTimeQPC == long.MaxValue, "Thread ending on ended process", data);
+ thread.endTimeQPC = data.TimeStampQPC;
+ thread.userStackBase = (Address)data.StackBaseAddress;
+ if (data.Opcode == TraceEventOpcode.DataCollectionStop)
+ {
+ thread.endTimeQPC = sessionEndTimeQPC;
+ bookKeepingEvent = true;
+ bookeepingEventThatMayHaveStack = true;
+ }
+
+ // Keep threadIDtoThread table under control by removing old entries.
+ if (IsRealTime)
+ {
+ Threads.threadIDtoThread.Remove((Address)data.ThreadId);
+ }
+ };
+
+ processMetadataParser.ModuleStart += delegate(ModuleLoadArgsTraceData data)
+ {
+ var isLoad = (data.Opcode == (TraceEventOpcode)10) || (data.Opcode == TraceEventOpcode.DataCollectionStart);
+
+ var moduleFile = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).LoadedModules.ImageLoadOrUnload(data, (ulong)data.LoadAddress, (int)data.ModuleSize, isLoad, data.ModuleFilePath);
+ moduleFile.pdbName = data.DebugModuleFileName;
+ moduleFile.pdbSignature = data.DebugGuid;
+ moduleFile.pdbAge = data.DebugAge;
+ hasPdbInfo = true;
+ };
+
+ processMetadataParser.ModuleStop += delegate (ModuleUnloadArgsTraceData data)
+ {
+ var isLoad = (data.Opcode == (TraceEventOpcode)10) || (data.Opcode == TraceEventOpcode.DataCollectionStart);
+ var moduleFile = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC).LoadedModules.ImageLoadOrUnload(data, (ulong)data.LoadAddress, (int)data.ModuleSize, isLoad, data.ModuleFilePath);
+ };
}
///
@@ -5566,7 +5657,7 @@ public override string ToString()
// #ProcessHandlersCalledFromTraceLog
//
// called from TraceLog.CopyRawEvents
- internal void ProcessStart(ProcessTraceData data)
+ internal void ProcessStart(TraceEvent data, string cmdLine, string moduleFileName, int parentId)
{
Log.DebugWarn(parentID == 0, "Events for process happen before process start. PrevEventTime: " + StartTimeRelativeMsec.ToString("f4"), data);
@@ -5580,21 +5671,21 @@ internal void ProcessStart(ProcessTraceData data)
Debug.Assert(endTimeQPC == long.MaxValue); // We would create a new Process record otherwise
startTimeQPC = data.TimeStampQPC;
}
- commandLine = data.CommandLine;
- imageFileName = data.ImageFileName;
- parentID = data.ParentID;
+ commandLine = cmdLine;
+ imageFileName = moduleFileName;
+ parentID = parentId;
}
- internal void ProcessEnd(ProcessTraceData data)
+ internal void ProcessEnd(TraceEvent data, string cmdLine, string moduleFileName, int parentId, int exitCode)
{
if (commandLine.Length == 0)
{
- commandLine = data.CommandLine;
+ commandLine = cmdLine;
}
- imageFileName = data.ImageFileName; // Always overwrite as we might have guessed via the image loads
- if (parentID == 0 && data.ParentID != 0)
+ imageFileName = moduleFileName; // Always overwrite as we might have guessed via the image loads
+ if (parentID == 0 && parentId != 0)
{
- parentID = data.ParentID;
+ parentID = parentId;
}
if (data.Opcode != TraceEventOpcode.DataCollectionStop)
@@ -5603,7 +5694,7 @@ internal void ProcessEnd(ProcessTraceData data)
// Only set the exit code if it really is a process exit (not a DCStop).
if (data.Opcode == TraceEventOpcode.Stop)
{
- exitStatus = data.ExitStatus;
+ exitStatus = exitCode;
}
endTimeQPC = data.TimeStampQPC;
@@ -6523,26 +6614,22 @@ internal TraceLoadedModule GetLoadedModule(string fileName, long timeQPC)
}
// #ModuleHandlersCalledFromTraceLog
- internal TraceModuleFile ImageLoadOrUnload(ImageLoadTraceData data, bool isLoad, string dataFileName = null)
+ internal TraceModuleFile ImageLoadOrUnload(TraceEvent data, Address imageBase, int imageSize, bool isLoad, string dataFileName)
{
int index;
- if (dataFileName == null)
- {
- dataFileName = data.FileName;
- }
- TraceLoadedModule module = FindModuleAndIndexContainingAddress(data.ImageBase, data.TimeStampQPC, out index);
+ TraceLoadedModule module = FindModuleAndIndexContainingAddress(imageBase, data.TimeStampQPC, out index);
if (module == null)
{
// We need to make a new module
- TraceModuleFile newModuleFile = process.Log.ModuleFiles.GetOrCreateModuleFile(dataFileName, data.ImageBase);
- newModuleFile.imageSize = data.ImageSize;
- module = new TraceLoadedModule(process, newModuleFile, data.ImageBase);
+ TraceModuleFile newModuleFile = process.Log.ModuleFiles.GetOrCreateModuleFile(dataFileName, imageBase);
+ newModuleFile.imageSize = imageSize;
+ module = new TraceLoadedModule(process, newModuleFile, imageBase);
InsertAndSetOverlap(index + 1, module);
}
// If we load a module higher than 32 bits can do, then we must be a 64 bit process.
- if (!process.loadedAModuleHigh && (ulong)data.ImageBase >= 0x100000000L)
+ if (!process.loadedAModuleHigh && (ulong)imageBase >= 0x100000000L)
{
// On win8 ntdll gets loaded into 32 bit processes so ignore it
if (!dataFileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase))
@@ -6569,14 +6656,14 @@ internal TraceModuleFile ImageLoadOrUnload(ImageLoadTraceData data, bool isLoad,
int start2 = dataFileName.Length - len;
process.Log.DebugWarn(string.Compare(module.ModuleFile.FilePath, start1, dataFileName, start2, len, StringComparison.OrdinalIgnoreCase) == 0,
"Filename Load/Unload mismatch.\r\n FILE1: " + module.ModuleFile.FilePath, data);
- process.Log.DebugWarn(module.ModuleFile.ImageSize == 0 || module.ModuleFile.ImageSize == data.ImageSize,
+ process.Log.DebugWarn(module.ModuleFile.ImageSize == 0 || module.ModuleFile.ImageSize == imageSize,
"ImageSize not consistent over all Loads Size 0x" + module.ModuleFile.ImageSize.ToString("x"), data);
/* TODO this one fails. decide what to do about it.
process.Log.DebugWarn(module.ModuleFile.DefaultBase == 0 || module.ModuleFile.DefaultBase == data.DefaultBase,
"DefaultBase not consistent over all Loads Size 0x" + module.ModuleFile.DefaultBase.ToString("x"), data);
***/
- moduleFile.imageSize = data.ImageSize;
+ moduleFile.imageSize = imageSize;
if (isLoad)
{
process.Log.DebugWarn(module.loadTimeQPC == 0 || data.Opcode == TraceEventOpcode.DataCollectionStart, "Events for module happened before load. PrevEventTime: " + module.LoadTimeRelativeMSec.ToString("f4"), data);
@@ -6610,7 +6697,7 @@ internal TraceModuleFile ImageLoadOrUnload(ImageLoadTraceData data, bool isLoad,
}
// Look for all code addresses those that don't have modules that are in my range are assumed to be mine.
- Process.Log.CodeAddresses.ForAllUnresolvedCodeAddressesInRange(process, data.ImageBase, data.ImageSize, false,
+ Process.Log.CodeAddresses.ForAllUnresolvedCodeAddressesInRange(process, imageBase, imageSize, false,
delegate (ref Microsoft.Diagnostics.Tracing.Etlx.TraceCodeAddresses.CodeAddressInfo info)
{
info.SetModuleFileIndex(moduleFile);