Browse code

Vendor Microsoft/go-winio@c599b533

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2019/03/22 05:11:06
Showing 29 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 # the following lines are in sorted order, FYI
2 2
 github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
3 3
 github.com/Microsoft/hcsshim ada9cb39f715fb568e1030e7613732bb4f1e4aeb
4
-github.com/Microsoft/go-winio 4de24ed3e8c509e6d1f609a8cb6b1c9fd9816e6d
4
+github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13
5 5
 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
6 6
 github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
7 7
 github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
8 8
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-// Package etw provides support for TraceLogging-based ETW (Event Tracing
2
-// for Windows). TraceLogging is a format of ETW events that are self-describing
3
-// (the event contains information on its own schema). This allows them to be
4
-// decoded without needing a separate manifest with event information. The
5
-// implementation here is based on the information found in
6
-// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
7
-// set of C macros.
8
-package etw
9
-
10
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
11
-
12
-//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
13
-//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
14
-//sys eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
15
-//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
16 1
deleted file mode 100644
... ...
@@ -1,65 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/binary"
6
-)
7
-
8
-// EventData maintains a buffer which builds up the data for an ETW event. It
9
-// needs to be paired with EventMetadata which describes the event.
10
-type EventData struct {
11
-	buffer bytes.Buffer
12
-}
13
-
14
-// Bytes returns the raw binary data containing the event data. The returned
15
-// value is not copied from the internal buffer, so it can be mutated by the
16
-// EventData object after it is returned.
17
-func (ed *EventData) Bytes() []byte {
18
-	return ed.buffer.Bytes()
19
-}
20
-
21
-// WriteString appends a string, including the null terminator, to the buffer.
22
-func (ed *EventData) WriteString(data string) {
23
-	ed.buffer.WriteString(data)
24
-	ed.buffer.WriteByte(0)
25
-}
26
-
27
-// WriteInt8 appends a int8 to the buffer.
28
-func (ed *EventData) WriteInt8(value int8) {
29
-	ed.buffer.WriteByte(uint8(value))
30
-}
31
-
32
-// WriteInt16 appends a int16 to the buffer.
33
-func (ed *EventData) WriteInt16(value int16) {
34
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
35
-}
36
-
37
-// WriteInt32 appends a int32 to the buffer.
38
-func (ed *EventData) WriteInt32(value int32) {
39
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
40
-}
41
-
42
-// WriteInt64 appends a int64 to the buffer.
43
-func (ed *EventData) WriteInt64(value int64) {
44
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
45
-}
46
-
47
-// WriteUint8 appends a uint8 to the buffer.
48
-func (ed *EventData) WriteUint8(value uint8) {
49
-	ed.buffer.WriteByte(value)
50
-}
51
-
52
-// WriteUint16 appends a uint16 to the buffer.
53
-func (ed *EventData) WriteUint16(value uint16) {
54
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
55
-}
56
-
57
-// WriteUint32 appends a uint32 to the buffer.
58
-func (ed *EventData) WriteUint32(value uint32) {
59
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
60
-}
61
-
62
-// WriteUint64 appends a uint64 to the buffer.
63
-func (ed *EventData) WriteUint64(value uint64) {
64
-	binary.Write(&ed.buffer, binary.LittleEndian, value)
65
-}
66 1
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"unsafe"
5
-)
6
-
7
-type eventDataDescriptorType uint8
8
-
9
-const (
10
-	eventDataDescriptorTypeUserData eventDataDescriptorType = iota
11
-	eventDataDescriptorTypeEventMetadata
12
-	eventDataDescriptorTypeProviderMetadata
13
-)
14
-
15
-type eventDataDescriptor struct {
16
-	ptr       ptr64
17
-	size      uint32
18
-	dataType  eventDataDescriptorType
19
-	reserved1 uint8
20
-	reserved2 uint16
21
-}
22
-
23
-func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
24
-	return eventDataDescriptor{
25
-		ptr:      ptr64{ptr: unsafe.Pointer(&buffer[0])},
26
-		size:     uint32(len(buffer)),
27
-		dataType: dataType,
28
-	}
29
-}
30 1
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-package etw
2
-
3
-// Channel represents the ETW logging channel that is used. It can be used by
4
-// event consumers to give an event special treatment.
5
-type Channel uint8
6
-
7
-const (
8
-	// ChannelTraceLogging is the default channel for TraceLogging events. It is
9
-	// not required to be used for TraceLogging, but will prevent decoding
10
-	// issues for these events on older operating systems.
11
-	ChannelTraceLogging Channel = 11
12
-)
13
-
14
-// Level represents the ETW logging level. There are several predefined levels
15
-// that are commonly used, but technically anything from 0-255 is allowed.
16
-// Lower levels indicate more important events, and 0 indicates an event that
17
-// will always be collected.
18
-type Level uint8
19
-
20
-// Predefined ETW log levels.
21
-const (
22
-	LevelAlways Level = iota
23
-	LevelCritical
24
-	LevelError
25
-	LevelWarning
26
-	LevelInfo
27
-	LevelVerbose
28
-)
29
-
30
-// EventDescriptor represents various metadata for an ETW event.
31
-type EventDescriptor struct {
32
-	id      uint16
33
-	version uint8
34
-	Channel Channel
35
-	Level   Level
36
-	Opcode  uint8
37
-	Task    uint16
38
-	Keyword uint64
39
-}
40
-
41
-// NewEventDescriptor returns an EventDescriptor initialized for use with
42
-// TraceLogging.
43
-func NewEventDescriptor() *EventDescriptor {
44
-	// Standard TraceLogging events default to the TraceLogging channel, and
45
-	// verbose level.
46
-	return &EventDescriptor{
47
-		Channel: ChannelTraceLogging,
48
-		Level:   LevelVerbose,
49
-	}
50
-}
51
-
52
-// Identity returns the identity of the event. If the identity is not 0, it
53
-// should uniquely identify the other event metadata (contained in
54
-// EventDescriptor, and field metadata). Only the lower 24 bits of this value
55
-// are relevant.
56
-func (ed *EventDescriptor) Identity() uint32 {
57
-	return (uint32(ed.version) << 16) | uint32(ed.id)
58
-}
59
-
60
-// SetIdentity sets the identity of the event. If the identity is not 0, it
61
-// should uniquely identify the other event metadata (contained in
62
-// EventDescriptor, and field metadata). Only the lower 24 bits of this value
63
-// are relevant.
64
-func (ed *EventDescriptor) SetIdentity(identity uint32) {
65
-	ed.id = uint16(identity)
66
-	ed.version = uint8(identity >> 16)
67
-}
68 1
deleted file mode 100644
... ...
@@ -1,177 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/binary"
6
-)
7
-
8
-// InType indicates the type of data contained in the ETW event.
9
-type InType byte
10
-
11
-// Various InType definitions for TraceLogging. These must match the definitions
12
-// found in TraceLoggingProvider.h in the Windows SDK.
13
-const (
14
-	InTypeNull InType = iota
15
-	InTypeUnicodeString
16
-	InTypeANSIString
17
-	InTypeInt8
18
-	InTypeUint8
19
-	InTypeInt16
20
-	InTypeUint16
21
-	InTypeInt32
22
-	InTypeUint32
23
-	InTypeInt64
24
-	InTypeUint64
25
-	InTypeFloat
26
-	InTypeDouble
27
-	InTypeBool32
28
-	InTypeBinary
29
-	InTypeGUID
30
-	InTypePointerUnsupported
31
-	InTypeFileTime
32
-	InTypeSystemTime
33
-	InTypeSID
34
-	InTypeHexInt32
35
-	InTypeHexInt64
36
-	InTypeCountedString
37
-	InTypeCountedANSIString
38
-	InTypeStruct
39
-	InTypeCountedBinary
40
-	InTypeCountedArray InType = 32
41
-	InTypeArray        InType = 64
42
-)
43
-
44
-// OutType specifies a hint to the event decoder for how the value should be
45
-// formatted.
46
-type OutType byte
47
-
48
-// Various OutType definitions for TraceLogging. These must match the
49
-// definitions found in TraceLoggingProvider.h in the Windows SDK.
50
-const (
51
-	// OutTypeDefault indicates that the default formatting for the InType will
52
-	// be used by the event decoder.
53
-	OutTypeDefault OutType = iota
54
-	OutTypeNoPrint
55
-	OutTypeString
56
-	OutTypeBoolean
57
-	OutTypeHex
58
-	OutTypePID
59
-	OutTypeTID
60
-	OutTypePort
61
-	OutTypeIPv4
62
-	OutTypeIPv6
63
-	OutTypeSocketAddress
64
-	OutTypeXML
65
-	OutTypeJSON
66
-	OutTypeWin32Error
67
-	OutTypeNTStatus
68
-	OutTypeHResult
69
-	OutTypeFileTime
70
-	OutTypeSigned
71
-	OutTypeUnsigned
72
-	OutTypeUTF8              OutType = 35
73
-	OutTypePKCS7WithTypeInfo OutType = 36
74
-	OutTypeCodePointer       OutType = 37
75
-	OutTypeDateTimeUTC       OutType = 38
76
-)
77
-
78
-// EventMetadata maintains a buffer which builds up the metadata for an ETW
79
-// event. It needs to be paired with EventData which describes the event.
80
-type EventMetadata struct {
81
-	buffer bytes.Buffer
82
-}
83
-
84
-// Bytes returns the raw binary data containing the event metadata. Before being
85
-// returned, the current size of the buffer is written to the start of the
86
-// buffer. The returned value is not copied from the internal buffer, so it can
87
-// be mutated by the EventMetadata object after it is returned.
88
-func (em *EventMetadata) Bytes() []byte {
89
-	// Finalize the event metadata buffer by filling in the buffer length at the
90
-	// beginning.
91
-	binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
92
-	return em.buffer.Bytes()
93
-}
94
-
95
-// WriteEventHeader writes the metadata for the start of an event to the buffer.
96
-// This specifies the event name and tags.
97
-func (em *EventMetadata) WriteEventHeader(name string, tags uint32) {
98
-	binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
99
-	em.writeTags(tags)
100
-	em.buffer.WriteString(name)
101
-	em.buffer.WriteByte(0) // Null terminator for name
102
-}
103
-
104
-func (em *EventMetadata) writeField(name string, inType InType, outType OutType, tags uint32, arrSize uint16) {
105
-	em.buffer.WriteString(name)
106
-	em.buffer.WriteByte(0) // Null terminator for name
107
-
108
-	if outType == OutTypeDefault && tags == 0 {
109
-		em.buffer.WriteByte(byte(inType))
110
-	} else {
111
-		em.buffer.WriteByte(byte(inType | 128))
112
-		if tags == 0 {
113
-			em.buffer.WriteByte(byte(outType))
114
-		} else {
115
-			em.buffer.WriteByte(byte(outType | 128))
116
-			em.writeTags(tags)
117
-		}
118
-	}
119
-
120
-	if arrSize != 0 {
121
-		binary.Write(&em.buffer, binary.LittleEndian, arrSize)
122
-	}
123
-}
124
-
125
-// writeTags writes out the tags value to the event metadata. Tags is a 28-bit
126
-// value, interpreted as bit flags, which are only relevant to the event
127
-// consumer. The event consumer may choose to attribute special meaning to tags
128
-// (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
129
-// bytes, each containing 7 bits of tag value, with the high bit set if there is
130
-// more tag data in the following byte. This allows for a more compact
131
-// representation when not all of the tag bits are needed.
132
-func (em *EventMetadata) writeTags(tags uint32) {
133
-	// Only use the top 28 bits of the tags value.
134
-	tags &= 0xfffffff
135
-
136
-	for {
137
-		// Tags are written with the most significant bits (e.g. 21-27) first.
138
-		val := tags >> 21
139
-
140
-		if tags&0x1fffff == 0 {
141
-			// If there is no more data to write after this, write this value
142
-			// without the high bit set, and return.
143
-			em.buffer.WriteByte(byte(val & 0x7f))
144
-			return
145
-		}
146
-
147
-		em.buffer.WriteByte(byte(val | 0x80))
148
-
149
-		tags <<= 7
150
-	}
151
-}
152
-
153
-// WriteField writes the metadata for a simple field to the buffer.
154
-func (em *EventMetadata) WriteField(name string, inType InType, outType OutType, tags uint32) {
155
-	em.writeField(name, inType, outType, tags, 0)
156
-}
157
-
158
-// WriteArray writes the metadata for an array field to the buffer. The number
159
-// of elements in the array must be written as a uint16 in the event data,
160
-// immediately preceeding the event data.
161
-func (em *EventMetadata) WriteArray(name string, inType InType, outType OutType, tags uint32) {
162
-	em.writeField(name, inType|InTypeArray, outType, tags, 0)
163
-}
164
-
165
-// WriteCountedArray writes the metadata for an array field to the buffer. The
166
-// size of a counted array is fixed, and the size is written into the metadata
167
-// directly.
168
-func (em *EventMetadata) WriteCountedArray(name string, count uint16, inType InType, outType OutType, tags uint32) {
169
-	em.writeField(name, inType|InTypeCountedArray, outType, tags, count)
170
-}
171
-
172
-// WriteStruct writes the metadata for a nested struct to the buffer. The struct
173
-// contains the next N fields in the metadata, where N is specified by the
174
-// fieldCount argument.
175
-func (em *EventMetadata) WriteStruct(name string, fieldCount uint8, tags uint32) {
176
-	em.writeField(name, InTypeStruct, OutType(fieldCount), tags, 0)
177
-}
178 1
deleted file mode 100644
... ...
@@ -1,63 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"golang.org/x/sys/windows"
5
-)
6
-
7
-type eventOptions struct {
8
-	descriptor        *EventDescriptor
9
-	activityID        *windows.GUID
10
-	relatedActivityID *windows.GUID
11
-	tags              uint32
12
-}
13
-
14
-// EventOpt defines the option function type that can be passed to
15
-// Provider.WriteEvent to specify general event options, such as level and
16
-// keyword.
17
-type EventOpt func(options *eventOptions)
18
-
19
-// WithEventOpts returns the variadic arguments as a single slice.
20
-func WithEventOpts(opts ...EventOpt) []EventOpt {
21
-	return opts
22
-}
23
-
24
-// WithLevel specifies the level of the event to be written.
25
-func WithLevel(level Level) EventOpt {
26
-	return func(options *eventOptions) {
27
-		options.descriptor.Level = level
28
-	}
29
-}
30
-
31
-// WithKeyword specifies the keywords of the event to be written. Multiple uses
32
-// of this option are OR'd together.
33
-func WithKeyword(keyword uint64) EventOpt {
34
-	return func(options *eventOptions) {
35
-		options.descriptor.Keyword |= keyword
36
-	}
37
-}
38
-
39
-func WithChannel(channel Channel) EventOpt {
40
-	return func(options *eventOptions) {
41
-		options.descriptor.Channel = channel
42
-	}
43
-}
44
-
45
-// WithTags specifies the tags of the event to be written. Tags is a 28-bit
46
-// value (top 4 bits are ignored) which are interpreted by the event consumer.
47
-func WithTags(newTags uint32) EventOpt {
48
-	return func(options *eventOptions) {
49
-		options.tags |= newTags
50
-	}
51
-}
52
-
53
-func WithActivityID(activityID *windows.GUID) EventOpt {
54
-	return func(options *eventOptions) {
55
-		options.activityID = activityID
56
-	}
57
-}
58
-
59
-func WithRelatedActivityID(activityID *windows.GUID) EventOpt {
60
-	return func(options *eventOptions) {
61
-		options.relatedActivityID = activityID
62
-	}
63
-}
64 1
deleted file mode 100644
... ...
@@ -1,379 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"math"
5
-	"unsafe"
6
-)
7
-
8
-// FieldOpt defines the option function type that can be passed to
9
-// Provider.WriteEvent to add fields to the event.
10
-type FieldOpt func(em *EventMetadata, ed *EventData)
11
-
12
-// WithFields returns the variadic arguments as a single slice.
13
-func WithFields(opts ...FieldOpt) []FieldOpt {
14
-	return opts
15
-}
16
-
17
-// BoolField adds a single bool field to the event.
18
-func BoolField(name string, value bool) FieldOpt {
19
-	return func(em *EventMetadata, ed *EventData) {
20
-		em.WriteField(name, InTypeUint8, OutTypeBoolean, 0)
21
-		bool8 := uint8(0)
22
-		if value {
23
-			bool8 = uint8(1)
24
-		}
25
-		ed.WriteUint8(bool8)
26
-	}
27
-}
28
-
29
-// BoolArray adds an array of bool to the event.
30
-func BoolArray(name string, values []bool) FieldOpt {
31
-	return func(em *EventMetadata, ed *EventData) {
32
-		em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0)
33
-		ed.WriteUint16(uint16(len(values)))
34
-		for _, v := range values {
35
-			bool8 := uint8(0)
36
-			if v {
37
-				bool8 = uint8(1)
38
-			}
39
-			ed.WriteUint8(bool8)
40
-		}
41
-	}
42
-}
43
-
44
-// StringField adds a single string field to the event.
45
-func StringField(name string, value string) FieldOpt {
46
-	return func(em *EventMetadata, ed *EventData) {
47
-		em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0)
48
-		ed.WriteString(value)
49
-	}
50
-}
51
-
52
-// StringArray adds an array of string to the event.
53
-func StringArray(name string, values []string) FieldOpt {
54
-	return func(em *EventMetadata, ed *EventData) {
55
-		em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0)
56
-		ed.WriteUint16(uint16(len(values)))
57
-		for _, v := range values {
58
-			ed.WriteString(v)
59
-		}
60
-	}
61
-}
62
-
63
-// IntField adds a single int field to the event.
64
-func IntField(name string, value int) FieldOpt {
65
-	switch unsafe.Sizeof(value) {
66
-	case 4:
67
-		return Int32Field(name, int32(value))
68
-	case 8:
69
-		return Int64Field(name, int64(value))
70
-	default:
71
-		panic("Unsupported int size")
72
-	}
73
-}
74
-
75
-// IntArray adds an array of int to the event.
76
-func IntArray(name string, values []int) FieldOpt {
77
-	inType := InTypeNull
78
-	var writeItem func(*EventData, int)
79
-	switch unsafe.Sizeof(values[0]) {
80
-	case 4:
81
-		inType = InTypeInt32
82
-		writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) }
83
-	case 8:
84
-		inType = InTypeInt64
85
-		writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) }
86
-	default:
87
-		panic("Unsupported int size")
88
-	}
89
-
90
-	return func(em *EventMetadata, ed *EventData) {
91
-		em.WriteArray(name, inType, OutTypeDefault, 0)
92
-		ed.WriteUint16(uint16(len(values)))
93
-		for _, v := range values {
94
-			writeItem(ed, v)
95
-		}
96
-	}
97
-}
98
-
99
-// Int8Field adds a single int8 field to the event.
100
-func Int8Field(name string, value int8) FieldOpt {
101
-	return func(em *EventMetadata, ed *EventData) {
102
-		em.WriteField(name, InTypeInt8, OutTypeDefault, 0)
103
-		ed.WriteInt8(value)
104
-	}
105
-}
106
-
107
-// Int8Array adds an array of int8 to the event.
108
-func Int8Array(name string, values []int8) FieldOpt {
109
-	return func(em *EventMetadata, ed *EventData) {
110
-		em.WriteArray(name, InTypeInt8, OutTypeDefault, 0)
111
-		ed.WriteUint16(uint16(len(values)))
112
-		for _, v := range values {
113
-			ed.WriteInt8(v)
114
-		}
115
-	}
116
-}
117
-
118
-// Int16Field adds a single int16 field to the event.
119
-func Int16Field(name string, value int16) FieldOpt {
120
-	return func(em *EventMetadata, ed *EventData) {
121
-		em.WriteField(name, InTypeInt16, OutTypeDefault, 0)
122
-		ed.WriteInt16(value)
123
-	}
124
-}
125
-
126
-// Int16Array adds an array of int16 to the event.
127
-func Int16Array(name string, values []int16) FieldOpt {
128
-	return func(em *EventMetadata, ed *EventData) {
129
-		em.WriteArray(name, InTypeInt16, OutTypeDefault, 0)
130
-		ed.WriteUint16(uint16(len(values)))
131
-		for _, v := range values {
132
-			ed.WriteInt16(v)
133
-		}
134
-	}
135
-}
136
-
137
-// Int32Field adds a single int32 field to the event.
138
-func Int32Field(name string, value int32) FieldOpt {
139
-	return func(em *EventMetadata, ed *EventData) {
140
-		em.WriteField(name, InTypeInt32, OutTypeDefault, 0)
141
-		ed.WriteInt32(value)
142
-	}
143
-}
144
-
145
-// Int32Array adds an array of int32 to the event.
146
-func Int32Array(name string, values []int32) FieldOpt {
147
-	return func(em *EventMetadata, ed *EventData) {
148
-		em.WriteArray(name, InTypeInt32, OutTypeDefault, 0)
149
-		ed.WriteUint16(uint16(len(values)))
150
-		for _, v := range values {
151
-			ed.WriteInt32(v)
152
-		}
153
-	}
154
-}
155
-
156
-// Int64Field adds a single int64 field to the event.
157
-func Int64Field(name string, value int64) FieldOpt {
158
-	return func(em *EventMetadata, ed *EventData) {
159
-		em.WriteField(name, InTypeInt64, OutTypeDefault, 0)
160
-		ed.WriteInt64(value)
161
-	}
162
-}
163
-
164
-// Int64Array adds an array of int64 to the event.
165
-func Int64Array(name string, values []int64) FieldOpt {
166
-	return func(em *EventMetadata, ed *EventData) {
167
-		em.WriteArray(name, InTypeInt64, OutTypeDefault, 0)
168
-		ed.WriteUint16(uint16(len(values)))
169
-		for _, v := range values {
170
-			ed.WriteInt64(v)
171
-		}
172
-	}
173
-}
174
-
175
-// UintField adds a single uint field to the event.
176
-func UintField(name string, value uint) FieldOpt {
177
-	switch unsafe.Sizeof(value) {
178
-	case 4:
179
-		return Uint32Field(name, uint32(value))
180
-	case 8:
181
-		return Uint64Field(name, uint64(value))
182
-	default:
183
-		panic("Unsupported uint size")
184
-	}
185
-}
186
-
187
-// UintArray adds an array of uint to the event.
188
-func UintArray(name string, values []uint) FieldOpt {
189
-	inType := InTypeNull
190
-	var writeItem func(*EventData, uint)
191
-	switch unsafe.Sizeof(values[0]) {
192
-	case 4:
193
-		inType = InTypeUint32
194
-		writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) }
195
-	case 8:
196
-		inType = InTypeUint64
197
-		writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) }
198
-	default:
199
-		panic("Unsupported uint size")
200
-	}
201
-
202
-	return func(em *EventMetadata, ed *EventData) {
203
-		em.WriteArray(name, inType, OutTypeDefault, 0)
204
-		ed.WriteUint16(uint16(len(values)))
205
-		for _, v := range values {
206
-			writeItem(ed, v)
207
-		}
208
-	}
209
-}
210
-
211
-// Uint8Field adds a single uint8 field to the event.
212
-func Uint8Field(name string, value uint8) FieldOpt {
213
-	return func(em *EventMetadata, ed *EventData) {
214
-		em.WriteField(name, InTypeUint8, OutTypeDefault, 0)
215
-		ed.WriteUint8(value)
216
-	}
217
-}
218
-
219
-// Uint8Array adds an array of uint8 to the event.
220
-func Uint8Array(name string, values []uint8) FieldOpt {
221
-	return func(em *EventMetadata, ed *EventData) {
222
-		em.WriteArray(name, InTypeUint8, OutTypeDefault, 0)
223
-		ed.WriteUint16(uint16(len(values)))
224
-		for _, v := range values {
225
-			ed.WriteUint8(v)
226
-		}
227
-	}
228
-}
229
-
230
-// Uint16Field adds a single uint16 field to the event.
231
-func Uint16Field(name string, value uint16) FieldOpt {
232
-	return func(em *EventMetadata, ed *EventData) {
233
-		em.WriteField(name, InTypeUint16, OutTypeDefault, 0)
234
-		ed.WriteUint16(value)
235
-	}
236
-}
237
-
238
-// Uint16Array adds an array of uint16 to the event.
239
-func Uint16Array(name string, values []uint16) FieldOpt {
240
-	return func(em *EventMetadata, ed *EventData) {
241
-		em.WriteArray(name, InTypeUint16, OutTypeDefault, 0)
242
-		ed.WriteUint16(uint16(len(values)))
243
-		for _, v := range values {
244
-			ed.WriteUint16(v)
245
-		}
246
-	}
247
-}
248
-
249
-// Uint32Field adds a single uint32 field to the event.
250
-func Uint32Field(name string, value uint32) FieldOpt {
251
-	return func(em *EventMetadata, ed *EventData) {
252
-		em.WriteField(name, InTypeUint32, OutTypeDefault, 0)
253
-		ed.WriteUint32(value)
254
-	}
255
-}
256
-
257
-// Uint32Array adds an array of uint32 to the event.
258
-func Uint32Array(name string, values []uint32) FieldOpt {
259
-	return func(em *EventMetadata, ed *EventData) {
260
-		em.WriteArray(name, InTypeUint32, OutTypeDefault, 0)
261
-		ed.WriteUint16(uint16(len(values)))
262
-		for _, v := range values {
263
-			ed.WriteUint32(v)
264
-		}
265
-	}
266
-}
267
-
268
-// Uint64Field adds a single uint64 field to the event.
269
-func Uint64Field(name string, value uint64) FieldOpt {
270
-	return func(em *EventMetadata, ed *EventData) {
271
-		em.WriteField(name, InTypeUint64, OutTypeDefault, 0)
272
-		ed.WriteUint64(value)
273
-	}
274
-}
275
-
276
-// Uint64Array adds an array of uint64 to the event.
277
-func Uint64Array(name string, values []uint64) FieldOpt {
278
-	return func(em *EventMetadata, ed *EventData) {
279
-		em.WriteArray(name, InTypeUint64, OutTypeDefault, 0)
280
-		ed.WriteUint16(uint16(len(values)))
281
-		for _, v := range values {
282
-			ed.WriteUint64(v)
283
-		}
284
-	}
285
-}
286
-
287
-// UintptrField adds a single uintptr field to the event.
288
-func UintptrField(name string, value uintptr) FieldOpt {
289
-	inType := InTypeNull
290
-	var writeItem func(*EventData, uintptr)
291
-	switch unsafe.Sizeof(value) {
292
-	case 4:
293
-		inType = InTypeHexInt32
294
-		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
295
-	case 8:
296
-		inType = InTypeHexInt64
297
-		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
298
-	default:
299
-		panic("Unsupported uintptr size")
300
-	}
301
-
302
-	return func(em *EventMetadata, ed *EventData) {
303
-		em.WriteField(name, inType, OutTypeDefault, 0)
304
-		writeItem(ed, value)
305
-	}
306
-}
307
-
308
-// UintptrArray adds an array of uintptr to the event.
309
-func UintptrArray(name string, values []uintptr) FieldOpt {
310
-	inType := InTypeNull
311
-	var writeItem func(*EventData, uintptr)
312
-	switch unsafe.Sizeof(values[0]) {
313
-	case 4:
314
-		inType = InTypeHexInt32
315
-		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
316
-	case 8:
317
-		inType = InTypeHexInt64
318
-		writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
319
-	default:
320
-		panic("Unsupported uintptr size")
321
-	}
322
-
323
-	return func(em *EventMetadata, ed *EventData) {
324
-		em.WriteArray(name, inType, OutTypeDefault, 0)
325
-		ed.WriteUint16(uint16(len(values)))
326
-		for _, v := range values {
327
-			writeItem(ed, v)
328
-		}
329
-	}
330
-}
331
-
332
-// Float32Field adds a single float32 field to the event.
333
-func Float32Field(name string, value float32) FieldOpt {
334
-	return func(em *EventMetadata, ed *EventData) {
335
-		em.WriteField(name, InTypeFloat, OutTypeDefault, 0)
336
-		ed.WriteUint32(math.Float32bits(value))
337
-	}
338
-}
339
-
340
-// Float32Array adds an array of float32 to the event.
341
-func Float32Array(name string, values []float32) FieldOpt {
342
-	return func(em *EventMetadata, ed *EventData) {
343
-		em.WriteArray(name, InTypeFloat, OutTypeDefault, 0)
344
-		ed.WriteUint16(uint16(len(values)))
345
-		for _, v := range values {
346
-			ed.WriteUint32(math.Float32bits(v))
347
-		}
348
-	}
349
-}
350
-
351
-// Float64Field adds a single float64 field to the event.
352
-func Float64Field(name string, value float64) FieldOpt {
353
-	return func(em *EventMetadata, ed *EventData) {
354
-		em.WriteField(name, InTypeDouble, OutTypeDefault, 0)
355
-		ed.WriteUint64(math.Float64bits(value))
356
-	}
357
-}
358
-
359
-// Float64Array adds an array of float64 to the event.
360
-func Float64Array(name string, values []float64) FieldOpt {
361
-	return func(em *EventMetadata, ed *EventData) {
362
-		em.WriteArray(name, InTypeDouble, OutTypeDefault, 0)
363
-		ed.WriteUint16(uint16(len(values)))
364
-		for _, v := range values {
365
-			ed.WriteUint64(math.Float64bits(v))
366
-		}
367
-	}
368
-}
369
-
370
-// Struct adds a nested struct to the event, the FieldOpts in the opts argument
371
-// are used to specify the fields of the struct.
372
-func Struct(name string, opts ...FieldOpt) FieldOpt {
373
-	return func(em *EventMetadata, ed *EventData) {
374
-		em.WriteStruct(name, uint8(len(opts)), 0)
375
-		for _, opt := range opts {
376
-			opt(em, ed)
377
-		}
378
-	}
379
-}
380 1
deleted file mode 100644
... ...
@@ -1,279 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"bytes"
5
-	"crypto/sha1"
6
-	"encoding/binary"
7
-	"encoding/hex"
8
-	"fmt"
9
-	"strings"
10
-	"unicode/utf16"
11
-	"unsafe"
12
-
13
-	"golang.org/x/sys/windows"
14
-)
15
-
16
-// Provider represents an ETW event provider. It is identified by a provider
17
-// name and ID (GUID), which should always have a 1:1 mapping to each other
18
-// (e.g. don't use multiple provider names with the same ID, or vice versa).
19
-type Provider struct {
20
-	ID         *windows.GUID
21
-	handle     providerHandle
22
-	metadata   []byte
23
-	callback   EnableCallback
24
-	index      uint
25
-	enabled    bool
26
-	level      Level
27
-	keywordAny uint64
28
-	keywordAll uint64
29
-}
30
-
31
-// String returns the `provider`.ID as a string
32
-func (provider *Provider) String() string {
33
-	data1 := make([]byte, 4)
34
-	binary.BigEndian.PutUint32(data1, provider.ID.Data1)
35
-	data2 := make([]byte, 2)
36
-	binary.BigEndian.PutUint16(data2, provider.ID.Data2)
37
-	data3 := make([]byte, 2)
38
-	binary.BigEndian.PutUint16(data3, provider.ID.Data3)
39
-	return fmt.Sprintf(
40
-		"%s-%s-%s-%s-%s",
41
-		hex.EncodeToString(data1),
42
-		hex.EncodeToString(data2),
43
-		hex.EncodeToString(data3),
44
-		hex.EncodeToString(provider.ID.Data4[:2]),
45
-		hex.EncodeToString(provider.ID.Data4[2:]))
46
-}
47
-
48
-type providerHandle windows.Handle
49
-
50
-// ProviderState informs the provider EnableCallback what action is being
51
-// performed.
52
-type ProviderState uint32
53
-
54
-const (
55
-	// ProviderStateDisable indicates the provider is being disabled.
56
-	ProviderStateDisable ProviderState = iota
57
-	// ProviderStateEnable indicates the provider is being enabled.
58
-	ProviderStateEnable
59
-	// ProviderStateCaptureState indicates the provider is having its current
60
-	// state snap-shotted.
61
-	ProviderStateCaptureState
62
-)
63
-
64
-type eventInfoClass uint32
65
-
66
-const (
67
-	eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
68
-	eventInfoClassProviderSetReserved1
69
-	eventInfoClassProviderSetTraits
70
-	eventInfoClassProviderUseDescriptorType
71
-)
72
-
73
-// EnableCallback is the form of the callback function that receives provider
74
-// enable/disable notifications from ETW.
75
-type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
76
-
77
-func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
78
-	provider := providers.getProvider(uint(i))
79
-
80
-	switch state {
81
-	case ProviderStateDisable:
82
-		provider.enabled = false
83
-	case ProviderStateEnable:
84
-		provider.enabled = true
85
-		provider.level = level
86
-		provider.keywordAny = matchAnyKeyword
87
-		provider.keywordAll = matchAllKeyword
88
-	}
89
-
90
-	if provider.callback != nil {
91
-		provider.callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData)
92
-	}
93
-}
94
-
95
-// providerCallbackAdapter acts as the first-level callback from the C/ETW side
96
-// for provider notifications. Because Go has trouble with callback arguments of
97
-// different size, it has only pointer-sized arguments, which are then cast to
98
-// the appropriate types when calling providerCallback.
99
-func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
100
-	providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
101
-	return 0
102
-}
103
-
104
-// providerIDFromName generates a provider ID based on the provider name. It
105
-// uses the same algorithm as used by .NET's EventSource class, which is based
106
-// on RFC 4122. More information on the algorithm can be found here:
107
-// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/
108
-// The algorithm is roughly:
109
-// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
110
-// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
111
-func providerIDFromName(name string) *windows.GUID {
112
-	buffer := sha1.New()
113
-
114
-	namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
115
-	buffer.Write(namespace)
116
-
117
-	binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
118
-
119
-	sum := buffer.Sum(nil)
120
-	sum[7] = (sum[7] & 0xf) | 0x50
121
-
122
-	return &windows.GUID{
123
-		Data1: binary.LittleEndian.Uint32(sum[0:4]),
124
-		Data2: binary.LittleEndian.Uint16(sum[4:6]),
125
-		Data3: binary.LittleEndian.Uint16(sum[6:8]),
126
-		Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]},
127
-	}
128
-}
129
-
130
-// NewProvider creates and registers a new ETW provider. The provider ID is
131
-// generated based on the provider name.
132
-func NewProvider(name string, callback EnableCallback) (provider *Provider, err error) {
133
-	return NewProviderWithID(name, providerIDFromName(name), callback)
134
-}
135
-
136
-// NewProviderWithID creates and registers a new ETW provider, allowing the
137
-// provider ID to be manually specified. This is most useful when there is an
138
-// existing provider ID that must be used to conform to existing diagnostic
139
-// infrastructure.
140
-func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) {
141
-	providerCallbackOnce.Do(func() {
142
-		globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
143
-	})
144
-
145
-	provider = providers.newProvider()
146
-	defer func() {
147
-		if err != nil {
148
-			providers.removeProvider(provider)
149
-		}
150
-	}()
151
-	provider.ID = id
152
-	provider.callback = callback
153
-
154
-	if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
155
-		return nil, err
156
-	}
157
-
158
-	metadata := &bytes.Buffer{}
159
-	binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
160
-	metadata.WriteString(name)
161
-	metadata.WriteByte(0)                                                   // Null terminator for name
162
-	binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
163
-	provider.metadata = metadata.Bytes()
164
-
165
-	if err := eventSetInformation(
166
-		provider.handle,
167
-		eventInfoClassProviderSetTraits,
168
-		uintptr(unsafe.Pointer(&provider.metadata[0])),
169
-		uint32(len(provider.metadata))); err != nil {
170
-
171
-		return nil, err
172
-	}
173
-
174
-	return provider, nil
175
-}
176
-
177
-// Close unregisters the provider.
178
-func (provider *Provider) Close() error {
179
-	providers.removeProvider(provider)
180
-	return eventUnregister(provider.handle)
181
-}
182
-
183
-// IsEnabled calls IsEnabledForLevelAndKeywords with LevelAlways and all
184
-// keywords set.
185
-func (provider *Provider) IsEnabled() bool {
186
-	return provider.IsEnabledForLevelAndKeywords(LevelAlways, ^uint64(0))
187
-}
188
-
189
-// IsEnabledForLevel calls IsEnabledForLevelAndKeywords with the specified level
190
-// and all keywords set.
191
-func (provider *Provider) IsEnabledForLevel(level Level) bool {
192
-	return provider.IsEnabledForLevelAndKeywords(level, ^uint64(0))
193
-}
194
-
195
-// IsEnabledForLevelAndKeywords allows event producer code to check if there are
196
-// any event sessions that are interested in an event, based on the event level
197
-// and keywords. Although this check happens automatically in the ETW
198
-// infrastructure, it can be useful to check if an event will actually be
199
-// consumed before doing expensive work to build the event data.
200
-func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
201
-	if !provider.enabled {
202
-		return false
203
-	}
204
-
205
-	// ETW automatically sets the level to 255 if it is specified as 0, so we
206
-	// don't need to worry about the level=0 (all events) case.
207
-	if level > provider.level {
208
-		return false
209
-	}
210
-
211
-	if keywords != 0 && (keywords&provider.keywordAny == 0 || keywords&provider.keywordAll != provider.keywordAll) {
212
-		return false
213
-	}
214
-
215
-	return true
216
-}
217
-
218
-// WriteEvent writes a single ETW event from the provider. The event is
219
-// constructed based on the EventOpt and FieldOpt values that are passed as
220
-// opts.
221
-func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
222
-	options := eventOptions{descriptor: NewEventDescriptor()}
223
-	em := &EventMetadata{}
224
-	ed := &EventData{}
225
-
226
-	// We need to evaluate the EventOpts first since they might change tags, and
227
-	// we write out the tags before evaluating FieldOpts.
228
-	for _, opt := range eventOpts {
229
-		opt(&options)
230
-	}
231
-
232
-	if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) {
233
-		return nil
234
-	}
235
-
236
-	em.WriteEventHeader(name, options.tags)
237
-
238
-	for _, opt := range fieldOpts {
239
-		opt(em, ed)
240
-	}
241
-
242
-	// Don't pass a data blob if there is no event data. There will always be
243
-	// event metadata (e.g. for the name) so we don't need to do this check for
244
-	// the metadata.
245
-	dataBlobs := [][]byte{}
246
-	if len(ed.Bytes()) > 0 {
247
-		dataBlobs = [][]byte{ed.Bytes()}
248
-	}
249
-
250
-	return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, dataBlobs)
251
-}
252
-
253
-// WriteEventRaw writes a single ETW event from the provider. This function is
254
-// less abstracted than WriteEvent, and presents a fairly direct interface to
255
-// the event writing functionality. It expects a series of event metadata and
256
-// event data blobs to be passed in, which must conform to the TraceLogging
257
-// schema. The functions on EventMetadata and EventData can help with creating
258
-// these blobs. The blobs of each type are effectively concatenated together by
259
-// the ETW infrastructure.
260
-func (provider *Provider) WriteEventRaw(
261
-	descriptor *EventDescriptor,
262
-	activityID *windows.GUID,
263
-	relatedActivityID *windows.GUID,
264
-	metadataBlobs [][]byte,
265
-	dataBlobs [][]byte) error {
266
-
267
-	dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
268
-	dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
269
-
270
-	dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
271
-	for _, blob := range metadataBlobs {
272
-		dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
273
-	}
274
-	for _, blob := range dataBlobs {
275
-		dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
276
-	}
277
-
278
-	return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0])
279
-}
280 1
deleted file mode 100644
... ...
@@ -1,52 +0,0 @@
1
-package etw
2
-
3
-import (
4
-	"sync"
5
-)
6
-
7
-// Because the provider callback function needs to be able to access the
8
-// provider data when it is invoked by ETW, we need to keep provider data stored
9
-// in a global map based on an index. The index is passed as the callback
10
-// context to ETW.
11
-type providerMap struct {
12
-	m    map[uint]*Provider
13
-	i    uint
14
-	lock sync.Mutex
15
-	once sync.Once
16
-}
17
-
18
-var providers = providerMap{
19
-	m: make(map[uint]*Provider),
20
-}
21
-
22
-func (p *providerMap) newProvider() *Provider {
23
-	p.lock.Lock()
24
-	defer p.lock.Unlock()
25
-
26
-	i := p.i
27
-	p.i++
28
-
29
-	provider := &Provider{
30
-		index: i,
31
-	}
32
-
33
-	p.m[i] = provider
34
-	return provider
35
-}
36
-
37
-func (p *providerMap) removeProvider(provider *Provider) {
38
-	p.lock.Lock()
39
-	defer p.lock.Unlock()
40
-
41
-	delete(p.m, provider.index)
42
-}
43
-
44
-func (p *providerMap) getProvider(index uint) *Provider {
45
-	p.lock.Lock()
46
-	defer p.lock.Unlock()
47
-
48
-	return p.m[index]
49
-}
50
-
51
-var providerCallbackOnce sync.Once
52
-var globalProviderCallback uintptr
53 1
deleted file mode 100644
... ...
@@ -1,16 +0,0 @@
1
-// +build 386 arm
2
-
3
-package etw
4
-
5
-import (
6
-	"unsafe"
7
-)
8
-
9
-// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
10
-// be 64 bits, regardless of the actual size of a pointer on the platform. This
11
-// is intended for use with certain Windows APIs that expect a pointer as a
12
-// ULONGLONG.
13
-type ptr64 struct {
14
-	ptr unsafe.Pointer
15
-	_   uint32
16
-}
17 1
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-// +build amd64 arm64
2
-
3
-package etw
4
-
5
-import (
6
-	"unsafe"
7
-)
8
-
9
-// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
10
-// be 64 bits, regardless of the actual size of a pointer on the platform. This
11
-// is intended for use with certain Windows APIs that expect a pointer as a
12
-// ULONGLONG.
13
-type ptr64 struct {
14
-	ptr unsafe.Pointer
15
-}
16 1
deleted file mode 100644
... ...
@@ -1,78 +0,0 @@
1
-// Code generated by 'go generate'; DO NOT EDIT.
2
-
3
-package etw
4
-
5
-import (
6
-	"syscall"
7
-	"unsafe"
8
-
9
-	"golang.org/x/sys/windows"
10
-)
11
-
12
-var _ unsafe.Pointer
13
-
14
-// Do the interface allocations only once for common
15
-// Errno values.
16
-const (
17
-	errnoERROR_IO_PENDING = 997
18
-)
19
-
20
-var (
21
-	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
22
-)
23
-
24
-// errnoErr returns common boxed Errno values, to prevent
25
-// allocations at runtime.
26
-func errnoErr(e syscall.Errno) error {
27
-	switch e {
28
-	case 0:
29
-		return nil
30
-	case errnoERROR_IO_PENDING:
31
-		return errERROR_IO_PENDING
32
-	}
33
-	// TODO: add more here, after collecting data on the common
34
-	// error values see on Windows. (perhaps when running
35
-	// all.bat?)
36
-	return e
37
-}
38
-
39
-var (
40
-	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
41
-
42
-	procEventRegister       = modadvapi32.NewProc("EventRegister")
43
-	procEventUnregister     = modadvapi32.NewProc("EventUnregister")
44
-	procEventWriteTransfer  = modadvapi32.NewProc("EventWriteTransfer")
45
-	procEventSetInformation = modadvapi32.NewProc("EventSetInformation")
46
-)
47
-
48
-func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) {
49
-	r0, _, _ := syscall.Syscall6(procEventRegister.Addr(), 4, uintptr(unsafe.Pointer(providerId)), uintptr(callback), uintptr(callbackContext), uintptr(unsafe.Pointer(providerHandle)), 0, 0)
50
-	if r0 != 0 {
51
-		win32err = syscall.Errno(r0)
52
-	}
53
-	return
54
-}
55
-
56
-func eventUnregister(providerHandle providerHandle) (win32err error) {
57
-	r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
58
-	if r0 != 0 {
59
-		win32err = syscall.Errno(r0)
60
-	}
61
-	return
62
-}
63
-
64
-func eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
65
-	r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
66
-	if r0 != 0 {
67
-		win32err = syscall.Errno(r0)
68
-	}
69
-	return
70
-}
71
-
72
-func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
73
-	r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
74
-	if r0 != 0 {
75
-		win32err = syscall.Errno(r0)
76
-	}
77
-	return
78
-}
79 1
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// Package etw provides support for TraceLogging-based ETW (Event Tracing
1
+// for Windows). TraceLogging is a format of ETW events that are self-describing
2
+// (the event contains information on its own schema). This allows them to be
3
+// decoded without needing a separate manifest with event information. The
4
+// implementation here is based on the information found in
5
+// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
6
+// set of C macros.
7
+package etw
8
+
9
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
10
+
11
+//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
12
+//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
13
+//sys eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
14
+//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
0 15
new file mode 100644
... ...
@@ -0,0 +1,65 @@
0
+package etw
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/binary"
5
+)
6
+
7
+// eventData maintains a buffer which builds up the data for an ETW event. It
8
+// needs to be paired with EventMetadata which describes the event.
9
+type eventData struct {
10
+	buffer bytes.Buffer
11
+}
12
+
13
+// bytes returns the raw binary data containing the event data. The returned
14
+// value is not copied from the internal buffer, so it can be mutated by the
15
+// eventData object after it is returned.
16
+func (ed *eventData) bytes() []byte {
17
+	return ed.buffer.Bytes()
18
+}
19
+
20
+// writeString appends a string, including the null terminator, to the buffer.
21
+func (ed *eventData) writeString(data string) {
22
+	ed.buffer.WriteString(data)
23
+	ed.buffer.WriteByte(0)
24
+}
25
+
26
+// writeInt8 appends a int8 to the buffer.
27
+func (ed *eventData) writeInt8(value int8) {
28
+	ed.buffer.WriteByte(uint8(value))
29
+}
30
+
31
+// writeInt16 appends a int16 to the buffer.
32
+func (ed *eventData) writeInt16(value int16) {
33
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
34
+}
35
+
36
+// writeInt32 appends a int32 to the buffer.
37
+func (ed *eventData) writeInt32(value int32) {
38
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
39
+}
40
+
41
+// writeInt64 appends a int64 to the buffer.
42
+func (ed *eventData) writeInt64(value int64) {
43
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
44
+}
45
+
46
+// writeUint8 appends a uint8 to the buffer.
47
+func (ed *eventData) writeUint8(value uint8) {
48
+	ed.buffer.WriteByte(value)
49
+}
50
+
51
+// writeUint16 appends a uint16 to the buffer.
52
+func (ed *eventData) writeUint16(value uint16) {
53
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
54
+}
55
+
56
+// writeUint32 appends a uint32 to the buffer.
57
+func (ed *eventData) writeUint32(value uint32) {
58
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
59
+}
60
+
61
+// writeUint64 appends a uint64 to the buffer.
62
+func (ed *eventData) writeUint64(value uint64) {
63
+	binary.Write(&ed.buffer, binary.LittleEndian, value)
64
+}
0 65
new file mode 100644
... ...
@@ -0,0 +1,29 @@
0
+package etw
1
+
2
+import (
3
+	"unsafe"
4
+)
5
+
6
+type eventDataDescriptorType uint8
7
+
8
+const (
9
+	eventDataDescriptorTypeUserData eventDataDescriptorType = iota
10
+	eventDataDescriptorTypeEventMetadata
11
+	eventDataDescriptorTypeProviderMetadata
12
+)
13
+
14
+type eventDataDescriptor struct {
15
+	ptr       ptr64
16
+	size      uint32
17
+	dataType  eventDataDescriptorType
18
+	reserved1 uint8
19
+	reserved2 uint16
20
+}
21
+
22
+func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
23
+	return eventDataDescriptor{
24
+		ptr:      ptr64{ptr: unsafe.Pointer(&buffer[0])},
25
+		size:     uint32(len(buffer)),
26
+		dataType: dataType,
27
+	}
28
+}
0 29
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package etw
1
+
2
+// Channel represents the ETW logging channel that is used. It can be used by
3
+// event consumers to give an event special treatment.
4
+type Channel uint8
5
+
6
+const (
7
+	// ChannelTraceLogging is the default channel for TraceLogging events. It is
8
+	// not required to be used for TraceLogging, but will prevent decoding
9
+	// issues for these events on older operating systems.
10
+	ChannelTraceLogging Channel = 11
11
+)
12
+
13
+// Level represents the ETW logging level. There are several predefined levels
14
+// that are commonly used, but technically anything from 0-255 is allowed.
15
+// Lower levels indicate more important events, and 0 indicates an event that
16
+// will always be collected.
17
+type Level uint8
18
+
19
+// Predefined ETW log levels.
20
+const (
21
+	LevelAlways Level = iota
22
+	LevelCritical
23
+	LevelError
24
+	LevelWarning
25
+	LevelInfo
26
+	LevelVerbose
27
+)
28
+
29
+// EventDescriptor represents various metadata for an ETW event.
30
+type eventDescriptor struct {
31
+	id      uint16
32
+	version uint8
33
+	channel Channel
34
+	level   Level
35
+	opcode  uint8
36
+	task    uint16
37
+	keyword uint64
38
+}
39
+
40
+// NewEventDescriptor returns an EventDescriptor initialized for use with
41
+// TraceLogging.
42
+func newEventDescriptor() *eventDescriptor {
43
+	// Standard TraceLogging events default to the TraceLogging channel, and
44
+	// verbose level.
45
+	return &eventDescriptor{
46
+		channel: ChannelTraceLogging,
47
+		level:   LevelVerbose,
48
+	}
49
+}
50
+
51
+// Identity returns the identity of the event. If the identity is not 0, it
52
+// should uniquely identify the other event metadata (contained in
53
+// EventDescriptor, and field metadata). Only the lower 24 bits of this value
54
+// are relevant.
55
+func (ed *eventDescriptor) identity() uint32 {
56
+	return (uint32(ed.version) << 16) | uint32(ed.id)
57
+}
58
+
59
+// SetIdentity sets the identity of the event. If the identity is not 0, it
60
+// should uniquely identify the other event metadata (contained in
61
+// EventDescriptor, and field metadata). Only the lower 24 bits of this value
62
+// are relevant.
63
+func (ed *eventDescriptor) setIdentity(identity uint32) {
64
+	ed.id = uint16(identity)
65
+	ed.version = uint8(identity >> 16)
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,177 @@
0
+package etw
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/binary"
5
+)
6
+
7
+// inType indicates the type of data contained in the ETW event.
8
+type inType byte
9
+
10
+// Various inType definitions for TraceLogging. These must match the definitions
11
+// found in TraceLoggingProvider.h in the Windows SDK.
12
+const (
13
+	inTypeNull inType = iota
14
+	inTypeUnicodeString
15
+	inTypeANSIString
16
+	inTypeInt8
17
+	inTypeUint8
18
+	inTypeInt16
19
+	inTypeUint16
20
+	inTypeInt32
21
+	inTypeUint32
22
+	inTypeInt64
23
+	inTypeUint64
24
+	inTypeFloat
25
+	inTypeDouble
26
+	inTypeBool32
27
+	inTypeBinary
28
+	inTypeGUID
29
+	inTypePointerUnsupported
30
+	inTypeFileTime
31
+	inTypeSystemTime
32
+	inTypeSID
33
+	inTypeHexInt32
34
+	inTypeHexInt64
35
+	inTypeCountedString
36
+	inTypeCountedANSIString
37
+	inTypeStruct
38
+	inTypeCountedBinary
39
+	inTypeCountedArray inType = 32
40
+	inTypeArray        inType = 64
41
+)
42
+
43
+// outType specifies a hint to the event decoder for how the value should be
44
+// formatted.
45
+type outType byte
46
+
47
+// Various outType definitions for TraceLogging. These must match the
48
+// definitions found in TraceLoggingProvider.h in the Windows SDK.
49
+const (
50
+	// outTypeDefault indicates that the default formatting for the inType will
51
+	// be used by the event decoder.
52
+	outTypeDefault outType = iota
53
+	outTypeNoPrint
54
+	outTypeString
55
+	outTypeBoolean
56
+	outTypeHex
57
+	outTypePID
58
+	outTypeTID
59
+	outTypePort
60
+	outTypeIPv4
61
+	outTypeIPv6
62
+	outTypeSocketAddress
63
+	outTypeXML
64
+	outTypeJSON
65
+	outTypeWin32Error
66
+	outTypeNTStatus
67
+	outTypeHResult
68
+	outTypeFileTime
69
+	outTypeSigned
70
+	outTypeUnsigned
71
+	outTypeUTF8              outType = 35
72
+	outTypePKCS7WithTypeInfo outType = 36
73
+	outTypeCodePointer       outType = 37
74
+	outTypeDateTimeUTC       outType = 38
75
+)
76
+
77
+// eventMetadata maintains a buffer which builds up the metadata for an ETW
78
+// event. It needs to be paired with EventData which describes the event.
79
+type eventMetadata struct {
80
+	buffer bytes.Buffer
81
+}
82
+
83
+// bytes returns the raw binary data containing the event metadata. Before being
84
+// returned, the current size of the buffer is written to the start of the
85
+// buffer. The returned value is not copied from the internal buffer, so it can
86
+// be mutated by the eventMetadata object after it is returned.
87
+func (em *eventMetadata) bytes() []byte {
88
+	// Finalize the event metadata buffer by filling in the buffer length at the
89
+	// beginning.
90
+	binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
91
+	return em.buffer.Bytes()
92
+}
93
+
94
+// writeEventHeader writes the metadata for the start of an event to the buffer.
95
+// This specifies the event name and tags.
96
+func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
97
+	binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
98
+	em.writeTags(tags)
99
+	em.buffer.WriteString(name)
100
+	em.buffer.WriteByte(0) // Null terminator for name
101
+}
102
+
103
+func (em *eventMetadata) writeFieldInner(name string, inType inType, outType outType, tags uint32, arrSize uint16) {
104
+	em.buffer.WriteString(name)
105
+	em.buffer.WriteByte(0) // Null terminator for name
106
+
107
+	if outType == outTypeDefault && tags == 0 {
108
+		em.buffer.WriteByte(byte(inType))
109
+	} else {
110
+		em.buffer.WriteByte(byte(inType | 128))
111
+		if tags == 0 {
112
+			em.buffer.WriteByte(byte(outType))
113
+		} else {
114
+			em.buffer.WriteByte(byte(outType | 128))
115
+			em.writeTags(tags)
116
+		}
117
+	}
118
+
119
+	if arrSize != 0 {
120
+		binary.Write(&em.buffer, binary.LittleEndian, arrSize)
121
+	}
122
+}
123
+
124
+// writeTags writes out the tags value to the event metadata. Tags is a 28-bit
125
+// value, interpreted as bit flags, which are only relevant to the event
126
+// consumer. The event consumer may choose to attribute special meaning to tags
127
+// (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
128
+// bytes, each containing 7 bits of tag value, with the high bit set if there is
129
+// more tag data in the following byte. This allows for a more compact
130
+// representation when not all of the tag bits are needed.
131
+func (em *eventMetadata) writeTags(tags uint32) {
132
+	// Only use the top 28 bits of the tags value.
133
+	tags &= 0xfffffff
134
+
135
+	for {
136
+		// Tags are written with the most significant bits (e.g. 21-27) first.
137
+		val := tags >> 21
138
+
139
+		if tags&0x1fffff == 0 {
140
+			// If there is no more data to write after this, write this value
141
+			// without the high bit set, and return.
142
+			em.buffer.WriteByte(byte(val & 0x7f))
143
+			return
144
+		}
145
+
146
+		em.buffer.WriteByte(byte(val | 0x80))
147
+
148
+		tags <<= 7
149
+	}
150
+}
151
+
152
+// writeField writes the metadata for a simple field to the buffer.
153
+func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
154
+	em.writeFieldInner(name, inType, outType, tags, 0)
155
+}
156
+
157
+// writeArray writes the metadata for an array field to the buffer. The number
158
+// of elements in the array must be written as a uint16 in the event data,
159
+// immediately preceeding the event data.
160
+func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
161
+	em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
162
+}
163
+
164
+// writeCountedArray writes the metadata for an array field to the buffer. The
165
+// size of a counted array is fixed, and the size is written into the metadata
166
+// directly.
167
+func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
168
+	em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
169
+}
170
+
171
+// writeStruct writes the metadata for a nested struct to the buffer. The struct
172
+// contains the next N fields in the metadata, where N is specified by the
173
+// fieldCount argument.
174
+func (em *eventMetadata) writeStruct(name string, fieldCount uint8, tags uint32) {
175
+	em.writeFieldInner(name, inTypeStruct, outType(fieldCount), tags, 0)
176
+}
0 177
new file mode 100644
... ...
@@ -0,0 +1,63 @@
0
+package etw
1
+
2
+import (
3
+	"golang.org/x/sys/windows"
4
+)
5
+
6
+type eventOptions struct {
7
+	descriptor        *eventDescriptor
8
+	activityID        *windows.GUID
9
+	relatedActivityID *windows.GUID
10
+	tags              uint32
11
+}
12
+
13
+// EventOpt defines the option function type that can be passed to
14
+// Provider.WriteEvent to specify general event options, such as level and
15
+// keyword.
16
+type EventOpt func(options *eventOptions)
17
+
18
+// WithEventOpts returns the variadic arguments as a single slice.
19
+func WithEventOpts(opts ...EventOpt) []EventOpt {
20
+	return opts
21
+}
22
+
23
+// WithLevel specifies the level of the event to be written.
24
+func WithLevel(level Level) EventOpt {
25
+	return func(options *eventOptions) {
26
+		options.descriptor.level = level
27
+	}
28
+}
29
+
30
+// WithKeyword specifies the keywords of the event to be written. Multiple uses
31
+// of this option are OR'd together.
32
+func WithKeyword(keyword uint64) EventOpt {
33
+	return func(options *eventOptions) {
34
+		options.descriptor.keyword |= keyword
35
+	}
36
+}
37
+
38
+func WithChannel(channel Channel) EventOpt {
39
+	return func(options *eventOptions) {
40
+		options.descriptor.channel = channel
41
+	}
42
+}
43
+
44
+// WithTags specifies the tags of the event to be written. Tags is a 28-bit
45
+// value (top 4 bits are ignored) which are interpreted by the event consumer.
46
+func WithTags(newTags uint32) EventOpt {
47
+	return func(options *eventOptions) {
48
+		options.tags |= newTags
49
+	}
50
+}
51
+
52
+func WithActivityID(activityID *windows.GUID) EventOpt {
53
+	return func(options *eventOptions) {
54
+		options.activityID = activityID
55
+	}
56
+}
57
+
58
+func WithRelatedActivityID(activityID *windows.GUID) EventOpt {
59
+	return func(options *eventOptions) {
60
+		options.relatedActivityID = activityID
61
+	}
62
+}
0 63
new file mode 100644
... ...
@@ -0,0 +1,379 @@
0
+package etw
1
+
2
+import (
3
+	"math"
4
+	"unsafe"
5
+)
6
+
7
+// FieldOpt defines the option function type that can be passed to
8
+// Provider.WriteEvent to add fields to the event.
9
+type FieldOpt func(em *eventMetadata, ed *eventData)
10
+
11
+// WithFields returns the variadic arguments as a single slice.
12
+func WithFields(opts ...FieldOpt) []FieldOpt {
13
+	return opts
14
+}
15
+
16
+// BoolField adds a single bool field to the event.
17
+func BoolField(name string, value bool) FieldOpt {
18
+	return func(em *eventMetadata, ed *eventData) {
19
+		em.writeField(name, inTypeUint8, outTypeBoolean, 0)
20
+		bool8 := uint8(0)
21
+		if value {
22
+			bool8 = uint8(1)
23
+		}
24
+		ed.writeUint8(bool8)
25
+	}
26
+}
27
+
28
+// BoolArray adds an array of bool to the event.
29
+func BoolArray(name string, values []bool) FieldOpt {
30
+	return func(em *eventMetadata, ed *eventData) {
31
+		em.writeArray(name, inTypeUint8, outTypeBoolean, 0)
32
+		ed.writeUint16(uint16(len(values)))
33
+		for _, v := range values {
34
+			bool8 := uint8(0)
35
+			if v {
36
+				bool8 = uint8(1)
37
+			}
38
+			ed.writeUint8(bool8)
39
+		}
40
+	}
41
+}
42
+
43
+// StringField adds a single string field to the event.
44
+func StringField(name string, value string) FieldOpt {
45
+	return func(em *eventMetadata, ed *eventData) {
46
+		em.writeField(name, inTypeANSIString, outTypeUTF8, 0)
47
+		ed.writeString(value)
48
+	}
49
+}
50
+
51
+// StringArray adds an array of string to the event.
52
+func StringArray(name string, values []string) FieldOpt {
53
+	return func(em *eventMetadata, ed *eventData) {
54
+		em.writeArray(name, inTypeANSIString, outTypeUTF8, 0)
55
+		ed.writeUint16(uint16(len(values)))
56
+		for _, v := range values {
57
+			ed.writeString(v)
58
+		}
59
+	}
60
+}
61
+
62
+// IntField adds a single int field to the event.
63
+func IntField(name string, value int) FieldOpt {
64
+	switch unsafe.Sizeof(value) {
65
+	case 4:
66
+		return Int32Field(name, int32(value))
67
+	case 8:
68
+		return Int64Field(name, int64(value))
69
+	default:
70
+		panic("Unsupported int size")
71
+	}
72
+}
73
+
74
+// IntArray adds an array of int to the event.
75
+func IntArray(name string, values []int) FieldOpt {
76
+	inType := inTypeNull
77
+	var writeItem func(*eventData, int)
78
+	switch unsafe.Sizeof(values[0]) {
79
+	case 4:
80
+		inType = inTypeInt32
81
+		writeItem = func(ed *eventData, item int) { ed.writeInt32(int32(item)) }
82
+	case 8:
83
+		inType = inTypeInt64
84
+		writeItem = func(ed *eventData, item int) { ed.writeInt64(int64(item)) }
85
+	default:
86
+		panic("Unsupported int size")
87
+	}
88
+
89
+	return func(em *eventMetadata, ed *eventData) {
90
+		em.writeArray(name, inType, outTypeDefault, 0)
91
+		ed.writeUint16(uint16(len(values)))
92
+		for _, v := range values {
93
+			writeItem(ed, v)
94
+		}
95
+	}
96
+}
97
+
98
+// Int8Field adds a single int8 field to the event.
99
+func Int8Field(name string, value int8) FieldOpt {
100
+	return func(em *eventMetadata, ed *eventData) {
101
+		em.writeField(name, inTypeInt8, outTypeDefault, 0)
102
+		ed.writeInt8(value)
103
+	}
104
+}
105
+
106
+// Int8Array adds an array of int8 to the event.
107
+func Int8Array(name string, values []int8) FieldOpt {
108
+	return func(em *eventMetadata, ed *eventData) {
109
+		em.writeArray(name, inTypeInt8, outTypeDefault, 0)
110
+		ed.writeUint16(uint16(len(values)))
111
+		for _, v := range values {
112
+			ed.writeInt8(v)
113
+		}
114
+	}
115
+}
116
+
117
+// Int16Field adds a single int16 field to the event.
118
+func Int16Field(name string, value int16) FieldOpt {
119
+	return func(em *eventMetadata, ed *eventData) {
120
+		em.writeField(name, inTypeInt16, outTypeDefault, 0)
121
+		ed.writeInt16(value)
122
+	}
123
+}
124
+
125
+// Int16Array adds an array of int16 to the event.
126
+func Int16Array(name string, values []int16) FieldOpt {
127
+	return func(em *eventMetadata, ed *eventData) {
128
+		em.writeArray(name, inTypeInt16, outTypeDefault, 0)
129
+		ed.writeUint16(uint16(len(values)))
130
+		for _, v := range values {
131
+			ed.writeInt16(v)
132
+		}
133
+	}
134
+}
135
+
136
+// Int32Field adds a single int32 field to the event.
137
+func Int32Field(name string, value int32) FieldOpt {
138
+	return func(em *eventMetadata, ed *eventData) {
139
+		em.writeField(name, inTypeInt32, outTypeDefault, 0)
140
+		ed.writeInt32(value)
141
+	}
142
+}
143
+
144
+// Int32Array adds an array of int32 to the event.
145
+func Int32Array(name string, values []int32) FieldOpt {
146
+	return func(em *eventMetadata, ed *eventData) {
147
+		em.writeArray(name, inTypeInt32, outTypeDefault, 0)
148
+		ed.writeUint16(uint16(len(values)))
149
+		for _, v := range values {
150
+			ed.writeInt32(v)
151
+		}
152
+	}
153
+}
154
+
155
+// Int64Field adds a single int64 field to the event.
156
+func Int64Field(name string, value int64) FieldOpt {
157
+	return func(em *eventMetadata, ed *eventData) {
158
+		em.writeField(name, inTypeInt64, outTypeDefault, 0)
159
+		ed.writeInt64(value)
160
+	}
161
+}
162
+
163
+// Int64Array adds an array of int64 to the event.
164
+func Int64Array(name string, values []int64) FieldOpt {
165
+	return func(em *eventMetadata, ed *eventData) {
166
+		em.writeArray(name, inTypeInt64, outTypeDefault, 0)
167
+		ed.writeUint16(uint16(len(values)))
168
+		for _, v := range values {
169
+			ed.writeInt64(v)
170
+		}
171
+	}
172
+}
173
+
174
+// UintField adds a single uint field to the event.
175
+func UintField(name string, value uint) FieldOpt {
176
+	switch unsafe.Sizeof(value) {
177
+	case 4:
178
+		return Uint32Field(name, uint32(value))
179
+	case 8:
180
+		return Uint64Field(name, uint64(value))
181
+	default:
182
+		panic("Unsupported uint size")
183
+	}
184
+}
185
+
186
+// UintArray adds an array of uint to the event.
187
+func UintArray(name string, values []uint) FieldOpt {
188
+	inType := inTypeNull
189
+	var writeItem func(*eventData, uint)
190
+	switch unsafe.Sizeof(values[0]) {
191
+	case 4:
192
+		inType = inTypeUint32
193
+		writeItem = func(ed *eventData, item uint) { ed.writeUint32(uint32(item)) }
194
+	case 8:
195
+		inType = inTypeUint64
196
+		writeItem = func(ed *eventData, item uint) { ed.writeUint64(uint64(item)) }
197
+	default:
198
+		panic("Unsupported uint size")
199
+	}
200
+
201
+	return func(em *eventMetadata, ed *eventData) {
202
+		em.writeArray(name, inType, outTypeDefault, 0)
203
+		ed.writeUint16(uint16(len(values)))
204
+		for _, v := range values {
205
+			writeItem(ed, v)
206
+		}
207
+	}
208
+}
209
+
210
+// Uint8Field adds a single uint8 field to the event.
211
+func Uint8Field(name string, value uint8) FieldOpt {
212
+	return func(em *eventMetadata, ed *eventData) {
213
+		em.writeField(name, inTypeUint8, outTypeDefault, 0)
214
+		ed.writeUint8(value)
215
+	}
216
+}
217
+
218
+// Uint8Array adds an array of uint8 to the event.
219
+func Uint8Array(name string, values []uint8) FieldOpt {
220
+	return func(em *eventMetadata, ed *eventData) {
221
+		em.writeArray(name, inTypeUint8, outTypeDefault, 0)
222
+		ed.writeUint16(uint16(len(values)))
223
+		for _, v := range values {
224
+			ed.writeUint8(v)
225
+		}
226
+	}
227
+}
228
+
229
+// Uint16Field adds a single uint16 field to the event.
230
+func Uint16Field(name string, value uint16) FieldOpt {
231
+	return func(em *eventMetadata, ed *eventData) {
232
+		em.writeField(name, inTypeUint16, outTypeDefault, 0)
233
+		ed.writeUint16(value)
234
+	}
235
+}
236
+
237
+// Uint16Array adds an array of uint16 to the event.
238
+func Uint16Array(name string, values []uint16) FieldOpt {
239
+	return func(em *eventMetadata, ed *eventData) {
240
+		em.writeArray(name, inTypeUint16, outTypeDefault, 0)
241
+		ed.writeUint16(uint16(len(values)))
242
+		for _, v := range values {
243
+			ed.writeUint16(v)
244
+		}
245
+	}
246
+}
247
+
248
+// Uint32Field adds a single uint32 field to the event.
249
+func Uint32Field(name string, value uint32) FieldOpt {
250
+	return func(em *eventMetadata, ed *eventData) {
251
+		em.writeField(name, inTypeUint32, outTypeDefault, 0)
252
+		ed.writeUint32(value)
253
+	}
254
+}
255
+
256
+// Uint32Array adds an array of uint32 to the event.
257
+func Uint32Array(name string, values []uint32) FieldOpt {
258
+	return func(em *eventMetadata, ed *eventData) {
259
+		em.writeArray(name, inTypeUint32, outTypeDefault, 0)
260
+		ed.writeUint16(uint16(len(values)))
261
+		for _, v := range values {
262
+			ed.writeUint32(v)
263
+		}
264
+	}
265
+}
266
+
267
+// Uint64Field adds a single uint64 field to the event.
268
+func Uint64Field(name string, value uint64) FieldOpt {
269
+	return func(em *eventMetadata, ed *eventData) {
270
+		em.writeField(name, inTypeUint64, outTypeDefault, 0)
271
+		ed.writeUint64(value)
272
+	}
273
+}
274
+
275
+// Uint64Array adds an array of uint64 to the event.
276
+func Uint64Array(name string, values []uint64) FieldOpt {
277
+	return func(em *eventMetadata, ed *eventData) {
278
+		em.writeArray(name, inTypeUint64, outTypeDefault, 0)
279
+		ed.writeUint16(uint16(len(values)))
280
+		for _, v := range values {
281
+			ed.writeUint64(v)
282
+		}
283
+	}
284
+}
285
+
286
+// UintptrField adds a single uintptr field to the event.
287
+func UintptrField(name string, value uintptr) FieldOpt {
288
+	inType := inTypeNull
289
+	var writeItem func(*eventData, uintptr)
290
+	switch unsafe.Sizeof(value) {
291
+	case 4:
292
+		inType = inTypeHexInt32
293
+		writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
294
+	case 8:
295
+		inType = inTypeHexInt64
296
+		writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
297
+	default:
298
+		panic("Unsupported uintptr size")
299
+	}
300
+
301
+	return func(em *eventMetadata, ed *eventData) {
302
+		em.writeField(name, inType, outTypeDefault, 0)
303
+		writeItem(ed, value)
304
+	}
305
+}
306
+
307
+// UintptrArray adds an array of uintptr to the event.
308
+func UintptrArray(name string, values []uintptr) FieldOpt {
309
+	inType := inTypeNull
310
+	var writeItem func(*eventData, uintptr)
311
+	switch unsafe.Sizeof(values[0]) {
312
+	case 4:
313
+		inType = inTypeHexInt32
314
+		writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
315
+	case 8:
316
+		inType = inTypeHexInt64
317
+		writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
318
+	default:
319
+		panic("Unsupported uintptr size")
320
+	}
321
+
322
+	return func(em *eventMetadata, ed *eventData) {
323
+		em.writeArray(name, inType, outTypeDefault, 0)
324
+		ed.writeUint16(uint16(len(values)))
325
+		for _, v := range values {
326
+			writeItem(ed, v)
327
+		}
328
+	}
329
+}
330
+
331
+// Float32Field adds a single float32 field to the event.
332
+func Float32Field(name string, value float32) FieldOpt {
333
+	return func(em *eventMetadata, ed *eventData) {
334
+		em.writeField(name, inTypeFloat, outTypeDefault, 0)
335
+		ed.writeUint32(math.Float32bits(value))
336
+	}
337
+}
338
+
339
+// Float32Array adds an array of float32 to the event.
340
+func Float32Array(name string, values []float32) FieldOpt {
341
+	return func(em *eventMetadata, ed *eventData) {
342
+		em.writeArray(name, inTypeFloat, outTypeDefault, 0)
343
+		ed.writeUint16(uint16(len(values)))
344
+		for _, v := range values {
345
+			ed.writeUint32(math.Float32bits(v))
346
+		}
347
+	}
348
+}
349
+
350
+// Float64Field adds a single float64 field to the event.
351
+func Float64Field(name string, value float64) FieldOpt {
352
+	return func(em *eventMetadata, ed *eventData) {
353
+		em.writeField(name, inTypeDouble, outTypeDefault, 0)
354
+		ed.writeUint64(math.Float64bits(value))
355
+	}
356
+}
357
+
358
+// Float64Array adds an array of float64 to the event.
359
+func Float64Array(name string, values []float64) FieldOpt {
360
+	return func(em *eventMetadata, ed *eventData) {
361
+		em.writeArray(name, inTypeDouble, outTypeDefault, 0)
362
+		ed.writeUint16(uint16(len(values)))
363
+		for _, v := range values {
364
+			ed.writeUint64(math.Float64bits(v))
365
+		}
366
+	}
367
+}
368
+
369
+// Struct adds a nested struct to the event, the FieldOpts in the opts argument
370
+// are used to specify the fields of the struct.
371
+func Struct(name string, opts ...FieldOpt) FieldOpt {
372
+	return func(em *eventMetadata, ed *eventData) {
373
+		em.writeStruct(name, uint8(len(opts)), 0)
374
+		for _, opt := range opts {
375
+			opt(em, ed)
376
+		}
377
+	}
378
+}
0 379
new file mode 100644
... ...
@@ -0,0 +1,279 @@
0
+package etw
1
+
2
+import (
3
+	"bytes"
4
+	"crypto/sha1"
5
+	"encoding/binary"
6
+	"encoding/hex"
7
+	"fmt"
8
+	"strings"
9
+	"unicode/utf16"
10
+	"unsafe"
11
+
12
+	"golang.org/x/sys/windows"
13
+)
14
+
15
+// Provider represents an ETW event provider. It is identified by a provider
16
+// name and ID (GUID), which should always have a 1:1 mapping to each other
17
+// (e.g. don't use multiple provider names with the same ID, or vice versa).
18
+type Provider struct {
19
+	ID         *windows.GUID
20
+	handle     providerHandle
21
+	metadata   []byte
22
+	callback   EnableCallback
23
+	index      uint
24
+	enabled    bool
25
+	level      Level
26
+	keywordAny uint64
27
+	keywordAll uint64
28
+}
29
+
30
+// String returns the `provider`.ID as a string
31
+func (provider *Provider) String() string {
32
+	data1 := make([]byte, 4)
33
+	binary.BigEndian.PutUint32(data1, provider.ID.Data1)
34
+	data2 := make([]byte, 2)
35
+	binary.BigEndian.PutUint16(data2, provider.ID.Data2)
36
+	data3 := make([]byte, 2)
37
+	binary.BigEndian.PutUint16(data3, provider.ID.Data3)
38
+	return fmt.Sprintf(
39
+		"%s-%s-%s-%s-%s",
40
+		hex.EncodeToString(data1),
41
+		hex.EncodeToString(data2),
42
+		hex.EncodeToString(data3),
43
+		hex.EncodeToString(provider.ID.Data4[:2]),
44
+		hex.EncodeToString(provider.ID.Data4[2:]))
45
+}
46
+
47
+type providerHandle windows.Handle
48
+
49
+// ProviderState informs the provider EnableCallback what action is being
50
+// performed.
51
+type ProviderState uint32
52
+
53
+const (
54
+	// ProviderStateDisable indicates the provider is being disabled.
55
+	ProviderStateDisable ProviderState = iota
56
+	// ProviderStateEnable indicates the provider is being enabled.
57
+	ProviderStateEnable
58
+	// ProviderStateCaptureState indicates the provider is having its current
59
+	// state snap-shotted.
60
+	ProviderStateCaptureState
61
+)
62
+
63
+type eventInfoClass uint32
64
+
65
+const (
66
+	eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
67
+	eventInfoClassProviderSetReserved1
68
+	eventInfoClassProviderSetTraits
69
+	eventInfoClassProviderUseDescriptorType
70
+)
71
+
72
+// EnableCallback is the form of the callback function that receives provider
73
+// enable/disable notifications from ETW.
74
+type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
75
+
76
+func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
77
+	provider := providers.getProvider(uint(i))
78
+
79
+	switch state {
80
+	case ProviderStateDisable:
81
+		provider.enabled = false
82
+	case ProviderStateEnable:
83
+		provider.enabled = true
84
+		provider.level = level
85
+		provider.keywordAny = matchAnyKeyword
86
+		provider.keywordAll = matchAllKeyword
87
+	}
88
+
89
+	if provider.callback != nil {
90
+		provider.callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData)
91
+	}
92
+}
93
+
94
+// providerCallbackAdapter acts as the first-level callback from the C/ETW side
95
+// for provider notifications. Because Go has trouble with callback arguments of
96
+// different size, it has only pointer-sized arguments, which are then cast to
97
+// the appropriate types when calling providerCallback.
98
+func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
99
+	providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
100
+	return 0
101
+}
102
+
103
+// providerIDFromName generates a provider ID based on the provider name. It
104
+// uses the same algorithm as used by .NET's EventSource class, which is based
105
+// on RFC 4122. More information on the algorithm can be found here:
106
+// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/
107
+// The algorithm is roughly:
108
+// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
109
+// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
110
+func providerIDFromName(name string) *windows.GUID {
111
+	buffer := sha1.New()
112
+
113
+	namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
114
+	buffer.Write(namespace)
115
+
116
+	binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
117
+
118
+	sum := buffer.Sum(nil)
119
+	sum[7] = (sum[7] & 0xf) | 0x50
120
+
121
+	return &windows.GUID{
122
+		Data1: binary.LittleEndian.Uint32(sum[0:4]),
123
+		Data2: binary.LittleEndian.Uint16(sum[4:6]),
124
+		Data3: binary.LittleEndian.Uint16(sum[6:8]),
125
+		Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]},
126
+	}
127
+}
128
+
129
+// NewProvider creates and registers a new ETW provider. The provider ID is
130
+// generated based on the provider name.
131
+func NewProvider(name string, callback EnableCallback) (provider *Provider, err error) {
132
+	return NewProviderWithID(name, providerIDFromName(name), callback)
133
+}
134
+
135
+// NewProviderWithID creates and registers a new ETW provider, allowing the
136
+// provider ID to be manually specified. This is most useful when there is an
137
+// existing provider ID that must be used to conform to existing diagnostic
138
+// infrastructure.
139
+func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) {
140
+	providerCallbackOnce.Do(func() {
141
+		globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
142
+	})
143
+
144
+	provider = providers.newProvider()
145
+	defer func() {
146
+		if err != nil {
147
+			providers.removeProvider(provider)
148
+		}
149
+	}()
150
+	provider.ID = id
151
+	provider.callback = callback
152
+
153
+	if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
154
+		return nil, err
155
+	}
156
+
157
+	metadata := &bytes.Buffer{}
158
+	binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
159
+	metadata.WriteString(name)
160
+	metadata.WriteByte(0)                                                   // Null terminator for name
161
+	binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
162
+	provider.metadata = metadata.Bytes()
163
+
164
+	if err := eventSetInformation(
165
+		provider.handle,
166
+		eventInfoClassProviderSetTraits,
167
+		uintptr(unsafe.Pointer(&provider.metadata[0])),
168
+		uint32(len(provider.metadata))); err != nil {
169
+
170
+		return nil, err
171
+	}
172
+
173
+	return provider, nil
174
+}
175
+
176
+// Close unregisters the provider.
177
+func (provider *Provider) Close() error {
178
+	providers.removeProvider(provider)
179
+	return eventUnregister(provider.handle)
180
+}
181
+
182
+// IsEnabled calls IsEnabledForLevelAndKeywords with LevelAlways and all
183
+// keywords set.
184
+func (provider *Provider) IsEnabled() bool {
185
+	return provider.IsEnabledForLevelAndKeywords(LevelAlways, ^uint64(0))
186
+}
187
+
188
+// IsEnabledForLevel calls IsEnabledForLevelAndKeywords with the specified level
189
+// and all keywords set.
190
+func (provider *Provider) IsEnabledForLevel(level Level) bool {
191
+	return provider.IsEnabledForLevelAndKeywords(level, ^uint64(0))
192
+}
193
+
194
+// IsEnabledForLevelAndKeywords allows event producer code to check if there are
195
+// any event sessions that are interested in an event, based on the event level
196
+// and keywords. Although this check happens automatically in the ETW
197
+// infrastructure, it can be useful to check if an event will actually be
198
+// consumed before doing expensive work to build the event data.
199
+func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
200
+	if !provider.enabled {
201
+		return false
202
+	}
203
+
204
+	// ETW automatically sets the level to 255 if it is specified as 0, so we
205
+	// don't need to worry about the level=0 (all events) case.
206
+	if level > provider.level {
207
+		return false
208
+	}
209
+
210
+	if keywords != 0 && (keywords&provider.keywordAny == 0 || keywords&provider.keywordAll != provider.keywordAll) {
211
+		return false
212
+	}
213
+
214
+	return true
215
+}
216
+
217
+// WriteEvent writes a single ETW event from the provider. The event is
218
+// constructed based on the EventOpt and FieldOpt values that are passed as
219
+// opts.
220
+func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
221
+	options := eventOptions{descriptor: newEventDescriptor()}
222
+	em := &eventMetadata{}
223
+	ed := &eventData{}
224
+
225
+	// We need to evaluate the EventOpts first since they might change tags, and
226
+	// we write out the tags before evaluating FieldOpts.
227
+	for _, opt := range eventOpts {
228
+		opt(&options)
229
+	}
230
+
231
+	if !provider.IsEnabledForLevelAndKeywords(options.descriptor.level, options.descriptor.keyword) {
232
+		return nil
233
+	}
234
+
235
+	em.writeEventHeader(name, options.tags)
236
+
237
+	for _, opt := range fieldOpts {
238
+		opt(em, ed)
239
+	}
240
+
241
+	// Don't pass a data blob if there is no event data. There will always be
242
+	// event metadata (e.g. for the name) so we don't need to do this check for
243
+	// the metadata.
244
+	dataBlobs := [][]byte{}
245
+	if len(ed.bytes()) > 0 {
246
+		dataBlobs = [][]byte{ed.bytes()}
247
+	}
248
+
249
+	return provider.writeEventRaw(options.descriptor, nil, nil, [][]byte{em.bytes()}, dataBlobs)
250
+}
251
+
252
+// writeEventRaw writes a single ETW event from the provider. This function is
253
+// less abstracted than WriteEvent, and presents a fairly direct interface to
254
+// the event writing functionality. It expects a series of event metadata and
255
+// event data blobs to be passed in, which must conform to the TraceLogging
256
+// schema. The functions on EventMetadata and EventData can help with creating
257
+// these blobs. The blobs of each type are effectively concatenated together by
258
+// the ETW infrastructure.
259
+func (provider *Provider) writeEventRaw(
260
+	descriptor *eventDescriptor,
261
+	activityID *windows.GUID,
262
+	relatedActivityID *windows.GUID,
263
+	metadataBlobs [][]byte,
264
+	dataBlobs [][]byte) error {
265
+
266
+	dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
267
+	dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
268
+
269
+	dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
270
+	for _, blob := range metadataBlobs {
271
+		dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
272
+	}
273
+	for _, blob := range dataBlobs {
274
+		dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
275
+	}
276
+
277
+	return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0])
278
+}
0 279
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+package etw
1
+
2
+import (
3
+	"sync"
4
+)
5
+
6
+// Because the provider callback function needs to be able to access the
7
+// provider data when it is invoked by ETW, we need to keep provider data stored
8
+// in a global map based on an index. The index is passed as the callback
9
+// context to ETW.
10
+type providerMap struct {
11
+	m    map[uint]*Provider
12
+	i    uint
13
+	lock sync.Mutex
14
+	once sync.Once
15
+}
16
+
17
+var providers = providerMap{
18
+	m: make(map[uint]*Provider),
19
+}
20
+
21
+func (p *providerMap) newProvider() *Provider {
22
+	p.lock.Lock()
23
+	defer p.lock.Unlock()
24
+
25
+	i := p.i
26
+	p.i++
27
+
28
+	provider := &Provider{
29
+		index: i,
30
+	}
31
+
32
+	p.m[i] = provider
33
+	return provider
34
+}
35
+
36
+func (p *providerMap) removeProvider(provider *Provider) {
37
+	p.lock.Lock()
38
+	defer p.lock.Unlock()
39
+
40
+	delete(p.m, provider.index)
41
+}
42
+
43
+func (p *providerMap) getProvider(index uint) *Provider {
44
+	p.lock.Lock()
45
+	defer p.lock.Unlock()
46
+
47
+	return p.m[index]
48
+}
49
+
50
+var providerCallbackOnce sync.Once
51
+var globalProviderCallback uintptr
0 52
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+// +build 386 arm
1
+
2
+package etw
3
+
4
+import (
5
+	"unsafe"
6
+)
7
+
8
+// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
9
+// be 64 bits, regardless of the actual size of a pointer on the platform. This
10
+// is intended for use with certain Windows APIs that expect a pointer as a
11
+// ULONGLONG.
12
+type ptr64 struct {
13
+	ptr unsafe.Pointer
14
+	_   uint32
15
+}
0 16
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build amd64 arm64
1
+
2
+package etw
3
+
4
+import (
5
+	"unsafe"
6
+)
7
+
8
+// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
9
+// be 64 bits, regardless of the actual size of a pointer on the platform. This
10
+// is intended for use with certain Windows APIs that expect a pointer as a
11
+// ULONGLONG.
12
+type ptr64 struct {
13
+	ptr unsafe.Pointer
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,78 @@
0
+// Code generated by 'go generate'; DO NOT EDIT.
1
+
2
+package etw
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+
8
+	"golang.org/x/sys/windows"
9
+)
10
+
11
+var _ unsafe.Pointer
12
+
13
+// Do the interface allocations only once for common
14
+// Errno values.
15
+const (
16
+	errnoERROR_IO_PENDING = 997
17
+)
18
+
19
+var (
20
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
21
+)
22
+
23
+// errnoErr returns common boxed Errno values, to prevent
24
+// allocations at runtime.
25
+func errnoErr(e syscall.Errno) error {
26
+	switch e {
27
+	case 0:
28
+		return nil
29
+	case errnoERROR_IO_PENDING:
30
+		return errERROR_IO_PENDING
31
+	}
32
+	// TODO: add more here, after collecting data on the common
33
+	// error values see on Windows. (perhaps when running
34
+	// all.bat?)
35
+	return e
36
+}
37
+
38
+var (
39
+	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
40
+
41
+	procEventRegister       = modadvapi32.NewProc("EventRegister")
42
+	procEventUnregister     = modadvapi32.NewProc("EventUnregister")
43
+	procEventWriteTransfer  = modadvapi32.NewProc("EventWriteTransfer")
44
+	procEventSetInformation = modadvapi32.NewProc("EventSetInformation")
45
+)
46
+
47
+func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) {
48
+	r0, _, _ := syscall.Syscall6(procEventRegister.Addr(), 4, uintptr(unsafe.Pointer(providerId)), uintptr(callback), uintptr(callbackContext), uintptr(unsafe.Pointer(providerHandle)), 0, 0)
49
+	if r0 != 0 {
50
+		win32err = syscall.Errno(r0)
51
+	}
52
+	return
53
+}
54
+
55
+func eventUnregister(providerHandle providerHandle) (win32err error) {
56
+	r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
57
+	if r0 != 0 {
58
+		win32err = syscall.Errno(r0)
59
+	}
60
+	return
61
+}
62
+
63
+func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
64
+	r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
65
+	if r0 != 0 {
66
+		win32err = syscall.Errno(r0)
67
+	}
68
+	return
69
+}
70
+
71
+func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
72
+	r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
73
+	if r0 != 0 {
74
+		win32err = syscall.Errno(r0)
75
+	}
76
+	return
77
+}
... ...
@@ -4,26 +4,31 @@ import (
4 4
 	"fmt"
5 5
 	"reflect"
6 6
 
7
-	"github.com/Microsoft/go-winio/internal/etw"
7
+	"github.com/Microsoft/go-winio/pkg/etw"
8 8
 	"github.com/sirupsen/logrus"
9 9
 )
