You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1081 lines
37 KiB
1081 lines
37 KiB
//---------------------------------------------------------------------------
|
|
// File: TraceEvent
|
|
//
|
|
// A Managed wrapper for Event Tracing for Windows
|
|
//
|
|
// Author: Melur Raghuraman
|
|
// Extended By: Baskar Sridharan (7 June 2002).
|
|
// Date: 10 Oct 2001
|
|
//---------------------------------------------------------------------------
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
namespace Microsoft.Win32.Diagnostics
|
|
{
|
|
//
|
|
// TODO: Cover all possible EventTypes
|
|
//
|
|
[System.CLSCompliant(false)]
|
|
public sealed class EventType
|
|
{
|
|
// Ensure class cannot be instantiated
|
|
private EventType() {}
|
|
public const uint Info = 0x00; // Information or Point Event
|
|
public const uint StartEvent = 0x01; // Start of an activity
|
|
public const uint EndEvent = 0x02; // End of an activity
|
|
public const uint DcStart = 0x03; // Event at Start of Data Collection
|
|
public const uint DcEnd = 0x04; // Event at End of Data Collection
|
|
public const uint Extension = 0x05; // Extension Event
|
|
public const uint Reply = 0x06; // Request-Reply Event
|
|
public const uint Dequeue = 0x07; // Enqueue-Dequeue Event
|
|
public const uint Checkpoint = 0x08;// Checkpoint Event
|
|
public const uint Reserved = 0x09; // Reserved Event
|
|
public const uint Message = 0xFF; // Debug Message Event Type
|
|
|
|
// new Event Types beyond Win32 types
|
|
public const uint Connect = 0x10; // Connect Event Type
|
|
public const uint Disconnect = 0x11;// Disconnect Event Type
|
|
|
|
|
|
// Open-Close, Connect-Disconnect, Request-Response
|
|
// Send-Receive, Start-End, Enqueue-Dequeue, Lock-Unlock
|
|
// Enter-Leave, Parent-child, Read-Write, Create-Delete
|
|
// new-dispose, alloc-free, client-server,
|
|
|
|
// Checkpoint/Marker,
|
|
}
|
|
|
|
|
|
[System.CLSCompliant(false)]
|
|
internal struct TypeNumberMap
|
|
{
|
|
internal const byte NULL_NO=0;
|
|
internal const byte OBJECT_NO = 1;
|
|
internal const byte STRING_NO = 2;
|
|
internal const byte SBYTE_NO = 3;
|
|
internal const byte BYTE_NO = 4;
|
|
internal const byte INT16_NO = 5;
|
|
internal const byte UINT16_NO = 6;
|
|
internal const byte INT32_NO = 7;
|
|
internal const byte UINT32_NO = 8;
|
|
internal const byte INT64_NO = 9;
|
|
internal const byte UINT64_NO = 10;
|
|
internal const byte CHAR_NO = 11;
|
|
internal const byte SINGLE_NO = 12;
|
|
internal const byte DOUBLE_NO = 13;
|
|
internal const byte BOOLEAN_NO = 14;
|
|
internal const byte DECIMAL_NO = 15;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// TODO: Check with Debug Level constants in NT and System.Diagnostics
|
|
//
|
|
|
|
public enum TraceFlags: int
|
|
{
|
|
Error=1, Warning=2, Info=4, Info1=8, Info2=16, Info3=32, Info4=64, Info5=128, Info6=256, Info7=512, Info8=1024,
|
|
Performance=2048, Performance1=4096, Performance2=8192, Performance3=16384, Performance4=32768, Performance5=65536,
|
|
Performance6=131072, Performance7=262144, Performance8=524288
|
|
}
|
|
[Guid("189456B1-2B4C-473f-A249-3856DD93F9D3")]
|
|
[System.CLSCompliant(false)]
|
|
public interface ITraceMessageDecoder
|
|
{
|
|
unsafe int DecodeTraceMessage(byte* message, char* buffer, int bufferSize, ref int dataSize);
|
|
}
|
|
|
|
[System.CLSCompliant(false)]
|
|
[Guid("748004CA-4959-409a-887C-6546438CF48E")]
|
|
public class TraceProvider : ITraceMessageDecoder
|
|
{
|
|
static private EtwTrace.EtwProc etwProc; // Trace Callback function
|
|
private ulong registrationHandle; // Trace Registration Handle
|
|
private ulong traceHandle; // Trace Logger Handle from callback
|
|
|
|
private uint level; // Tracing Level
|
|
private uint flags; // Trace Enable Flags
|
|
private bool enabled; // Enabled flag from Trace callback
|
|
private const byte noOfBytesPerArg = 3;
|
|
private string defaultString = "Foo";
|
|
private string defaultFmtStr = "Default Format String";
|
|
private Hashtable messageFormatTable = new Hashtable();
|
|
string applicationName= "CSharp Software Tracing App";
|
|
//Default GUID used by Trace Message Strings.
|
|
private Guid MessageGuid = new Guid("{b4955bf0-3af1-4740-b475-99055d3fe9aa}");
|
|
|
|
|
|
public TraceProvider()
|
|
{
|
|
//Such a default constructor is required for COM Interop
|
|
}
|
|
public TraceProvider(string applicationName, Guid controlGuid)
|
|
{
|
|
Level = 0;
|
|
flags = 0;
|
|
IsEnabled= false;
|
|
traceHandle = 0;
|
|
registrationHandle = 0;
|
|
this.applicationName = applicationName; //Currently, we don't use this variable
|
|
//
|
|
// Register the controlGuid with ETW
|
|
//
|
|
Register(controlGuid);
|
|
}
|
|
|
|
|
|
public TraceProvider(ulong traceHandle)
|
|
{
|
|
this.traceHandle = traceHandle;
|
|
}
|
|
|
|
~TraceProvider()
|
|
{
|
|
//
|
|
// Unregister from ETW using the registrationHandle saved from
|
|
// the register call.
|
|
//
|
|
EtwTrace.UnregisterTraceGuids(registrationHandle);
|
|
GC.KeepAlive(etwProc);
|
|
}
|
|
|
|
public uint Flags
|
|
{
|
|
get{
|
|
return flags;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
internal uint Level
|
|
{
|
|
get
|
|
{
|
|
return level;
|
|
}
|
|
// set should not be public
|
|
set
|
|
{
|
|
level = value;
|
|
}
|
|
}
|
|
|
|
public bool IsEnabled
|
|
{
|
|
get
|
|
{
|
|
return enabled;
|
|
}
|
|
set
|
|
{
|
|
enabled = value;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// This callback function is called by ETW to enable or disable Tracing dynamically
|
|
//
|
|
public unsafe uint MyCallback(uint requestCode, System.IntPtr context, System.IntPtr bufferSize, byte* byteBuffer)
|
|
{
|
|
try
|
|
{
|
|
BaseEvent* buffer = (BaseEvent *)byteBuffer;
|
|
switch(requestCode)
|
|
{
|
|
case EtwTrace.RequestCodes.EnableEvents:
|
|
traceHandle = buffer->HistoricalContext;
|
|
//traceHandle = EtwTrace.GetTraceLoggerHandle((BaseEvent *)buffer);
|
|
flags = (uint)EtwTrace.GetTraceEnableFlags((ulong)buffer->HistoricalContext);
|
|
Level = (uint)EtwTrace.GetTraceEnableLevel((ulong)buffer->HistoricalContext);
|
|
IsEnabled = true;
|
|
break;
|
|
case EtwTrace.RequestCodes.DisableEvents:
|
|
IsEnabled = false;
|
|
traceHandle = 0;
|
|
Level = 0 ;
|
|
flags = 0 ;
|
|
break;
|
|
default:
|
|
IsEnabled = false;
|
|
traceHandle = 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
Console.WriteLine("Exception caught - '{0}'", e.Message);
|
|
return 0;//TODO: Shouldn't we be returning a different value here ?
|
|
}
|
|
}
|
|
//
|
|
// Registers a Dynamically Generated GUID automatically with an inbuilt callback
|
|
//
|
|
private unsafe uint Register(Guid controlGuid)
|
|
{
|
|
uint status;
|
|
TraceGuidRegistration guidReg = new TraceGuidRegistration();
|
|
Guid dummyGuid = new Guid("{b4955bf0-3af1-4740-b475-99055d3fe9aa}");
|
|
|
|
etwProc = new EtwTrace.EtwProc(MyCallback);
|
|
|
|
|
|
guidReg.Guid = &dummyGuid;
|
|
guidReg.RegHandle = null;
|
|
|
|
status = EtwTrace.RegisterTraceGuids(etwProc, null, ref controlGuid, 1, ref guidReg, null, null, out registrationHandle);
|
|
|
|
if (status != 0)
|
|
{
|
|
Console.WriteLine("Register() call Failed with Status {0}", status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype)
|
|
{
|
|
BaseEvent ev; // Takes up 192 bytes on the stack
|
|
ev.ClientContext = 0;
|
|
ev.Guid = eventGuid;
|
|
ev.ProviderId = evtype;
|
|
ev.BufferSize = 48; // sizeof(EVENT_TRACE_HEADER)
|
|
|
|
return EtwTrace.TraceEvent(traceHandle, (char*)&ev);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// This is the 1 object overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, null, null, null, null, null, null, null, null);
|
|
}
|
|
|
|
|
|
//
|
|
// This is the 2 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, null, null, null, null, null, null, null);
|
|
}
|
|
|
|
//
|
|
// This is the 3 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, null, null, null, null, null, null);
|
|
}
|
|
|
|
|
|
//
|
|
// This is the 4 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, null, null, null, null, null);
|
|
}
|
|
|
|
//
|
|
// This is the 5 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, null, null, null, null);
|
|
}
|
|
|
|
//
|
|
// This is the 6 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, null, null, null);
|
|
}
|
|
|
|
//
|
|
// This is the 7 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, data6, null, null);
|
|
}
|
|
|
|
//
|
|
// This is the 8 argument overload
|
|
//
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6, object data7)
|
|
{
|
|
return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, data6, data7, null);
|
|
}
|
|
|
|
public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6, object data7, object data8)
|
|
{
|
|
uint status = 0;
|
|
BaseEvent ev; // Takes up 192 bytes on the stack
|
|
char* buffer = stackalloc char[128];
|
|
uint offset = 0;
|
|
char* ptr = buffer;
|
|
string s0 , s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8;
|
|
int stringMask = 0;
|
|
uint argCount=0;
|
|
|
|
s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = defaultString;
|
|
|
|
ev.Flags = 0x00120000; // define Constants
|
|
ev.Guid = eventGuid;
|
|
ev.ProviderId = evtype;
|
|
MofField *be = null;
|
|
if (data0 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[0];
|
|
if ((s0 = ProcessOneObject(data0, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000001;
|
|
}
|
|
}
|
|
if (data1 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[1];
|
|
ptr = buffer + offset;
|
|
if ((s1 = ProcessOneObject(data1, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000002;
|
|
}
|
|
}
|
|
if (data2 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[2];
|
|
ptr = buffer + offset;
|
|
if ((s2 = ProcessOneObject(data2, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000004;
|
|
}
|
|
}
|
|
if (data3 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[3];
|
|
ptr = buffer + offset;
|
|
if ((s3 = ProcessOneObject(data3, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000008;
|
|
}
|
|
}
|
|
if (data4 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[4];
|
|
ptr = buffer + offset;
|
|
if ((s4 = ProcessOneObject(data4, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000010;
|
|
}
|
|
}
|
|
if (data5 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[5];
|
|
ptr = buffer + offset;
|
|
if ((s5 = ProcessOneObject(data5, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000020;
|
|
}
|
|
}
|
|
if (data6 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[6];
|
|
ptr = buffer + offset;
|
|
if ((s6 = ProcessOneObject(data6, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000040;
|
|
}
|
|
}
|
|
if (data7 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[7];
|
|
ptr = buffer + offset;
|
|
if ((s7 = ProcessOneObject(data7, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000080;
|
|
}
|
|
}
|
|
if (data8 != null)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[8];
|
|
ptr = buffer + offset;
|
|
if ((s8 = ProcessOneObject(data8, be, ptr, ref offset)) != null)
|
|
{
|
|
stringMask |= 0x00000100;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now pin all the strings and use the stringMask to pass them over through
|
|
// mofField.
|
|
//
|
|
|
|
fixed (char* vptr0 = s0, vptr1 = s1, vptr2 = s2, vptr3 = s3, vptr4 = s4, vptr5 = s5, vptr6 = s6, vptr7 = s7, vptr8 = s8 )
|
|
{
|
|
if ((stringMask & 0x00000001) != 0)
|
|
{
|
|
(&ev.UserData)[0].DataLength = (uint) s0.Length * 2;
|
|
(&ev.UserData)[0].DataPointer = (void*)vptr0;
|
|
|
|
}
|
|
if ((stringMask & 0x00000002)!= 0)
|
|
{
|
|
(&ev.UserData)[1].DataLength = (uint) s1.Length * 2;
|
|
(&ev.UserData)[1].DataPointer = (void*)vptr1;
|
|
|
|
}
|
|
if ((stringMask & 0x00000004)!= 0)
|
|
{
|
|
(&ev.UserData)[2].DataLength = (uint) s2.Length * 2;
|
|
(&ev.UserData)[2].DataPointer = (void*)vptr2;
|
|
|
|
}
|
|
if ((stringMask & 0x00000008)!= 0)
|
|
{
|
|
(&ev.UserData)[3].DataLength = (uint) s3.Length * 2;
|
|
(&ev.UserData)[3].DataPointer = (void*)vptr3;
|
|
|
|
}
|
|
if ((stringMask & 0x00000010)!= 0)
|
|
{
|
|
(&ev.UserData)[4].DataLength = (uint) s4.Length * 2;
|
|
(&ev.UserData)[4].DataPointer = (void*)vptr4;
|
|
|
|
}
|
|
if ((stringMask & 0x00000020)!= 0)
|
|
{
|
|
(&ev.UserData)[5].DataLength = (uint) s5.Length * 2;
|
|
(&ev.UserData)[5].DataPointer = (void*)vptr5;
|
|
|
|
}
|
|
if ((stringMask & 0x00000040)!= 0)
|
|
{
|
|
(&ev.UserData)[6].DataLength = (uint) s6.Length * 2;
|
|
(&ev.UserData)[6].DataPointer = (void*)vptr6;
|
|
|
|
}
|
|
if ((stringMask & 0x00000080)!= 0)
|
|
{
|
|
(&ev.UserData)[7].DataLength = (uint) s7.Length * 2;
|
|
(&ev.UserData)[7].DataPointer = (void*)vptr7;
|
|
|
|
}
|
|
if ((stringMask & 0x00000100)!= 0)
|
|
{
|
|
(&ev.UserData)[8].DataLength = (uint) s8.Length * 2;
|
|
(&ev.UserData)[8].DataPointer = (void*)vptr8;
|
|
|
|
}
|
|
ev.BufferSize = 48 + argCount * 16;
|
|
status = EtwTrace.TraceEvent(traceHandle, (char*)&ev);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
private unsafe string ProcessOneObject(object data, MofField * mofField, char* ptr, ref uint offSet)
|
|
{
|
|
return EncodeObject(data, mofField, ptr, ref offSet, (byte *)null);
|
|
}
|
|
//TODO[1]: Need to accomodate Win64 alignment issues. Code that might cause problems
|
|
// have been tagged with "WIN64 Changes".
|
|
private unsafe string EncodeObject(object data, MofField * mofField, char* ptr, ref uint offSet, byte* ptrArgInfo)
|
|
{
|
|
if (data == null)
|
|
{
|
|
*ptrArgInfo = (byte)0; //NULL type, WIN64 Changes
|
|
*(ushort *)(ptrArgInfo+1) = (ushort)0;
|
|
mofField->DataLength = 0;
|
|
mofField->DataPointer=(void *)null; //WIN64 Changes (?)
|
|
return null;
|
|
}
|
|
string sRet = data as string;
|
|
if (sRet != null)
|
|
{
|
|
*ptrArgInfo = (byte)2; //WIN64 Changes
|
|
*(ushort *)(ptrArgInfo+1) = (ushort)(sRet.Length<65535?sRet.Length:65535); //WIN64 Changes
|
|
return sRet;
|
|
}
|
|
if (data is sbyte)
|
|
{
|
|
|
|
mofField->DataLength = sizeof(sbyte);
|
|
*ptrArgInfo = (byte)3; //WIN64 Changes
|
|
sbyte* sbyteptr = (sbyte*)ptr;
|
|
*sbyteptr = (sbyte) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) sbyteptr;
|
|
offSet += sizeof(sbyte);
|
|
}
|
|
else if (data is byte)
|
|
{
|
|
mofField->DataLength = sizeof(byte);
|
|
*ptrArgInfo = (byte)4; //WIN64 Changes
|
|
byte* byteptr = (byte*)ptr;
|
|
*byteptr = (byte) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) byteptr;
|
|
offSet += sizeof(byte);
|
|
}
|
|
else if (data is short)
|
|
{
|
|
mofField->DataLength = sizeof(short);
|
|
*ptrArgInfo = (byte)5; //WIN64 Changes
|
|
short* shortptr = (short*)ptr;
|
|
*shortptr = (short) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) shortptr;
|
|
offSet += sizeof(short);
|
|
}
|
|
else if (data is ushort)
|
|
{
|
|
mofField->DataLength = sizeof(ushort);
|
|
*ptrArgInfo = (byte)6; //WIN64 Changes
|
|
ushort* ushortptr = (ushort*)ptr;
|
|
*ushortptr = (ushort) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) ushortptr;
|
|
offSet += sizeof(ushort);
|
|
}
|
|
|
|
else if (data is int)
|
|
{
|
|
mofField->DataLength = sizeof(int);
|
|
*ptrArgInfo = (byte)7; //WIN64 Changes
|
|
int* intptr = (int*)ptr;
|
|
*intptr = (int) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) intptr;
|
|
offSet += sizeof(int);
|
|
}
|
|
else if (data is uint )
|
|
{
|
|
mofField->DataLength = sizeof(uint);
|
|
*ptrArgInfo = (byte)8; //WIN64 Changes
|
|
uint* uintptr = (uint*)ptr;
|
|
*uintptr = (uint) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) uintptr;
|
|
offSet += sizeof(uint);
|
|
}
|
|
else if (data is long )
|
|
{
|
|
mofField->DataLength = sizeof(long);
|
|
*ptrArgInfo = (byte)9; //WIN64 Changes
|
|
long* longptr = (long*)ptr;
|
|
*longptr = (long) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) longptr;
|
|
offSet += sizeof(long);
|
|
}
|
|
else if (data is ulong )
|
|
{
|
|
mofField->DataLength = sizeof(ulong);
|
|
*ptrArgInfo = (byte)10; //WIN64 Changes
|
|
ulong* ulongptr = (ulong*)ptr;
|
|
*ulongptr = (ulong) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) ulongptr;
|
|
offSet += sizeof(ulong);
|
|
}
|
|
else if (data is char)
|
|
{
|
|
mofField->DataLength = sizeof(char);
|
|
*ptrArgInfo = (byte)11; //WIN64 Changes
|
|
char* charptr = (char*)ptr;
|
|
*charptr = (char) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) charptr;
|
|
offSet += sizeof(char);
|
|
}
|
|
else if (data is float)
|
|
{
|
|
mofField->DataLength = sizeof(float);
|
|
*ptrArgInfo = (byte)12; //WIN64 Changes
|
|
float* floatptr = (float*)ptr;
|
|
*floatptr = (float) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) floatptr;
|
|
offSet += sizeof(float);
|
|
}
|
|
else if (data is double)
|
|
{
|
|
mofField->DataLength = sizeof(double);
|
|
*ptrArgInfo = (byte)13; //WIN64 Changes
|
|
double* doubleptr = (double*)ptr;
|
|
*doubleptr = (double) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) doubleptr;
|
|
offSet += sizeof(double);
|
|
}
|
|
else if (data is bool)
|
|
{
|
|
mofField->DataLength = sizeof(bool);
|
|
*ptrArgInfo = (byte)14; //WIN64 Changes
|
|
bool* boolptr = (bool*)ptr;
|
|
*boolptr = (bool) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) boolptr;
|
|
offSet += sizeof(bool);
|
|
}
|
|
else if (data is decimal)
|
|
{
|
|
mofField->DataLength = (uint)sizeof(decimal);
|
|
*ptrArgInfo = (byte)15; //WIN64 Changes
|
|
decimal* decimalptr = (decimal*)ptr;
|
|
*decimalptr = (decimal) data; //WIN64 Changes
|
|
mofField->DataPointer = (void *) decimalptr;
|
|
offSet += (uint)sizeof(decimal);
|
|
}
|
|
else
|
|
{
|
|
//To our eyes, everything else is a just a string
|
|
sRet = data.ToString();
|
|
*ptrArgInfo = (byte)2; //WIN64 Changes
|
|
*(ushort *)(ptrArgInfo+1) = (ushort)(sRet.Length<65535?sRet.Length:65535); //WIN64 Changes
|
|
return sRet;
|
|
}
|
|
*(ushort *)(ptrArgInfo+1) = (ushort)(mofField->DataLength); //WIN64 Changes (?)
|
|
return sRet;
|
|
|
|
}
|
|
|
|
|
|
private unsafe uint EncodeTraceMessage(Guid eventGuid, uint evtype, byte nargs, object formatstring, object data2, object data3, object data4, object data5, object data6, object data7, object data8, object data9)
|
|
{
|
|
uint status = 0;
|
|
BaseEvent ev; // Takes up 208 bytes on the stack
|
|
char* buffer = stackalloc char[144+(1+9*noOfBytesPerArg)/sizeof(char)];//28 characters would be 56 bytes!!!. We are allocating more space than we require.
|
|
//Header structure:
|
|
//1 byte for number of args
|
|
//3 byte for format string type information,
|
|
//3 bytes each for the type information for a maximum of 8 arguments
|
|
byte *header = (byte *)(buffer+144);
|
|
uint offset = 0;
|
|
char* ptr = buffer;
|
|
string s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8, s9;
|
|
int stringMask = 0;
|
|
uint argCount=0;
|
|
byte *ptrHeader = header;
|
|
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = defaultString;
|
|
|
|
ev.Flags = 0x00120000; // define Constants
|
|
ev.Guid = eventGuid;
|
|
//IMP: evtype MUST be the same as the one specified in the typeve field for CSharp in default.tmf
|
|
ev.ProviderId = evtype;
|
|
MofField *be = null;
|
|
if (header != null)
|
|
{
|
|
be = &(&ev.UserData)[0];
|
|
header[0] = (byte)nargs; //WIN64 Changes (?)
|
|
be->DataPointer = (void *)header;
|
|
be->DataLength = (uint)(1+nargs*noOfBytesPerArg);
|
|
}
|
|
|
|
if (formatstring == null)
|
|
formatstring = defaultFmtStr;
|
|
if (formatstring != null)
|
|
{
|
|
//data1 would, in most cases, be the format string
|
|
argCount++;
|
|
be = &(&ev.UserData)[1];
|
|
ptr = buffer + offset;
|
|
if ((s1 = EncodeObject(formatstring, be, ptr, ref offset, ++header)) != null)
|
|
{
|
|
stringMask |= 0x00000002;
|
|
}
|
|
}
|
|
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[2];
|
|
ptr = buffer + offset;
|
|
if ((s2 = EncodeObject(data2, be, ptr, ref offset, header+1*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000004;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[3];
|
|
ptr = buffer + offset;
|
|
if ((s3 = EncodeObject(data3, be, ptr, ref offset, header+2*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000008;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[4];
|
|
ptr = buffer + offset;
|
|
if ((s4 = EncodeObject(data4, be, ptr, ref offset, header+3*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000010;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[5];
|
|
ptr = buffer + offset;
|
|
if ((s5 = EncodeObject(data5, be, ptr, ref offset, header+4*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000020;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[6];
|
|
ptr = buffer + offset;
|
|
if ((s6 = EncodeObject(data6, be, ptr, ref offset,header+5*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000040;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[7];
|
|
ptr = buffer + offset;
|
|
if ((s7 = EncodeObject(data7, be, ptr, ref offset,header+6*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000080;
|
|
}
|
|
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[8];
|
|
ptr = buffer + offset;
|
|
if ((s8 = EncodeObject(data8, be, ptr, ref offset,header+7*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000100;
|
|
}
|
|
}
|
|
if (argCount <= nargs)
|
|
{
|
|
argCount++;
|
|
be = &(&ev.UserData)[9];
|
|
ptr = buffer + offset;
|
|
if ((s9 = EncodeObject(data9, be, ptr, ref offset, header+8*noOfBytesPerArg)) != null)
|
|
{
|
|
stringMask |= 0x00000200;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now pin all the strings and use the stringMask to pass them over through
|
|
// mofField.
|
|
//
|
|
|
|
fixed (char* vptr1 = s1, vptr2 = s2, vptr3 = s3, vptr4 = s4, vptr5 = s5, vptr6 = s6, vptr7 = s7, vptr8 = s8, vptr9 = s9 )
|
|
{
|
|
|
|
if ((stringMask & 0x00000002)!= 0)
|
|
{
|
|
|
|
(&ev.UserData)[1].DataLength = (uint) (s1.Length<65535/2?s1.Length*2:65535);//s1.Length*2;
|
|
|
|
(&ev.UserData)[1].DataPointer = (void*)(vptr1);
|
|
}
|
|
if ((stringMask & 0x00000004)!= 0)
|
|
{
|
|
(&ev.UserData)[2].DataLength = (uint) (s2.Length<65535/2?s2.Length*2:65535);//s2.Length * 2;
|
|
|
|
(&ev.UserData)[2].DataPointer = (void*)(vptr2);
|
|
}
|
|
if ((stringMask & 0x00000008)!= 0)
|
|
{
|
|
(&ev.UserData)[3].DataLength = (uint) (s3.Length<65535/2?s3.Length*2:65535);//s3.Length * 2;
|
|
(&ev.UserData)[3].DataPointer = (void*)(vptr3);
|
|
}
|
|
if ((stringMask & 0x00000010)!= 0)
|
|
{
|
|
(&ev.UserData)[4].DataLength = (uint) (s4.Length<65535/2?s4.Length*2:65535);//s4.Length * 2;
|
|
(&ev.UserData)[4].DataPointer = (void*)(vptr4);
|
|
}
|
|
if ((stringMask & 0x00000020)!= 0)
|
|
{
|
|
(&ev.UserData)[5].DataLength = (uint) (s5.Length<65535/2?s5.Length*2:65535);//s5.Length * 2;
|
|
(&ev.UserData)[5].DataPointer = (void*)(vptr5);
|
|
}
|
|
if ((stringMask & 0x00000040)!= 0)
|
|
{
|
|
(&ev.UserData)[6].DataLength = (uint) (s6.Length<65535/2?s6.Length*2:65535);//s6.Length * 2;
|
|
(&ev.UserData)[6].DataPointer = (void*)(vptr6);
|
|
}
|
|
if ((stringMask & 0x00000080)!= 0)
|
|
{
|
|
(&ev.UserData)[7].DataLength = (uint) (s7.Length<65535/2?s7.Length*2:65535);//s7.Length * 2;
|
|
(&ev.UserData)[7].DataPointer = (void*)(vptr7);
|
|
}
|
|
if ((stringMask & 0x00000100)!= 0)
|
|
{
|
|
(&ev.UserData)[8].DataLength = (uint) (s8.Length<65535/2?s8.Length*2:65535);//s8.Length * 2;
|
|
(&ev.UserData)[8].DataPointer = (void*)(vptr8);
|
|
}
|
|
if ((stringMask & 0x00000200)!= 0)
|
|
{
|
|
(&ev.UserData)[9].DataLength = (uint) (s9.Length<65535/2?s9.Length*2:65535);//s9.Length * 2;
|
|
(&ev.UserData)[9].DataPointer = (void*)(vptr9);
|
|
}
|
|
ev.BufferSize = 48 + (argCount+1) * 16;//the extra mof field is for the header
|
|
status = EtwTrace.TraceEvent(traceHandle, (char*)&ev);
|
|
}
|
|
return status;
|
|
}
|
|
public unsafe int DecodeTraceMessage(byte* message, char* buffer, int bufferSize /* in chars */, ref int dataSize /*Note: This is # of *chars* and not bytes*/)
|
|
{
|
|
if (buffer == null || message == null || bufferSize <= 0)
|
|
return 0; //TODO[1]: Do we need a more detailed error code ?
|
|
try
|
|
{
|
|
int i=0;
|
|
byte nargs = *message;
|
|
ushort lenFmtStr = *(ushort *)(message+2);
|
|
char* pcFmtStr = (char *)(message+1+nargs*noOfBytesPerArg);//start of the format string
|
|
byte* argData = message+1+nargs*noOfBytesPerArg+lenFmtStr*2; //start of the argument data
|
|
object[] argObject = new object[nargs];
|
|
byte argType;
|
|
ushort argLen;
|
|
String formatString = new String(pcFmtStr,0,lenFmtStr);
|
|
//Excluding the format string
|
|
for(i = 0; i < nargs-1; i++)
|
|
{
|
|
argType = *(message+1+(i+1)*noOfBytesPerArg);
|
|
argLen = *(ushort *)(message+1+(i+1)*noOfBytesPerArg+1); //WIN64 Changes (?)
|
|
switch(argType)
|
|
{
|
|
case TypeNumberMap.NULL_NO:
|
|
argObject[i] = null;
|
|
break;
|
|
case TypeNumberMap.STRING_NO:
|
|
{
|
|
String s;
|
|
if (argLen == 0)
|
|
s = "";
|
|
else s = new String((char *)argData,0,argLen);
|
|
argObject[i] = s;
|
|
argLen *= 2; //adjust the length
|
|
break;
|
|
}
|
|
case TypeNumberMap.SBYTE_NO:
|
|
{
|
|
sbyte sb = *(sbyte *)argData; //WIN64 Changes
|
|
argObject[i] = sb;
|
|
break;
|
|
}
|
|
case TypeNumberMap.BYTE_NO:
|
|
{
|
|
byte b = *argData; //WIN64 Changes
|
|
argObject[i] = b;
|
|
break;
|
|
}
|
|
case TypeNumberMap.INT16_NO:
|
|
{
|
|
short s = *(short *)argData; //WIN64 Changes
|
|
argObject[i] = s;
|
|
break;
|
|
}
|
|
case TypeNumberMap.UINT16_NO:
|
|
{
|
|
ushort us = *(ushort *)argData; //WIN64 Changes
|
|
argObject[i] = us;
|
|
break;
|
|
}
|
|
case TypeNumberMap.INT32_NO:
|
|
{
|
|
int id = *(int *)argData; //WIN64 Changes
|
|
argObject[i] = id;
|
|
break;
|
|
}
|
|
case TypeNumberMap.UINT32_NO:
|
|
{
|
|
uint uid = *(uint *)argData; //WIN64 Changes
|
|
argObject[i] = uid;
|
|
break;
|
|
}
|
|
case TypeNumberMap.INT64_NO:
|
|
{
|
|
long l = *(long *)argData; //WIN64 Changes
|
|
argObject[i] = l;
|
|
break;
|
|
}
|
|
case TypeNumberMap.UINT64_NO:
|
|
{
|
|
ulong ul = *(ulong *)argData; //WIN64 Changes
|
|
argObject[i] = ul;
|
|
break;
|
|
}
|
|
case TypeNumberMap.CHAR_NO:
|
|
{
|
|
char c = *(char *)argData; //WIN64 Changes
|
|
argObject[i] = c;
|
|
break;
|
|
}
|
|
case TypeNumberMap.SINGLE_NO:
|
|
{
|
|
float f = *(float *)argData; //WIN64 Changes
|
|
argObject[i] = f;
|
|
break;
|
|
}
|
|
case TypeNumberMap.DOUBLE_NO:
|
|
{
|
|
double d = *(double *)argData; //WIN64 Changes
|
|
argObject[i] = d;
|
|
break;
|
|
}
|
|
case TypeNumberMap.BOOLEAN_NO:
|
|
{
|
|
bool b = *(bool *)argData; //WIN64 Changes
|
|
argObject[i] = b;
|
|
break;
|
|
}
|
|
case TypeNumberMap.DECIMAL_NO:
|
|
{
|
|
decimal d = *(decimal *)argData; //WIN64 Changes
|
|
argObject[i] = d;
|
|
break;
|
|
}
|
|
|
|
}
|
|
argData += argLen;
|
|
|
|
}
|
|
string fStr = String.Format(formatString,argObject);
|
|
if (fStr.Length==0)//empty string
|
|
fStr="Format string was empty!";
|
|
int arrLen = fStr.Length*2;
|
|
dataSize = arrLen+1;
|
|
fixed(char* carray = fStr.ToCharArray())
|
|
{
|
|
|
|
if (arrLen+1 <= bufferSize)
|
|
{
|
|
for(i = 0; i < arrLen; i++)
|
|
buffer[i] = carray[i]; //WIN64 Changes (?)
|
|
//add null terminator
|
|
buffer[i+1] = (char)0x00; //WIN64 Changes (?)
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
//TODO[1]: Do we need to copy as many characters as we can ?
|
|
//Not sure if it is useful to do so because the caller may have to come back
|
|
//with the right buffer size to get all the data. So why copy part of the data twice ?
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
Console.WriteLine("Exception caught: {0}", e.Message);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
// ========================================================================
|
|
// The following are the Message String Wrappers for Software Tracing Messages
|
|
// using Flags.
|
|
// There are entried for Format string and zero through 8 arguments.
|
|
// These are kept small so they will be inlined
|
|
// ========================================================================
|
|
// Just the format string
|
|
public unsafe void TraceMessage(uint traceFlags, object format )
|
|
{
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14,1, format, null, null, null, null, null, null, null, null);
|
|
}
|
|
}
|
|
// Just one argument
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1 )
|
|
{
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
|
|
EncodeTraceMessage(MessageGuid, (int)14, 2, format, data1, null, null, null, null, null, null,null);
|
|
}
|
|
|
|
}
|
|
// Just two arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2 )
|
|
{
|
|
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
|
|
EncodeTraceMessage(MessageGuid, (int)14, 3, format, data1, data2, null, null, null, null, null, null);
|
|
}
|
|
}
|
|
// Just three arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3 )
|
|
{
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14, 4, format, data1, data2, data3, null, null, null, null, null);
|
|
}
|
|
}
|
|
// Just four arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4 )
|
|
{
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14, 5, format, data1, data2, data3, data4, null, null, null, null);
|
|
}
|
|
}
|
|
// Just five arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5 )
|
|
{
|
|
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14, 6, format, data1, data2, data3, data4, data5, null, null, null);
|
|
}
|
|
}
|
|
// Just six arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6 )
|
|
{
|
|
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14, 7, format, data1, data2, data3, data4, data5, data6, null, null);
|
|
}
|
|
}
|
|
// Just seven arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6, object data7 )
|
|
{
|
|
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
|
|
EncodeTraceMessage(MessageGuid, (int)14, 8, format, data1, data2, data3, data4, data5, data6, data7, null);
|
|
}
|
|
|
|
}
|
|
// Just eight arguments
|
|
public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6, object data7, object data8 )
|
|
{
|
|
|
|
if ((traceFlags&Flags) != 0)
|
|
{
|
|
EncodeTraceMessage(MessageGuid, (int)14, 9, format, data1, data2, data3, data4, data5, data6, data7, data8);
|
|
}
|
|
}
|
|
}
|
|
}
|