newprovider.go 2.4 KB

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