10 10
 
11 11
 // Hook is a Logrus hook which logs received events to ETW.
12 12
 type Hook struct {
13
-	provider *etw.Provider
13
+	provider      *etw.Provider
14
+	closeProvider bool
14 15
 }
15 16
 
16
-// NewHook registers a new ETW provider and returns a hook to log from it.
17
+// NewHook registers a new ETW provider and returns a hook to log from it. The
18
+// provider will be closed when the hook is closed.
17 19
 func NewHook(providerName string) (*Hook, error) {
18
-	hook := Hook{}
19
-
20 20
 	provider, err := etw.NewProvider(providerName, nil)
21 21
 	if err != nil {
22 22
 		return nil, err
23 23
 	}
24
-	hook.provider = provider
25 24
 
26
-	return &hook, nil
25
+	return &Hook{provider, true}, nil
26
+}
27
+
28
+// NewHookFromProvider creates a new hook based on an existing ETW provider. The
29
+// provider will not be closed when the hook is closed.
30
+func NewHookFromProvider(provider *etw.Provider) (*Hook, error) {
31
+	return &Hook{provider, false}, nil
27 32
 }
28 33
 
29 34
 // Levels returns the set of levels that this hook wants to receive log entries
... ...
@@ -40,9 +45,22 @@ func (h *Hook) Levels() []logrus.Level {
40 40
 	}
