in src/TraceEvent/RegisteredTraceEventParser.cs [88:514]
public static string GetManifestForRegisteredProvider(Guid providerGuid)
{
int buffSize = 84000; // Still in the small object heap.
byte* buffer = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(buffSize);
byte* enumBuffer = null;
TraceEventNativeMethods.EVENT_RECORD eventRecord = new TraceEventNativeMethods.EVENT_RECORD();
eventRecord.EventHeader.ProviderId = providerGuid;
// We keep events of a given event number together in the output
string providerName = null;
SortedDictionary<int, StringWriter> events = new SortedDictionary<int, StringWriter>();
// We keep tasks separated by task ID
SortedDictionary<int, TaskInfo> tasks = new SortedDictionary<int, TaskInfo>();
// Templates where the KEY is the template string and the VALUE is the template name (backwards)
Dictionary<string, string> templateIntern = new Dictionary<string, string>(8);
// Remember any enum types we have. Value is XML for the enum (normal)
Dictionary<string, string> enumIntern = new Dictionary<string, string>();
StringWriter enumLocalizations = new StringWriter();
// Any task names used so far
Dictionary<string, int> taskNames = new Dictionary<string, int>();
// Any es used so far
Dictionary<string, int> opcodeNames = new Dictionary<string, int>();
// This ensures that we have unique event names.
Dictionary<string, int> eventNames = new Dictionary<string, int>();
SortedDictionary<ulong, string> keywords = new SortedDictionary<ulong, string>();
List<ProviderDataItem> keywordsItems = TraceEventProviders.GetProviderKeywords(providerGuid);
if (keywordsItems != null)
{
foreach (var keywordItem in keywordsItems)
{
// Skip the reserved keywords.
if (keywordItem.Value >= 1000000000000UL)
{
continue;
}
keywords[keywordItem.Value] = MakeLegalIdentifier(keywordItem.Name);
}
}
for (int ver = 0; ver <= 255; ver++)
{
eventRecord.EventHeader.Version = (byte) ver;
int count;
int status;
for (; ; )
{
int dummy;
status = ETWParsing.TdhGetAllEventsInformation(&eventRecord, IntPtr.Zero, out dummy, out count, buffer, ref buffSize);
if (status != 122 || 20000000 < buffSize) // 122 == Insufficient buffer keep it under 2Meg
{
break;
}
Marshal.FreeHGlobal((IntPtr)buffer);
buffer = (byte*)Marshal.AllocHGlobal(buffSize);
}
// TODO FIX NOW deal with too small of a buffer.
if (status == 0)
{
TRACE_EVENT_INFO** eventInfos = (TRACE_EVENT_INFO**)buffer;
for (int i = 0; i < count; i++)
{
TRACE_EVENT_INFO* eventInfo = eventInfos[i];
byte* eventInfoBuff = (byte*)eventInfo;
EVENT_PROPERTY_INFO* propertyInfos = &eventInfo->EventPropertyInfoArray;
if (providerName == null)
{
if (eventInfo->ProviderNameOffset != 0)
{
providerName = new string((char*)(&eventInfoBuff[eventInfo->ProviderNameOffset]));
}
else
{
providerName = "provider(" + eventInfo->ProviderGuid.ToString() + ")";
}
}
// Compute task name
string taskName = null;
if (eventInfo->TaskNameOffset != 0)
{
taskName = MakeLegalIdentifier((new string((char*)(&eventInfoBuff[eventInfo->TaskNameOffset]))));
}
if (taskName == null)
{
taskName = "task_" + eventInfo->EventDescriptor.Task.ToString();
}
// Ensure task name is unique.
int taskNumForName;
if (taskNames.TryGetValue(taskName, out taskNumForName) && taskNumForName != eventInfo->EventDescriptor.Task)
{
taskName = taskName + "_" + eventInfo->EventDescriptor.Task.ToString();
}
taskNames[taskName] = eventInfo->EventDescriptor.Task;
// Compute opcode name
string opcodeName = "";
if (eventInfo->EventDescriptor.Opcode != 0)
{
if (eventInfo->OpcodeNameOffset != 0)
{
opcodeName = MakeLegalIdentifier((new string((char*)(&eventInfoBuff[eventInfo->OpcodeNameOffset]))));
}
else
{
opcodeName = "opcode_" + eventInfo->EventDescriptor.Opcode.ToString();
}
}
// Ensure opcode name is unique.
int opcodeNumForName;
if (opcodeNames.TryGetValue(opcodeName, out opcodeNumForName) && opcodeNumForName != eventInfo->EventDescriptor.Opcode)
{
// If we did not find a name, use 'opcode and the disambiguator
if (eventInfo->OpcodeNameOffset == 0)
{
opcodeName = "opcode";
}
opcodeName = opcodeName + "_" + eventInfo->EventDescriptor.Task.ToString() + "_" + eventInfo->EventDescriptor.Opcode.ToString();
}
opcodeNames[opcodeName] = eventInfo->EventDescriptor.Opcode;
// And event name
string eventName = taskName;
if (!taskName.EndsWith(opcodeName, StringComparison.OrdinalIgnoreCase))
{
eventName += Capitalize(opcodeName);
}
// Ensure uniqueness of the event name
int eventNumForName;
if (eventNames.TryGetValue(eventName, out eventNumForName) && eventNumForName != eventInfo->EventDescriptor.Id)
{
eventName = eventName + eventInfo->EventDescriptor.Id.ToString();
}
eventNames[eventName] = eventInfo->EventDescriptor.Id;
// Get task information
TaskInfo taskInfo;
if (!tasks.TryGetValue(eventInfo->EventDescriptor.Task, out taskInfo))
{
tasks[eventInfo->EventDescriptor.Task] = taskInfo = new TaskInfo() { Name = taskName };
}
var symbolName = eventName;
if (eventInfo->EventDescriptor.Version > 0)
{
symbolName += "_V" + eventInfo->EventDescriptor.Version;
}
StringWriter eventWriter;
if (!events.TryGetValue(eventInfo->EventDescriptor.Id, out eventWriter))
{
events[eventInfo->EventDescriptor.Id] = eventWriter = new StringWriter();
}
eventWriter.Write(" <event value=\"{0}\" symbol=\"{1}\" version=\"{2}\" task=\"{3}\"",
eventInfo->EventDescriptor.Id,
symbolName,
eventInfo->EventDescriptor.Version,
taskName);
if (eventInfo->EventDescriptor.Opcode != 0)
{
string opcodeId;
if (eventInfo->EventDescriptor.Opcode < 10) // It is a reserved opcode.
{
// For some reason opcodeName does not have the underscore, which we need.
if (eventInfo->EventDescriptor.Opcode == (byte)TraceEventOpcode.DataCollectionStart)
{
opcodeId = "win:DC_Start";
}
else if (eventInfo->EventDescriptor.Opcode == (byte)TraceEventOpcode.DataCollectionStop)
{
opcodeId = "win:DC_Stop";
}
else
{
opcodeId = "win:" + opcodeName;
}
}
else
{
opcodeId = opcodeName;
if (taskInfo.Opcodes == null)
{
taskInfo.Opcodes = new SortedDictionary<int, string>();
}
if (!taskInfo.Opcodes.ContainsKey(eventInfo->EventDescriptor.Opcode))
{
taskInfo.Opcodes[eventInfo->EventDescriptor.Opcode] = opcodeId;
}
}
eventWriter.Write(" opcode=\"{0}\"", opcodeId);
}
// TODO handle cases outside standard levels
if ((int)TraceEventLevel.Always <= eventInfo->EventDescriptor.Level && eventInfo->EventDescriptor.Level <= (int)TraceEventLevel.Verbose)
{
var asLevel = (TraceEventLevel)eventInfo->EventDescriptor.Level;
var levelName = "win:" + asLevel;
eventWriter.Write(" level=\"{0}\"", levelName);
}
var keywordStr = GetKeywordStr(keywords, (ulong)eventInfo->EventDescriptor.Keyword);
if (keywordStr.Length > 0)
{
eventWriter.Write(" keywords=\"" + keywordStr + "\"", eventInfo->EventDescriptor.Keyword);
}
if (eventInfo->TopLevelPropertyCount != 0)
{
var templateWriter = new StringWriter();
string[] propertyNames = new string[eventInfo->TopLevelPropertyCount];
for (int j = 0; j < eventInfo->TopLevelPropertyCount; j++)
{
EVENT_PROPERTY_INFO* propertyInfo = &propertyInfos[j];
var propertyName = new string((char*)(&eventInfoBuff[propertyInfo->NameOffset]));
propertyNames[j] = propertyName;
var enumAttrib = "";
// Deal with any maps (bit fields or enumerations)
if (propertyInfo->MapNameOffset != 0)
{
string mapName = new string((char*)(&eventInfoBuff[propertyInfo->MapNameOffset]));
if (enumBuffer == null)
{
enumBuffer = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(buffSize);
}
if (!enumIntern.ContainsKey(mapName))
{
EVENT_MAP_INFO* enumInfo = (EVENT_MAP_INFO*)enumBuffer;
var hr = TdhGetEventMapInformation(&eventRecord, mapName, enumInfo, ref buffSize);
if (hr == 0)
{
// We only support manifest enums for now.
if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP ||
enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_BITMAP)
{
StringWriter enumWriter = new StringWriter();
string enumName = new string((char*)(&enumBuffer[enumInfo->NameOffset]));
enumAttrib = " map=\"" + enumName + "\"";
if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP)
{
enumWriter.WriteLine(" <valueMap name=\"{0}\">", enumName);
}
else
{
enumWriter.WriteLine(" <bitMap name=\"{0}\">", enumName);
}
EVENT_MAP_ENTRY* mapEntries = &enumInfo->MapEntryArray;
for (int k = 0; k < enumInfo->EntryCount; k++)
{
int value = mapEntries[k].Value;
string valueName = new string((char*)(&enumBuffer[mapEntries[k].NameOffset])).Trim();
enumWriter.WriteLine(" <map value=\"0x{0:x}\" message=\"$(string.map_{1}{2})\"/>", value, enumName, valueName);
enumLocalizations.WriteLine(" <string id=\"map_{0}{1}\" value=\"{2}\"/>", enumName, valueName, valueName);
}
if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP)
{
enumWriter.WriteLine(" </valueMap>", enumName);
}
else
{
enumWriter.WriteLine(" </bitMap>", enumName);
}
enumIntern[mapName] = enumWriter.ToString();
}
}
}
}
// Remove anything that does not look like an ID (.e.g space)
propertyName = Regex.Replace(propertyName, "[^A-Za-z0-9_]", "");
TdhInputType propertyType = propertyInfo->InType;
string countOrLengthAttrib = "";
if ((propertyInfo->Flags & PROPERTY_FLAGS.ParamCount) != 0)
{
countOrLengthAttrib = " count=\"" + propertyNames[propertyInfo->CountOrCountIndex] + "\"";
}
else if ((propertyInfo->Flags & PROPERTY_FLAGS.ParamLength) != 0)
{
countOrLengthAttrib = " length=\"" + propertyNames[propertyInfo->LengthOrLengthIndex] + "\"";
}
templateWriter.WriteLine(" <data name=\"{0}\" inType=\"win:{1}\"{2}{3}/>", propertyName, propertyType.ToString(), enumAttrib, countOrLengthAttrib);
}
var templateStr = templateWriter.ToString();
// See if this template already exists, and if not make it
string templateName;
if (!templateIntern.TryGetValue(templateStr, out templateName))
{
templateName = eventName + "Args";
if (eventInfo->EventDescriptor.Version > 0)
{
templateName += "_V" + eventInfo->EventDescriptor.Version;
}
templateIntern[templateStr] = templateName;
}
eventWriter.Write(" template=\"{0}\"", templateName);
}
eventWriter.WriteLine("/>");
}
}
else if (status == 1168 && ver != 0) // Not Found give up
{
break;
}
}
if (enumBuffer != null)
{
System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)enumBuffer);
}
System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)buffer);
if (providerName == null)
{
throw new ApplicationException("Could not find provider with at GUID of " + providerGuid.ToString());
}
StringWriter manifest = new StringWriter();
manifest.WriteLine("<instrumentationManifest xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
manifest.WriteLine(" <instrumentation xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\">");
manifest.WriteLine(" <events>");
manifest.WriteLine(" <provider name=\"{0}\" guid=\"{{{1}}}\" resourceFileName=\"{0}\" messageFileName=\"{0}\" symbol=\"{2}\" source=\"Xml\" >",
providerName, providerGuid, Regex.Replace(providerName, @"[^\w]", ""));
StringWriter localizedStrings = new StringWriter();
if (keywords != null)
{
manifest.WriteLine(" <keywords>");
foreach (var keyValue in keywords)
{
manifest.WriteLine(" <keyword name=\"{0}\" message=\"$(string.keyword_{1})\" mask=\"0x{2:x}\"/>",
keyValue.Value, keyValue.Value, keyValue.Key);
localizedStrings.WriteLine(" <string id=\"keyword_{0}\" value=\"{1}\"/>", keyValue.Value, keyValue.Value);
}
manifest.WriteLine(" </keywords>");
}
manifest.WriteLine(" <tasks>");
foreach (var taskValue in tasks.Keys)
{
var task = tasks[taskValue];
manifest.WriteLine(" <task name=\"{0}\" message=\"$(string.task_{1})\" value=\"{2}\"{3}>", task.Name, task.Name, taskValue,
task.Opcodes == null ? "/" : ""); // If no opcodes, terminate immediately.
localizedStrings.WriteLine(" <string id=\"task_{0}\" value=\"{1}\"/>", task.Name, task.Name);
if (task.Opcodes != null)
{
manifest.WriteLine(">");
manifest.WriteLine(" <opcodes>");
foreach (var keyValue in task.Opcodes)
{
manifest.WriteLine(" <opcode name=\"{0}\" message=\"$(string.opcode_{1}{2})\" value=\"{3}\"/>",
keyValue.Value, task.Name, keyValue.Value, keyValue.Key);
localizedStrings.WriteLine(" <string id=\"opcode_{0}{1}\" value=\"{2}\"/>", task.Name, keyValue.Value, keyValue.Value);
}
manifest.WriteLine(" </opcodes>");
manifest.WriteLine(" </task>");
}
}
manifest.WriteLine(" </tasks>");
if (enumIntern.Count > 0)
{
manifest.WriteLine(" <maps>");
foreach (var map in enumIntern.Values)
{
manifest.Write(map);
}
manifest.WriteLine(" </maps>");
localizedStrings.Write(enumLocalizations.ToString());
}
manifest.WriteLine(" <events>");
foreach (StringWriter eventStr in events.Values)
{
manifest.Write(eventStr.ToString());
}
manifest.WriteLine(" </events>");
manifest.WriteLine(" <templates>");
foreach (var keyValue in templateIntern)
{
manifest.WriteLine(" <template tid=\"{0}\">", keyValue.Value);
manifest.Write(keyValue.Key);
manifest.WriteLine(" </template>");
}
manifest.WriteLine(" </templates>");
manifest.WriteLine(" </provider>");
manifest.WriteLine(" </events>");
manifest.WriteLine(" </instrumentation>");
string strings = localizedStrings.ToString();
if (strings.Length > 0)
{
manifest.WriteLine(" <localization>");
manifest.WriteLine(" <resources culture=\"{0}\">", IetfLanguageTag(CultureInfo.CurrentCulture));
manifest.WriteLine(" <stringTable>");
manifest.Write(strings);
manifest.WriteLine(" </stringTable>");
manifest.WriteLine(" </resources>");
manifest.WriteLine(" </localization>");
}
manifest.WriteLine("</instrumentationManifest>");
return manifest.ToString(); ;
}