RpcInvestigator/UnitTests/EtwTests.cs

182 lines
6.8 KiB
C#

//
// Copyright (c) 2022-present, Trail of Bits, Inc.
// All rights reserved.
//
// This source code is licensed in accordance with the terms specified in
// the LICENSE file found in the root directory of this source tree.
//
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using RpcInvestigator.Util;
using System.IO;
namespace UnitTests
{
using static NativeTraceConsumer;
using static NativeTraceControl;
[TestClass]
public class EtwTests
{
private readonly Guid s_RpcEtwGuid =
new Guid("6ad52b32-d609-4be9-ae07-ce8dae937e39");
private readonly int s_NumEvents = 1000;
[DataTestMethod]
[DataRow(true)]
[DataRow(false)]
public async Task RealTimeEtwTraceTest(bool EnableDebugEvents)
{
var env = new Environment();
env.Initialize();
int eventsConsumed = 0;
await Task.Run(() =>
{
//
// This trace will automatically terminate after a set number
// of ETW events have been successfully consumed/parsed.
//
using (var trace = new EtwRealTimeTrace(
"RPC Investigator Unit Test Real-Time Tracing",
s_RpcEtwGuid,
EnableDebugEvents))
using (var parserBuffers = new EtwEventParserBuffers())
{
try
{
trace.Start();
//
// Begin consuming events. This is a blocking call.
//
trace.Consume(new EventRecordCallback((Event) =>
{
var evt = (EVENT_RECORD)Marshal.PtrToStructure(
Event, typeof(EVENT_RECORD));
var parser = new EtwEventParser(
evt,
parserBuffers,
trace.GetPerfFreq());
try
{
var result = parser.Parse();
Assert.IsNotNull(result);
}
catch (Exception ex)
{
Assert.Fail("Unable to parse event: " + ex.Message);
}
eventsConsumed++;
}),
new BufferCallback((LogFile) =>
{
var logfile = new EVENT_TRACE_LOGFILE();
try
{
logfile = (EVENT_TRACE_LOGFILE)
Marshal.PtrToStructure(LogFile, typeof(EVENT_TRACE_LOGFILE));
}
catch (Exception ex)
{
Assert.Fail("Unable to cast EVENT_TRACE_LOGFILE: " + ex.Message);
}
if (eventsConsumed >= s_NumEvents)
{
return 0;
}
return 1;
}));
}
catch (Exception ex)
{
Assert.Fail("An exception occurred when consuming events: " + ex.Message);
}
}
});
}
[TestMethod]
[DeploymentItem(@"..\..\data\trace_files\ms-rpc-capture-arrays.etl")]
public void FileEtwTraceTest()
{
var env = new Environment();
env.Initialize();
int eventsConsumed = 0;
//
// This trace will automatically terminate after a set number
// of ETW events have been successfully consumed/parsed.
//
var current = Directory.GetCurrentDirectory();
var target = Path.Combine(current, "ms-rpc-capture-arrays.etl");
using (var trace = new EtwFileTrace(target))
using (var parserBuffers = new EtwEventParserBuffers())
{
try
{
//
// Begin consuming events. This is a blocking call.
//
trace.Consume(new EventRecordCallback((Event) =>
{
var evt = (EVENT_RECORD)Marshal.PtrToStructure(
Event, typeof(EVENT_RECORD));
if (!evt.EventHeader.ProviderId.Equals(s_RpcEtwGuid))
{
//
// Skip events from other providers, because it might not
// be a builtin provider, in which case we'd need to go
// find the right manifest and that is overly complex for
// this unit test.
//
return;
}
var parser = new EtwEventParser(
evt,
parserBuffers,
trace.GetPerfFreq());
try
{
var result = parser.Parse();
Assert.IsNotNull(result, "Failed to parse the event");
}
catch (Exception ex)
{
Assert.Fail("Unable to parse event: " + ex.Message);
}
eventsConsumed++;
}),
new BufferCallback((LogFile) =>
{
var logfile = new EVENT_TRACE_LOGFILE();
try
{
logfile = (EVENT_TRACE_LOGFILE)
Marshal.PtrToStructure(LogFile, typeof(EVENT_TRACE_LOGFILE));
}
catch (Exception ex)
{
Assert.Fail("Unable to cast EVENT_TRACE_LOGFILE: " + ex.Message);
}
if (eventsConsumed >= s_NumEvents)
{
return 0;
}
return 1;
}));
}
catch (Exception ex)
{
Assert.Fail("An exception occurred when consuming events: " + ex.Message);
}
}
}
}
}