41 41
 }
42 42
 
43
+var logrusToETWLevelMap = map[logrus.Level]etw.Level{
44
+	logrus.PanicLevel: etw.LevelAlways,
45
+	logrus.FatalLevel: etw.LevelCritical,
46
+	logrus.ErrorLevel: etw.LevelError,
47
+	logrus.WarnLevel:  etw.LevelWarning,
48
+	logrus.InfoLevel:  etw.LevelInfo,
49
+	logrus.DebugLevel: etw.LevelVerbose,
50
+	logrus.TraceLevel: etw.LevelVerbose,
51
+}
52
+
43 53
 // Fire receives each Logrus entry as it is logged, and logs it to ETW.
44 54
 func (h *Hook) Fire(e *logrus.Entry) error {
45
-	level := etw.Level(e.Level)
55
+	// Logrus defines more levels than ETW typically uses, but analysis is
56
+	// easiest when using a consistent set of levels across ETW providers, so we
57
+	// map the Logrus levels to ETW levels.
58
+	level := logrusToETWLevelMap[e.Level]
46 59
 	if !h.provider.IsEnabledForLevel(level) {
47 60
 		return nil
48 61
 	}
... ...
@@ -56,9 +74,6 @@ func (h *Hook) Fire(e *logrus.Entry) error {
56 56
 		fields = append(fields, getFieldOpt(k, v))
57 57
 	}
58 58
 
59
-	// We could try to map Logrus levels to ETW levels, but we would lose some
60
-	// fidelity as there are fewer ETW levels. So instead we use the level
61
-	// directly.
62 59
 	return h.provider.WriteEvent(
63 60
 		"LogrusEntry",
64 61
 		etw.WithEventOpts(etw.WithLevel(level)),
... ...
@@ -186,7 +201,12 @@ func getFieldOpt(k string, v interface{}) etw.FieldOpt {
186 186
 	return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v))
187 187
 }
