/// <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); }