Include ETWDeserializer as source

This commit is contained in:
Mukul Sabharwal 2017-09-21 00:45:24 -07:00
Родитель 408dbc1801
Коммит 86555a081f
31 изменённых файлов: 6887 добавлений и 20 удалений

Просмотреть файл

@ -0,0 +1,19 @@
namespace ETWDeserializer.CustomParsers
{
using System;
/// <summary>
/// Much of this knowledge has been acquired thanks to:
/// https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/Parsers/kerneltraceeventparser.cs.base
/// https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/Parsers/SymbolTraceEventParser.cs
/// </summary>
internal static class CustomParserGuids
{
public static Guid KernelTraceControlImageIdGuid = new Guid("b3e675d7-2554-4f18-830b-2762732560de");
public static Guid KernelTraceControlMetaDataGuid = new Guid("bbccf6c1-6cd1-48c4-80ff-839482e37671");
public static Guid KernelStackWalkGuid = new Guid("def2fe46-7bd6-4b80-bd94-f57fe20d0ce3");
}
}

Просмотреть файл

@ -0,0 +1,65 @@
namespace ETWDeserializer.CustomParsers
{
using System;
internal sealed class KernelStackWalkEventParser
{
private static readonly EventMetadata EventMetadata;
private static readonly PropertyMetadata StacksPropertyMetadata;
private static readonly PropertyMetadata StackProcessMetadata;
private static readonly PropertyMetadata StackThreadMetadata;
private static readonly PropertyMetadata EventTimeStampMetadata;
static KernelStackWalkEventParser()
{
EventTimeStampMetadata = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT64, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDLONG, "EventTimeStamp", false, false, 0, null);
StackProcessMetadata = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "StackProcess", false, false, 0, null);
StackThreadMetadata = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "StackThread", false, false, 0, null);
StacksPropertyMetadata = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_POINTER, TDH_OUT_TYPE.TDH_OUTTYPE_HEXINT64, "Stacks", false, false, 0, null);
EventMetadata = new EventMetadata(
new Guid("def2fe46-7bd6-4b80-bd94-f57fe20d0ce3"),
32,
0,
"Kernel/Stack/StackWalk",
new[] { EventTimeStampMetadata, StackProcessMetadata, StackThreadMetadata, StacksPropertyMetadata });
}
public void Parse<T>(EventRecordReader reader, T writer, EventMetadata[] metadataArray, RuntimeEventMetadata runtimeMetadata)
where T : IEtwWriter
{
writer.WriteEventBegin(EventMetadata, runtimeMetadata);
int pointerSize = (runtimeMetadata.Flags & Etw.EVENT_HEADER_FLAG_32_BIT_HEADER) != 0 ? 4 : 8;
int numberOfStacks = (runtimeMetadata.UserDataLength - 16) / pointerSize;
writer.WritePropertyBegin(EventTimeStampMetadata);
writer.WriteUInt64(reader.ReadUInt64());
writer.WritePropertyEnd();
writer.WritePropertyBegin(StackProcessMetadata);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(StackThreadMetadata);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyBegin(StacksPropertyMetadata);
writer.WriteArrayBegin();
for (int i = 0; i < numberOfStacks; ++i)
{
writer.WritePointer(reader.ReadPointer());
}
writer.WriteArrayEnd();
writer.WritePropertyEnd();
writer.WriteEventEnd();
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
namespace ETWDeserializer.CustomParsers
{
using System;
internal sealed class KernelTraceControlDbgIdParser
{
private static readonly EventMetadata EventMetadata;
private static readonly PropertyMetadata ImageBase;
private static readonly PropertyMetadata ProcessId;
private static readonly PropertyMetadata GuidSig;
private static readonly PropertyMetadata Age;
private static readonly PropertyMetadata PdbFileName;
static KernelTraceControlDbgIdParser()
{
ImageBase = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT64, TDH_OUT_TYPE.TDH_OUTTYPE_HEXINT64, "ImageBase", false, false, 0, null);
ProcessId = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UINT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "ProcessID", false, false, 0, null);
GuidSig = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_GUID, TDH_OUT_TYPE.TDH_OUTTYPE_GUID, "GuidSig", false, false, 0, null);
Age = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UINT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "Age", false, false, 0, null);
PdbFileName = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "PdbFileName", false, false, 0, null);
EventMetadata = new EventMetadata(
new Guid("b3e675d7-2554-4f18-830b-2762732560de"),
36,
0,
"KernelTraceControl/ImageID/DbgID_RSDS",
new[] { ImageBase, ProcessId, GuidSig, Age, PdbFileName });
}
public void Parse<T>(EventRecordReader reader, T writer, EventMetadata[] metadataArray, RuntimeEventMetadata runtimeMetadata)
where T : IEtwWriter
{
writer.WriteEventBegin(EventMetadata, runtimeMetadata);
writer.WritePropertyBegin(ImageBase);
writer.WriteUInt64(reader.ReadUInt64());
writer.WritePropertyEnd();
writer.WritePropertyBegin(ProcessId);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(GuidSig);
writer.WriteGuid(reader.ReadGuid());
writer.WritePropertyEnd();
writer.WritePropertyBegin(Age);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(PdbFileName);
writer.WriteAnsiString(reader.ReadAnsiString());
writer.WritePropertyEnd();
writer.WriteEventEnd();
}
}
}

Просмотреть файл

@ -0,0 +1,111 @@
namespace ETWDeserializer.CustomParsers
{
using System;
internal sealed class KernelTraceControlImageIdFileVersionParser
{
private static readonly EventMetadata EventMetadata;
private static readonly PropertyMetadata ImageSize;
private static readonly PropertyMetadata TimeDateStamp;
private static readonly PropertyMetadata OrigFileName;
private static readonly PropertyMetadata FileDescription;
private static readonly PropertyMetadata FileVersion;
private static readonly PropertyMetadata BinFileVersion;
private static readonly PropertyMetadata VerLanguage;
private static readonly PropertyMetadata ProductName;
private static readonly PropertyMetadata CompanyName;
private static readonly PropertyMetadata ProductVersion;
private static readonly PropertyMetadata FileId;
private static readonly PropertyMetadata ProgramId;
static KernelTraceControlImageIdFileVersionParser()
{
ImageSize = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "ImageSize", false, false, 0, null);
TimeDateStamp = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_INT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "TimeDateStamp", false, false, 0, null);
OrigFileName = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "OrigFileName", false, false, 0, null);
FileDescription = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "FileDescription", false, false, 0, null);
FileVersion = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "FileVersion", false, false, 0, null);
BinFileVersion = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "BinFileVersion", false, false, 0, null);
VerLanguage = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "VerLanguage", false, false, 0, null);
ProductName = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "ProductName", false, false, 0, null);
CompanyName = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "CompanyName", false, false, 0, null);
ProductVersion = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "ProductVersion", false, false, 0, null);
FileId = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "FileId", false, false, 0, null);
ProgramId = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "ProgramId", false, false, 0, null);
EventMetadata = new EventMetadata(
new Guid("b3e675d7-2554-4f18-830b-2762732560de"),
64,
0,
"KernelTraceControl/ImageID/FileVersion",
new[] { ImageSize, TimeDateStamp, OrigFileName, FileDescription, FileVersion, BinFileVersion, VerLanguage, ProductName, CompanyName, ProductVersion, FileId, ProgramId });
}
public void Parse<T>(EventRecordReader reader, T writer, EventMetadata[] metadataArray, RuntimeEventMetadata runtimeMetadata)
where T : IEtwWriter
{
writer.WriteEventBegin(EventMetadata, runtimeMetadata);
writer.WritePropertyBegin(ImageSize);
writer.WriteUInt64(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(TimeDateStamp);
writer.WriteUInt64(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(OrigFileName);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(FileDescription);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(FileVersion);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(BinFileVersion);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(VerLanguage);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(ProductName);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(CompanyName);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(ProductVersion);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(FileId);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WritePropertyBegin(ProgramId);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WriteEventEnd();
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
namespace ETWDeserializer.CustomParsers
{
using System;
internal sealed class KernelTraceControlImageIdParser
{
private static readonly EventMetadata EventMetadata;
private static readonly PropertyMetadata ImageBase;
private static readonly PropertyMetadata ImageSize;
private static readonly PropertyMetadata TimeDateStamp;
private static readonly PropertyMetadata OriginalFileName;
static KernelTraceControlImageIdParser()
{
ImageBase = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_POINTER, TDH_OUT_TYPE.TDH_OUTTYPE_HEXINT64, "ImageBase", false, false, 0, null);
ImageSize = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UINT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "ImageSize", false, false, 0, null);
TimeDateStamp = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UINT32, TDH_OUT_TYPE.TDH_OUTTYPE_UNSIGNEDINT, "TimeDateStamp", false, false, 0, null);
OriginalFileName = new PropertyMetadata(TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING, TDH_OUT_TYPE.TDH_OUTTYPE_STRING, "OriginalFileName", false, false, 0, null);
EventMetadata = new EventMetadata(
new Guid("b3e675d7-2554-4f18-830b-2762732560de"),
36,
0,
"KernelTraceControl/ImageID",
new[] { ImageBase, ImageSize, TimeDateStamp, OriginalFileName, });
}
public void Parse<T>(EventRecordReader reader, T writer, EventMetadata[] metadataArray, RuntimeEventMetadata runtimeMetadata)
where T : IEtwWriter
{
writer.WriteEventBegin(EventMetadata, runtimeMetadata);
writer.WritePropertyBegin(ImageBase);
writer.WritePointer(reader.ReadPointer());
writer.WritePropertyEnd();
writer.WritePropertyBegin(ImageSize);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyEnd();
reader.ReadPointer();
writer.WritePropertyBegin(TimeDateStamp);
writer.WriteUInt32(reader.ReadUInt32());
writer.WritePropertyEnd();
writer.WritePropertyBegin(OriginalFileName);
writer.WriteUnicodeString(reader.ReadUnicodeString());
writer.WritePropertyEnd();
writer.WriteEventEnd();
}
}
}

Просмотреть файл