188 188
 
189
-// Close cleans up the hook and closes the ETW provider.
189
+// Close cleans up the hook and closes the ETW provider. If the provder was
190
+// registered by etwlogrus, it will be closed as part of `Close`. If the
191
+// provider was passed in, it will not be closed.
190 192
 func (h *Hook) Close() error {
191
-	return h.provider.Close()
193
+	if h.closeProvider {
194
+		return h.provider.Close()
195
+	}
196
+	return nil
192 197
 }
193 198
new file mode 100644
... ...
@@ -0,0 +1,159 @@
0
+package security
1
+
2
+import (
3
+	"os"
4
+	"syscall"
5
+	"unsafe"
6
+
7
+	"github.com/pkg/errors"
8
+)
9
+
10
+type (
11
+	accessMask          uint32
12
+	accessMode          uint32
13
+	desiredAccess       uint32
14
+	inheritMode         uint32
15
+	objectType          uint32
16
+	shareMode           uint32
17
+	securityInformation uint32
18
+	trusteeForm         uint32
19
+	trusteeType         uint32
20
+
21
+	explicitAccess struct {
22
+		accessPermissions accessMask
23
+		accessMode        accessMode
24
+		inheritance       inheritMode
25
+		trustee           trustee
26
+	}
27
+
28
+	trustee struct {
29
+		multipleTrustee          *trustee
30
+		multipleTrusteeOperation int32
31
+		trusteeForm              trusteeForm
32
+		trusteeType              trusteeType
33
+		name                     uintptr
34
+	}
35
+)
36
+
37
+const (
38
+	accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
39
+
40
+	accessModeGrant accessMode = 1
41
+
42
+	desiredAccessReadControl desiredAccess = 0x20000
43
+	desiredAccessWriteDac    desiredAccess = 0x40000
44
+
45
+	gvmga = "GrantVmGroupAccess:"
46
+
47
+	inheritModeNoInheritance                  inheritMode = 0x0
48
+	inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
49
+
50
+	objectTypeFileObject objectType = 0x1
51
+
52
+	securityInformationDACL securityInformation = 0x4
53
+
54
+	shareModeRead  shareMode = 0x1
55
+	shareModeWrite shareMode = 0x2
56
+
57
+	sidVmGroup = "S-1-5-83-0"
58
+
59
+	trusteeFormIsSid trusteeForm = 0
60
+
61
+	trusteeTypeWellKnownGroup trusteeType = 5
62
+)
63
+
64
+// GrantVMGroupAccess sets the DACL for a specified file or directory to
65
+// include Grant ACE entries for the VM Group SID. This is a golang re-
66
+// implementation of the same function in vmcompute, just not exported in
67
+// RS5. Which kind of sucks. Sucks a lot :/
68
+func GrantVmGroupAccess(name string) error {
69
+	// Stat (to determine if `name` is a directory).
70
+	s, err := os.Stat(name)
71
+	if err != nil {
72
+		return errors.Wrapf(err, "%s os.Stat %s", gvmga, name)
73
+	}
74
+
75
+	// Get a handle to the file/directory. Must defer Close on success.
76
+	fd, err := createFile(name, s.IsDir())
77
+	if err != nil {
78
+		return err // Already wrapped
79
+	}
80
+	defer syscall.CloseHandle(fd)
81
+
82
+	// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
83
+	ot := objectTypeFileObject
84
+	si := securityInformationDACL
85
+	sd := uintptr(0)
86
+	origDACL := uintptr(0)
87
+	if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
88
+		return errors.Wrapf(err, "%s GetSecurityInfo %s", gvmga, name)
89
+	}
90
+	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
91
+
92
+	// Generate a new DACL which is the current DACL with the required ACEs added.
93
+	// Must defer LocalFree on success.
94
+	newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), origDACL)
95
+	if err != nil {
96
+		return err // Already wrapped
97
+	}
98
+	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
99
+
100
+	// And finally use SetSecurityInfo to apply the updated DACL.
101
+	if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
102
+		return errors.Wrapf(err, "%s SetSecurityInfo %s", gvmga, name)
103
+	}
104
+
105
+	return nil
106
+}
107
+
108
+// createFile is a helper function to call [Nt]CreateFile to get a handle to
109
+// the file or directory.
110
+func createFile(name string, isDir bool) (syscall.Handle, error) {
111
+	namep := syscall.StringToUTF16(name)
112
+	da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
113
+	sm := uint32(shareModeRead | shareModeWrite)
114
+	fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
115
+	if isDir {
116
+		fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
117
+	}
118
+	fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
119
+	if err != nil {
120
+		return 0, errors.Wrapf(err, "%s syscall.CreateFile %s", gvmga, name)
121
+	}
122
+	return fd, nil
123
+}
124
+
125
+// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
126
+// The caller is responsible for LocalFree of the returned DACL on success.
127
+func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
128
+	// Generate pointers to the SIDs based on the string SIDs
129
+	sid, err := syscall.StringToSid(sidVmGroup)
130
+	if err != nil {
131
+		return 0, errors.Wrapf(err, "%s syscall.StringToSid %s %s", gvmga, name, sidVmGroup)
132
+	}
133
+
134
+	inheritance := inheritModeNoInheritance
135
+	if isDir {
136
+		inheritance = inheritModeSubContainersAndObjectsInherit
137
+	}
138
+
139
+	eaArray := []explicitAccess{
140
+		explicitAccess{
141
+			accessPermissions: accessMaskDesiredPermission,
142
+			accessMode:        accessModeGrant,
143
+			inheritance:       inheritance,
144
+			trustee: trustee{
145
+				trusteeForm: trusteeFormIsSid,
146
+				trusteeType: trusteeTypeWellKnownGroup,
147
+				name:        uintptr(unsafe.Pointer(sid)),
148
+			},
149
+		},
150
+	}
151
+
152
+	modifiedDACL := uintptr(0)
153
+	if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
154
+		return 0, errors.Wrapf(err, "%s SetEntriesInAcl %s", gvmga, name)
155
+	}
156
+
157
+	return modifiedDACL, nil
158
+}
0 159
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package security
1
+
2
+//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
3
+
4
+//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
5
+//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) [failretval!=0] = advapi32.SetSecurityInfo
6
+//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) [failretval!=0] = advapi32.SetEntriesInAclW
0 7
new file mode 100644
... ...
@@ -0,0 +1,81 @@
0
+// Code generated mksyscall_windows.exe DO NOT EDIT
1
+
2
+package security
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+
8
+	"golang.org/x/sys/windows"
9
+)
10
+
11
+var _ unsafe.Pointer
12
+
13
+// Do the interface allocations only once for common
14
+// Errno values.
15
+const (
16
+	errnoERROR_IO_PENDING = 997
17
+)
18
+
19
+var (
20
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
21
+)
22
+
23
+// errnoErr returns common boxed Errno values, to prevent
24
+// allocations at runtime.
25
+func errnoErr(e syscall.Errno) error {
26
+	switch e {
27
+	case 0:
28
+		return nil
29
+	case errnoERROR_IO_PENDING:
30
+		return errERROR_IO_PENDING
31
+	}
32
+	// TODO: add more here, after collecting data on the common
33
+	// error values see on Windows. (perhaps when running
34
+	// all.bat?)
35
+	return e
36
+}
37
+
38
+var (
39
+	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
40
+
41
+	procGetSecurityInfo  = modadvapi32.NewProc("GetSecurityInfo")
42
+	procSetSecurityInfo  = modadvapi32.NewProc("SetSecurityInfo")
43
+	procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
44
+)
45
+
46
+func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) {
47
+	r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
48
+	if r1 != 0 {
49
+		if e1 != 0 {
50
+			err = errnoErr(e1)
51
+		} else {
52
+			err = syscall.EINVAL
53
+		}
54
+	}
55
+	return
56
+}
57
+
58
+func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) {
59
+	r1, _, e1 := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
60
+	if r1 != 0 {
61
+		if e1 != 0 {
62
+			err = errnoErr(e1)
63
+		} else {
64
+			err = syscall.EINVAL
65
+		}
66
+	}
67
+	return
68
+}
69
+
70
+func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) {
71
+	r1, _, e1 := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
72
+	if r1 != 0 {
73
+		if e1 != 0 {
74
+			err = errnoErr(e1)
75
+		} else {
76
+			err = syscall.EINVAL
77
+		}
78
+	}
79
+	return
80
+}