Skip to content

Commit

Permalink
Add trace sessions and related unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lilhoser committed Oct 21, 2023
1 parent 3f04968 commit 32e47a5
Show file tree
Hide file tree
Showing 6 changed files with 618 additions and 0 deletions.
84 changes: 84 additions & 0 deletions NativeDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public enum EventControlCode : uint
CaptureState = 2,
}

[Flags]
public enum EnableTraceProperties : uint
{
Sid = 0x1,
Expand Down Expand Up @@ -151,6 +152,46 @@ public enum WNodeClientContext : uint
CpuCycleCounter = 3
}

public enum TRACE_QUERY_INFO_CLASS : uint
{
TraceGuidQueryList = 0,
TraceGuidQueryInfo = 1,
TraceGuidQueryProcess = 2,
TraceStackTracingInfo = 3,
TraceSystemTraceEnableFlagsInfo = 4,
TraceSampledProfileIntervalInfo = 5,
TraceProfileSourceConfigInfo = 6,
TraceProfileSourceListInfo = 7,
TracePmcEventListInfo = 8,
TracePmcCounterListInfo = 9,
TraceSetDisallowList = 10,
TraceVersionInfo = 11,
TraceGroupQueryList = 12,
TraceGroupQueryInfo = 13,
TraceDisallowListQuery = 14,
TraceInfoReserved15,
TracePeriodicCaptureStateListInfo = 16,
TracePeriodicCaptureStateInfo = 17,
TraceProviderBinaryTracking = 18,
TraceMaxLoggersQuery = 19,
TraceLbrConfigurationInfo = 20,
TraceLbrEventListInfo = 21,
TraceMaxPmcCounterQuery = 22,
TraceStreamCount = 23,
TraceStackCachingInfo = 24,
TracePmcCounterOwners = 25,
TraceUnifiedStackCachingInfo = 26,
TracePmcSessionInformation = 27,
MaxTraceSetInfoClass = 28
}

[Flags]
public enum TRACE_PROVIDER_INSTANCE_FLAGS : uint
{
TRACE_PROVIDER_FLAG_LEGACY = 1,
TRACE_PROVIDER_FLAG_PRE_ENABLE = 2
}

//
// ETW filtering
//
Expand Down Expand Up @@ -321,6 +362,38 @@ public struct EVENT_FILTER_LEVEL_KW
public bool FilterIn;
}