@ -0,0 +1,273 @@
namespace ETWDeserializer
{
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using CustomParsers;
public sealed class Deserializer<T>
where T : IEtwWriter
{
private static readonly Type ReaderType = typeof(EventRecordReader);
private static readonly Type EventMetadataArrayType = typeof(EventMetadata[]);
private static readonly Type RuntimeMetadataType = typeof(RuntimeEventMetadata);
private static readonly Regex InvalidCharacters = new Regex("[:\\/*?\"<>|\"-]");
private static readonly Type WriterType = typeof(T);
private readonly Dictionary<TraceEventKey, Action<EventRecordReader, T, EventMetadata[], RuntimeEventMetadata>> actionTable = new Dictionary<TraceEventKey, Action<EventRecordReader, T, EventMetadata[], RuntimeEventMetadata>>();
private readonly Dictionary<Guid, EventSourceManifest> eventSourceManifestCache = new Dictionary<Guid, EventSourceManifest>();
private readonly List<EventMetadata> eventMetadataTableList = new List<EventMetadata>();
private readonly T writer;
private EventMetadata[] eventMetadataTable;
public Deserializer(T writer)
{
this.writer = writer;
}
[AllowReversePInvokeCalls]
public bool BufferCallback(IntPtr logfile)
{
return true;
}
[AllowReversePInvokeCalls]
public unsafe void Deserialize(EVENT_RECORD* eventRecord)
{
eventRecord->UserDataFixed = eventRecord->UserData;
var eventRecordReader = new EventRecordReader(eventRecord);
var runtimeMetadata = new RuntimeEventMetadata(eventRecord);
var key = new TraceEventKey(
eventRecord->ProviderId,
(eventRecord->Flags & Etw.EVENT_HEADER_FLAG_CLASSIC_HEADER) != 0 ? eventRecord->Opcode : eventRecord->Id,
eventRecord->Version);
Action<EventRecordReader, T, EventMetadata[], RuntimeEventMetadata> action;
if (this.actionTable.TryGetValue(key, out action))
{
action(eventRecordReader, this.writer, this.eventMetadataTable, runtimeMetadata);
}
else
{
this.SlowLookup(eventRecord, eventRecordReader, runtimeMetadata, ref key);
}
}
private static unsafe IEventTraceOperand BuildOperandFromXml(EVENT_RECORD* eventRecord, Dictionary<Guid, EventSourceManifest> cache, EventRecordReader eventRecordReader, int metadataTableIndex)
{
EventSourceManifest manifest;
Guid providerGuid = eventRecord->ProviderId;
if (!cache.TryGetValue(providerGuid, out manifest))
{
manifest = CreateEventSourceManifest(providerGuid, cache, eventRecord, eventRecordReader);
}
if (manifest == null)
{
return null;
}
return !manifest.IsComplete ? null : EventTraceOperandBuilder.Build(manifest.Schema, eventRecord->Id, metadataTableIndex);
}
private static unsafe IEventTraceOperand BuildOperandFromTdh(EVENT_RECORD* eventRecord, int metadataTableIndex)
{
uint bufferSize;
byte* buffer = (byte*)0;
// Not Found
if (Tdh.GetEventInformation(eventRecord, 0, IntPtr.Zero, buffer, out bufferSize) == 1168)
{
return null;
}
buffer = (byte*)Marshal.AllocHGlobal((int)bufferSize);
Tdh.GetEventInformation(eventRecord, 0, IntPtr.Zero, buffer, out bufferSize);
var traceEventInfo = (TRACE_EVENT_INFO*)buffer;
IEventTraceOperand traceEventOperand = EventTraceOperandBuilder.Build(traceEventInfo, metadataTableIndex);
Marshal.FreeHGlobal((IntPtr)buffer);
return traceEventOperand;
}
private static unsafe IEventTraceOperand BuildUnknownOperand(EVENT_RECORD* eventRecord, int metadataTableIndex)
{
return new UnknownOperandBuilder(eventRecord->ProviderId, metadataTableIndex);
}
private static unsafe EventSourceManifest CreateEventSourceManifest(Guid providerGuid, Dictionary<Guid, EventSourceManifest> cache, EVENT_RECORD* eventRecord, EventRecordReader eventRecordReader)
{
// EventSource Schema events have the following signature:
// { byte Format, byte MajorVersion, byte MinorVersion, byte Magic, ushort TotalChunks, ushort ChunkNumber } == 8 bytes, followed by the XML schema
if (eventRecord->UserDataLength <= 8)
{
return null;
}
var format = eventRecordReader.ReadUInt8();
var majorVersion = eventRecordReader.ReadUInt8();
var minorVersion = eventRecordReader.ReadUInt8();
var magic = eventRecordReader.ReadUInt8();
ushort totalChunks = eventRecordReader.ReadUInt16();
ushort chunkNumber = eventRecordReader.ReadUInt16();
if (!(format == 1 && magic == 0x5B))
{
return null;
}
EventSourceManifest manifest;
if (!cache.TryGetValue(providerGuid, out manifest))
{
manifest = new EventSourceManifest(eventRecord->ProviderId, format, majorVersion, minorVersion, magic, totalChunks);
cache.Add(providerGuid, manifest);
}
// if manifest is complete, maybe the data changed? ideally version should have changed
// this is essentially a reset
if (manifest.IsComplete && chunkNumber == 0)
{
cache[providerGuid] = manifest;
}
string schemaChunk = eventRecordReader.ReadAnsiString();
manifest.AddChunk(schemaChunk);
return manifest;
}
private unsafe IEventTraceOperand BuildOperand(EVENT_RECORD* eventRecord, EventRecordReader eventRecordReader, int metadataTableIndex, ref bool isSpecialKernelTraceMetaDataEvent)
{
if (eventRecord->ProviderId == CustomParserGuids.KernelTraceControlMetaDataGuid && eventRecord->Opcode == 32)
{
isSpecialKernelTraceMetaDataEvent = true;
return EventTraceOperandBuilder.Build((TRACE_EVENT_INFO*)eventRecord->UserData, metadataTableIndex);
}
IEventTraceOperand operand;
if ((operand = BuildOperandFromTdh(eventRecord, metadataTableIndex)) == null)
{
operand = BuildOperandFromXml(eventRecord, this.eventSourceManifestCache, eventRecordReader, metadataTableIndex);
}
if (operand == null && eventRecord->Id != 65534) // don't show manifest events
{
operand = BuildUnknownOperand(eventRecord, metadataTableIndex);
}
return operand;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe bool CustomParserLookup(EVENT_RECORD* eventRecord, ref TraceEventKey key)
{
bool success;
// events added by KernelTraceControl.dll (i.e. Microsoft tools like WPR and PerfView)
if (eventRecord->ProviderId == CustomParserGuids.KernelTraceControlImageIdGuid)
{
switch (eventRecord->Opcode)
{
case 0:
this.actionTable.Add(key, new KernelTraceControlImageIdParser().Parse);
success = true;
break;
case 36:
this.actionTable.Add(key, new KernelTraceControlDbgIdParser().Parse);
success = true;
break;
case 64:
this.actionTable.Add(key, new KernelTraceControlImageIdFileVersionParser().Parse);
success = true;
break;
default:
success = false;
break;
}
}
// events by the Kernel Stack Walker (need this because the MOF events always says 32 stacks, but in reality there can be fewer or more
else if (eventRecord->ProviderId == CustomParserGuids.KernelStackWalkGuid)
{
if (eventRecord->Opcode == 32)
{
this.actionTable.Add(key, new KernelStackWalkEventParser().Parse);
success = true;
}
else
{
success = false;
}
}
else
{
success = false;
}
return success;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe void SlowLookup(EVENT_RECORD* eventRecord, EventRecordReader eventRecordReader, RuntimeEventMetadata runtimeMetadata, ref TraceEventKey key)
{
if (this.CustomParserLookup(eventRecord, ref key))
{
return;
}
bool isSpecialKernelTraceMetaDataEvent = false;
var operand = this.BuildOperand(eventRecord, eventRecordReader, this.eventMetadataTableList.Count, ref isSpecialKernelTraceMetaDataEvent);
if (operand != null)
{
this.eventMetadataTableList.Add(operand.Metadata);
this.eventMetadataTable = this.eventMetadataTableList.ToArray(); // TODO: Need to improve this
var eventRecordReaderParam = Expression.Parameter(ReaderType);
var eventWriterParam = Expression.Parameter(WriterType);
var eventMetadataTableParam = Expression.Parameter(EventMetadataArrayType);
var runtimeMetadataParam = Expression.Parameter(RuntimeMetadataType);
var parameters = new[] { eventRecordReaderParam, eventWriterParam, eventMetadataTableParam, runtimeMetadataParam };
var name = Regex.Replace(InvalidCharacters.Replace(operand.Metadata.Name, "_"), @"\s+", "_");
var body = EventTraceOperandExpressionBuilder.Build(operand, eventRecordReaderParam, eventWriterParam, eventMetadataTableParam, runtimeMetadataParam);
LambdaExpression expression = Expression.Lambda<Action<EventRecordReader, T, EventMetadata[], RuntimeEventMetadata>>(body, "Read_" + name, parameters);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, name + ".dll");
var typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("Read", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { ReaderType, WriterType, EventMetadataArrayType, RuntimeMetadataType });
expression.CompileToMethod(methodBuilder);
var action = (Action<EventRecordReader, T, EventMetadata[], RuntimeEventMetadata>)Delegate.CreateDelegate(expression.Type, typeBuilder.CreateType().GetMethod("Read"));
if (isSpecialKernelTraceMetaDataEvent)
{
var e = (TRACE_EVENT_INFO*)eventRecord->UserDataFixed;
this.actionTable.AddOrUpdate(new TraceEventKey(e->ProviderGuid, e->EventGuid == Guid.Empty ? e->Id : e->Opcode, e->Version), action);
}
else
{
this.actionTable.Add(key, action);
action(eventRecordReader, this.writer, this.eventMetadataTable, runtimeMetadata);
}
}
}
}
}

70
Deserializer/Etw.cs Normal file
Просмотреть файл

@ -0,0 +1,70 @@
namespace ETWDeserializer
{
using System.Runtime.InteropServices;
using ULONG = System.UInt32;
using ULONG64 = System.UInt64;
using ULONGLONG = System.UInt64;
using LARGE_INTEGER = System.Int64;
using USHORT = System.UInt16;
using GUID = System.Guid;
using UCHAR = System.Byte;
[StructLayout(LayoutKind.Sequential)]
public unsafe struct EVENT_RECORD
{
public USHORT Size; // Event Size
public USHORT HeaderType; // Header Type
public USHORT Flags; // Flags
public USHORT EventProperty; // User given event property
public ULONG ThreadId; // Thread Id
public ULONG ProcessId; // Process Id
public LARGE_INTEGER TimeStamp; // Event Timestamp
public GUID ProviderId; // Provider Id
public USHORT Id;
public UCHAR Version;
public UCHAR Channel;
public UCHAR Level;
public UCHAR Opcode;
public USHORT Task;
public ULONGLONG Keyword;
public ULONG64 ProcessorTime; // Processor Clock
public GUID ActivityId; // Activity Id
public UCHAR ProcessorNumber;
public UCHAR Alignment;
public USHORT LoggerId;
public USHORT ExtendedDataCount; // Number of extended // data items
public USHORT UserDataLength; // User data length
public EVENT_HEADER_EXTENDED_DATA_ITEM* ExtendedData; // Pointer to an array of extended data items
public byte* UserData; // Pointer to user data
public byte* UserDataFixed; // NOTE: actual field is "UserContext", but since we don't use it, using it for other purposes :-)
}
[StructLayout(LayoutKind.Sequential)]
public struct EVENT_HEADER_EXTENDED_DATA_ITEM
{
public USHORT Reserved1;
public USHORT ExtType;
public USHORT Reserved2;
public USHORT DataSize;
public ULONGLONG DataPtr;
}
internal static class Etw
{
internal const USHORT EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID = 0x0001;
internal const USHORT EVENT_HEADER_EXT_TYPE_SID = 0x0002;
internal const USHORT EVENT_HEADER_EXT_TYPE_TS_ID = 0x0003;
internal const USHORT EVENT_HEADER_EXT_TYPE_INSTANCE_INFO = 0x0004;
internal const USHORT EVENT_HEADER_EXT_TYPE_STACK_TRACE32 = 0x0005;
internal const USHORT EVENT_HEADER_EXT_TYPE_STACK_TRACE64 = 0x0006;
internal const USHORT EVENT_HEADER_EXT_TYPE_PEBS_INDEX = 0x0007;
internal const USHORT EVENT_HEADER_EXT_TYPE_PMC_COUNTERS = 0x0008;
internal const USHORT EVENT_HEADER_FLAG_STRING_ONLY = 0x0004;
internal const USHORT EVENT_HEADER_FLAG_TRACE_MESSAGE = 0x0008;
internal const USHORT EVENT_HEADER_FLAG_32_BIT_HEADER = 0x0020;
internal const USHORT EVENT_HEADER_FLAG_64_BIT_HEADER = 0x0040;
internal const USHORT EVENT_HEADER_FLAG_CLASSIC_HEADER = 0x0100;
}
}

3919
Deserializer/EventMan.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,26 @@
namespace ETWDeserializer
{
using System;
public sealed class EventMetadata
{
internal EventMetadata(Guid providerGuid, ushort id, byte version, string name, PropertyMetadata[] properties)
{
this.ProviderGuid = providerGuid;
this.Id = id;
this.Version = version;
this.Name = name;
this.Properties = properties;
}
public Guid ProviderGuid { get; private set; }
public ushort Id { get; private set; }
public byte Version { get; private set; }
public string Name { get; private set; }
public PropertyMetadata[] Properties { get; private set; }
}
}

Просмотреть файл

@ -0,0 +1,494 @@
namespace ETWDeserializer
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Principal;
public struct EventRecordReader
{
private readonly unsafe EVENT_RECORD* eventRecord;
internal unsafe EventRecordReader(EVENT_RECORD* eventRecord)
{
this.eventRecord = eventRecord;
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODESTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadUnicodeString()
{
int length = 0;
byte* ptr = this.eventRecord->UserData;
long maxLength = this.eventRecord->UserDataLength - (this.eventRecord->UserData - this.eventRecord->UserDataFixed);
while (!(ptr[length] == 0 && ptr[length + 1] == 0) && length < maxLength)
{
++length;
}
string value = new string((char*)this.eventRecord->UserData, 0, (length + 1) / 2);
this.eventRecord->UserData += (value.Length + 1) * 2; // +2 (via the multiplication)
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODESTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUnicodeString(short length)
{
return this.ReadUnicodeStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODESTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUnicodeString(ushort length)
{
return this.ReadUnicodeStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODESTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUnicodeString(int length)
{
return this.ReadUnicodeStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODESTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadUnicodeString(uint length)
{
return this.ReadUnicodeStringHelper((int)length);
}
/// <summary>
/// Reader for TDH_INTYPE_ANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadAnsiString()
{
int length = 0;
byte* ptr = this.eventRecord->UserData;
long maxLength = this.eventRecord->UserDataLength - (this.eventRecord->UserData - this.eventRecord->UserDataFixed);
while (ptr[length] != 0 && length < maxLength)
{
++length;
}
var arr = new char[length];
for (int i = 0; i < length; ++i)
{
arr[i] = (char)*ptr++;
}
this.eventRecord->UserData += length + 1; // +1 for null terminator
return new string(arr);
}
/// <summary>
/// Reader for TDH_INTYPE_ANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAnsiString(short length)
{
return this.ReadAnsiStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_ANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAnsiString(ushort length)
{
return this.ReadAnsiStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_ANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAnsiString(int length)
{
return this.ReadAnsiStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_ANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadAnsiString(uint length)
{
return this.ReadAnsiStringHelper((int)length);
}
/// <summary>
/// Reader for TDH_INTYPE_INT8
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe sbyte ReadInt8()
{
sbyte value = *(sbyte*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(sbyte);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_UINT8
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte ReadUInt8()
{
byte value = *this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(byte);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_INT16
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe short ReadInt16()
{
short value = *(short*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(short);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_UINT16
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ushort ReadUInt16()
{
ushort value = *(ushort*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(ushort);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_INT32
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe int ReadInt32()
{
int value = *(int*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(int);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_UINT32
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe uint ReadUInt32()
{
uint value = *(uint*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(uint);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_INT64
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe long ReadInt64()
{
long value = *(long*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(long);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_UINT64
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ulong ReadUInt64()
{
ulong value = *(ulong*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(ulong);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_FLOAT
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe float ReadFloat()
{
float value = *(float*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(float);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_DOUBLE
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe double ReadDouble()
{
double value = *(double*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(double);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_BOOLEAN
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe bool ReadBoolean()
{
bool value = *(int*)this.eventRecord->UserData != 0;
this.eventRecord->UserData += sizeof(int);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_BINARY
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte[] ReadBinary(short size)
{
var value = new byte[size];
Marshal.Copy((IntPtr)this.eventRecord->UserData, value, 0, size);
this.eventRecord->UserData += size;
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_BINARY
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte[] ReadBinary(ushort size)
{
var value = new byte[size];
Marshal.Copy((IntPtr)this.eventRecord->UserData, value, 0, size);
this.eventRecord->UserData += size;
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_BINARY
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte[] ReadBinary(int size)
{
var value = new byte[size];
Marshal.Copy((IntPtr)this.eventRecord->UserData, value, 0, size);
this.eventRecord->UserData += size;
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_BINARY
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte[] ReadBinary(uint size)
{
var value = new byte[size];
Marshal.Copy((IntPtr)this.eventRecord->UserData, value, 0, (int)size);
this.eventRecord->UserData += size;
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_GUID
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Guid ReadGuid()
{
Guid value = *(Guid*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(Guid);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_POINTER
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ulong ReadPointer()
{
if ((eventRecord->Flags & Etw.EVENT_HEADER_FLAG_32_BIT_HEADER) == Etw.EVENT_HEADER_FLAG_32_BIT_HEADER)
{
return this.ReadUInt32();
}
return this.ReadUInt64();
}
/// <summary>
/// Reader for TDH_INTYPE_FILETIME
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public DateTime ReadFileTime()
{
return DateTime.FromFileTimeUtc(this.ReadInt64());
}
/// <summary>
/// Reader for TDH_INTYPE_SYSTEMTIME
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public DateTime ReadSystemTime()
{
int year = this.ReadInt16();
int month = this.ReadInt16();
this.ReadInt16();
int day = this.ReadInt16();
int hour = this.ReadInt16();
int minute = this.ReadInt16();
int second = this.ReadInt16();
int milliseconds = this.ReadInt16();
return new DateTime(year, month, day, hour, minute, second, milliseconds);
}
/// <summary>
/// Reader for TDH_INTYPE_SID
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadSid()
{
var value = new SecurityIdentifier((IntPtr)this.eventRecord->UserData);
this.eventRecord->UserData += value.BinaryLength;
return value.Value;
}
/// <summary>
/// Reader for TDH_INTYPE_COUNTEDSTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadCountedString()
{
ushort length = *(ushort*)this.eventRecord->UserData;
return this.ReadUnicodeStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_COUNTEDANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadCountedAnsiString()
{
ushort length = *(ushort*)this.eventRecord->UserData;
return this.ReadAnsiStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_REVERSEDCOUNTEDSTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadReversedCountedString()
{
byte low = (byte)((ushort)this.eventRecord->UserData & 0xFF);
byte high = (byte)((ushort)this.eventRecord->UserData >> 8);
ushort length = (ushort)(((uint)low & 0xFF) | ((uint)high & 0xFF) << 8);
return this.ReadUnicodeStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_REVERSEDCOUNTEDANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadReversedCountedAnsiString()
{
byte low = (byte)((ushort)this.eventRecord->UserData & 0xFF);
byte high = (byte)((ushort)this.eventRecord->UserData >> 8);
ushort length = (ushort)(((uint)low & 0xFF) | ((uint)high & 0xFF) << 8);
return this.ReadAnsiStringHelper(length);
}
/// <summary>
/// Reader for TDH_INTYPE_NONNULLTERMINATEDSTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadNonNullTerminatedString()
{
return this.ReadUnicodeStringHelper(this.eventRecord->UserDataLength);
}
/// <summary>
/// Reader for TDH_INTYPE_NONNULLTERMINATEDANSISTRING
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadNonNullTerminatedAnsiString()
{
return this.ReadAnsiStringHelper(this.eventRecord->UserDataLength);
}
/// <summary>
/// Reader for TDH_INTYPE_UNICODECHAR
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe char ReadUnicodeChar()
{
char value = *(char*)this.eventRecord->UserData;
this.eventRecord->UserData += sizeof(char);
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_ANSICHAR
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe char ReadAnsiChar()
{
char value = (char)*this.eventRecord->UserData;
this.eventRecord->UserData += 1;
return value;
}
/// <summary>
/// Reader for TDH_INTYPE_HEXDUMP
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363800(v=vs.85).aspx
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] ReadHexDump()
{
return this.ReadBinary(this.ReadInt32());
}
/// <summary>
/// Reader for TDH_INTYPE_WBEMSID
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe string ReadWbemSid()
{
int pointerSize = (eventRecord->Flags & Etw.EVENT_HEADER_FLAG_32_BIT_HEADER) == Etw.EVENT_HEADER_FLAG_32_BIT_HEADER ? 4 : 8;
this.eventRecord->UserData += pointerSize * 2;
return this.ReadSid();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe string ReadAnsiStringHelper(int length)
{
byte* ptr = this.eventRecord->UserData;
var arr = new char[length];
for (int i = 0; i < length; ++i)
{
arr[i] = (char)*ptr++;
}
this.eventRecord->UserData += length;
return new string(arr);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe string ReadUnicodeStringHelper(int length)
{
string value = new string((char*)this.eventRecord->UserData, 0, length / 2);
this.eventRecord->UserData += value.Length * 2;
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,113 @@
namespace ETWDeserializer
{
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
internal sealed class EventSourceManifest
{
private readonly StringBuilder chunkBuilder = new StringBuilder();
private readonly Guid providerGuid;
private readonly byte format;
private readonly byte majorVersion;
private readonly byte minorVersion;
private readonly byte magic;
private readonly ushort totalChunks;
private ushort chunksReceived;
private instrumentationManifest manifest;
public EventSourceManifest(Guid providerGuid, byte format, byte majorVersion, byte minorVersion, byte magic, ushort totalChunks)
{
this.providerGuid = providerGuid;
this.format = format;
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
this.magic = magic;
this.totalChunks = totalChunks;
}
public bool IsComplete => this.chunksReceived == this.totalChunks;
public instrumentationManifest Schema
{
get
{
if (this.chunksReceived != this.totalChunks)
{
throw new Exception("Schema is incomplete as not all chunks have been received");
}
if (this.manifest == null)
{
string value = this.chunkBuilder.ToString();
var bytes = Encoding.ASCII.GetBytes(value);
using (var ms = new MemoryStream(bytes))
{
XmlSerializer serializer = new XmlSerializer(typeof(instrumentationManifest));
this.manifest = (instrumentationManifest)serializer.Deserialize(ms);
}
}
return this.manifest;
}
}
public Guid ProviderGuid => this.providerGuid;
public byte Format => this.format;
public byte MajorVersion => this.majorVersion;
public byte MinorVersion => this.minorVersion;
public byte Magic => this.magic;
public ushort TotalChunks => this.totalChunks;
public void AddChunk(string schemaChunk)
{
this.chunkBuilder.Append(schemaChunk);
++this.chunksReceived;
}
public override bool Equals(object obj)
{
var other = obj as EventSourceManifest;
return other != null && this.Equals(other);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = this.providerGuid.GetHashCode();
hashCode = (hashCode * 397) ^ this.format.GetHashCode();
hashCode = (hashCode * 397) ^ this.majorVersion.GetHashCode();
hashCode = (hashCode * 397) ^ this.minorVersion.GetHashCode();
hashCode = (hashCode * 397) ^ this.magic.GetHashCode();
hashCode = (hashCode * 397) ^ this.totalChunks.GetHashCode();
return hashCode;
}
}
public bool Equals(EventSourceManifest other)
{
return this.providerGuid.Equals(other.providerGuid)
&& this.format == other.format
&& this.majorVersion == other.majorVersion
&& this.minorVersion == other.minorVersion
&& this.magic == other.magic
&& this.totalChunks == other.totalChunks;
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
namespace ETWDeserializer
{
using System.Collections.Generic;
internal sealed class EventTraceOperand : IEventTraceOperand
{
internal EventTraceOperand(EventMetadata metadata, int eventMetadataTableIndex, IEnumerable<IEventTracePropertyOperand> operands)
{
this.Metadata = metadata;
this.EventMetadataTableIndex = eventMetadataTableIndex;
this.EventPropertyOperands = operands;
}
public int EventMetadataTableIndex { get; }
public EventMetadata Metadata { get; }
public IEnumerable<IEventTracePropertyOperand> EventPropertyOperands { get; }
}
}

Просмотреть файл

@ -0,0 +1,296 @@
namespace ETWDeserializer
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
internal static unsafe class EventTraceOperandBuilder
{
public static IEventTraceOperand Build(TRACE_EVENT_INFO* traceEventInfo, int metadataIndex)
{
return new EventTraceOperandBuilderFromTDH(traceEventInfo).Build(metadataIndex);
}
public static IEventTraceOperand Build(instrumentationManifest manifest, ushort eventId, int metadataIndex)
{
return new TraceEventOperandBuilderFromXml(manifest, eventId).Build(metadataIndex);
}
private sealed class TraceEventOperandBuilderFromXml
{
private readonly instrumentationManifest manifest;
private readonly ushort eventId;
public TraceEventOperandBuilderFromXml(instrumentationManifest manifest, ushort eventId)
{
this.manifest = manifest;
this.eventId = eventId;
}
public IEventTraceOperand Build(int eventMetadataTableIndex)
{
foreach (var instrumentationManifestTypeItem in this.manifest.Items)
{
var instrumentationType = instrumentationManifestTypeItem as InstrumentationType;
if (instrumentationType != null)
{
foreach (var instrumentationTypeItem in instrumentationType.Items)
{
var eventTypes = instrumentationTypeItem as EventsType;
if (eventTypes != null)
{
foreach (var eventTypeItem in eventTypes.Items)
{
var providerType = eventTypeItem as ProviderType;
if (providerType != null)
{
var providerName = providerType.name;
var providerGuid = new Guid(providerType.guid);
foreach (var providerTypeItem in providerType.Items)
{
var definitionType = providerTypeItem as DefinitionType;
if (definitionType != null)
{
foreach (EventDefinitionType definitionTypeItem in definitionType.Items)
{
if (string.Equals(definitionTypeItem.value, this.eventId.ToString("D")))
{
string task = definitionTypeItem.task == null ? string.IsNullOrEmpty(definitionTypeItem.symbol) ? "Task" : definitionTypeItem.symbol : definitionTypeItem.task.Name;
string opcode = definitionTypeItem.opcode == null ? string.Empty : definitionTypeItem.opcode.Name;
string version = definitionTypeItem.version;
string template = definitionTypeItem.template;
string name = providerName + "/" + task + (opcode == string.Empty ? string.Empty : "/" + opcode);
var properties = new List<IEventTracePropertyOperand>();
foreach (var item in providerType.Items)
{
var templateList = item as TemplateListType;
if (templateList != null)
{
foreach (var templateTid in templateList.template)
{
if (string.Equals(templateTid.tid, template))
{
int i = 0;
foreach (DataDefinitionType propertyItem in templateTid.Items)
{
var inType = Extensions.ToTdhInType(propertyItem.inType.Name);
var outType = TDH_OUT_TYPE.TDH_OUTTYPE_NOPRINT;
var metadata = new PropertyMetadata(inType, outType, propertyItem.name, false, false, 0, null);
properties.Add(new EventTracePropertyOperand(metadata, i++, false, false, false, false, false));
}
}
}
}
}
var operand = new EventTraceOperand(
new EventMetadata(
providerGuid,
this.eventId,
byte.Parse(version),
name,
properties.Select(t => t.Metadata).ToArray()), eventMetadataTableIndex,
properties);
return operand;
}
}
}
}
}
}
}
}
}
}
return null;
}
}
private sealed class EventTraceOperandBuilderFromTDH
{
private readonly TRACE_EVENT_INFO* traceEventInfo;
private readonly List<IEventTracePropertyOperand> flatPropertyList = new List<IEventTracePropertyOperand>();
public EventTraceOperandBuilderFromTDH(TRACE_EVENT_INFO* traceEventInfo)
{
this.traceEventInfo = traceEventInfo;
}
public IEventTraceOperand Build(int eventMetadataTableIndex)
{
var buffer = (byte*)this.traceEventInfo;
EVENT_PROPERTY_INFO* eventPropertyInfoArr = (EVENT_PROPERTY_INFO*)&this.traceEventInfo->EventPropertyInfoArray;
string provider = this.BuildName("Provider", this.traceEventInfo->ProviderGuid.ToString(), this.traceEventInfo->ProviderNameOffset);
string task = this.BuildName("EventID", this.traceEventInfo->Id.ToString(), this.traceEventInfo->TaskNameOffset);
string opcode = this.BuildName("Opcode", this.traceEventInfo->Opcode.ToString(), this.traceEventInfo->OpcodeNameOffset);
var topLevelOperands = this.IterateProperties(buffer, 0, (int)traceEventInfo->TopLevelPropertyCount, eventPropertyInfoArr);
return new EventTraceOperand(new EventMetadata(this.traceEventInfo->ProviderGuid, this.traceEventInfo->Id, this.traceEventInfo->Version, provider + "/" + task + "/" + opcode, this.flatPropertyList.Select(t => t.Metadata).ToArray()), eventMetadataTableIndex, topLevelOperands);
}
private string BuildName(string prefix, string value, uint offset)
{
var buffer = (byte*)this.traceEventInfo;
string item = prefix + "(" + value + ")";
if (offset != 0)
{
item = new string((char*)&buffer[offset]).Trim();
}
return item;
}
private List<EventTracePropertyOperand> IterateProperties(byte* buffer, int start, int end, EVENT_PROPERTY_INFO* eventPropertyInfoArr)
{
var operands = new List<EventTracePropertyOperand>();
return this.IterateProperties(buffer, operands, start, end, eventPropertyInfoArr);
}
private List<EventTracePropertyOperand> IterateProperties(byte* buffer, List<EventTracePropertyOperand> operands, int start, int end, EVENT_PROPERTY_INFO* eventPropertyInfoArr)
{
var returnList = new List<EventTracePropertyOperand>();
for (int i = start; i < end; ++i)
{
var eventPropertyInfo = &eventPropertyInfoArr[i];
string propertyName = new string((char*)&buffer[eventPropertyInfo->NameOffset]);
int structchildren = eventPropertyInfo->StructType.NumOfStructMembers;
bool isStruct = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyStruct) == PROPERTY_FLAGS.PropertyStruct;
bool isVariableArray = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyParamCount) == PROPERTY_FLAGS.PropertyParamCount;
bool isFixedArray = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyParamFixedCount) == PROPERTY_FLAGS.PropertyParamFixedCount;
bool isVariableLength = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyParamLength) == PROPERTY_FLAGS.PropertyParamLength;
bool isFixedLength = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyParamFixedLength) == PROPERTY_FLAGS.PropertyParamFixedLength;
bool isWbemXmlFragment = (eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyWBEMXmlFragment) == PROPERTY_FLAGS.PropertyWBEMXmlFragment;
// NOTE: Do not remove this special case, there are cases like this, we just assume it's a fixed array
if (!isFixedArray && !isVariableArray && eventPropertyInfo->count > 1)
{
isFixedArray = true;
}
string mapName = null;
Dictionary<uint, string> mapOfValues = null;
if (eventPropertyInfo->NonStructType.MapNameOffset != 0)
{
byte* mapBuffer = (byte*)0;
uint bufferSize;
var fakeEventRecord = new EVENT_RECORD { ProviderId = this.traceEventInfo->ProviderGuid };
mapName = new string((char*)&buffer[eventPropertyInfo->NonStructType.MapNameOffset]);
Tdh.GetEventMapInformation(&fakeEventRecord, mapName, mapBuffer, out bufferSize);
mapBuffer = (byte*)Marshal.AllocHGlobal((int)bufferSize);
Tdh.GetEventMapInformation(&fakeEventRecord, mapName, mapBuffer, out bufferSize);
EVENT_MAP_INFO* mapInfo = (EVENT_MAP_INFO*)mapBuffer;
if (mapInfo->MapEntryValueType == MAP_VALUETYPE.EVENTMAP_ENTRY_VALUETYPE_ULONG)
{
var mapEntry = (EVENT_MAP_ENTRY*)&mapInfo->MapEntryArray;
mapOfValues = new Dictionary<uint, string>();
for (int j = 0; j < mapInfo->EntryCount; ++j)
{
var offset = mapEntry[j].OutputOffset;
if (offset > bufferSize)
{
// TDH has a bug (it seems) that is giving rogue values here
// We should log this
}
else
{
var mapEntryValue = mapEntry[j].Value;
string mapEntryName;
if (!mapOfValues.TryGetValue(mapEntryValue, out mapEntryName))
{
mapEntryName = new string((char*)&mapBuffer[offset]);
mapOfValues.Add(mapEntryValue, mapEntryName);
}
}
}
}
Marshal.FreeHGlobal((IntPtr)mapBuffer);
}
/* save important information in an object */
var operand = new EventTracePropertyOperand(
new PropertyMetadata((TDH_IN_TYPE)eventPropertyInfo->NonStructType.InType, (TDH_OUT_TYPE)eventPropertyInfo->NonStructType.OutType, propertyName, mapOfValues != null, isStruct, isStruct ? structchildren : 0, new MapInformation(mapName, mapOfValues)),
i,
isVariableArray,
isFixedArray,
isVariableLength,
isFixedLength,
isWbemXmlFragment);
this.flatPropertyList.Add(operand);
operands.Add(operand);
returnList.Add(operand);
/* if this references a previous field, we need to capture that as a local */
if (isVariableArray)
{
var reference = operands[eventPropertyInfo->countPropertyIndex];
reference.IsReferencedByOtherProperties = true;
operand.SetVariableArraySize(reference);
}
else if (isFixedArray)
{
operand.SetFixedArraySize(eventPropertyInfo->count);
}
/* if this references a previous field, we need to capture that as a local */
if (isVariableLength)
{
var reference = operands[eventPropertyInfo->lengthPropertyIndex];
reference.IsReferencedByOtherProperties = true;
operand.SetVariableLengthSize(reference);
}
else if (isFixedLength)
{
operand.SetFixedLengthSize(eventPropertyInfo->length);
}
if ((eventPropertyInfo->Flags & PROPERTY_FLAGS.PropertyStruct) == PROPERTY_FLAGS.PropertyStruct)
{
var innerProps = this.IterateProperties(
buffer,
operands,
eventPropertyInfo->StructType.StructStartIndex,
eventPropertyInfo->StructType.StructStartIndex + eventPropertyInfo->StructType.NumOfStructMembers,
eventPropertyInfoArr);
foreach (var innerProp in innerProps)
{
operand.Children.Add(innerProp);
}
}
}
return returnList;
}
}
}
internal sealed class UnknownOperandBuilder : IEventTraceOperand
{
public UnknownOperandBuilder(Guid providerGuid, int metadataTableIndex)
{
this.EventMetadataTableIndex = metadataTableIndex;
this.Metadata = new EventMetadata(providerGuid, 0, 0, "UnknownProvider(" + providerGuid.ToString() + ")", new PropertyMetadata[0]);
}
public int EventMetadataTableIndex { get; set; }
public EventMetadata Metadata { get; set; }
public IEnumerable<IEventTracePropertyOperand> EventPropertyOperands => Enumerable.Empty<IEventTracePropertyOperand>();
}
}

Просмотреть файл

@ -0,0 +1,197 @@
namespace ETWDeserializer
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
internal static class EventTraceOperandExpressionBuilder
{
public static Expression Build(
IEventTraceOperand operand,
ParameterExpression eventRecordReader,
ParameterExpression eventRecordWriter,
ParameterExpression eventMetadataTable,
ParameterExpression runtimeMetadata)
{
return new EventTraceOperandExpressionBuilderImpl().Build(operand, eventRecordReader, eventRecordWriter, eventMetadataTable, runtimeMetadata);
}
public static MethodCallExpression Call(this ParameterExpression instance, string methodName, params Expression[] arguments)
{
Type[] parameterTypes = arguments.Select(t => t.Type).ToArray();
var methodInfo = instance.Type.GetMethod(methodName, parameterTypes);
return Expression.Call(instance, methodInfo, arguments);
}
}
internal sealed class EventTraceOperandExpressionBuilderImpl
{
public Expression Build(IEventTraceOperand operand, ParameterExpression eventRecordReader, ParameterExpression eventRecordWriter, ParameterExpression eventMetadataTable, ParameterExpression runtimeMetadata)
{
var eventMetadata = Expression.Parameter(typeof(EventMetadata));
var properties = Expression.Parameter(typeof(PropertyMetadata[]));
var variables = new List<ParameterExpression>
{
eventMetadata,
properties
};
var expGenerator = new ExpressionGenerator(eventRecordReader, eventRecordWriter, properties);
var list = new List<Expression>
{
Expression.Assign(eventMetadata, Expression.ArrayAccess(eventMetadataTable, Expression.Constant(operand.EventMetadataTableIndex))),
Expression.Assign(properties, Expression.PropertyOrField(eventMetadata, "Properties")),
eventRecordWriter.Call("WriteEventBegin", eventMetadata, runtimeMetadata),
expGenerator.CodeGenerate(operand.EventPropertyOperands),
eventRecordWriter.Call("WriteEventEnd")
};
var returnExpression = Expression.Block(variables, list);
return returnExpression;
}
private sealed class ExpressionGenerator
{
private readonly Dictionary<IEventTracePropertyOperand, Expression> operandReferenceTable = new Dictionary<IEventTracePropertyOperand, Expression>();
private readonly ParameterExpression eventRecordReader;
private readonly ParameterExpression eventRecordWriter;
private readonly ParameterExpression properties;
public ExpressionGenerator(ParameterExpression eventRecordReader, ParameterExpression eventRecordWriter, ParameterExpression properties)
{
this.eventRecordReader = eventRecordReader;
this.eventRecordWriter = eventRecordWriter;
this.properties = properties;
}
public Expression CodeGenerate(IEnumerable<IEventTracePropertyOperand> operands)
{
var variables = new List<ParameterExpression>();
var list = new List<Expression>();
foreach (var operand in operands)
{
var inType = operand.Metadata.InType;
Expression c; /* running expression for this operand */
list.Add(this.eventRecordWriter.Call("WritePropertyBegin", Expression.ArrayAccess(this.properties, Expression.Constant(operand.PropertyIndex))));
/* if struct, recurse */
if (operand.Children.Count > 0)
{
c = Expression.Block(
this.eventRecordWriter.Call("WriteStructBegin"),
this.CodeGenerate(operand.Children),
this.eventRecordWriter.Call("WriteStructEnd"));
}
else
{
Expression readValue;
/* otherwise, if operand has a length parameter, look it up or make constant */
if (operand.IsVariableLength || operand.IsFixedLength)
{
var length = operand.IsVariableLength
? this.operandReferenceTable[operand.VariableLengthSize]
: Expression.Constant(operand.FixedLengthSize);
readValue = Call(this.eventRecordReader, inType.ReadMethodInfo(this.eventRecordReader.Type, length.Type), length);
}
/* otherwise, it's just a normal call, no args */
else
{
readValue = Call(this.eventRecordReader, inType.ReadMethodInfo(this.eventRecordReader.Type));
}
/* save the operand because someone else maybe needing it */
/* and change the running variable */
if (operand.IsReferencedByOtherProperties)
{
var local = Expression.Parameter(inType.CSharpType(), operand.Metadata.Name);
this.operandReferenceTable.Add(operand, local);
variables.Add(local);
c = Expression.Block(Expression.Assign(local, readValue), Call(this.eventRecordWriter, inType.WriteMethodInfo(this.eventRecordWriter.Type, local.Type), local));
}
else
{
c = Call(this.eventRecordWriter, inType.WriteMethodInfo(this.eventRecordWriter.Type, inType.CSharpType()), readValue);
}
}
if (operand.IsVariableArray || operand.IsFixedArray)
{
var loopVariable = Expression.Parameter(typeof(int));
variables.Add(loopVariable);
var end = operand.IsVariableArray
? this.operandReferenceTable[operand.VariableArraySize]
: Expression.Constant(operand.FixedArraySize);
var expr = (Expression)loopVariable;
ConvertIfNecessary(ref expr, ref end);
list.Add(this.eventRecordWriter.Call("WriteArrayBegin"));
list.Add(For(loopVariable, Expression.Constant(0), Expression.LessThan(expr, end), Expression.AddAssign(loopVariable, Expression.Constant(1)), c));
list.Add(this.eventRecordWriter.Call("WriteArrayEnd"));
}
else
{
list.Add(c);
}
list.Add(this.eventRecordWriter.Call("WritePropertyEnd"));
}
return list.Count == 0 ? (Expression)Expression.Empty() : Expression.Block(variables, list);
}
private static MethodCallExpression Call(ParameterExpression instance, MethodInfo methodInfo, params Expression[] arguments)
{
return Expression.Call(instance, methodInfo, arguments);
}
private static Expression For(ParameterExpression parameter, Expression initial, Expression condition, Expression increment, params Expression[] body)
{
var breakLabel = Expression.Label("break");
var loop = Expression.Block(
new[] { parameter },
Expression.Assign(parameter, initial),
Expression.Loop(
Expression.IfThenElse(
condition,
Expression.Block(
body.Concat(new[] { increment })),
Expression.Break(breakLabel)),
breakLabel));
return loop;
}
private static void ConvertIfNecessary(ref Expression left, ref Expression right)
{
var leftTypeCode = Type.GetTypeCode(left.Type);
var rightTypeCode = Type.GetTypeCode(right.Type);
if (leftTypeCode == rightTypeCode)
{
return;
}
if (leftTypeCode > rightTypeCode)
{
right = Expression.Convert(right, left.Type);
}
else
{
left = Expression.Convert(left, right.Type);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
namespace ETWDeserializer
{
using System.Collections.Generic;
internal sealed class EventTracePropertyOperand : IEventTracePropertyOperand
{
public EventTracePropertyOperand(PropertyMetadata metadata, int propertyIndex, bool isVariableArray, bool isFixedArray, bool isVariableLength, bool isFixedLength, bool isWbemXml)
{
this.Metadata = metadata;
this.PropertyIndex = propertyIndex;
this.IsVariableArray = isVariableArray;
this.IsFixedArray = isFixedArray;
this.IsVariableLength = isVariableLength;
this.IsFixedLength = isFixedLength;
this.IsWbemXMLFragment = isWbemXml;
this.Children = new List<IEventTracePropertyOperand>();
}
public PropertyMetadata Metadata { get; }
public int PropertyIndex { get; }
public bool IsVariableArray { get; }
public IEventTracePropertyOperand VariableArraySize { get; private set; }
public bool IsVariableLength { get; }
public IEventTracePropertyOperand VariableLengthSize { get; private set; }
public bool IsFixedArray { get; }
public int FixedArraySize { get; private set; }
public bool IsFixedLength { get; }
public int FixedLengthSize { get; private set; }
public bool IsWbemXMLFragment { get; }
public bool IsReferencedByOtherProperties { get; set; }
public List<IEventTracePropertyOperand> Children { get; }
public void SetFixedArraySize(int fixedArraySize)
{
this.FixedArraySize = fixedArraySize;
}
public void SetVariableArraySize(IEventTracePropertyOperand reference)
{
this.VariableArraySize = reference;
}
public void SetFixedLengthSize(int fixedLengthSize)
{
this.FixedLengthSize = fixedLengthSize;
}
public void SetVariableLengthSize(IEventTracePropertyOperand reference)
{
this.VariableLengthSize = reference;
}
}
}

372
Deserializer/Extensions.cs Normal file
Просмотреть файл

@ -0,0 +1,372 @@
namespace ETWDeserializer
{
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
internal static class Extensions
{
public static void AddOrUpdate<K, V>(this Dictionary<K, V> dict, K k, V v)
{
if (dict.ContainsKey(k))
{
dict[k] = v;
}
else
{
dict.Add(k, v);
}
}
public static TDH_IN_TYPE ToTdhInType(string value)
{
value = value.ToLowerInvariant();
switch (value)
{
case "unicodestring":
return TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING;
case "ansistring":
return TDH_IN_TYPE.TDH_INTYPE_ANSISTRING;
case "int8":
return TDH_IN_TYPE.TDH_INTYPE_INT8;
case "uint8":
return TDH_IN_TYPE.TDH_INTYPE_UINT8;
case "int16":
return TDH_IN_TYPE.TDH_INTYPE_INT16;
case "uint16":
return TDH_IN_TYPE.TDH_INTYPE_UINT16;
case "int32":
return TDH_IN_TYPE.TDH_INTYPE_INT32;
case "uint32":
return TDH_IN_TYPE.TDH_INTYPE_UINT32;
case "int64":
return TDH_IN_TYPE.TDH_INTYPE_INT64;
case "uint64":
return TDH_IN_TYPE.TDH_INTYPE_UINT64;
case "float":
return TDH_IN_TYPE.TDH_INTYPE_FLOAT;
case "double":
return TDH_IN_TYPE.TDH_INTYPE_DOUBLE;
case "boolean":
return TDH_IN_TYPE.TDH_INTYPE_BOOLEAN;
case "binary":
return TDH_IN_TYPE.TDH_INTYPE_BINARY;
case "guid":
return TDH_IN_TYPE.TDH_INTYPE_GUID;
case "sizet":
case "pointer":
return TDH_IN_TYPE.TDH_INTYPE_POINTER;
case "filetime":
return TDH_IN_TYPE.TDH_INTYPE_FILETIME;
case "systemtime":
return TDH_IN_TYPE.TDH_INTYPE_SYSTEMTIME;
case "sid":
return TDH_IN_TYPE.TDH_INTYPE_SID;
case "hextint32":
return TDH_IN_TYPE.TDH_INTYPE_HEXINT32;
case "hexint64":
return TDH_IN_TYPE.TDH_INTYPE_HEXINT64;
default:
throw new Exception("Unreachable");
}
}
public static Expression SizeOF(this TDH_IN_TYPE tdhType)
{
switch (tdhType)
{
case TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_ANSISTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_INT8:
return Expression.Constant(sizeof(sbyte));
case TDH_IN_TYPE.TDH_INTYPE_UINT8:
return Expression.Constant(sizeof(byte));
case TDH_IN_TYPE.TDH_INTYPE_INT16:
return Expression.Constant(sizeof(short));
case TDH_IN_TYPE.TDH_INTYPE_UINT16:
return Expression.Constant(sizeof(ushort));
case TDH_IN_TYPE.TDH_INTYPE_INT32:
return Expression.Constant(sizeof(int));
case TDH_IN_TYPE.TDH_INTYPE_UINT32:
return Expression.Constant(sizeof(uint));
case TDH_IN_TYPE.TDH_INTYPE_INT64:
return Expression.Constant(sizeof(long));
case TDH_IN_TYPE.TDH_INTYPE_UINT64:
return Expression.Constant(sizeof(ulong));
case TDH_IN_TYPE.TDH_INTYPE_FLOAT:
return Expression.Constant(sizeof(float));
case TDH_IN_TYPE.TDH_INTYPE_DOUBLE:
return Expression.Constant(sizeof(double));
case TDH_IN_TYPE.TDH_INTYPE_BOOLEAN:
return Expression.Constant(4); // this is because in Windows we have bools as ints
case TDH_IN_TYPE.TDH_INTYPE_BINARY:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_GUID:
return Expression.Constant(16); // otherwise requires unsafe
case TDH_IN_TYPE.TDH_INTYPE_POINTER:
return Expression.Constant(4); // TODO: FIXME with conditional
case TDH_IN_TYPE.TDH_INTYPE_FILETIME:
return Expression.Constant(16); // Windows
case TDH_IN_TYPE.TDH_INTYPE_SYSTEMTIME:
return Expression.Constant(16); // Windows
case TDH_IN_TYPE.TDH_INTYPE_SID:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_HEXINT32:
return Expression.Constant(sizeof(int));
case TDH_IN_TYPE.TDH_INTYPE_HEXINT64:
return Expression.Constant(sizeof(long));
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDSTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDANSISTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDSTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDSTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDANSISTRING:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_UNICODECHAR:
return Expression.Constant(sizeof(char));
case TDH_IN_TYPE.TDH_INTYPE_ANSICHAR:
return Expression.Constant(sizeof(byte));
case TDH_IN_TYPE.TDH_INTYPE_SIZET:
return Expression.Constant(4); // TODO: FIXME with conditional
case TDH_IN_TYPE.TDH_INTYPE_HEXDUMP:
return Expression.Constant(0); // size check happens inside his reader
case TDH_IN_TYPE.TDH_INTYPE_WBEMSID:
return Expression.Constant(0); // size check happens inside his reader
default:
throw new Exception("Unreachable");
}
}
public static Type CSharpType(this TDH_IN_TYPE tdhType)
{
switch (tdhType)
{
case TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_ANSISTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_INT8:
return typeof(sbyte);
case TDH_IN_TYPE.TDH_INTYPE_UINT8:
return typeof(byte);
case TDH_IN_TYPE.TDH_INTYPE_INT16:
return typeof(short);
case TDH_IN_TYPE.TDH_INTYPE_UINT16:
return typeof(ushort);
case TDH_IN_TYPE.TDH_INTYPE_INT32:
return typeof(int);
case TDH_IN_TYPE.TDH_INTYPE_UINT32:
return typeof(uint);
case TDH_IN_TYPE.TDH_INTYPE_INT64:
return typeof(long);
case TDH_IN_TYPE.TDH_INTYPE_UINT64:
return typeof(ulong);
case TDH_IN_TYPE.TDH_INTYPE_FLOAT:
return typeof(float);
case TDH_IN_TYPE.TDH_INTYPE_DOUBLE:
return typeof(double);
case TDH_IN_TYPE.TDH_INTYPE_BOOLEAN:
return typeof(bool);
case TDH_IN_TYPE.TDH_INTYPE_BINARY:
return typeof(byte[]);
case TDH_IN_TYPE.TDH_INTYPE_GUID:
return typeof(Guid);
case TDH_IN_TYPE.TDH_INTYPE_POINTER:
return typeof(ulong);
case TDH_IN_TYPE.TDH_INTYPE_FILETIME:
return typeof(DateTime);
case TDH_IN_TYPE.TDH_INTYPE_SYSTEMTIME:
return typeof(DateTime);
case TDH_IN_TYPE.TDH_INTYPE_SID:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT32:
return typeof(int);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT64:
return typeof(long);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDSTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDANSISTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDSTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDSTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDANSISTRING:
return typeof(string);
case TDH_IN_TYPE.TDH_INTYPE_UNICODECHAR:
return typeof(char);
case TDH_IN_TYPE.TDH_INTYPE_ANSICHAR:
return typeof(char);
case TDH_IN_TYPE.TDH_INTYPE_SIZET:
return typeof(ulong);
case TDH_IN_TYPE.TDH_INTYPE_HEXDUMP:
return typeof(byte[]);
case TDH_IN_TYPE.TDH_INTYPE_WBEMSID:
return typeof(string);
default:
throw new Exception("Unreachable");
}
}
public static MethodInfo ReadMethodInfo(this TDH_IN_TYPE tdhType, Type type, params Type[] parameterType)
{
switch (tdhType)
{
case TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING:
return GetMethodInfo(type, "ReadUnicodeString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_ANSISTRING:
return GetMethodInfo(type, "ReadAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT8:
return GetMethodInfo(type, "ReadInt8", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT8:
return GetMethodInfo(type, "ReadUInt8", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT16:
return GetMethodInfo(type, "ReadInt16", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT16:
return GetMethodInfo(type, "ReadUInt16", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT32:
return GetMethodInfo(type, "ReadInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT32:
return GetMethodInfo(type, "ReadUInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT64:
return GetMethodInfo(type, "ReadInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT64:
return GetMethodInfo(type, "ReadUInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_FLOAT:
return GetMethodInfo(type, "ReadFloat", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_DOUBLE:
return GetMethodInfo(type, "ReadDouble", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_BOOLEAN:
return GetMethodInfo(type, "ReadBoolean", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_BINARY:
return GetMethodInfo(type, "ReadBinary", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_GUID:
return GetMethodInfo(type, "ReadGuid", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_POINTER:
return GetMethodInfo(type, "ReadPointer", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_FILETIME:
return GetMethodInfo(type, "ReadFileTime", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SYSTEMTIME:
return GetMethodInfo(type, "ReadSystemTime", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SID:
return GetMethodInfo(type, "ReadSid", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT32:
return GetMethodInfo(type, "ReadInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT64:
return GetMethodInfo(type, "ReadInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDSTRING:
return GetMethodInfo(type, "ReadCountedString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDANSISTRING:
return GetMethodInfo(type, "ReadCountedAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDSTRING:
return GetMethodInfo(type, "ReadReversedCountedString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:
return GetMethodInfo(type, "ReadReversedCountedAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDSTRING:
return GetMethodInfo(type, "ReadNonNullTerminatedString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDANSISTRING:
return GetMethodInfo(type, "ReadNonNullTerminatedAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UNICODECHAR:
return GetMethodInfo(type, "ReadUnicodeChar", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_ANSICHAR:
return GetMethodInfo(type, "ReadAnsiChar", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SIZET:
return GetMethodInfo(type, "ReadPointer", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXDUMP:
return GetMethodInfo(type, "ReadHexDump", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_WBEMSID:
return GetMethodInfo(type, "ReadWbemSid", parameterType);
default:
throw new Exception("Unreachable");
}
}
public static MethodInfo WriteMethodInfo(this TDH_IN_TYPE tdhType, Type type, params Type[] parameterType)
{
switch (tdhType)
{
case TDH_IN_TYPE.TDH_INTYPE_UNICODESTRING:
return GetMethodInfo(type, "WriteUnicodeString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_ANSISTRING:
return GetMethodInfo(type, "WriteAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT8:
return GetMethodInfo(type, "WriteInt8", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT8:
return GetMethodInfo(type, "WriteUInt8", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT16:
return GetMethodInfo(type, "WriteInt16", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT16:
return GetMethodInfo(type, "WriteUInt16", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT32:
return GetMethodInfo(type, "WriteInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT32:
return GetMethodInfo(type, "WriteUInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_INT64:
return GetMethodInfo(type, "WriteInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UINT64:
return GetMethodInfo(type, "WriteUInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_FLOAT:
return GetMethodInfo(type, "WriteFloat", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_DOUBLE:
return GetMethodInfo(type, "WriteDouble", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_BOOLEAN:
return GetMethodInfo(type, "WriteBoolean", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_BINARY:
return GetMethodInfo(type, "WriteBinary", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_GUID:
return GetMethodInfo(type, "WriteGuid", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_POINTER:
return GetMethodInfo(type, "WritePointer", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_FILETIME:
return GetMethodInfo(type, "WriteFileTime", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SYSTEMTIME:
return GetMethodInfo(type, "WriteSystemTime", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SID:
return GetMethodInfo(type, "WriteSid", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT32:
return GetMethodInfo(type, "WriteInt32", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXINT64:
return GetMethodInfo(type, "WriteInt64", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDSTRING:
return GetMethodInfo(type, "WriteUnicodeString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_COUNTEDANSISTRING:
return GetMethodInfo(type, "WriteAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDSTRING:
return GetMethodInfo(type, "WriteUnicodeString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:
return GetMethodInfo(type, "WriteAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDSTRING:
return GetMethodInfo(type, "WriteUnicodeString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_NONNULLTERMINATEDANSISTRING:
return GetMethodInfo(type, "WriteAnsiString", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_UNICODECHAR:
return GetMethodInfo(type, "WriteUnicodeChar", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_ANSICHAR:
return GetMethodInfo(type, "WriteAnsiChar", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_SIZET:
return GetMethodInfo(type, "WritePointer", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_HEXDUMP:
return GetMethodInfo(type, "WriteBinary", parameterType);
case TDH_IN_TYPE.TDH_INTYPE_WBEMSID:
return GetMethodInfo(type, "WriteSid", parameterType);
default:
throw new Exception("Unreachable");
}
}
private static MethodInfo GetMethodInfo(Type type, string name, params Type[] parameterType)
{
return type.GetMethod(name, parameterType);
}
}
}

Просмотреть файл

@ -0,0 +1,6 @@
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1121:Use built-in type alias", Justification = "<Pending>")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "<Pending>")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1611:Element parameters must be documented", Justification = "<Pending>")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "<Pending>")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1615:Element return value must be documented", Justification = "<Pending>")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names must not contain underscore", Justification = "<Pending>")]

Просмотреть файл

@ -0,0 +1,69 @@
namespace ETWDeserializer
{
using System;
public interface IEtwWriter
{
void WriteEventBegin(EventMetadata metadata, RuntimeEventMetadata runtimeMetadata);
void WriteEventEnd();
void WriteStructBegin();
void WriteStructEnd();
void WritePropertyBegin(PropertyMetadata metadata);
void WritePropertyEnd();
void WriteArrayBegin();
void WriteArrayEnd();
void WriteAnsiString(string value);
void WriteUnicodeString(string value);
void WriteInt8(sbyte value);
void WriteUInt8(byte value);
void WriteInt16(short value);
void WriteUInt16(ushort value);
void WriteInt32(int value);
void WriteUInt32(uint value);
void WriteInt64(long value);
void WriteUInt64(ulong value);
void WriteFloat(float value);
void WriteDouble(double value);
void WriteBoolean(bool value);
void WriteBinary(byte[] value);
void WriteGuid(Guid value);
void WritePointer(ulong value);
void WriteFileTime(DateTime value);
void WriteSystemTime(DateTime value);
void WriteSid(string value);
void WriteUnicodeChar(char value);
void WriteAnsiChar(char value);
void WriteHexDump(byte[] value);
void WriteWbemSid(string value);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
namespace ETWDeserializer
{
using System.Collections.Generic;
public interface IEventTraceOperand
{
int EventMetadataTableIndex { get; }
EventMetadata Metadata { get; }
IEnumerable<IEventTracePropertyOperand> EventPropertyOperands { get; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
namespace ETWDeserializer
{
using System.Collections.Generic;
public interface IEventTracePropertyOperand
{
PropertyMetadata Metadata { get; }
int PropertyIndex { get; }
bool IsVariableArray { get; }
IEventTracePropertyOperand VariableArraySize { get; }
bool IsVariableLength { get; }
IEventTracePropertyOperand VariableLengthSize { get; }
bool IsFixedArray { get; }
int FixedArraySize { get; }
bool IsFixedLength { get; }
int FixedLengthSize { get; }
bool IsWbemXMLFragment { get; }
bool IsReferencedByOtherProperties { get; }
List<IEventTracePropertyOperand> Children { get; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
namespace ETWDeserializer
{
using System.Collections.Generic;
public sealed class MapInformation
{
private readonly Dictionary<uint, string> mapOfValues;
internal MapInformation(string name, Dictionary<uint, string> mapOfValues)
{
this.Name = name;
this.mapOfValues = mapOfValues;
}
public string Name { get; private set; }
public string this[uint i] => this.mapOfValues[i];
}
}

Просмотреть файл

@ -0,0 +1,30 @@
namespace ETWDeserializer
{
public sealed class PropertyMetadata
{
internal PropertyMetadata(TDH_IN_TYPE inType, TDH_OUT_TYPE outType, string name, bool isMapValue, bool isStruct, int childrenCount, MapInformation map)
{
this.InType = inType;
this.OutType = outType;
this.Name = name;
this.IsMapValue = isMapValue;
this.IsStruct = isStruct;
this.ChildrenCount = childrenCount;
this.Map = map;
}
public TDH_IN_TYPE InType { get; private set; }
public TDH_OUT_TYPE OutType { get; private set; }
public bool IsMapValue { get; private set; }
public bool IsStruct { get; private set; }
public int ChildrenCount { get; private set; }
public MapInformation Map { get; private set; }
public string Name { get; private set; }
}
}

23
Deserializer/README.md Normal file
Просмотреть файл

@ -0,0 +1,23 @@
# ETWDeserializer
ETWDeserializer is a general-purpose Windows ETW event deserialization library. It can decode events from almost all sources of Windows including the Kernel (MOF Classes), Manifest events (those available beyond Windows Vista), XPERF performance profiling events, and .NET EventSource-style events.
**NOTE**: This is a support library, i.e. the user of this library must setup the boiler-plate code involved in setting up an ETW Session or reading an ETW log file (.ETL). [**ETW2JSON**](http://github.com/ETWTools/ETW2JSON) and [**ETW2SQLite**](http://github.com/ETWTools/ETW2SQLite) are two such applications.
## Usage
Implement the ``IEtwWriter`` interface exposed by the library and add boiler plate code to set up an ETW event session or reading from an ETW log file (.ETL)
[**ETW2JSON**](http://github.com/ETWTools/ETW2JSON) and [**ETW2SQLite**](http://github.com/ETWTools/ETW2SQLite) each implement their own ``IEtwWriter`` and also the code involved in reading an ETW log file from disk.
## Nuget package
This library is available on Nuget -- https://www.nuget.org/packages/ETWDeserializer/1.2.0
## Building ETWDeserializer
Since this is a Windows-specific library, I'm assuming you're also building on Windows and have MSBuild Tools installed, in which case:
``msbuild ETWDeserializer.csproj``
is all you need to do.

Просмотреть файл

@ -0,0 +1,187 @@
namespace ETWDeserializer
{
using System;
public struct RuntimeEventMetadata
{
private readonly unsafe EVENT_RECORD* eventRecord;
internal unsafe RuntimeEventMetadata(EVENT_RECORD* eventRecord)
{
this.eventRecord = eventRecord;
}
public ushort Flags
{
get
{
unsafe
{
return this.eventRecord->Flags;
}
}
}
public uint ThreadId
{
get
{
unsafe
{
return this.eventRecord->ThreadId;
}
}
}
public uint ProcessId
{
get
{
unsafe
{
return this.eventRecord->ProcessId;
}
}
}
public long Timestamp
{
get
{
unsafe
{
return this.eventRecord->TimeStamp;
}
}
}
public Guid ProviderId
{
get
{
unsafe
{
return this.eventRecord->ProviderId;
}
}
}
public ushort EventId
{
get
{
unsafe
{
return this.eventRecord->Id;
}
}
}
public Guid ActivityId
{
get
{
unsafe
{
return this.eventRecord->ActivityId;
}
}
}
public ushort UserDataLength
{
get
{
unsafe
{
return this.eventRecord->UserDataLength;
}
}
}
public Guid RelatedActivityId
{
get
{
unsafe
{
var extendedData = this.eventRecord->ExtendedData;
for (int i = 0; i < this.eventRecord->ExtendedDataCount; ++i)
{
if (extendedData[i].ExtType == Etw.EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID)
{
return *((Guid*)extendedData[i].DataPtr);
}
}
return Guid.Empty;
}
}
}
// logic from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd392308(v=vs.85).aspx
public ulong[] GetStacks(out ulong matchId)
{
unsafe
{
var extendedData = this.eventRecord->ExtendedData;
for (int i = 0; i < this.eventRecord->ExtendedDataCount; ++i)
{
switch (extendedData[i].ExtType)
{
case Etw.EVENT_HEADER_EXT_TYPE_STACK_TRACE32:
{
var numberOfInstructionPointers = (extendedData[i].DataSize - sizeof(ulong)) / sizeof(uint);
return GetStacks32(numberOfInstructionPointers, ref extendedData[i], out matchId);
}
case Etw.EVENT_HEADER_EXT_TYPE_STACK_TRACE64:
{
var numberOfInstructionPointers = (extendedData[i].DataSize - sizeof(ulong)) / sizeof(ulong);
return GetStacks64(numberOfInstructionPointers, ref extendedData[i], out matchId);
}
}
}
matchId = 0;
return null;
}
}
private static unsafe ulong[] GetStacks64(int numberOfInstructionPointers, ref EVENT_HEADER_EXTENDED_DATA_ITEM extendedData, out ulong matchId)
{
var retArr = new ulong[numberOfInstructionPointers];
matchId = *(ulong*)extendedData.DataPtr;
extendedData.DataPtr += sizeof(ulong);
var dataPtr = (ulong*)extendedData.DataPtr;
for (int j = 0; j < numberOfInstructionPointers; ++j)
{
retArr[j] = *dataPtr;
dataPtr++;
}
return retArr;
}
private static unsafe ulong[] GetStacks32(int numberOfInstructionPointers, ref EVENT_HEADER_EXTENDED_DATA_ITEM extendedData, out ulong matchId)
{
var retArr = new ulong[numberOfInstructionPointers];
matchId = *(ulong*)extendedData.DataPtr;
extendedData.DataPtr += sizeof(ulong);
var dataPtr = (int*)extendedData.DataPtr;
for (int j = 0; j < numberOfInstructionPointers; ++j)
{
retArr[j] = (ulong)*dataPtr;
dataPtr++;
}
return retArr;
}
}
}

265
Deserializer/Tdh.cs Normal file
Просмотреть файл

@ -0,0 +1,265 @@
namespace ETWDeserializer
{
using System;
using System.Runtime.InteropServices;
using System.Security;
using ULONG = System.UInt32;
using ULONGLONG = System.UInt64;
using USHORT = System.UInt16;
using GUID = System.Guid;
using UCHAR = System.Byte;
[StructLayout(LayoutKind.Explicit)]
internal struct EVENT_MAP_ENTRY
{
[FieldOffset(0)]
public ULONG OutputOffset;
[FieldOffset(4)]
public ULONG Value; // For ULONG value (valuemap and bitmap).
[FieldOffset(4)]
public ULONG InputOffset; // For String value (patternmap or valuemap in WBEM).
}
[Flags]
internal enum MAP_FLAGS
{
EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP = 0x1,
EVENTMAP_INFO_FLAG_MANIFEST_BITMAP = 0x2,
EVENTMAP_INFO_FLAG_MANIFEST_PATTERNMAP = 0x4,
EVENTMAP_INFO_FLAG_WBEM_VALUEMAP = 0x8,
EVENTMAP_INFO_FLAG_WBEM_BITMAP = 0x10,
EVENTMAP_INFO_FLAG_WBEM_FLAG = 0x20,
EVENTMAP_INFO_FLAG_WBEM_NO_MAP = 0x40
}
internal enum MAP_VALUETYPE
{
EVENTMAP_ENTRY_VALUETYPE_ULONG,
EVENTMAP_ENTRY_VALUETYPE_STRING
}
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct EVENT_MAP_INFO
{
[FieldOffset(0)]
public ULONG NameOffset;
[FieldOffset(4)]
public MAP_FLAGS Flag;
[FieldOffset(8)]
public ULONG EntryCount;
[FieldOffset(12)]
public MAP_VALUETYPE MapEntryValueType;
[FieldOffset(12)]
public ULONG FormatStringOffset;
[FieldOffset(16)]
public EVENT_MAP_ENTRY* MapEntryArray;
}
// Intypes and outtypes are defined in winmeta.xml.
public enum TDH_IN_TYPE
{
TDH_INTYPE_NULL,
TDH_INTYPE_UNICODESTRING,
TDH_INTYPE_ANSISTRING,
TDH_INTYPE_INT8,
TDH_INTYPE_UINT8,
TDH_INTYPE_INT16,
TDH_INTYPE_UINT16,
TDH_INTYPE_INT32,
TDH_INTYPE_UINT32,
TDH_INTYPE_INT64,
TDH_INTYPE_UINT64,
TDH_INTYPE_FLOAT,
TDH_INTYPE_DOUBLE,
TDH_INTYPE_BOOLEAN,
TDH_INTYPE_BINARY,
TDH_INTYPE_GUID,
TDH_INTYPE_POINTER,
TDH_INTYPE_FILETIME,
TDH_INTYPE_SYSTEMTIME,
TDH_INTYPE_SID,
TDH_INTYPE_HEXINT32,
TDH_INTYPE_HEXINT64, // End of winmeta intypes.
TDH_INTYPE_COUNTEDSTRING = 300, // Start of TDH intypes for WBEM.
TDH_INTYPE_COUNTEDANSISTRING,
TDH_INTYPE_REVERSEDCOUNTEDSTRING,
TDH_INTYPE_REVERSEDCOUNTEDANSISTRING,
TDH_INTYPE_NONNULLTERMINATEDSTRING,
TDH_INTYPE_NONNULLTERMINATEDANSISTRING,
TDH_INTYPE_UNICODECHAR,
TDH_INTYPE_ANSICHAR,
TDH_INTYPE_SIZET,
TDH_INTYPE_HEXDUMP,
TDH_INTYPE_WBEMSID
}
public enum TDH_OUT_TYPE
{
TDH_OUTTYPE_NULL,
TDH_OUTTYPE_STRING,
TDH_OUTTYPE_DATETIME,
TDH_OUTTYPE_BYTE,
TDH_OUTTYPE_UNSIGNEDBYTE,
TDH_OUTTYPE_SHORT,
TDH_OUTTYPE_UNSIGNEDSHORT,
TDH_OUTTYPE_INT,
TDH_OUTTYPE_UNSIGNEDINT,
TDH_OUTTYPE_LONG,
TDH_OUTTYPE_UNSIGNEDLONG,
TDH_OUTTYPE_FLOAT,
TDH_OUTTYPE_DOUBLE,
TDH_OUTTYPE_BOOLEAN,
TDH_OUTTYPE_GUID,
TDH_OUTTYPE_HEXBINARY,
TDH_OUTTYPE_HEXINT8,
TDH_OUTTYPE_HEXINT16,
TDH_OUTTYPE_HEXINT32,
TDH_OUTTYPE_HEXINT64,
TDH_OUTTYPE_PID,
TDH_OUTTYPE_TID,
TDH_OUTTYPE_PORT,
TDH_OUTTYPE_IPV4,
TDH_OUTTYPE_IPV6,
TDH_OUTTYPE_SOCKETADDRESS,
TDH_OUTTYPE_CIMDATETIME,
TDH_OUTTYPE_ETWTIME,
TDH_OUTTYPE_XML,
TDH_OUTTYPE_ERRORCODE,
TDH_OUTTYPE_WIN32ERROR,
TDH_OUTTYPE_NTSTATUS,
TDH_OUTTYPE_HRESULT, // End of winmeta outtypes.
TDH_OUTTYPE_CULTURE_INSENSITIVE_DATETIME, // Culture neutral datetime string.
TDH_OUTTYPE_JSON,
TDH_OUTTYPE_REDUCEDSTRING = 300, // Start of TDH outtypes for WBEM.
TDH_OUTTYPE_NOPRINT
}
[Flags]
internal enum PROPERTY_FLAGS
{
PropertyStruct = 0x1, // Type is struct.
PropertyParamLength = 0x2, // Length field is index of param with length.
PropertyParamCount = 0x4, // Count file is index of param with count.
PropertyWBEMXmlFragment = 0x8, // WBEM extension flag for property.
PropertyParamFixedLength = 0x10, // Length of the parameter is fixed.
PropertyParamFixedCount = 0x20, // Count of the parameter is fixed.
PropertyHasTags = 0x40 // The Tags field has been initialized.
}
[StructLayout(LayoutKind.Explicit)]
internal struct EVENT_PROPERTY_INFO
{
[FieldOffset(0)]
public PROPERTY_FLAGS Flags;
[FieldOffset(4)]
public ULONG NameOffset;
[FieldOffset(8)]
public nonStructType NonStructType;
[FieldOffset(8)]
public structType StructType;
[FieldOffset(16)]
public USHORT count;
[FieldOffset(16)]
public USHORT countPropertyIndex;
[FieldOffset(18)]
public USHORT length;
[FieldOffset(18)]
public USHORT lengthPropertyIndex;
[FieldOffset(18)]
public ULONG Reserved;
[StructLayout(LayoutKind.Sequential)]
internal struct nonStructType
{
public USHORT InType;
public USHORT OutType;
public ULONG MapNameOffset;
}
[StructLayout(LayoutKind.Sequential)]
internal struct structType
{
public USHORT StructStartIndex;
public USHORT NumOfStructMembers;
public ULONG padding;
}
}
internal enum DECODING_SOURCE
{
DecodingSourceXMLFile,
DecodingSourceWbem,
DecodingSourceWPP,
DecodingSourceTlg,
DecodingSourceMax
}
internal enum TEMPLATE_FLAGS
{
TEMPLATE_EVENT_DATA = 1, // Used when custom xml is not specified.
TEMPLATE_USER_DATA = 2 // Used when custom xml is specified.
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct TRACE_EVENT_INFO
{
public GUID ProviderGuid;
public GUID EventGuid;
public USHORT Id;
public UCHAR Version;
public UCHAR Channel;
public UCHAR Level;
public UCHAR Opcode;
public USHORT Task;
public ULONGLONG Keyword;
public DECODING_SOURCE DecodingSource;
public ULONG ProviderNameOffset;
public ULONG LevelNameOffset;
public ULONG ChannelNameOffset;
public ULONG KeywordsNameOffset;
public ULONG TaskNameOffset;
public ULONG OpcodeNameOffset;
public ULONG EventMessageOffset;
public ULONG ProviderMessageOffset;
public ULONG BinaryXMLOffset;
public ULONG BinaryXMLSize;
public ULONG ActivityIDNameOffset;
public ULONG RelatedActivityIDNameOffset;
public ULONG PropertyCount;
public ULONG TopLevelPropertyCount;
public TEMPLATE_FLAGS Flags;
public EVENT_PROPERTY_INFO* EventPropertyInfoArray;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROPERTY_DATA_DESCRIPTOR
{
public ULONGLONG PropertyName; // Pointer to property name.
public ULONG ArrayIndex; // Array Index.
public ULONG Reserved;
}
internal static class Tdh
{
[DllImport("tdh.dll", EntryPoint = "TdhGetEventInformation")]
internal static extern unsafe int GetEventInformation(EVENT_RECORD* pEvent, uint TdhContextCount, IntPtr pTdhContext, byte* pBuffer, out uint pBufferSize);
[DllImport("tdh.dll", EntryPoint = "TdhGetEventMapInformation", CharSet = CharSet.Unicode)]
internal static extern unsafe int GetEventMapInformation(EVENT_RECORD* pEvent, string pMapName, byte* pBuffer, out uint pBufferSize);
}
}

Просмотреть файл

@ -0,0 +1,46 @@
namespace ETWDeserializer
{
using System;
internal struct TraceEventKey : IEquatable<TraceEventKey>
{
private readonly Guid providerId;
private readonly ushort id;
private readonly byte version;
public TraceEventKey(Guid providerId, ushort id, byte version)
{
this.providerId = providerId;
this.id = id;
this.version = version;
}
public bool Equals(TraceEventKey other)
{
return this.providerId.Equals(other.providerId) && this.id == other.id && this.version == other.version;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is TraceEventKey && this.Equals((TraceEventKey)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = this.providerId.GetHashCode();
hashCode = (hashCode * 397) ^ this.id.GetHashCode();
hashCode = (hashCode * 397) ^ this.version.GetHashCode();
return hashCode;
}
}
}
}

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StyleCop.Analyzers" version="1.0.0" targetFramework="net45" developmentDependency="true" />
</packages>

Просмотреть файл

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<ProjectGuid>{82423166-99F9-48FE-8453-0E7DDB1D6192}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ETW2JSON</RootNamespace>
<AssemblyName>ETW2JSON</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -15,10 +18,6 @@
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -26,22 +25,40 @@
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="ETWDeserializer, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\ETWDeserializer.1.2.0\lib\net45\ETWDeserializer.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Deserializer\CustomParsers\CustomParserGuids.cs" />
<Compile Include="Deserializer\CustomParsers\KernelStackWalkEventParser.cs" />
<Compile Include="Deserializer\CustomParsers\KernelTraceControlDbgIdParser.cs" />
<Compile Include="Deserializer\CustomParsers\KernelTraceControlImageIdFileVersionParser.cs" />
<Compile Include="Deserializer\CustomParsers\KernelTraceControlImageIdParser.cs" />
<Compile Include="Deserializer\Deserializer.cs" />
<Compile Include="Deserializer\Etw.cs" />
<Compile Include="Deserializer\EventMan.cs" />
<Compile Include="Deserializer\EventMetadata.cs" />
<Compile Include="Deserializer\EventRecordReader.cs" />
<Compile Include="Deserializer\EventSourceManifest.cs" />
<Compile Include="Deserializer\EventTraceOperand.cs" />
<Compile Include="Deserializer\EventTraceOperandBuilder.cs" />
<Compile Include="Deserializer\EventTraceOperandExpressionBuilder.cs" />
<Compile Include="Deserializer\EventTracePropertyOperand.cs" />
<Compile Include="Deserializer\Extensions.cs" />
<Compile Include="Deserializer\GlobalSuppressions.cs" />
<Compile Include="Deserializer\IEtwWriter.cs" />
<Compile Include="Deserializer\IEventTraceOperand.cs" />
<Compile Include="Deserializer\IEventTracePropertyOperand.cs" />
<Compile Include="Deserializer\MapInformation.cs" />
<Compile Include="Deserializer\PropertyMetadata.cs" />
<Compile Include="Deserializer\RuntimeEventMetadata.cs" />
<Compile Include="Deserializer\Tdh.cs" />
<Compile Include="Deserializer\TraceEventKey.cs" />
<Compile Include="Etw.cs" />
<Compile Include="EtwJsonWriter.cs" />
<Compile Include="Program.cs" />

Просмотреть файл

@ -79,10 +79,7 @@
for (int i = 0; i < count; ++i)
{
unsafe
{
Etw.CloseTrace(handles[i]);
}
Etw.CloseTrace(handles[i]);
}
return true;

Просмотреть файл

@ -12,7 +12,7 @@ ETW2JSON is a tool that converts ETW Log Files (.ETL) to JSON using the Newtonso
## Nuget package
This library is available on Nuget -- https://www.nuget.org/packages/ETW2JSON/1.2.0
This library is available on Nuget -- https://www.nuget.org/packages/ETW2JSON/1.3.3
## Why JSON?
@ -35,7 +35,7 @@ You can now view this data in a variety of JSON log viewers, merge it with your
## Does it understand Kernel, .NET EventSource, XPERF, etc. events?
ETW2JSON is built upon [ETWDeserializer](http://github.com/ETWTools/ETWDeserializer), a library that understands Windows MOF Classes events, Windows Vista Manifest events and EventSource .NET events. It also understands events that XPERF (WPR) adds as part of its merging process (to give PDB information) for profiler tools like the Windows Performance Recorder.
ETW2JSON is a library that understands Windows MOF Classes events, Windows Vista Manifest events and EventSource .NET events. It also understands events that XPERF (WPR) adds as part of its merging process (to give PDB information) for profiler tools like the Windows Performance Recorder.
## Example output

Просмотреть файл

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ETWDeserializer" version="1.2.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
</packages>