Last active
December 25, 2017 03:51
-
-
Save 303248153/ee9870d70a39f97b487f504ecee40360 to your computer and use it in GitHub Desktop.
The code is a piece of shit invokes the worst api microsoft ever made but should just work, requires mingw and win above vista
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/packetzero/etwrealtime/blob/master/etwrealtime/packet_trace.cpp | |
// https://mollyrocket.com/casey/stream_0029.html | |
// https://docs.microsoft.com/en-us/dotnet/framework/performance/clr-etw-providers | |
#define WINNT | |
#include <windows.h> | |
#include <evntrace.h> | |
#include <evntprov.h> | |
#include <iostream> | |
#include <array> | |
#define PROCESS_TRACE_MODE_REAL_TIME 0x00000100 | |
#define PROCESS_TRACE_MODE_RAW_TIMESTAMP 0x00001000 | |
#define PROCESS_TRACE_MODE_EVENT_RECORD 0x10000000 | |
typedef struct _EVENT_HEADER_EXTENDED_DATA_ITEM { | |
USHORT Reserved1; // Reserved for internal use | |
USHORT ExtType; // Extended info type | |
struct { | |
USHORT Linkage : 1; // Indicates additional extended | |
// data item | |
USHORT Reserved2 : 15; | |
}; | |
USHORT DataSize; // Size of extended info data | |
ULONGLONG DataPtr; // Pointer to extended info data | |
} EVENT_HEADER_EXTENDED_DATA_ITEM, *PEVENT_HEADER_EXTENDED_DATA_ITEM; | |
typedef struct _EVENT_HEADER { | |
USHORT Size; // Event Size | |
USHORT HeaderType; // Header Type | |
USHORT Flags; // Flags | |
USHORT EventProperty; // User given event property | |
ULONG ThreadId; // Thread Id | |
ULONG ProcessId; // Process Id | |
LARGE_INTEGER TimeStamp; // Event Timestamp | |
GUID ProviderId; // Provider Id | |
EVENT_DESCRIPTOR EventDescriptor; // Event Descriptor | |
union { | |
struct { | |
ULONG KernelTime; // Kernel Mode CPU ticks | |
ULONG UserTime; // User mode CPU ticks | |
} DUMMYSTRUCTNAME; | |
ULONG64 ProcessorTime; // Processor Clock | |
// for private session events | |
} DUMMYUNIONNAME; | |
GUID ActivityId; // Activity Id | |
} EVENT_HEADER, *PEVENT_HEADER; | |
typedef struct _EVENT_RECORD { | |
EVENT_HEADER EventHeader; // Event header | |
ETW_BUFFER_CONTEXT BufferContext; // Buffer context | |
USHORT ExtendedDataCount; // Number of extended | |
// data items | |
USHORT UserDataLength; // User data length | |
PEVENT_HEADER_EXTENDED_DATA_ITEM // Pointer to an array of | |
ExtendedData; // extended data items | |
PVOID UserData; // Pointer to user data | |
PVOID UserContext; // Context from OpenTrace | |
} EVENT_RECORD, *PEVENT_RECORD; | |
namespace { | |
static const GUID ClrRuntimeProvider = { | |
0xe13c0d23, 0xccbc, 0x4e12, { 0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4 } | |
}; | |
static const GUID ClrRundownProvider = { | |
0xa669021c, 0xc450, 0x4609, { 0xa0, 0x35, 0x5a, 0xf5, 0x9a, 0xf4, 0xdf, 0x18 } | |
}; | |
static const GUID myGuid = | |
{ 0x10101010, 0x2345, 0xabcd, { 0xAA, 0x22, 0x71, 0x00, 0x00, 0x00, 0x08, 0xFF } }; | |
std::string mySessionName = "aaaaaaa"; | |
DWORD dwEnableFlags = 0; | |
struct EventTraceProperties { | |
EVENT_TRACE_PROPERTIES props; | |
char sessionNameBuffer[1024]; | |
}; | |
// https://stackoverflow.com/questions/29242/off-the-shelf-c-hex-dump-code | |
void hexdump(const void *ptr, int buflen) { | |
unsigned char *buf = (unsigned char*)ptr; | |
int i, j; | |
for (i=0; i<buflen; i+=16) { | |
printf("%06x: ", i); | |
for (j=0; j<16; j++) | |
if (i+j < buflen) | |
printf("%02x ", buf[i+j]); | |
else | |
printf(" "); | |
printf(" "); | |
for (j=0; j<16; j++) | |
if (i+j < buflen) | |
printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.'); | |
printf("\n"); | |
} | |
} | |
static VOID WINAPI StaticRecordEventCallback(PEVENT_RECORD pEvent) | |
{ | |
std::cout << "StaticRecordEventCallback" << std::endl; | |
auto &header = pEvent->EventHeader; | |
UCHAR processorNumber = pEvent->BufferContext.ProcessorNumber; | |
int64_t cycleTime = header.TimeStamp.QuadPart; | |
std::string userdata((char*)pEvent->UserData, pEvent->UserDataLength); | |
std::cout << "ProcessorNumber: " << +processorNumber << std::endl; | |
std::cout << "ProcessID: " << header.ProcessId << std::endl; | |
std::cout << "ThreadID: " << header.ThreadId << std::endl; | |
std::cout << "CycleTime: " << cycleTime << std::endl; | |
std::cout << "EventDescriptor.Id " << header.EventDescriptor.Id << std::endl; | |
std::cout << "EventDescriptor.Keyword 0x" << std::hex << header.EventDescriptor.Keyword << std::dec << std::endl; | |
std::cout << "UserDataLength: " << userdata.size() << std::endl; | |
if (userdata.size() < 256) | |
hexdump(userdata.c_str(), userdata.size()); | |
std::cout << std::endl; | |
} | |
static BOOL WINAPI StaticBufferEventCallback(PEVENT_TRACE_LOGFILE buf) | |
{ | |
std::cout << "StaticBufferEventCallback" << std::endl << std::endl; | |
return TRUE; | |
} | |
} | |
int main() { | |
EventTraceProperties prop = {}; | |
prop.props.Wnode.BufferSize = sizeof(prop); | |
prop.props.Wnode.Guid = myGuid; | |
prop.props.Wnode.ClientContext = 1; | |
prop.props.Wnode.Flags = WNODE_FLAG_TRACED_GUID; | |
prop.props.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; | |
prop.props.LogFileNameOffset = 0; | |
prop.props.LoggerNameOffset = offsetof(EventTraceProperties, sessionNameBuffer); | |
prop.props.FlushTimer = 1; | |
prop.props.EnableFlags = dwEnableFlags; | |
memcpy(prop.sessionNameBuffer ,mySessionName.c_str(), mySessionName.size() + 1); | |
::ControlTrace(0, mySessionName.c_str(), &prop.props, EVENT_TRACE_CONTROL_STOP); | |
TRACEHANDLE handle; | |
ULONG status = ::StartTrace(&handle, mySessionName.c_str(), &prop.props); | |
std::cout << "StartTrace: " << status << std::endl; | |
if (ERROR_ALREADY_EXISTS == status) { | |
std::cout << "already exists" << std::endl; | |
} else if (status != ERROR_SUCCESS) { | |
std::cout << "error" << std::endl; | |
} else { | |
status = ::EnableTrace(true, 0xffffffff, TRACE_LEVEL_VERBOSE, &ClrRuntimeProvider, handle); | |
std::cout << "EnableTrace: " << status << std::endl; | |
} | |
EVENT_TRACE_LOGFILE trace = { }; | |
trace.LoggerName = (char*)mySessionName.c_str(); | |
trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK)(StaticRecordEventCallback); | |
trace.BufferCallback = (PEVENT_TRACE_BUFFER_CALLBACK)(StaticBufferEventCallback); | |
trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_REAL_TIME; | |
TRACEHANDLE sessionHandle = ::OpenTrace(&trace); | |
if (sessionHandle == INVALID_PROCESSTRACE_HANDLE) { | |
std::cout << "OpenTrace error" << std::endl; | |
return -1; | |
} | |
ULONG processStatus = ::ProcessTrace(&sessionHandle, 1, nullptr, nullptr); | |
::ControlTrace(0, mySessionName.c_str(), &prop.props, EVENT_TRACE_CONTROL_STOP); | |
::CloseTrace(handle); | |
::CloseTrace(sessionHandle); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment