...

Source file src/github.com/Microsoft/go-winio/pkg/etw/eventmetadata.go

Documentation: github.com/Microsoft/go-winio/pkg/etw

     1  //go:build windows
     2  
     3  package etw
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/binary"
     8  )
     9  
    10  // inType indicates the type of data contained in the ETW event.
    11  type inType byte
    12  
    13  // Various inType definitions for TraceLogging. These must match the definitions
    14  // found in TraceLoggingProvider.h in the Windows SDK.
    15  //
    16  //nolint:deadcode,varcheck // keep unused constants for potential future use
    17  const (
    18  	inTypeNull inType = iota
    19  	inTypeUnicodeString
    20  	inTypeANSIString
    21  	inTypeInt8
    22  	inTypeUint8
    23  	inTypeInt16
    24  	inTypeUint16
    25  	inTypeInt32
    26  	inTypeUint32
    27  	inTypeInt64
    28  	inTypeUint64
    29  	inTypeFloat
    30  	inTypeDouble
    31  	inTypeBool32
    32  	inTypeBinary
    33  	inTypeGUID
    34  	inTypePointerUnsupported
    35  	inTypeFileTime
    36  	inTypeSystemTime
    37  	inTypeSID
    38  	inTypeHexInt32
    39  	inTypeHexInt64
    40  	inTypeCountedString
    41  	inTypeCountedANSIString
    42  	inTypeStruct
    43  	inTypeCountedBinary
    44  	inTypeCountedArray inType = 32
    45  	inTypeArray        inType = 64
    46  )
    47  
    48  // outType specifies a hint to the event decoder for how the value should be
    49  // formatted.
    50  type outType byte
    51  
    52  // Various outType definitions for TraceLogging. These must match the
    53  // definitions found in TraceLoggingProvider.h in the Windows SDK.
    54  //
    55  //nolint:deadcode,varcheck // keep unused constants for potential future use
    56  const (
    57  	// outTypeDefault indicates that the default formatting for the inType will
    58  	// be used by the event decoder.
    59  	outTypeDefault outType = iota
    60  	outTypeNoPrint
    61  	outTypeString
    62  	outTypeBoolean
    63  	outTypeHex
    64  	outTypePID
    65  	outTypeTID
    66  	outTypePort
    67  	outTypeIPv4
    68  	outTypeIPv6
    69  	outTypeSocketAddress
    70  	outTypeXML
    71  	outTypeJSON
    72  	outTypeWin32Error
    73  	outTypeNTStatus
    74  	outTypeHResult
    75  	outTypeFileTime
    76  	outTypeSigned
    77  	outTypeUnsigned
    78  	outTypeUTF8              outType = 35
    79  	outTypePKCS7WithTypeInfo outType = 36
    80  	outTypeCodePointer       outType = 37
    81  	outTypeDateTimeUTC       outType = 38
    82  )
    83  
    84  // eventMetadata maintains a buffer which builds up the metadata for an ETW
    85  // event. It needs to be paired with EventData which describes the event.
    86  type eventMetadata struct {
    87  	buffer bytes.Buffer
    88  }
    89  
    90  // toBytes returns the raw binary data containing the event metadata. Before being
    91  // returned, the current size of the buffer is written to the start of the
    92  // buffer. The returned value is not copied from the internal buffer, so it can
    93  // be mutated by the eventMetadata object after it is returned.
    94  func (em *eventMetadata) toBytes() []byte {
    95  	// Finalize the event metadata buffer by filling in the buffer length at the
    96  	// beginning.
    97  	binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
    98  	return em.buffer.Bytes()
    99  }
   100  
   101  // writeEventHeader writes the metadata for the start of an event to the buffer.
   102  // This specifies the event name and tags.
   103  func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
   104  	_ = binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
   105  	em.writeTags(tags)
   106  	em.buffer.WriteString(name)
   107  	em.buffer.WriteByte(0) // Null terminator for name
   108  }
   109  
   110  func (em *eventMetadata) writeFieldInner(name string, inType inType, outType outType, tags uint32, arrSize uint16) {
   111  	em.buffer.WriteString(name)
   112  	em.buffer.WriteByte(0) // Null terminator for name
   113  
   114  	if outType == outTypeDefault && tags == 0 {
   115  		em.buffer.WriteByte(byte(inType))
   116  	} else {
   117  		em.buffer.WriteByte(byte(inType | 128))
   118  		if tags == 0 {
   119  			em.buffer.WriteByte(byte(outType))
   120  		} else {
   121  			em.buffer.WriteByte(byte(outType | 128))
   122  			em.writeTags(tags)
   123  		}
   124  	}
   125  
   126  	if arrSize != 0 {
   127  		_ = binary.Write(&em.buffer, binary.LittleEndian, arrSize)
   128  	}
   129  }
   130  
   131  // writeTags writes out the tags value to the event metadata. Tags is a 28-bit
   132  // value, interpreted as bit flags, which are only relevant to the event
   133  // consumer. The event consumer may choose to attribute special meaning to tags
   134  // (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
   135  // bytes, each containing 7 bits of tag value, with the high bit set if there is
   136  // more tag data in the following byte. This allows for a more compact
   137  // representation when not all of the tag bits are needed.
   138  func (em *eventMetadata) writeTags(tags uint32) {
   139  	// Only use the top 28 bits of the tags value.
   140  	tags &= 0xfffffff
   141  
   142  	for {
   143  		// Tags are written with the most significant bits (e.g. 21-27) first.
   144  		val := tags >> 21
   145  
   146  		if tags&0x1fffff == 0 {
   147  			// If there is no more data to write after this, write this value
   148  			// without the high bit set, and return.
   149  			em.buffer.WriteByte(byte(val & 0x7f))
   150  			return
   151  		}
   152  
   153  		em.buffer.WriteByte(byte(val | 0x80))
   154  
   155  		tags <<= 7
   156  	}
   157  }
   158  
   159  // writeField writes the metadata for a simple field to the buffer.
   160  //
   161  //nolint:unparam // tags is currently always 0, may change in the future
   162  func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
   163  	em.writeFieldInner(name, inType, outType, tags, 0)
   164  }
   165  
   166  // writeArray writes the metadata for an array field to the buffer. The number
   167  // of elements in the array must be written as a uint16 in the event data,
   168  // immediately preceding the event data.
   169  //
   170  //nolint:unparam // tags is currently always 0, may change in the future
   171  func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
   172  	em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
   173  }
   174  
   175  // writeCountedArray writes the metadata for an array field to the buffer. The
   176  // size of a counted array is fixed, and the size is written into the metadata
   177  // directly.
   178  //
   179  //nolint:unused // keep for future use
   180  func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
   181  	em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
   182  }
   183  
   184  // writeStruct writes the metadata for a nested struct to the buffer. The struct
   185  // contains the next N fields in the metadata, where N is specified by the
   186  // fieldCount argument.
   187  func (em *eventMetadata) writeStruct(name string, fieldCount uint8, tags uint32) {
   188  	em.writeFieldInner(name, inTypeStruct, outType(fieldCount), tags, 0)
   189  }
   190  

View as plain text