//
// advapi structs for enumerating trace sessions
//
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TRACE_GUID_INFO
{
public uint InstanceCount;
public uint Reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TRACE_PROVIDER_INSTANCE_INFO
{
public uint NextOffset;
public uint EnableCount;
public uint Pid;
public TRACE_PROVIDER_INSTANCE_FLAGS Flags;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TRACE_ENABLE_INFO
{
public uint IsEnabled;
public EventTraceLevel Level;
public byte Reserved1;
public ushort LoggerId;
public EnableTraceProperties EnableProperty;
public uint Reserved2;
public ulong MatchAnyKeyword;
public ulong MatchAllKeyword;
}

#endregion

#region APIs
Expand Down Expand Up @@ -904,6 +977,16 @@ internal static extern uint TdhQueryProviderFieldInformation(
[In, Out] nint Buffer, // PPROVIDER_FIELD_INFOARRAY
[In, Out] ref uint BufferSize
);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint EnumerateTraceGuidsEx(
[In] NativeTraceControl.TRACE_QUERY_INFO_CLASS InfoClass,
[In] nint InBuffer,
[In] uint InBufferSize,
[In, Out] nint OutBuffer,
[In] uint OutBufferSize,
[In, Out] ref uint ReturnLength
);
#endregion

public const int ERROR_SUCCESS = 0;
Expand All @@ -915,6 +998,7 @@ internal static extern uint TdhQueryProviderFieldInformation(
public const int ERROR_NOT_FOUND = 1168;
public const int ERROR_XML_PARSE_ERROR = 1465;
public const int ERROR_RESOURCE_TYPE_NOT_FOUND = 1813;
public const int ERROR_WMI_GUID_NOT_FOUND = 4200;
public const int ERROR_EMPTY = 4306;
public const int ERROR_EVT_INVALID_EVENT_DATA = 15005;
public const int ERROR_MUI_FILE_NOT_FOUND = 15100;
Expand Down
139 changes: 139 additions & 0 deletions ParsedEtwSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
using System.Text;

namespace etwlib
{
using static NativeTraceControl;

public class SessionEnabledProvider
{
public Guid ProviderId;
public uint ProcessId;
public TRACE_PROVIDER_INSTANCE_FLAGS InstanceFlags;
public EventTraceLevel Level;
public EnableTraceProperties EnableProperty;
public ulong MatchAnyKeyword;
public ulong MatchAllKeyword;

public SessionEnabledProvider(
Guid providerId,
uint processId,
TRACE_PROVIDER_INSTANCE_FLAGS instanceFlags,
EventTraceLevel level,
EnableTraceProperties enableProperty,
ulong matchAnyKeyword,
ulong matchAllKeyword)
{
ProviderId = providerId;
ProcessId = processId;
InstanceFlags = instanceFlags;
Level = level;
EnableProperty = enableProperty;
MatchAnyKeyword = matchAnyKeyword;
MatchAllKeyword = matchAllKeyword;
}

public override string ToString()
{
var enablePropertyStr = "";
if (EnableProperty != 0)
{
enablePropertyStr = $", EnableProperty={EnableProperty}";
}
return $"{ProviderId} registered by PID {ProcessId}, InstanceFlags={InstanceFlags}, "+
$"Level={Level}{enablePropertyStr}, AnyKeyword={MatchAnyKeyword:X}, "+
$"AllKeyword={MatchAllKeyword:X}";
}
}

public class ParsedEtwSession : IEquatable<ParsedEtwSession>, IComparable<ParsedEtwSession>
{
public ushort LoggerId;
public List<SessionEnabledProvider> EnabledProviders;

public ParsedEtwSession(ushort Id)
{
LoggerId = Id;
EnabledProviders = new List<SessionEnabledProvider>();
}

public override bool Equals(object? Other)
{
if (Other == null)
{
return false;
}
var field = Other as ParsedEtwSession;
if (field == null)
{
return false;
}
return Equals(Other);
}

public bool Equals(ParsedEtwSession? Other)
{
if (Other == null)
{
return false;
}
return LoggerId == Other.LoggerId;
}

public static bool operator ==(ParsedEtwSession? Session1, ParsedEtwSession? Session2)
{
if ((object)Session1 == null || (object)Session2 == null)
return Equals(Session1, Session2);
return Session1.Equals(Session2);
}

public static bool operator !=(ParsedEtwSession? Session1, ParsedEtwSession? Session2)
{
if ((object)Session1 == null || (object)Session2 == null)
return !Equals(Session1, Session2);
return !(Session1.Equals(Session2));
}

public override int GetHashCode()
{
return LoggerId.GetHashCode();
}

public int CompareTo(ParsedEtwSession? Other)
{
if (Other == null)
{
return 1;
}
return LoggerId.CompareTo(Other.LoggerId);
}

public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"Logger ID {LoggerId}");
foreach (var p in EnabledProviders)
{
sb.AppendLine($" {p}");
}
return sb.ToString();
}
}
}
42 changes: 42 additions & 0 deletions ProviderParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,48 @@ public static class ProviderParser
return results;
}

public
static
bool
IsManifestKnown(Guid ProviderGuid)
{
var buffer = nint.Zero;
try
{
uint bufferSize = 0;
for (; ; )
{
var status = TdhEnumerateManifestProviderEvents(
ref ProviderGuid,
buffer,
ref bufferSize);
switch (status)
{
case ERROR_SUCCESS:
case ERROR_INSUFFICIENT_BUFFER:
{
return true;
}
case ERROR_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
case ERROR_RESOURCE_TYPE_NOT_FOUND:
case ERROR_MUI_FILE_NOT_FOUND:
{
return false;
}
default:
{
return false;
}
}
}
}
catch (Exception)
{
return false;
}
}

private
static
List<ParsedEtwEvent>
Expand Down
Loading

0 comments on commit 32e47a5

Please sign in to comment.