private List<DynamicTraceEventData> CreateTemplatesForTMFFile(Guid taskGuid, string tmfPath) { List<DynamicTraceEventData> templates = new List<DynamicTraceEventData>(); List<Type> parameterTypes = new List<Type>(); using (StreamReader tmfData = File.OpenText(tmfPath)) { string taskName = null; string providerName = null; Guid providerGuid = Guid.Empty; Match m; for (; ; ) { var line = tmfData.ReadLine(); if (line == null) break; if (providerGuid == Guid.Empty) { m = Regex.Match(line, @"PDB: .*?(\w+)\.pdb\s*$", RegexOptions.IgnoreCase); if (m.Success) { // We use the name of the mof file (which is the same as the PDB file) as the provider name. if (string.IsNullOrEmpty(providerName)) providerName = m.Groups[1].Value; string mofFilePath; if (m_tmfDataFilePathsByFileNameBase.TryGetValue(providerName, out mofFilePath)) { if (mofFilePath.EndsWith(".mof", StringComparison.OrdinalIgnoreCase)) { using (var mofFile = File.OpenText(mofFilePath)) { for (; ; ) { var mofLine = mofFile.ReadLine(); if (mofLine == null) break; m = Regex.Match(mofLine, @"guid\(.{(.*)}.\)", RegexOptions.IgnoreCase); if (m.Success) { try { providerGuid = new Guid(m.Groups[1].Value); } catch (Exception) { } break; } } } } } } } if (taskName == null) { // 7113b9e1-a0cc-d313-1eab-57efe9d7e56c build.server // SRC=TTSEngineCom.cpp MJ= MN= m = Regex.Match(line, @"^\w+-\w+-\w+-\w+-\w+\s+(\S+)"); if (m.Success) taskName = m.Groups[1].Value; } else { // #typev ttstracing_cpp78 13 "%0%10!s! Error happens in Initializing %11!s!!" // LEVEL=TRACE_LEVEL_ERROR FLAGS=TTS_Trace_Engine_Initialization FUNC=CTTSTracingHelper::LogComponentInitialization m = Regex.Match(line, "^#typev\\s+(\\S*?)(\\d+)\\s+(\\d+)\\s+\"(.*)\""); if (m.Success) { var fileName = m.Groups[1].Value; var lineNum = int.Parse(m.Groups[2].Value); var eventId = int.Parse(m.Groups[3].Value); var formatStr = m.Groups[4].Value; var eventProviderName = taskName; if (providerName != null) eventProviderName = providerName + "/" + eventProviderName; var template = new DynamicTraceEventData(null, eventId, 0, fileName + "/" + m.Groups[2].Value, taskGuid, 0, "", providerGuid, eventProviderName); template.lookupAsWPP = true; // Use WPP lookup convetions. formatStr = formatStr.Replace("%0", ""); // TODO What is this? Why is it here? formatStr = Regex.Replace(formatStr, @"%(\d+)!.!", delegate(Match match) { return "%" + (int.Parse(match.Groups[1].Value) - 9).ToString(); }); template.MessageFormat = formatStr; parameterTypes.Clear(); for (; ; ) { line = tmfData.ReadLine(); if (line == null) break; if (line.Trim() == "}") break; // szPOSHeader, ItemString -- 10 m = Regex.Match(line, @"^\S+, Item(\w+) -- (\d+)"); if (m.Success) { var typeStr = m.Groups[1].Value; Type type = null; if (typeStr == "String") type = typeof(string); else if (typeStr == "Long") type = typeof(int); else if (typeStr == "Double") type = typeof(double); if (type != null) parameterTypes.Add(type); } } template.payloadNames = new string[parameterTypes.Count]; template.payloadFetches = new DynamicTraceEventData.PayloadFetch[parameterTypes.Count]; ushort offset = 0; for (int i = 0; i < parameterTypes.Count; i++) { template.payloadNames[i] = "Arg" + (i + 1).ToString(); template.payloadFetches[i].type = parameterTypes[i]; template.payloadFetches[i].offset = offset; var size = DynamicTraceEventData.SizeOfType(parameterTypes[i]); if (template.payloadFetches[i].type == typeof(string)) size |= DynamicTraceEventData.IS_ANSI; template.payloadFetches[i].size = size; if (size >= DynamicTraceEventData.SPECIAL_SIZES) offset = ushort.MaxValue; // Indicate that the offset must be computed at run time. else offset += size; } templates.Add(template); } } } } return templates; }
internal void AddProviderEvents(ITraceParserServices source, Action<TraceEvent> callback) { if (Error != null) return; if (!inited) Init(); try { Dictionary<string, int> opcodes = new Dictionary<string, int>(); opcodes.Add("win:Info", 0); opcodes.Add("win:Start", 1); opcodes.Add("win:Stop", 2); opcodes.Add("win:DC_Start", 3); opcodes.Add("win:DC_Stop", 4); opcodes.Add("win:Extension", 5); opcodes.Add("win:Reply", 6); opcodes.Add("win:Resume", 7); opcodes.Add("win:Suspend", 8); opcodes.Add("win:Send", 9); opcodes.Add("win:Receive", 240); Dictionary<string, TaskInfo> tasks = new Dictionary<string, TaskInfo>(); Dictionary<string, TemplateInfo> templates = new Dictionary<string, TemplateInfo>(); Dictionary<string, IDictionary<long, string>> maps = null; Dictionary<string, string> strings = new Dictionary<string, string>(); IDictionary<long, string> map = null; List<EventInfo> events = new List<EventInfo>(); bool alreadyReadMyCulture = false; // I read my culture some time in the past (I can igore things) string cultureBeingRead = null; while (reader.Read()) { // TODO I currently require opcodes,and tasks BEFORE events BEFORE templates. // Can be fixed by going multi-pass. switch (reader.Name) { case "event": { int taskNum = 0; Guid taskGuid = Guid; string taskName = reader.GetAttribute("task"); if (taskName != null) { TaskInfo taskInfo; if (tasks.TryGetValue(taskName, out taskInfo)) { taskNum = taskInfo.id; taskGuid = taskInfo.guid; } } else taskName = ""; int eventID = int.Parse(reader.GetAttribute("value")); int opcode = 0; string opcodeName = reader.GetAttribute("opcode"); if (opcodeName != null) { opcodes.TryGetValue(opcodeName, out opcode); // Strip off any namespace prefix. TODO is this a good idea? int colon = opcodeName.IndexOf(':'); if (colon >= 0) opcodeName = opcodeName.Substring(colon + 1); } else { opcodeName = ""; // opcodeName = "UnknownEvent" + eventID.ToString(); } DynamicTraceEventData eventTemplate = new DynamicTraceEventData( callback, eventID, taskNum, taskName, taskGuid, opcode, opcodeName, Guid, Name); events.Add(new EventInfo(eventTemplate, reader.GetAttribute("template"))); // This will be looked up in the string table in a second pass. eventTemplate.MessageFormat = reader.GetAttribute("message"); } break; case "template": { string templateName = reader.GetAttribute("tid"); Debug.Assert(templateName != null); #if DEBUG try { #endif templates.Add(templateName, ComputeFieldInfo(reader.ReadSubtree(), maps)); #if DEBUG } catch (Exception e) { Console.WriteLine("Error: Exception during processing template {0}: {1}", templateName, e.ToString()); throw; } #endif } break; case "opcode": // TODO use message for opcode if it is available so it is localized. opcodes.Add(reader.GetAttribute("name"), int.Parse(reader.GetAttribute("value"))); break; case "task": { TaskInfo info = new TaskInfo(); info.id = int.Parse(reader.GetAttribute("value")); string guidString = reader.GetAttribute("eventGUID"); if (guidString != null) info.guid = new Guid(guidString); tasks.Add(reader.GetAttribute("name"), info); } break; case "valueMap": map = new Dictionary<long, string>(); // value maps use dictionaries goto DoMap; case "bitMap": map = new SortedList<long, string>(); // Bitmaps stored as sorted lists goto DoMap; DoMap: string name = reader.GetAttribute("name"); var mapValues = reader.ReadSubtree(); while (mapValues.Read()) { if (mapValues.Name == "map") { string keyStr = reader.GetAttribute("value"); long key; if (keyStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) key = long.Parse(keyStr.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); else key = long.Parse(keyStr); string value = reader.GetAttribute("message"); map[key] = value; } } if (maps == null) maps = new Dictionary<string, IDictionary<long, string>>(); maps[name] = map; break; case "resources": { if (!alreadyReadMyCulture) { string desiredCulture = System.Globalization.CultureInfo.CurrentCulture.Name; if (cultureBeingRead != null && string.Compare(cultureBeingRead, desiredCulture, StringComparison.OrdinalIgnoreCase) == 0) alreadyReadMyCulture = true; cultureBeingRead = reader.GetAttribute("culture"); } } break; case "string": if (!alreadyReadMyCulture) strings[reader.GetAttribute("id")] = reader.GetAttribute("value"); break; } } // localize strings for maps. if (maps != null) { foreach (IDictionary<long, string> amap in maps.Values) { foreach (var keyValue in new List<KeyValuePair<long, string>>(amap)) { Match m = Regex.Match(keyValue.Value, @"^\$\(string\.(.*)\)$"); if (m.Success) { string newValue; if (strings.TryGetValue(m.Groups[1].Value, out newValue)) amap[keyValue.Key] = newValue; } } } } // Register all the events foreach (var eventInfo in events) { var event_ = eventInfo.eventTemplate; // Set the template if there is any. if (eventInfo.templateName != null) { var templateInfo = templates[eventInfo.templateName]; event_.payloadNames = templateInfo.payloadNames.ToArray(); event_.payloadFetches = templateInfo.payloadFetches.ToArray(); } else { event_.payloadNames = new string[0]; event_.payloadFetches = new DynamicTraceEventData.PayloadFetch[0]; } // before registering, localize any message format strings. string message = event_.MessageFormat; if (message != null) { // Expect $(STRINGNAME) where STRINGNAME needs to be looked up in the string table // TODO currently we just ignore messages without a valid string name. Is that OK? event_.MessageFormat = null; Match m = Regex.Match(message, @"^\$\(string\.(.*)\)$"); if (m.Success) strings.TryGetValue(m.Groups[1].Value, out event_.MessageFormat); } //SLAB update try/catch section try { source.RegisterEventTemplate(event_); } catch (NullReferenceException e) { // This error may be thrown when disposing source. Error = e; inited = false; // If we call it again, start over from the begining. return; } } //SLAB comment: // The below code was commented out to allow receiving manifest updates. // Note that this registration will set the manifest event as handled and will always send // the initial manifest (no updates) so this behavior will be useless for manifest caching scenarios // where stale manifest should be avoided by receiving new updates. // To recap, avoiding manifest event registration will force to get unhandled events on each new manifest event. //// Create an event for the manifest event itself so it looks pretty in dumps. //source.RegisterEventTemplate(new DynamicManifestTraceEventData(callback, this)); } catch (Exception e) { // TODO FIX NOW, log this! Debug.Assert(false, "Exception during manifest parsing"); #if DEBUG Console.WriteLine("Error: Exception during processing of in-log manifest for provider {0}. Symbolic information may not be complete.", Name); #endif Error = e; } inited = false; // If we call it again, start over from the begining. }
public EventInfo(DynamicTraceEventData eventTemplate, string templateName) { this.eventTemplate = eventTemplate; this.templateName = templateName; }
protected override DynamicTraceEventData TryLookup(TraceEvent unknownEvent) { DynamicTraceEventData ret = null; // TODO react if 4K is not big enough, cache the buffer?, handle more types, handle structs... int buffSize = 4096; byte* buffer = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(buffSize); int status = TdhGetEventInformation(unknownEvent.eventRecord, 0, null, buffer, &buffSize); if (status == 0) { TRACE_EVENT_INFO* eventInfo = (TRACE_EVENT_INFO*)buffer; EVENT_PROPERTY_INFO* propertyInfos = &eventInfo->EventPropertyInfoArray; string taskName = null; if (eventInfo->TaskNameOffset != 0) taskName = (new string((char*)(&buffer[eventInfo->TaskNameOffset]))).Trim(); string opcodeName = null; if (eventInfo->OpcodeNameOffset != 0) { opcodeName = (new string((char*)(&buffer[eventInfo->OpcodeNameOffset]))).Trim(); if (opcodeName.StartsWith("win:")) opcodeName = opcodeName.Substring(4); } string providerName = "UnknownProvider"; if (eventInfo->ProviderNameOffset != 0) providerName = new string((char*)(&buffer[eventInfo->ProviderNameOffset])); var eventID = unknownEvent.ClassicProvider ? TraceEventID.Illegal : unknownEvent.eventID; var newTemplate = new DynamicTraceEventData(null, (int)eventID, (int)unknownEvent.task, taskName, unknownEvent.taskGuid, (int)unknownEvent.Opcode, opcodeName, unknownEvent.ProviderGuid, providerName); newTemplate.payloadNames = new string[eventInfo->TopLevelPropertyCount]; newTemplate.payloadFetches = new DynamicTraceEventData.PayloadFetch[eventInfo->TopLevelPropertyCount]; ushort offset = 0; for (int i = 0; i < eventInfo->TopLevelPropertyCount; i++) { var propertyInfo = &propertyInfos[i]; var propertyName = new string((char*)(&buffer[propertyInfo->NameOffset])); // Remove anything that does not look like an ID (.e.g space) newTemplate.payloadNames[i] = Regex.Replace(propertyName, "[^A-Za-z0-9_]", ""); newTemplate.payloadFetches[i].type = GetTypeForTdhInType(propertyInfo->InType); // Determine whether the size variable or not, and set 'size' based on that. ushort size = DynamicTraceEventData.UNKNOWN_SIZE; // is this dynamically sized with another field specifying the length? if ((propertyInfo->Flags & PROPERTY_FLAGS.ParamLength) != 0) { if (propertyInfo->LengthOrLengthIndex == i - 1) { if (propertyInfos[i - 1].LengthOrLengthIndex == 4) size = DynamicTraceEventData.COUNT32_PRECEEDS; else if (propertyInfos[i - 1].LengthOrLengthIndex == 2) size = DynamicTraceEventData.COUNT16_PRECEEDS; else Trace.WriteLine("WARNING: Unexpected dynamic length, giving up"); } if (size != DynamicTraceEventData.UNKNOWN_SIZE && propertyInfo->InType == TdhInputType.AnsiString) size |= DynamicTraceEventData.IS_ANSI; } else { if (propertyInfo->InType == TdhInputType.AnsiString) size = DynamicTraceEventData.NULL_TERMINATED | DynamicTraceEventData.IS_ANSI; else if (propertyInfo->InType == TdhInputType.UnicodeString) size = DynamicTraceEventData.NULL_TERMINATED; else if (propertyInfo->InType == TdhInputType.Pointer) size = DynamicTraceEventData.POINTER_SIZE; else { // No, then it it fixed size (but give up if it is too big) var fixedSize = propertyInfo->CountOrCountIndex * propertyInfo->LengthOrLengthIndex; if (fixedSize < 0x7FF0) { size = (ushort)fixedSize; if (propertyInfo->InType == TdhInputType.AnsiString) size += 0x8000; } } } // Currently we give up on any other flags (arrays, structs). if ((propertyInfo->Flags & ~PROPERTY_FLAGS.ParamLength) != 0) size = DynamicTraceEventData.UNKNOWN_SIZE; newTemplate.payloadFetches[i].size = (ushort)size; newTemplate.payloadFetches[i].offset = offset; if (size >= DynamicTraceEventData.SPECIAL_SIZES) offset = ushort.MaxValue; // Indicate that the offset must be computed at run time. else if (offset != ushort.MaxValue) { Debug.Assert(offset + size < ushort.MaxValue); offset += size; } } ret = newTemplate; // return this as the event template for this lookup. } System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)buffer); return ret; }