From c19133d230eeb283dd42655006d120caeefc829e Mon Sep 17 00:00:00 2001 From: wwh1004 Date: Sun, 2 Feb 2025 23:25:14 +0800 Subject: [PATCH] Roughly handles WPP events to avoid RegisteredTraceEventParser assertions --- src/TraceEvent/ETWTraceEventSource.cs | 2 +- src/TraceEvent/RegisteredTraceEventParser.cs | 17 +++++--- src/TraceEvent/TraceEvent.cs | 45 ++++++++++++++------ src/TraceEvent/TraceEventNativeMethods.cs | 1 + src/TraceEvent/TraceLog.cs | 2 +- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/TraceEvent/ETWTraceEventSource.cs b/src/TraceEvent/ETWTraceEventSource.cs index 5fa723796..b6e2b3ed9 100644 --- a/src/TraceEvent/ETWTraceEventSource.cs +++ b/src/TraceEvent/ETWTraceEventSource.cs @@ -151,7 +151,7 @@ public override bool Process() /// /// Reprocess a pre-constructed event which this processor has presumably created. Helpful to re-examine /// "unknown" events, perhaps after a manifest has been received from the ETW stream. - /// Note when queuing events to reprocess you must Clone them first + /// Note when queuing events to reprocess you must Clone them first /// or certain internal data may no longer be available and you may receive memory access violations. /// /// Event to re-process. diff --git a/src/TraceEvent/RegisteredTraceEventParser.cs b/src/TraceEvent/RegisteredTraceEventParser.cs index 62665b62a..5b947fb2d 100644 --- a/src/TraceEvent/RegisteredTraceEventParser.cs +++ b/src/TraceEvent/RegisteredTraceEventParser.cs @@ -621,6 +621,12 @@ internal override DynamicTraceEventData TryLookup(TraceEvent unknownEvent) /// internal static DynamicTraceEventData TryLookupWorker(TraceEvent unknownEvent, Dictionary> mapTable = null) { + // We are not able to handle WPP events in this parser. + if (unknownEvent.lookupAsWPP) + { + return null; + } + // Is this a TraceLogging style DynamicTraceEventData ret = null; @@ -1192,7 +1198,7 @@ protected unsafe ExternalTraceEventParser(TraceEventSource source, bool dontRegi parsedTemplate = TryLookup(unknown); if (parsedTemplate == null) { - m_state.m_templates.Add(unknown.Clone(), null); // add an entry to remember that we tried and failed. + m_state.m_templates.Add(unknown.Clone(true), null); // add an entry to remember that we tried and failed. } } if (parsedTemplate == null) @@ -1369,7 +1375,6 @@ internal class TraceEventComparer : IEqualityComparer { public bool Equals(TraceEvent x, TraceEvent y) { - Debug.Assert(!(x.lookupAsWPP && x.lookupAsClassic)); if (x.lookupAsClassic != y.lookupAsClassic) { return false; @@ -1380,15 +1385,15 @@ public bool Equals(TraceEvent x, TraceEvent y) return false; } - if (x.lookupAsClassic) + if (x.lookupAsWPP) { Debug.Assert(x.taskGuid != Guid.Empty && y.taskGuid != Guid.Empty); - return (x.taskGuid == y.taskGuid) && (x.Opcode == y.Opcode); + return (x.taskGuid == y.taskGuid) && (x.ID == y.ID); } - else if (x.lookupAsWPP) + else if (x.lookupAsClassic) { Debug.Assert(x.taskGuid != Guid.Empty && y.taskGuid != Guid.Empty); - return (x.taskGuid == y.taskGuid) && (x.ID == y.ID); + return (x.taskGuid == y.taskGuid) && (x.Opcode == y.Opcode); } else { diff --git a/src/TraceEvent/TraceEvent.cs b/src/TraceEvent/TraceEvent.cs index 24dbbf480..32d85428e 100644 --- a/src/TraceEvent/TraceEvent.cs +++ b/src/TraceEvent/TraceEvent.cs @@ -977,6 +977,14 @@ public bool IsClassicProvider // [SecuritySafeCritical] get { return (eventRecord->EventHeader.Flags & TraceEventNativeMethods.EVENT_HEADER_FLAG_CLASSIC_HEADER) != 0; } } + /// + /// Returns true if this event is from the TraceMessage function (typically indicates from a WPP provider) + /// + public bool IsTraceMessage + { + // [SecuritySafeCritical] + get { return (eventRecord->EventHeader.Flags & TraceEventNativeMethods.EVENT_HEADER_FLAG_TRACE_MESSAGE) != 0; } + } /// /// The ID of the container that emitted the event, if available. @@ -1341,10 +1349,30 @@ public byte[] EventData(byte[] targetBuffer, int targetStartIndex, int sourceSta /// This method is more expensive than copy out all the event data from the TraceEvent instance /// to a type of your construction. /// - public virtual unsafe TraceEvent Clone() + public virtual TraceEvent Clone() { - TraceEvent ret = (TraceEvent)MemberwiseClone(); // Clone myself. - ret.next = null; // the clone is not in any linked list. + return Clone(false); + } + + internal unsafe TraceEvent Clone(bool toTemplate) + { + TraceEvent ret = (TraceEvent)MemberwiseClone(); // Clone myself. + ret.next = null; // the clone is not in any linked list. + + if (toTemplate) + { + // We are cloning to a template, so we don't need to clone the data. + ret.eventRecord = null; + ret.myBuffer = IntPtr.Zero; + ret.instanceContainerID = null; + + // Also zero out the dispatch-related fields. + ret.traceEventSource = null; + ret.Target = null; + + return ret; + } + if (eventRecord != null) { int userDataLength = (EventDataLength + 3) / 4 * 4; // DWORD align @@ -2013,15 +2041,6 @@ internal int ThreadIDforStacks() /// protected internal virtual void SetState(object state) { } - protected internal TraceEvent CloneToTemplate() - { - TraceEvent ret = Clone(); - ret.traceEventSource = null; - ret.eventRecord = null; - ret.Target = null; - return ret; - } - #endregion #region Private private static char HexDigit(int digit) @@ -3663,6 +3682,7 @@ internal TraceEvent Lookup(TraceEventNativeMethods.EVENT_RECORD* eventRecord) #if DEBUG // ASSERT we found the event using the mechanism we expected to use. Debug.Assert(((eventRecord->EventHeader.Flags & TraceEventNativeMethods.EVENT_HEADER_FLAG_CLASSIC_HEADER) != 0) == curTemplate.lookupAsClassic); + Debug.Assert(((eventRecord->EventHeader.Flags & TraceEventNativeMethods.EVENT_HEADER_FLAG_TRACE_MESSAGE) != 0) == curTemplate.lookupAsWPP); if (curTemplate.lookupAsClassic) { Debug.Assert(curTemplate.taskGuid == eventRecord->EventHeader.ProviderId); @@ -3710,6 +3730,7 @@ internal TraceEvent Lookup(TraceEventNativeMethods.EVENT_RECORD* eventRecord) unhandledEventTemplate.userData = eventRecord->UserData; unhandledEventTemplate.eventIndex = currentID; unhandledEventTemplate.lookupAsClassic = unhandledEventTemplate.IsClassicProvider; + unhandledEventTemplate.lookupAsWPP = unhandledEventTemplate.IsTraceMessage; if ((((int)currentID) & 0xFFFF) == 0) // Every 64K events allow Thread.Interrupt. { System.Threading.Thread.Sleep(0); diff --git a/src/TraceEvent/TraceEventNativeMethods.cs b/src/TraceEvent/TraceEventNativeMethods.cs index 2cf5af012..314255a79 100644 --- a/src/TraceEvent/TraceEventNativeMethods.cs +++ b/src/TraceEvent/TraceEventNativeMethods.cs @@ -399,6 +399,7 @@ internal static extern int TraceQueryInformation( */ internal const ushort EVENT_HEADER_FLAG_STRING_ONLY = 0x0004; + internal const ushort EVENT_HEADER_FLAG_TRACE_MESSAGE = 0x0008; internal const ushort EVENT_HEADER_FLAG_NO_CPUTIME = 0x0010; internal const ushort EVENT_HEADER_FLAG_32_BIT_HEADER = 0x0020; internal const ushort EVENT_HEADER_FLAG_64_BIT_HEADER = 0x0040; diff --git a/src/TraceEvent/TraceLog.cs b/src/TraceEvent/TraceLog.cs index 9ee3f6212..55abfe8c5 100644 --- a/src/TraceEvent/TraceLog.cs +++ b/src/TraceEvent/TraceLog.cs @@ -783,7 +783,7 @@ private unsafe TraceLog(TraceEventDispatcher source) } if (toSend.containsSelfDescribingMetadata) { - var template = toSend.CloneToTemplate(); + var template = toSend.Clone(true); realTimeSource.Dynamic.OnNewEventDefintion(template, true); return true; }