/// <summary> /// Given the EventPipe metaData header and a stream pointing at the serialized meta-data for the parameters for the /// event, create a new DynamicTraceEventData that knows how to parse that event. /// ReaderForParameters.Current is advanced past the parameter information. /// </summary> private DynamicTraceEventData ReadEventParametersAndBuildTemplate(EventPipeEventMetaDataHeader eventMetaDataHeader, PinnedStreamReader readerForParameters) { int opcode; string opcodeName; GetOpcodeFromEventName(eventMetaDataHeader.EventName, out opcode, out opcodeName); DynamicTraceEventData.PayloadFetchClassInfo classInfo = null; DynamicTraceEventData template = new DynamicTraceEventData(null, eventMetaDataHeader.EventId, 0, eventMetaDataHeader.EventName, Guid.Empty, opcode, opcodeName, eventMetaDataHeader.ProviderId, eventMetaDataHeader.ProviderName); // If the metadata contains no parameter metadata, don't attempt to read it. if (!eventMetaDataHeader.ContainsParameterMetadata) { template.payloadNames = new string[0]; template.payloadFetches = new DynamicTraceEventData.PayloadFetch[0]; return(template); } // Read the count of event payload fields. int fieldCount = readerForParameters.ReadInt32(); Debug.Assert(0 <= fieldCount && fieldCount < 0x4000); if (fieldCount > 0) { // Recursively parse the metadata, building up a list of payload names and payload field fetch objects. classInfo = ParseFields(readerForParameters, fieldCount); } else { classInfo = new DynamicTraceEventData.PayloadFetchClassInfo() { FieldNames = new string[0], FieldFetches = new DynamicTraceEventData.PayloadFetch[0] }; } template.payloadNames = classInfo.FieldNames; template.payloadFetches = classInfo.FieldFetches; return(template); }
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 }); }