eventmetadata.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //go:build windows
  2. package etw
  3. import (
  4. "bytes"
  5. "encoding/binary"
  6. )
  7. // inType indicates the type of data contained in the ETW event.
  8. type inType byte
  9. // Various inType definitions for TraceLogging. These must match the definitions
  10. // found in TraceLoggingProvider.h in the Windows SDK.
  11. //
  12. //nolint:deadcode,varcheck // keep unused constants for potential future use
  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. // outType specifies a hint to the event decoder for how the value should be
  44. // formatted.
  45. type outType byte
  46. // Various outType definitions for TraceLogging. These must match the
  47. // definitions found in TraceLoggingProvider.h in the Windows SDK.
  48. //
  49. //nolint:deadcode,varcheck // keep unused constants for potential future use
  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. // 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. // toBytes returns the raw binary data containing the event metadata. Before being
  83. // returned, the current size of the buffer is written to the start of the
  84. // buffer. The returned value is not copied from the internal buffer, so it can
  85. // be mutated by the eventMetadata object after it is returned.
  86. func (em *eventMetadata) toBytes() []byte {
  87. // Finalize the event metadata buffer by filling in the buffer length at the
  88. // beginning.
  89. binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
  90. return em.buffer.Bytes()
  91. }
  92. // writeEventHeader writes the metadata for the start of an event to the buffer.
  93. // This specifies the event name and tags.
  94. func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
  95. _ = binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
  96. em.writeTags(tags)
  97. em.buffer.WriteString(name)
  98. em.buffer.WriteByte(0) // Null terminator for name
  99. }
  100. func (em *eventMetadata) writeFieldInner(name string, inType inType, outType outType, tags uint32, arrSize uint16) {
  101. em.buffer.WriteString(name)
  102. em.buffer.WriteByte(0) // Null terminator for name
  103. if outType == outTypeDefault && tags == 0 {
  104. em.buffer.WriteByte(byte(inType))
  105. } else {
  106. em.buffer.WriteByte(byte(inType | 128))
  107. if tags == 0 {
  108. em.buffer.WriteByte(byte(outType))
  109. } else {
  110. em.buffer.WriteByte(byte(outType | 128))
  111. em.writeTags(tags)
  112. }
  113. }
  114. if arrSize != 0 {
  115. _ = binary.Write(&em.buffer, binary.LittleEndian, arrSize)
  116. }
  117. }
  118. // writeTags writes out the tags value to the event metadata. Tags is a 28-bit
  119. // value, interpreted as bit flags, which are only relevant to the event
  120. // consumer. The event consumer may choose to attribute special meaning to tags
  121. // (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
  122. // bytes, each containing 7 bits of tag value, with the high bit set if there is
  123. // more tag data in the following byte. This allows for a more compact
  124. // representation when not all of the tag bits are needed.
  125. func (em *eventMetadata) writeTags(tags uint32) {
  126. // Only use the top 28 bits of the tags value.
  127. tags &= 0xfffffff
  128. for {
  129. // Tags are written with the most significant bits (e.g. 21-27) first.
  130. val := tags >> 21
  131. if tags&0x1fffff == 0 {
  132. // If there is no more data to write after this, write this value
  133. // without the high bit set, and return.
  134. em.buffer.WriteByte(byte(val & 0x7f))
  135. return
  136. }
  137. em.buffer.WriteByte(byte(val | 0x80))
  138. tags <<= 7
  139. }
  140. }
  141. // writeField writes the metadata for a simple field to the buffer.
  142. //
  143. //nolint:unparam // tags is currently always 0, may change in the future
  144. func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
  145. em.writeFieldInner(name, inType, outType, tags, 0)
  146. }
  147. // writeArray writes the metadata for an array field to the buffer. The number
  148. // of elements in the array must be written as a uint16 in the event data,
  149. // immediately preceding the event data.
  150. //
  151. //nolint:unparam // tags is currently always 0, may change in the future
  152. func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
  153. em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
  154. }
  155. // writeCountedArray writes the metadata for an array field to the buffer. The
  156. // size of a counted array is fixed, and the size is written into the metadata
  157. // directly.
  158. //
  159. //nolint:unused // keep for future use
  160. func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
  161. em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
  162. }
  163. // writeStruct writes the metadata for a nested struct to the buffer. The struct
  164. // contains the next N fields in the metadata, where N is specified by the
  165. // fieldCount argument.
  166. func (em *eventMetadata) writeStruct(name string, fieldCount uint8, tags uint32) {
  167. em.writeFieldInner(name, inTypeStruct, outType(fieldCount), tags, 0)
  168. }