From 083046a6cdf51f15bf79d52acd601a3c3d145ac1 Mon Sep 17 00:00:00 2001 From: Kevin Parsons Date: Wed, 12 Dec 2018 18:20:51 -0800 Subject: [PATCH] Add comments --- etw/event.go | 53 +++++++++++++++++++++++++++++++++++--------- etw/eventdata.go | 8 +++++++ etw/eventmetadata.go | 7 ++++++ etw/provider.go | 18 ++++++++++----- 4 files changed, 70 insertions(+), 16 deletions(-) diff --git a/etw/event.go b/etw/event.go index 5639d0a..2a01d4f 100644 --- a/etw/event.go +++ b/etw/event.go @@ -1,13 +1,23 @@ package etw +// Channel represents the ETW logging channel that is used. It can be used by +// event consumers to give an event special treatment. type Channel uint8 const ( + // ChannelTracelogging is the default channel for tracelogging events. It is + // not required to be used for tracelogging, but will prevent decoding + // issues for these events on older operating systems. ChannelTracelogging Channel = 11 ) +// Level represents the ETW logging level. There are several predefined levels +// that are commonly used, but technically anything from 0-255 is allowed. +// Lower levels indicate more important events, and 0 indicates an event that +// will always be collected. type Level uint8 +// Predefined ETW log levels. const ( LevelAlways Level = iota LevelCritical @@ -17,15 +27,27 @@ const ( LevelVerbose ) +// Event represents a single ETW event. It can have field metadata and data +// added to it, and then be logged via a provider to actually send it to ETW. type Event struct { Descriptor *EventDescriptor Metadata *EventMetadata Data *EventData } +// NewEvent returns a new instance of an event object. +func NewEvent(name string, descriptor *EventDescriptor) *Event { + return &Event{ + Descriptor: descriptor, + Metadata: NewEventMetadata(name), + Data: &EventData{}, + } +} + +// EventDescriptor represents various metadata for an ETW event. type EventDescriptor struct { - ID uint16 - Version uint8 + id uint16 + version uint8 Channel Channel Level Level Opcode uint8 @@ -33,10 +55,12 @@ type EventDescriptor struct { Keyword uint64 } +// NewEventDescriptor returns an EventDescriptor initialized for use with +// tracelogging. func NewEventDescriptor() *EventDescriptor { return &EventDescriptor{ - ID: 0, - Version: 0, + id: 0, + version: 0, Channel: ChannelTracelogging, Level: LevelVerbose, Opcode: 0, @@ -45,10 +69,19 @@ func NewEventDescriptor() *EventDescriptor { } } -func NewEvent(name string, descriptor *EventDescriptor) *Event { - return &Event{ - Descriptor: descriptor, - Metadata: NewEventMetadata(name), - Data: &EventData{}, - } +// Identity returns the identity of the event. If the identity is not 0, it +// should uniquely identify the other event metadata (contained in +// EventDescriptor, and field metadata). Only the lower 24 bits of this value +// are relevant. +func (ed *EventDescriptor) Identity() uint32 { + return (uint32(ed.version) << 16) & uint32(ed.id) +} + +// SetIdentity sets the identity of the event. If the identity is not 0, it +// should uniquely identify the other event metadata (contained in +// EventDescriptor, and field metadata). Only the lower 24 bits of this value +// are relevant. +func (ed *EventDescriptor) SetIdentity(identity uint32) { + ed.id = uint16(identity) + ed.version = uint8(identity >> 16) } diff --git a/etw/eventdata.go b/etw/eventdata.go index 9fc5c4d..f847b9c 100644 --- a/etw/eventdata.go +++ b/etw/eventdata.go @@ -5,10 +5,18 @@ import ( "encoding/binary" ) +// EventData maintains a buffer which builds up the data for an ETW event. It +// needs to be paired with EventMetadata which describes the event. type EventData struct { buffer bytes.Buffer } +// NewEventData returns a new EventData with an empty buffer. +func NewEventData() *EventData { + return &EventData{} +} + +// AddString appends the data for a string to the end of the buffer. func (ed *EventData) AddString(data string) { binary.Write(&ed.buffer, binary.LittleEndian, []byte(data)) binary.Write(&ed.buffer, binary.LittleEndian, byte(0)) diff --git a/etw/eventmetadata.go b/etw/eventmetadata.go index 9c480d6..e4813c9 100644 --- a/etw/eventmetadata.go +++ b/etw/eventmetadata.go @@ -5,8 +5,10 @@ import ( "encoding/binary" ) +// InType indicates the type of data contained in the ETW event. type InType byte +// Various InType definitions for tracelogging. const ( InTypeNull InType = iota InTypeUnicodeString @@ -24,10 +26,14 @@ const ( InTypeBool32 ) +// EventMetadata maintains a buffer which builds up the metadatadata for an ETW +// event. It needs to be paired with EventData which describes the event. type EventMetadata struct { buffer bytes.Buffer } +// NewEventMetadata returns a new EventMetadata with event name and initial +// metadata written to the buffer. func NewEventMetadata(name string) *EventMetadata { em := EventMetadata{} binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder @@ -37,6 +43,7 @@ func NewEventMetadata(name string) *EventMetadata { return &em } +// AddField appends a single field to the end of the event metadata buffer. func (em *EventMetadata) AddField(name string, inType InType) { binary.Write(&em.buffer, binary.LittleEndian, []byte(name)) // Field name binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name diff --git a/etw/provider.go b/etw/provider.go index 47521eb..4c50278 100644 --- a/etw/provider.go +++ b/etw/provider.go @@ -16,6 +16,9 @@ const ( eventDataDescriptorTypeProviderMetadata ) +// Provider represents an ETW event provider. It is identified by a provider +// name and ID (GUID), which should always have a 1:1 mapping to each other +// (e.g. don't use multiple provider names with the same ID, or vice versa). type Provider struct { handle providerHandle metadata *bytes.Buffer @@ -23,6 +26,8 @@ type Provider struct { type providerHandle windows.Handle +// EnableCallback is the form of the callback function that receives provider +// enable/disable notifications from ETW. type EnableCallback func(*windows.GUID, uint32, byte, uint64, uint64, uintptr) type eventDataDescriptor struct { @@ -34,8 +39,9 @@ type eventDataDescriptor struct { } func (descriptor *eventDataDescriptor) set(dataType eventDataDescriptorType, buffer *bytes.Buffer) { - // Passing a pointer to Go-managed memory as part of a block of memory is risky since the GC doesn't know about it. - // If we find a better way to do this we should use it instead. + // Passing a pointer to Go-managed memory as part of a block of memory is + // risky since the GC doesn't know about it. If we find a better way to do + // this we should use it instead. descriptor.ptr = uint64(uintptr(unsafe.Pointer(&buffer.Bytes()[0]))) descriptor.size = uint32(buffer.Len()) descriptor.dataType = dataType @@ -56,10 +62,10 @@ func NewProvider(name string, id *windows.GUID, callback EnableCallback) (*Provi } var metadataBuffer bytes.Buffer - binary.Write(&metadataBuffer, binary.LittleEndian, uint16(0)) - binary.Write(&metadataBuffer, binary.LittleEndian, []byte(name)) - binary.Write(&metadataBuffer, binary.LittleEndian, byte(0)) - binary.LittleEndian.PutUint16(metadataBuffer.Bytes(), uint16(metadataBuffer.Len())) + binary.Write(&metadataBuffer, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later) + binary.Write(&metadataBuffer, binary.LittleEndian, []byte(name)) // Provider name + binary.Write(&metadataBuffer, binary.LittleEndian, byte(0)) // Null terminator for name + binary.LittleEndian.PutUint16(metadataBuffer.Bytes(), uint16(metadataBuffer.Len())) // Update the size at the beginning of the buffer return &Provider{ handle: providerHandle,