mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-06 00:57:19 -04:00
Rearrange etw packages
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package etw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type eventDataDescriptorType uint8
|
||||
|
||||
const (
|
||||
eventDataDescriptorTypeUserData eventDataDescriptorType = iota
|
||||
eventDataDescriptorTypeEventMetadata
|
||||
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
|
||||
}
|
||||
|
||||
type providerHandle windows.Handle
|
||||
|
||||
// ProviderState informs the provider EnableCallback what action is being
|
||||
// performed.
|
||||
type ProviderState uint32
|
||||
|
||||
const (
|
||||
// ProviderStateDisable indicates the provider is being disabled.
|
||||
ProviderStateDisable ProviderState = iota
|
||||
// ProviderStateEnable indicates the provider is being enabled.
|
||||
ProviderStateEnable
|
||||
// ProviderStateCaptureState indicates the provider is having its current
|
||||
// state snap-shotted.
|
||||
ProviderStateCaptureState
|
||||
)
|
||||
|
||||
// EnableCallback is the form of the callback function that receives provider
|
||||
// enable/disable notifications from ETW.
|
||||
type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
|
||||
|
||||
type eventDataDescriptor struct {
|
||||
ptr uint64
|
||||
size uint32
|
||||
dataType eventDataDescriptorType
|
||||
reserved1 uint8
|
||||
reserved2 uint16
|
||||
}
|
||||
|
||||
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.
|
||||
descriptor.ptr = uint64(uintptr(unsafe.Pointer(&buffer.Bytes()[0])))
|
||||
descriptor.size = uint32(buffer.Len())
|
||||
descriptor.dataType = dataType
|
||||
}
|
||||
|
||||
// NewProvider creates and registers a new provider.
|
||||
func NewProvider(name string, id *windows.GUID, callback EnableCallback) (*Provider, error) {
|
||||
innerCallback := func(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, _ uintptr) uintptr {
|
||||
if callback != nil {
|
||||
callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var providerHandle providerHandle
|
||||
if err := eventRegister(id, windows.NewCallback(innerCallback), 0, &providerHandle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var metadataBuffer bytes.Buffer
|
||||
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,
|
||||
metadata: &metadataBuffer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close unregisters the provider.
|
||||
func (provider *Provider) Close() error {
|
||||
return eventUnregister(provider.handle)
|
||||
}
|
||||
|
||||
// WriteEvent writes a single event to ETW, from this provider.
|
||||
func (provider *Provider) WriteEvent(event *Event) error {
|
||||
// Finalize the event metadata buffer by filling in the buffer length at the
|
||||
// beginning.
|
||||
binary.LittleEndian.PutUint16(event.Metadata.buffer.Bytes(), uint16(event.Metadata.buffer.Len()))
|
||||
|
||||
var dataDescriptors [3]eventDataDescriptor
|
||||
dataDescriptors[0].set(eventDataDescriptorTypeProviderMetadata, provider.metadata)
|
||||
dataDescriptors[1].set(eventDataDescriptorTypeEventMetadata, &event.Metadata.buffer)
|
||||
dataDescriptors[2].set(eventDataDescriptorTypeUserData, &event.Data.buffer)
|
||||
|
||||
return eventWriteTransfer(provider.handle, event.Descriptor, nil, nil, 3, &dataDescriptors[0])
|
||||
}
|
||||
Reference in New Issue
Block a user