Example #1
0
        private DynamicTraceEventData.PayloadFetchClassInfo ParseFields(PinnedStreamReader reader, int numFields)
        {
            string[] fieldNames = new string[numFields];
            DynamicTraceEventData.PayloadFetch[] fieldFetches = new DynamicTraceEventData.PayloadFetch[numFields];

            ushort offset = 0;

            for (int fieldIndex = 0; fieldIndex < numFields; fieldIndex++)
            {
                DynamicTraceEventData.PayloadFetch payloadFetch = new DynamicTraceEventData.PayloadFetch();

                // Read the TypeCode for the current field.
                TypeCode typeCode = (TypeCode)reader.ReadInt32();

                // Fill out the payload fetch object based on the TypeCode.
                switch (typeCode)
                {
                case TypeCode.Boolean:
                {
                    payloadFetch.Type   = typeof(bool);
                    payloadFetch.Size   = 4;       // We follow windows conventions and use 4 bytes for bool.
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Char:
                {
                    payloadFetch.Type   = typeof(char);
                    payloadFetch.Size   = sizeof(char);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.SByte:
                {
                    payloadFetch.Type   = typeof(SByte);
                    payloadFetch.Size   = sizeof(SByte);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Byte:
                {
                    payloadFetch.Type   = typeof(byte);
                    payloadFetch.Size   = sizeof(byte);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Int16:
                {
                    payloadFetch.Type   = typeof(Int16);
                    payloadFetch.Size   = sizeof(Int16);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.UInt16:
                {
                    payloadFetch.Type   = typeof(UInt16);
                    payloadFetch.Size   = sizeof(UInt16);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Int32:
                {
                    payloadFetch.Type   = typeof(Int32);
                    payloadFetch.Size   = sizeof(Int32);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.UInt32:
                {
                    payloadFetch.Type   = typeof(UInt32);
                    payloadFetch.Size   = sizeof(UInt32);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Int64:
                {
                    payloadFetch.Type   = typeof(Int64);
                    payloadFetch.Size   = sizeof(Int64);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.UInt64:
                {
                    payloadFetch.Type   = typeof(UInt64);
                    payloadFetch.Size   = sizeof(UInt64);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Single:
                {
                    payloadFetch.Type   = typeof(Single);
                    payloadFetch.Size   = sizeof(Single);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Double:
                {
                    payloadFetch.Type   = typeof(Double);
                    payloadFetch.Size   = sizeof(Double);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Decimal:
                {
                    payloadFetch.Type   = typeof(Decimal);
                    payloadFetch.Size   = sizeof(Decimal);
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.DateTime:
                {
                    payloadFetch.Type   = typeof(DateTime);
                    payloadFetch.Size   = 8;
                    payloadFetch.Offset = offset;
                    break;
                }

                case EventPipeEventSource.GuidTypeCode:
                {
                    payloadFetch.Type   = typeof(Guid);
                    payloadFetch.Size   = 16;
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.String:
                {
                    payloadFetch.Type   = typeof(String);
                    payloadFetch.Size   = DynamicTraceEventData.NULL_TERMINATED;
                    payloadFetch.Offset = offset;
                    break;
                }

                case TypeCode.Object:
                {
                    // TypeCode.Object represents an embedded struct.

                    // Read the number of fields in the struct.  Each of these fields could be an embedded struct,
                    // but these embedded structs are still counted as single fields.  They will be expanded when they are handled.
                    int structFieldCount = reader.ReadInt32();
                    DynamicTraceEventData.PayloadFetchClassInfo embeddedStructClassInfo = ParseFields(reader, structFieldCount);
                    if (embeddedStructClassInfo == null)
                    {
                        throw new Exception("Unable to parse metadata for embedded struct.");
                    }
                    payloadFetch = DynamicTraceEventData.PayloadFetch.StructPayloadFetch(offset, embeddedStructClassInfo);
                    break;
                }

                default:
                {
                    throw new NotSupportedException($"{typeCode} is not supported.");
                }
                }

                // Read the string name of the event payload field.
                fieldNames[fieldIndex] = reader.ReadNullTerminatedUnicodeString();

                // Update the offset into the event for the next payload fetch.
                if (payloadFetch.Size >= DynamicTraceEventData.SPECIAL_SIZES || offset == ushort.MaxValue)
                {
                    offset = ushort.MaxValue;           // Indicate that the offset must be computed at run time.
                }
                else
                {
                    offset += payloadFetch.Size;
                }

                // Save the current payload fetch.
                fieldFetches[fieldIndex] = payloadFetch;
            }

            return(new DynamicTraceEventData.PayloadFetchClassInfo()
            {
                FieldNames = fieldNames,
                FieldFetches = fieldFetches
            });
        }
        /// <summary>
        /// Creates a new MetaData instance from the serialized data at the current position of 'reader'
        /// of length 'length'.   This typically points at the PAYLOAD AREA of a meta-data events)
        /// 'fileFormatVersionNumber' is the version number of the file as a whole
        /// (since that affects the parsing of this data) and 'processID' is the process ID for the
        /// whole stream (since it needs to be put into the EVENT_RECORD.
        ///
        /// When this constructor returns the reader has read all data given to it (thus it has
        /// move the read pointer by 'length')
        /// </summary>
        public EventPipeEventMetaData(PinnedStreamReader reader, int length, int fileFormatVersionNumber, int pointerSize, int processId)
        {
            StreamLabel eventDataEnd = reader.Current.Add(length);

            _eventRecord = (TraceEventNativeMethods.EVENT_RECORD *)Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD));
            ClearMemory(_eventRecord, sizeof(TraceEventNativeMethods.EVENT_RECORD));

            if (pointerSize == 4)
            {
                _eventRecord->EventHeader.Flags = TraceEventNativeMethods.EVENT_HEADER_FLAG_32_BIT_HEADER;
            }
            else
            {
                _eventRecord->EventHeader.Flags = TraceEventNativeMethods.EVENT_HEADER_FLAG_64_BIT_HEADER;
            }

            _eventRecord->EventHeader.ProcessId = processId;

            StreamLabel metaDataStart = reader.Current;

            if (fileFormatVersionNumber == 1)
            {
                _eventRecord->EventHeader.ProviderId = reader.ReadGuid();
            }
            else
            {
                ProviderName = reader.ReadNullTerminatedUnicodeString();
                _eventRecord->EventHeader.ProviderId = GetProviderGuidFromProviderName(ProviderName);
            }

            var eventId = (ushort)reader.ReadInt32();

            _eventRecord->EventHeader.Id = eventId;
            Debug.Assert(_eventRecord->EventHeader.Id == eventId);  // No truncation

            var version = reader.ReadInt32();

            _eventRecord->EventHeader.Version = (byte)version;
            Debug.Assert(_eventRecord->EventHeader.Version == version);  // No truncation

            if (fileFormatVersionNumber >= 3)
            {
                long keywords = reader.ReadInt64();
                _eventRecord->EventHeader.Keyword = (ulong)keywords;
            }

            int metadataLength = reader.ReadInt32();

            Debug.Assert(0 <= metadataLength && metadataLength < length);
            if (0 < metadataLength)
            {
                // TODO why do we repeat the event number it is redundant.
                eventId = (ushort)reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Id == eventId);  // No truncation
                EventName = reader.ReadNullTerminatedUnicodeString();
                Debug.Assert(EventName.Length < length / 2);

                // Deduce the opcode from the name.
                if (EventName.EndsWith("Start", StringComparison.OrdinalIgnoreCase))
                {
                    _eventRecord->EventHeader.Opcode = (byte)TraceEventOpcode.Start;
                }
                else if (EventName.EndsWith("Stop", StringComparison.OrdinalIgnoreCase))
                {
                    _eventRecord->EventHeader.Opcode = (byte)TraceEventOpcode.Stop;
                }

                _eventRecord->EventHeader.Keyword = (ulong)reader.ReadInt64();

                // TODO why do we repeat the event number it is redundant.
                version = reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Version == version);     // No truncation

                _eventRecord->EventHeader.Level = (byte)reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Level <= 5);

                // Fetch the parameter information
                int parameterCount = reader.ReadInt32();
                Debug.Assert(0 <= parameterCount && parameterCount < length / 8); // Each parameter takes at least 8 bytes.
                if (parameterCount > 0)
                {
                    ParameterDefinitions = new Tuple <TypeCode, string> [parameterCount];
                    for (int i = 0; i < parameterCount; i++)
                    {
                        var type = (TypeCode)reader.ReadInt32();
                        Debug.Assert((uint)type < 24);      // There only a handful of type codes.
                        var name = reader.ReadNullTerminatedUnicodeString();
                        ParameterDefinitions[i] = new Tuple <TypeCode, string>(type, name);
                        Debug.Assert(reader.Current <= eventDataEnd);
                    }
                }
            }
            Debug.Assert(reader.Current == eventDataEnd);
        }