github.com/Serizao/go-winio@v0.0.0-20230906082528-f02f7f4ad6e8/pkg/etw/newprovider.go (about) 1 //go:build windows && (amd64 || arm64 || 386) 2 // +build windows 3 // +build amd64 arm64 386 4 5 package etw 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "unsafe" 11 12 "github.com/Serizao/go-winio/pkg/guid" 13 "golang.org/x/sys/windows" 14 ) 15 16 // NewProviderWithOptions creates and registers a new ETW provider, allowing 17 // the provider ID and Group to be manually specified. This is most useful when 18 // there is an existing provider ID that must be used to conform to existing 19 // diagnostic infrastructure. 20 func NewProviderWithOptions(name string, options ...ProviderOpt) (provider *Provider, err error) { 21 var opts providerOpts 22 for _, opt := range options { 23 opt(&opts) 24 } 25 26 if opts.id == (guid.GUID{}) { 27 opts.id = providerIDFromName(name) 28 } 29 30 providerCallbackOnce.Do(func() { 31 globalProviderCallback = windows.NewCallback(providerCallbackAdapter) 32 }) 33 34 provider = providers.newProvider() 35 defer func(provider *Provider) { 36 if err != nil { 37 providers.removeProvider(provider) 38 } 39 }(provider) 40 provider.ID = opts.id 41 provider.callback = opts.callback 42 43 if err := eventRegister((*windows.GUID)(&provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil { 44 return nil, err 45 } 46 47 trait := &bytes.Buffer{} 48 if opts.group != (guid.GUID{}) { 49 _ = binary.Write(trait, binary.LittleEndian, uint16(0)) // Write empty size for buffer (update later) 50 _ = binary.Write(trait, binary.LittleEndian, uint8(1)) // EtwProviderTraitTypeGroup 51 traitArray := opts.group.ToWindowsArray() // Append group guid 52 trait.Write(traitArray[:]) 53 binary.LittleEndian.PutUint16(trait.Bytes(), uint16(trait.Len())) // Update size 54 } 55 56 metadata := &bytes.Buffer{} 57 _ = binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later) 58 metadata.WriteString(name) 59 metadata.WriteByte(0) // Null terminator for name 60 _, _ = trait.WriteTo(metadata) // Add traits if applicable 61 binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer 62 provider.metadata = metadata.Bytes() 63 64 if err := eventSetInformation( 65 provider.handle, 66 eventInfoClassProviderSetTraits, 67 uintptr(unsafe.Pointer(&provider.metadata[0])), 68 uint32(len(provider.metadata)), 69 ); err != nil { 70 return nil, err 71 } 72 73 return provider, nil 74 }