Merge remote-tracking branch 'refs/remotes/origin/OpenSource' into ctf

This commit is contained in:
Lee Culver
2016-04-13 09:47:52 -07:00
4 changed files with 149 additions and 111 deletions
+88 -67
View File
@@ -496,14 +496,14 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
try
{
#if DEBUG
// Confirm that the serialization 'adds up'
var computedSize = SkipToField(payloadFetches, payloadFetches.Length, 0, EventDataLength);
Debug.Assert(computedSize <= this.EventDataLength);
if ((int)ID != 0xFFFE) // If it is not a manifest event
{
// TODO FIX NOW the || condition is a hack because PerfVIew.ClrEnableParameters fails.
Debug.Assert(computedSize == this.EventDataLength || this.ProviderName == "PerfView");
}
// Confirm that the serialization 'adds up'
var computedSize = SkipToField(payloadFetches, payloadFetches.Length, 0, EventDataLength);
Debug.Assert(computedSize <= this.EventDataLength);
if ((int)ID != 0xFFFE) // If it is not a manifest event
{
// TODO FIX NOW the || condition is a hack because PerfVIew.ClrEnableParameters fails.
Debug.Assert(computedSize == this.EventDataLength || this.ProviderName == "PerfView");
}
#endif
int offset = payloadFetches[index].Offset;
if (offset == ushort.MaxValue)
@@ -587,31 +587,33 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
if (size >= SPECIAL_SIZES)
{
isAnsi = ((size & IS_ANSI) != 0);
var format = (size & ~IS_ANSI);
if (format == NULL_TERMINATED)
if (IsNullTerminated(size))
{
if ((size & IS_ANSI) != 0)
if (isAnsi)
return GetUTF8StringAt(offset);
else
return GetUnicodeStringAt(offset);
}
else if (format == DynamicTraceEventData.SIZE32_PRECEEDS)
size = (ushort)GetInt32At(offset - 4);
else if (format == DynamicTraceEventData.SIZE16_PRECEEDS)
size = (ushort)GetInt16At(offset - 2);
else if (format == DynamicTraceEventData.SIZE16_PREFIX)
else if (IsCountedSize(size))
{
size = (ushort)GetInt16At(offset);
offset += 2;
bool unicodeByteCountString = !isAnsi && (size & ELEM_COUNT) == 0;
if (((size & BIT_32) != 0))
{
size = (ushort)GetInt32At(offset);
offset += 4; // skip size;
}
else
{
size = (ushort)GetInt16At(offset);
offset += 2; // skip size;
}
if (unicodeByteCountString)
size /= 2; // Unicode string with BYTE count. Element count is half that.
}
else
return "[CANT PARSE STRING]";
if (!isAnsi)
size = (ushort)(size / 2); // Size was a byte count, turn it into a char count.
}
else if (size > 0x8000)
else if (size > 0x8000) // What is this? looks like a hack.
{
size -= 0x8000;
isAnsi = true;
@@ -877,11 +879,13 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
{
int index = int.Parse(m.Groups[1].Value) - 1;
// If there are byte[] values, we hide the argument for the size that is in the manifest.
// Thus we remove it here as well.
// for some array and string values, we remove the length field. Account
// for that when we are resolving the %X qualifers.
for (int i = Math.Min(index, payloadFetches.Length) - 1; 0 <= i; --i)
if (payloadFetches[i].Size == DynamicTraceEventData.SIZE32_PREFIX && payloadFetches[i].Array != null)
{
if ((payloadFetches[i].Size & DynamicTraceEventData.CONSUMES_FIELD) != 0)
--index;
}
if ((uint)index < (uint)PayloadNames.Length)
return PayloadString(index, formatProvider);
@@ -930,19 +934,23 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
var arrayCount = arrayInfo.FixedCount;
if (arrayCount == 0)
{
if (payloadFetch.Size == DynamicTraceEventData.SIZE16_PREFIX)
// Arrays are not strings and thus should not have the ANSI bit set.
Debug.Assert((payloadFetch.Size & IS_ANSI) == 0);
// Arrays never use a byte count.
Debug.Assert((payloadFetch.Size & ELEM_COUNT) != 0);
if (DynamicTraceEventData.IsCountedSize(payloadFetch.Size))
{
arrayCount = (ushort)GetInt16At(offset);
offset += 2;
}
else if ((payloadFetch.Size == DynamicTraceEventData.SIZE16_PRECEEDS))
arrayCount = (ushort)GetInt16At(offset - 2);
else if (payloadFetch.Size == DynamicTraceEventData.SIZE32_PRECEEDS)
arrayCount = GetInt32At(offset - 4);
else if ((payloadFetch.Size == DynamicTraceEventData.SIZE32_PREFIX))
{
arrayCount = GetInt32At(offset);
offset += 4;
if (((payloadFetch.Size & DynamicTraceEventData.BIT_32) != 0))
{
arrayCount = GetInt32At(offset);
offset += 4;
}
else
{
arrayCount = GetInt16At(offset);
offset += 2;
}
}
else
{
@@ -987,14 +995,23 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
return SkipUTF8String(offset);
else if (size == POINTER_SIZE)
return offset + PointerSize;
else if ((size & ~IS_ANSI) == SIZE32_PRECEEDS)
return offset + GetInt32At(offset - 4);
else if ((size & ~IS_ANSI) == SIZE16_PRECEEDS)
return offset + (ushort)GetInt16At(offset - 2);
else if ((size & ~IS_ANSI) == SIZE32_PREFIX)
return offset + GetInt32At(offset) + 4;
else if ((size & ~IS_ANSI) == SIZE16_PREFIX)
return offset + (ushort)(GetInt16At(offset) + 2);
else if (IsCountedSize(size) && payloadFetch.Type == typeof(string))
{
int elemSize;
if (((size & BIT_32) != 0))
{
elemSize = GetInt32At(offset);
offset += 4; // skip size;
}
else
{
elemSize = GetInt16At(offset);
offset += 2; // skip size;
}
if ((size & IS_ANSI) == 0 && (size & ELEM_COUNT) != 0)
elemSize *= 2; // Counted (not byte counted) unicode string. chars are 2 wide.
return offset + elemSize;
}
else
return ushort.MaxValue; // Something sure to fail
}
@@ -1033,22 +1050,24 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
}
}
internal const ushort IS_ANSI = 1; // A bit mask that represents the string is ASCII
// NULL_TERMINATED | IS_ANSI == MaxValue
internal const ushort NULL_TERMINATED = ushort.MaxValue - 1;
// SIZE32_PRECEEDS | IS_ANSI == MaxValue - 2
internal const ushort SIZE32_PRECEEDS = ushort.MaxValue - 3; // binary, BYTE Count is a 32 bit int directly before
// SIZE16_PRECEEDS | IS_ANSI == MaxValue - 4
internal const ushort SIZE16_PRECEEDS = ushort.MaxValue - 5; // binary, BYTE Count is a 16 bit uint directly before this offset
// SIZE16_PREFIX | IS_ANSI == MaxValue - 6
internal const ushort SIZE16_PREFIX = ushort.MaxValue - 7; // binary/strings BYTE Count is a 16 bit uint at this offset followed by data. ALso used for arrays, where it is the COUNT of elements.
// SIZE16_PREFIX | IS_ANSI == MaxValue - 8
internal const ushort SIZE32_PREFIX = ushort.MaxValue - 9; // binary BYTE Count is a 32 bit int at this offset followed by data.
// SIZE16_PRECEEDS | IS_ANSI == MaxValue - 10
// The following 4 bits are used to modify the 'VARSIZE' constant
internal const ushort IS_ANSI = 1; // If set the string is ASCII, unset is UNICODE
internal const ushort BIT_32 = 2; // If set the count is a 32 bit number. unset is 16 bit
internal const ushort CONSUMES_FIELD = 4; // If set there was a explicit count field in the manifest, unset means no explicit field
internal const ushort ELEM_COUNT = 8; // If set count is a char/element count. unset means count is a count of BYTES. Does not include the size prefix itself
internal const ushort POINTER_SIZE = ushort.MaxValue - 14; // It is the pointer size of the target machine.
internal const ushort UNKNOWN_SIZE = ushort.MaxValue - 15; // Generic unknown.
internal const ushort SPECIAL_SIZES = ushort.MaxValue - 15; // Some room for growth.
internal static bool IsNullTerminated(ushort size) { return (size & ~IS_ANSI) == NULL_TERMINATED; }
internal static bool IsCountedSize(ushort size) { return size >= COUNTED_SIZE; }
// These are special sizes
// sizes from 0xFFF0 through 0xFFFF are variations of VAR_SIZE
internal const ushort COUNTED_SIZE = 0xFFF0; // The size is variable. Size preceeded the data, bits above tell more.
// Size 0xFFEF is NULL_TERMINATED | IS_ANSI
internal const ushort NULL_TERMINATED = 0xFFEE; // value is a null terminated string.
internal const ushort POINTER_SIZE = 0xFFED; // It is the pointer size of the target machine.
internal const ushort UNKNOWN_SIZE = 0xFFEC; // Generic unknown.
internal const ushort SPECIAL_SIZES = UNKNOWN_SIZE; // This is always the smallest size as an unsiged number.
internal struct PayloadFetch
{
@@ -1147,12 +1166,12 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
case RegisteredTraceEventParser.TdhInputType.CountedUtf16String:
case RegisteredTraceEventParser.TdhInputType.CountedString:
Type = typeof(string);
Size = DynamicTraceEventData.SIZE16_PREFIX;
Size = DynamicTraceEventData.COUNTED_SIZE; // Unicode, 16 bit, byteCount
break;
case RegisteredTraceEventParser.TdhInputType.CountedAnsiString:
case RegisteredTraceEventParser.TdhInputType.CountedMbcsString:
Type = typeof(string);
Size = DynamicTraceEventData.SIZE16_PREFIX | DynamicTraceEventData.IS_ANSI;
Size = DynamicTraceEventData.COUNTED_SIZE | DynamicTraceEventData.IS_ANSI + DynamicTraceEventData.ELEM_COUNT; // 16 Bit.
break;
case RegisteredTraceEventParser.TdhInputType.Struct:
Type = typeof(DynamicTraceEventData.StructValue);
@@ -1172,11 +1191,11 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
/// <summary>
/// Returns a payload fetch for a Array. If you know the count, then you can give it.
/// </summary>
public static PayloadFetch ArrayPayloadFetch(ushort offset, PayloadFetch element, ushort fixedCount = 0)
public static PayloadFetch ArrayPayloadFetch(ushort offset, PayloadFetch element, ushort size, ushort fixedCount = 0)
{
var ret = new PayloadFetch();
ret.Offset = offset;
ret.Size = DynamicTraceEventData.SIZE16_PRECEEDS;
ret.Size = size;
ret.info = new PayloadFetchArrayInfo() { Element = element, FixedCount = fixedCount };
return ret;
}
@@ -2000,8 +2019,10 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
ret.payloadNames.RemoveAt(prevFieldIdx);
ret.payloadFetches.RemoveAt(prevFieldIdx);
fieldFetch = DynamicTraceEventData.PayloadFetch.ArrayPayloadFetch(offset, fieldFetch);
size = fieldFetch.Size = DynamicTraceEventData.SIZE32_PREFIX; // Now the length is a prefix to the bytes.
// Now the length is a prefix to the bytes.
ushort fetchSize = DynamicTraceEventData.COUNTED_SIZE + DynamicTraceEventData.BIT_32 + DynamicTraceEventData.CONSUMES_FIELD + DynamicTraceEventData.ELEM_COUNT;
fieldFetch = DynamicTraceEventData.PayloadFetch.ArrayPayloadFetch(offset, fieldFetch, fetchSize);
size = fieldFetch.Size;
}
else
{
+47 -42
View File
@@ -1,4 +1,5 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#define USE_OS_DYNAMIC_EVENT_PARSING // TODO REMOVE
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -478,6 +479,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
}
}
#if USE_OS_DYNAMIC_EVENT_PARSING
// TODO FIX NOW after 2016. Windows is going to back-port the logic that makes TraceLogging
// events trigger the EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TDH extended data marker. When
// that happens this path where we parse the TraceLogging data explicitly will become
@@ -492,6 +494,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
return ret;
}
}
#endif
// TODO cache the buffer?, handle more types, handle structs...
int buffSize = 9000;
@@ -514,6 +517,8 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
return ret;
}
#if USE_OS_DYNAMIC_EVENT_PARSING
/*************************** TraceLogging format Support ********************************/
/// <summary>
/// Events that have this special special marker in their channel indicate that the
@@ -668,7 +673,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
if (countFlags != 0 || inType == TdhInputType.Binary)
{
payloadFetch = DynamicTraceEventData.PayloadFetch.ArrayPayloadFetch(fieldOffset, payloadFetch, fixedCount);
payloadFetch.Size = DynamicTraceEventData.SIZE16_PREFIX; // It is not an explicit field beforehand, but a prefix.
payloadFetch.Size = DynamicTraceEventData.COUNTED_SIZE + DynamicTraceEventData.ELEM_COUNT; // 16 bit, Unicode, does not consume field.
}
var size = payloadFetch.Size;
@@ -695,7 +700,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
return false;
}
#region private
#region private
// TODO we may not need all of these.
internal const byte InTypeTypeMask = 31;
@@ -711,13 +716,13 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
TraceEvent data;
int offset;
int eventMetaDataEnd;
#endregion // private
#endregion // private
}
/*************************** End TraceLogging format Support *****************************/
#endif
/// <summary>
/// TdhEvenParser takes the Trace Diagnostics Helper (TDH) TRACE_EVENT_INFO structure and
/// TdhEventParser takes the Trace Diagnostics Helper (TDH) TRACE_EVENT_INFO structure and
/// (passed as a byte*) and converts it to a DynamicTraceEventData which which
/// can be used to parse events of that type. You first create TdhEventParser and then
/// call ParseEventMetaData to do the parsing.
@@ -899,11 +904,10 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
if (countOrCountIndex == startField + curField - 1)
{
var lastFieldIdx = fieldFetches.Count - 1;
arraySize = DynamicTraceEventData.COUNTED_SIZE + DynamicTraceEventData.CONSUMES_FIELD + DynamicTraceEventData.ELEM_COUNT;
if (fieldFetches[lastFieldIdx].Size == 4)
arraySize = DynamicTraceEventData.SIZE32_PREFIX; // TODO we can probably remove this...
else if (fieldFetches[lastFieldIdx].Size == 2)
arraySize = DynamicTraceEventData.SIZE16_PREFIX;
else
arraySize += DynamicTraceEventData.BIT_32;
else if (fieldFetches[lastFieldIdx].Size != 2)
{
Trace.WriteLine("WARNING: Unexpected dynamic length size, giving up");
goto Exit;
@@ -922,18 +926,19 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
}
}
// Strings are treated specially (we don't treat them as an array of chars.
// Strings are treated specially (we don't treat them as an array of chars).
// They don't need an arrayFetch but DO need set the size and offset appropriately
if (propertyFetch.Type != typeof(string))
if (propertyFetch.Type == typeof(string))
{
// This is a string with its size determined by another field. Set the size
// based on 'arraySize' but preserver the IS_ANSI that we got from looking at the tdhInType.
propertyFetch.Size = (ushort)(arraySize | (propertyFetch.Size & DynamicTraceEventData.IS_ANSI));
propertyFetch.Offset = arrayFieldOffset;
}
else
{
Debug.WriteLine(" Field is an array of size " + ((fixedCount != 0) ? fixedCount.ToString() : "VARIABLE") + " of type " + ((propertyFetch.Type ?? typeof(void))) + " at offset " + arrayFieldOffset.ToString("x"));
propertyFetch = DynamicTraceEventData.PayloadFetch.ArrayPayloadFetch(arrayFieldOffset, propertyFetch, fixedCount);
propertyFetch.Size = arraySize;
}
else
{
propertyFetch.Size = arraySize;
propertyFetch.Offset = arrayFieldOffset;
propertyFetch = DynamicTraceEventData.PayloadFetch.ArrayPayloadFetch(arrayFieldOffset, propertyFetch, arraySize, fixedCount);
}
fieldOffset = ushort.MaxValue; // Indicate that the next offset must be computed at run time.
@@ -987,13 +992,13 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
return map;
}
#region private
#region private
TRACE_EVENT_INFO* eventInfo;
TraceEventNativeMethods.EVENT_RECORD* eventRecord;
Dictionary<MapKey, IDictionary<long, string>> mapTable; // table of enums that have defined.
EVENT_PROPERTY_INFO* propertyInfos;
byte* eventBuffer; // points at the eventInfo, but in increments of bytes
#endregion // private
#endregion // private
}
[DllImport("tdh.dll"), SuppressUnmanagedCodeSecurityAttribute]
@@ -1097,7 +1102,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
// Normally Count is 1 (thus every field in an array, it is just that most array have fixed size of 1)
public ushort CountOrCountIndex; // Flags & ParamFixedLength determines if it count, otherwise countIndex
// Normally Length is the size of InType (thus is fixed), but can be variable for blobs.
// Normally Length is the size of InType (thus is fixed), but can be variable for blobs.
public ushort LengthOrLengthIndex; // Flags & ParamLength determines if it lengthIndex otherwise it is the length InType
public int Reserved;
}
@@ -1153,7 +1158,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
HexDump,
WbemSID
};
#endregion
#endregion
}
/// <summary>
@@ -1181,11 +1186,11 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
{
DynamicTraceEventData template = (new RegisteredTraceEventParser.TdhEventParser((byte*)data.userData, null, MapTable)).ParseEventMetaData();
// Uncomment this if you want to see the template in the debugger at this point
// template.source = data.source;
// template.eventRecord = data.eventRecord;
// template.userData = data.userData;
m_state.m_templates[template] = template;
// Uncomment this if you want to see the template in the debugger at this point
// template.source = data.source;
// template.eventRecord = data.eventRecord;
// template.userData = data.userData;
m_state.m_templates[template] = template;
};
// Try to parse bitmap and value map information.
@@ -1210,8 +1215,8 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
this.source.RegisterUnhandledEvent(delegate (TraceEvent unknown)
{
// See if we already have this definition
DynamicTraceEventData parsedTemplate = null;
// See if we already have this definition
DynamicTraceEventData parsedTemplate = null;
if (!m_state.m_templates.TryGetValue(unknown, out parsedTemplate))
{
@@ -1222,17 +1227,17 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
if (parsedTemplate == null)
return false;
// registeredWithTraceEventSource is a fail safe. Basically if you added yourself to the table
// (In OnNewEventDefinition) then you should not come back as unknown, however because of dual events
// and just general fragility we don't want to rely on that. So we keep a bit and insure that we
// only add the event definition once.
if (!parsedTemplate.registeredWithTraceEventSource)
// registeredWithTraceEventSource is a fail safe. Basically if you added yourself to the table
// (In OnNewEventDefinition) then you should not come back as unknown, however because of dual events
// and just general fragility we don't want to rely on that. So we keep a bit and insure that we
// only add the event definition once.
if (!parsedTemplate.registeredWithTraceEventSource)
{
parsedTemplate.registeredWithTraceEventSource = true;
bool ret = OnNewEventDefintion(parsedTemplate, false) == EventFilterResponse.AcceptEvent;
// If we have subscribers, notify them as well.
var newEventDefinition = NewEventDefinition;
// If we have subscribers, notify them as well.
var newEventDefinition = NewEventDefinition;
if (newEventDefinition != null)
ret |= (NewEventDefinition(parsedTemplate, false) == EventFilterResponse.AcceptEvent);
return ret;
@@ -1247,7 +1252,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
/// </summary>
public override bool IsStatic { get { return false; } }
#region private
#region private
internal Func<DynamicTraceEventData, bool, EventFilterResponse> NewEventDefinition;
/// <summary>
@@ -1316,10 +1321,10 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
}
Dictionary<MapKey, IDictionary<long, string>> m_maps; // Any maps (enums or bitsets) defined by KernelTraceControl events.
#endregion
#endregion
}
#region internal classes
#region internal classes
/// <summary>
/// Used to look up Enums (provider x enumName); Very boring class.
/// </summary>
@@ -1404,7 +1409,7 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
}
}
#region IFastSerializable Members
#region IFastSerializable Members
/// <summary>
/// Implements IFastSerializable interface
/// </summary>
@@ -1447,8 +1452,8 @@ namespace Microsoft.Diagnostics.Tracing.Parsers
m_templates.Add(template, template);
}
}
#endregion
#endregion
}
#endregion
#endregion
}
+13 -1
View File
@@ -983,7 +983,19 @@ namespace Microsoft.Diagnostics.Tracing
if (0 <= index)
return PayloadValue(index);
return null;
}
}
/// <summary>
/// PayloadStringByName functions the same as PayloadByName, but uses PayloadString instead of PayloadValue.
/// <para>It will return null if propertyName is not found.</para>
/// <para>This method is not intended to be used in performance critical code.</para>
/// </summary>
public string PayloadStringByName(string propertyName, IFormatProvider formatProvider = null)
{
int index = PayloadIndex(propertyName);
if (0 <= index)
return PayloadString(index, formatProvider);
return null;
}
// Raw payload bytes
/// <summary>
/// The size of the event-specific data payload. (see EventData)
+1 -1
View File
@@ -3054,7 +3054,7 @@ namespace Microsoft.Diagnostics.Tracing.Etlx
}
int IFastSerializableVersion.Version
{
get { return 60; }
get { return 61; }
}
int IFastSerializableVersion.MinimumVersionCanRead
{