private IEnumerable <CtfField> ParseStructFields(string metadata, int begin, int end) { Debug.Assert(metadata[begin] == '{'); foreach (string statement in EnumerateStatements(metadata, begin + 1, end)) { int index; string name = null; CtfMetadataType type = ParseOneType(statement, out index); name = statement.Substring(index).Trim(); Debug.Assert(type != null); Debug.Assert(name != null); int openBracket = name.IndexOf('[') + 1; int closeBracket = openBracket > 0 ? name.IndexOf(']', openBracket + 1) : -1; if (closeBracket != -1) { string arrayVal = name.Substring(openBracket, closeBracket - openBracket).Trim(); name = name.Substring(0, openBracket - 1).Trim(); type = new CtfArray(type, arrayVal); } yield return(new CtfField(type, name)); } }
private object ReadType(CtfStruct strct, object[] result, CtfMetadataType type) { Align(type.Align); switch (type.CtfType) { case CtfTypes.Array: CtfArray array = (CtfArray)type; int len = array.GetLength(strct, result); object[] ret = new object[len]; for (int j = 0; j < len; j++) { ret[j] = ReadType(null, null, array.Type); } return(ret); case CtfTypes.Enum: return(ReadType(strct, result, ((CtfEnum)type).Type)); case CtfTypes.Float: CtfFloat flt = (CtfFloat)type; ReadBits(flt.Exp + flt.Mant); return(0f); // TODO: Not implemented. case CtfTypes.Integer: CtfInteger ctfInt = (CtfInteger)type; return(ReadInteger(ctfInt)); case CtfTypes.String: bool ascii = ((CtfString)type).IsAscii; return(ReadString(ascii)); case CtfTypes.Struct: return(ReadStruct((CtfStruct)type)); case CtfTypes.Variant: CtfVariant var = (CtfVariant)type; int i = strct.GetFieldIndex(var.Switch); CtfField field = strct.Fields[i]; CtfEnum enumType = (CtfEnum)field.Type; int value = strct.GetFieldValue <int>(result, i); string name = enumType.GetName(value); field = var.Union.Where(f => f.Name == name).Single(); return(ReadType(strct, result, field.Type)); default: throw new InvalidOperationException(); } }
public IEnumerable <CtfEventHeader> EnumerateEventHeaders() { CtfStruct header = _streamDefinition.EventHeader; CtfEnum id = (CtfEnum)header.GetField("id").Type; CtfVariant v = (CtfVariant)header.GetField("v").Type; CtfStruct extended = (CtfStruct)v.GetVariant("extended").Type; CtfInteger extendedId = (CtfInteger)extended.GetField("id").Type; CtfInteger extendedTimestamp = (CtfInteger)extended.GetField("timestamp").Type; CtfInteger compactTimestamp = (CtfInteger)((CtfStruct)v.GetVariant("compact").Type).GetField("timestamp").Type; CtfInteger pid = null; CtfInteger tid = null; CtfArray processName = null; string lastProcessName = ""; int processLen = 0; CtfStruct eventContext = _streamDefinition.EventContext; if (eventContext != null) { pid = (CtfInteger)eventContext.GetField("_vpid")?.Type; tid = (CtfInteger)eventContext.GetField("_vtid")?.Type; processName = (CtfArray)eventContext.GetField("_procname")?.Type; // We only handle ascii process names, which seems to be the only thing lttng provides. if (processName != null) { processLen = int.Parse(processName.Index); Debug.Assert(processName.Type.GetSize() == 8); if (processName.Type.GetSize() != 8) { processName = null; } } } uint extendedIdValue = (uint)id.GetValue("extended").End; ulong lowMask = 0, highMask = 0, overflowBit = 0; ulong lastTimestamp = 0; while (!_eof) { if (_readHeader) { throw new InvalidOperationException("Must read an events data before reading the header again."); } _header.Clear(); ResetBuffer(); ReadStruct(header); if (_eof) { break; } ulong timestamp; uint event_id = CtfInteger.ReadInt <uint>(id.Type, _buffer, id.BitOffset); if (event_id == extendedIdValue) { event_id = CtfInteger.ReadInt <uint>(extendedId, _buffer, extendedId.BitOffset); timestamp = CtfInteger.ReadInt <ulong>(extendedTimestamp, _buffer, extendedTimestamp.BitOffset); } else { if (overflowBit == 0) { overflowBit = (1ul << compactTimestamp.Size); lowMask = overflowBit - 1; highMask = ~lowMask; } ulong uint27timestamp = CtfInteger.ReadInt <ulong>(compactTimestamp, _buffer, compactTimestamp.BitOffset); ulong prevLowerBits = lastTimestamp & lowMask; if (prevLowerBits < uint27timestamp) { timestamp = (lastTimestamp & highMask) | uint27timestamp; } else { timestamp = (lastTimestamp & highMask) | uint27timestamp; timestamp += overflowBit; } } lastTimestamp = timestamp; CtfEvent evt = _streamDefinition.Events[(int)event_id]; _header.Event = evt; _header.Timestamp = timestamp; if (eventContext != null) { ReadStruct(eventContext); if (pid != null) { _header.Pid = CtfInteger.ReadInt <int>(pid, _buffer, pid.BitOffset); } if (tid != null) { _header.Tid = CtfInteger.ReadInt <int>(tid, _buffer, tid.BitOffset); } bool matches = true; int processNameOffset = processName.BitOffset >> 3; if (_buffer[processNameOffset] == 0) { lastProcessName = string.Empty; } else { int len = 0; for (; len < processLen && _buffer[processNameOffset + len] != 0; len++) { if (len >= lastProcessName.Length) { matches = false; } else { matches &= lastProcessName[len] == _buffer[processNameOffset + len]; } } if (!matches || len != lastProcessName.Length) { lastProcessName = Encoding.UTF8.GetString(_buffer, processName.BitOffset >> 3, len); } } _header.ProcessName = lastProcessName; } _readHeader = true; yield return(_header); } }
public void ReadTypeIntoBuffer(CtfStruct context, CtfMetadataType type) { Align(type.Align); type.BitOffset = _bitOffset; if (type.CtfType == CtfTypes.Enum) { type = ((CtfEnum)type).Type; type.BitOffset = _bitOffset; } else if (type.CtfType != CtfTypes.Struct && type.CtfType != CtfTypes.Variant) { int size = type.GetSize(); if (size != CtfEvent.SizeIndeterminate) { ReadBits(size); return; } } switch (type.CtfType) { case CtfTypes.Array: CtfArray array = (CtfArray)type; var indexType = context.GetField(array.Index).Type; int len = CtfInteger.ReadInt <int>(indexType, _buffer, indexType.BitOffset); int elemSize = array.Type.GetSize(); if (elemSize == CtfEvent.SizeIndeterminate) { for (int j = 0; j < len; j++) { ReadTypeIntoBuffer(null, array.Type); } } else { for (int j = 0; j < len; j++) { Align(type.Align); ReadBits(elemSize); } } break; case CtfTypes.Float: CtfFloat flt = (CtfFloat)type; ReadBits(flt.Exp + flt.Mant); break; case CtfTypes.Integer: CtfInteger ctfInt = (CtfInteger)type; ReadBits(ctfInt.Size); break; case CtfTypes.String: Debug.Assert((_bitOffset % 8) == 0); int startOffset = _bitOffset >> 3; int offset = startOffset; ReadBits(8); bool ascii = ((CtfString)type).IsAscii; if (ascii) { while (_buffer[offset++] != 0) { ReadBits(8); } } else { byte b = _buffer[offset]; while (b != 0) { switch (b) { default: break; case 0xc: case 0xd: ReadBits(8); break; case 0xe: ReadBits(16); break; case 0xf: ReadBits(24); break; } offset = ReadBits(8) >> 3; b = _buffer[offset]; } } int bufferLen = (_bitOffset >> 3) - startOffset; Encoding encoding = ascii ? Encoding.ASCII : Encoding.UTF8; byte[] newArr = Encoding.Convert(encoding, Encoding.Unicode, _buffer, startOffset, bufferLen); ((CtfString)type).Length = bufferLen; if (_buffer.Length < _bufferLength + newArr.Length) { byte[] buffer = ReallocateBuffer(_bufferLength + newArr.Length); System.Buffer.BlockCopy(buffer, 0, _buffer, 0, _bufferLength); } System.Buffer.BlockCopy(newArr, 0, _buffer, startOffset, newArr.Length); _bufferLength = startOffset + newArr.Length; _bitOffset = _bufferLength * 8; break; case CtfTypes.Struct: ReadStruct((CtfStruct)type); break; case CtfTypes.Variant: CtfVariant var = (CtfVariant)type; CtfField field = context.GetField(var.Switch); CtfEnum enumType = (CtfEnum)field.Type; int value = CtfInteger.ReadInt <int>(enumType, _buffer, enumType.BitOffset); string name = enumType.GetName(value); field = var.GetVariant(name); ReadTypeIntoBuffer(null, field.Type); break; default: throw new InvalidOperationException(); } }