// Builds a lookup table of class+method name. // // It's easier to build it at once by enumerating, once we have the table, we // can use the symbolIds to look up the sources when we need them. private static AssemblyData FetchSymbolData(IDiaSession session) { // This will be a *flat* enumerator of all classes. // // A nested class will not contain a '+' in it's name, just a '.' separating the parent class name from // the child class name. IDiaEnumSymbols diaClasses; session.findChildren( session.globalScope, // Search at the top-level. SymTagEnum.SymTagCompiland, // Just find classes. name: null, // Don't filter by name. compareFlags: 0u, // doesn't matter because name is null. ppResult: out diaClasses); var assemblyData = new AssemblyData(); // Resist the urge to use foreach here. It doesn't work well with these APIs. var classesFetched = 0u; IDiaSymbol diaClass; diaClasses.Next(1u, out diaClass, out classesFetched); while (classesFetched == 1 && diaClass != null) { var classData = new ClassData() { Name = diaClass.name, SymbolId = diaClass.symIndexId, }; assemblyData.Classes.Add(diaClass.name, classData); IDiaEnumSymbols diaMethods; session.findChildren( diaClass, SymTagEnum.SymTagFunction, name: null, // Don't filter by name. compareFlags: 0u, // doesn't matter because name is null. ppResult: out diaMethods); // Resist the urge to use foreach here. It doesn't work well with these APIs. var methodsFetched = 0u; IDiaSymbol diaMethod; diaMethods.Next(1u, out diaMethod, out methodsFetched); while (methodsFetched == 1 && diaMethod != null) { classData.Methods[diaMethod.name] = new MethodData() { Name = diaMethod.name, SymbolId = diaMethod.symIndexId, }; diaMethods.Next(1u, out diaMethod, out methodsFetched); } diaClasses.Next(1u, out diaClass, out classesFetched); } return(assemblyData); }
/// <summary> /// Attempt to load the PDB file from the given file location and populate the data table on the left /// </summary> /// <param name="FileName">Absolute file path of the PDB</param> /// <returns>Error message if failure</returns> public string LoadDataFromPdb(string FileName, BackgroundWorker LoadingWorker) { m_SymbolMap.Clear(); Stopwatch watch; if (FileName == null) { return("Empty file path provided! "); } m_DiaSource = new DiaSourceClass(); try { Reset(); watch = System.Diagnostics.Stopwatch.StartNew(); m_DiaSource.loadDataFromPdb(FileName); watch.Stop(); long elapsedMs = watch.ElapsedMilliseconds; Console.WriteLine("Loading data from {0} took {1}ms ({2} sec.)", FileName, elapsedMs, (elapsedMs * 1000)); m_DiaSource.openSession(out m_DiaSession); } catch (System.Runtime.InteropServices.COMException exc) { return(exc.ToString()); } try { IDiaEnumSymbols allSymbols; m_DiaSession.findChildren(m_DiaSession.globalScope, SymTagEnum.SymTagUDT, null, 0, out allSymbols); { watch = System.Diagnostics.Stopwatch.StartNew(); PopulateDataTable(m_table, allSymbols, LoadingWorker); watch.Stop(); long elapsedMs = watch.ElapsedMilliseconds; Console.WriteLine("PopulateDataTable took took {0}ms ({1} sec.)", elapsedMs, (elapsedMs * 1000)); } } catch (System.Exception e) { Console.WriteLine("Error populating data table: " + e.Message); } return(null); }
private ConstantCache LoadGlobalConstantsFromDiaSession(IDiaSession diaSession) { List <SConstantResult> constants = new List <SConstantResult>(); diaSession.findChildren(diaSession.globalScope, SymTagEnum.SymTagData, null, 0, out IDiaEnumSymbols symbols); foreach (IDiaSymbol symbol in symbols) { SymTagEnum symTag = (SymTagEnum)symbol.symTag; if (symbol.locationType == (uint)DiaHelpers.LocationType.LocIsConstant) { constants.Add(new SConstantResult() { ConstantName = symbol.name, Value = (ulong)symbol.value }); } } return(new ConstantCache(constants)); }
private Type GetBuiltinType(IDiaSession session, string module, string typename) { string strippedType = typename.Replace("unsigned", "").Replace("signed", "").Trim(); if (BuiltInTypes.ContainsKey(strippedType)) { return(new Type(module, typename, BuiltInTypes[strippedType], false, null, null, null)); } else if (strippedType.EndsWith("*")) { uint pointerSize = this.isPointer64Bit ? 8u : 4u; if (this.modulePointerSizes.ContainsKey(module)) { uint cachedPointerSize = this.modulePointerSizes[module]; if (cachedPointerSize != 0) { pointerSize = cachedPointerSize; } } else if (session != null) { // Try to infer the pointer size from the DIA Session. IDiaEnumSymbols pointerSymbols; session.findChildren(session.globalScope, SymTagEnum.SymTagPointerType, null, 0, out pointerSymbols); foreach (IDiaSymbol symbol in pointerSymbols) { pointerSize = (uint)symbol.length; break; } this.modulePointerSizes[module] = pointerSize; } return(new Type(module, typename, pointerSize, false, null, null, null)); } else { return(null); } }
private bool LoadSymbols(IDiaSession session, object sender, LoadPDBTask task) { var worker = sender as BackgroundWorker; worker?.ReportProgress(0, "Finding symbols"); IDiaEnumSymbols allSymbols; if (task.Filter.Length > 0) { uint compareFlags = 0; if (!task.WholeExpression || task.UseRegularExpression) { compareFlags |= 0x8; } if (!task.MatchCase) { compareFlags |= 0x2; } else { compareFlags |= 0x2; } if (task.UseRegularExpression) { session.findChildren(session.globalScope, SymTagEnum.SymTagUDT, @task.Filter, compareFlags, out allSymbols); } else if (task.WholeExpression) { session.findChildren(session.globalScope, SymTagEnum.SymTagUDT, task.Filter, compareFlags, out allSymbols); } else { string filter = '*' + task.Filter + '*'; session.findChildren(session.globalScope, SymTagEnum.SymTagUDT, @filter, compareFlags, out allSymbols); } } else { session.findChildren(session.globalScope, SymTagEnum.SymTagUDT, null, 0, out allSymbols); } if (allSymbols == null) { return(false); } worker?.ReportProgress(0, "Counting symbols"); var allSymbolsCount = worker != null ? allSymbols.count : 0; var i = 0; worker?.ReportProgress(0, "Adding symbols"); foreach (IDiaSymbol sym in allSymbols) { if (worker != null && worker.CancellationPending) { return(false); } if (task.SecondPDB) { SymbolInfo info = FindSymbolInfo(sym.name); if (info != null) { info.NewSize = sym.length; } } else { if (sym.length > 0 && !HasSymbolInfo(sym.name)) { var symbolInfo = new SymbolInfo(sym.name, sym.GetType().Name, sym.length); symbolInfo.ProcessChildren(sym); Symbols.Add(symbolInfo.Name, symbolInfo); if (symbolInfo.Name.Contains("::") && !symbolInfo.Name.Contains("<")) { RootNamespaces.Add(symbolInfo.Name.Substring(0, symbolInfo.Name.IndexOf("::"))); Namespaces.Add(symbolInfo.Name.Substring(0, symbolInfo.Name.LastIndexOf("::"))); } } } var percentProgress = (int)Math.Round((double)(100 * i++) / allSymbolsCount); percentProgress = Math.Max(Math.Min(percentProgress, 99), 1); worker?.ReportProgress(percentProgress, String.Format("Adding symbol {0} on {1}", i, allSymbolsCount)); } worker?.ReportProgress(100, String.Format("{0} symbols added", allSymbolsCount)); return(true); }
// Builds a lookup table of class+method name. // // It's easier to build it at once by enumerating, once we have the table, we // can use the symbolIds to look up the sources when we need them. private static AssemblyData FetchSymbolData(IDiaSession session) { // This will be a *flat* enumerator of all classes. // // A nested class will not contain a '+' in it's name, just a '.' separating the parent class name from // the child class name. IDiaEnumSymbols diaClasses; session.findChildren( session.globalScope, // Search at the top-level. SymTagEnum.SymTagCompiland, // Just find classes. name: null, // Don't filter by name. compareFlags: 0u, // doesn't matter because name is null. ppResult: out diaClasses); var assemblyData = new AssemblyData(); // Resist the urge to use foreach here. It doesn't work well with these APIs. var classesFetched = 0u; IDiaSymbol diaClass; diaClasses.Next(1u, out diaClass, out classesFetched); while (classesFetched == 1 && diaClass != null) { var classData = new ClassData() { Name = diaClass.name, SymbolId = diaClass.symIndexId, }; assemblyData.Classes.Add(diaClass.name, classData); IDiaEnumSymbols diaMethods; session.findChildren( diaClass, SymTagEnum.SymTagFunction, name: null, // Don't filter by name. compareFlags: 0u, // doesn't matter because name is null. ppResult: out diaMethods); // Resist the urge to use foreach here. It doesn't work well with these APIs. var methodsFetched = 0u; IDiaSymbol diaMethod; diaMethods.Next(1u, out diaMethod, out methodsFetched); while (methodsFetched == 1 && diaMethod != null) { classData.Methods[diaMethod.name] = new MethodData() { Name = diaMethod.name, SymbolId = diaMethod.symIndexId, }; diaMethods.Next(1u, out diaMethod, out methodsFetched); } diaClasses.Next(1u, out diaClass, out classesFetched); } return assemblyData; }
private async Task <Type> LoadTypeFromDiaSession(IDiaSession diaSession, string module, string typename, DiaHelpers.NameSearchOptions options) { IDiaEnumSymbols symbols; diaSession.findChildren(diaSession.globalScope, SymTagEnum.SymTagNull, typename, (uint)options, out symbols); foreach (IDiaSymbol iterationSymbol in symbols) { IDiaSymbol symbol = iterationSymbol; while ((SymTagEnum)symbol.symTag == SymTagEnum.SymTagTypedef) { symbol = symbol.type; } SymTagEnum symTag = (SymTagEnum)symbol.symTag; if (symTag == SymTagEnum.SymTagUDT || symTag == SymTagEnum.SymTagBaseType || symTag == SymTagEnum.SymTagEnum) { // Get the fields for this class. IDiaEnumSymbols dataSymbols; symbol.findChildren(SymTagEnum.SymTagData, null, 0, out dataSymbols); uint typeSize = (uint)symbol.length; Dictionary <string, SField> fields = new Dictionary <string, SField>(); Dictionary <string, ulong> constants = new Dictionary <string, ulong>(); foreach (IDiaSymbol dataSymbol in dataSymbols) { DiaHelpers.LocationType location = (DiaHelpers.LocationType)dataSymbol.locationType; if (location == DiaHelpers.LocationType.LocIsBitField) { byte bitOffset = (byte)dataSymbol.bitPosition; byte bitCount = (byte)dataSymbol.length; fields.Add(dataSymbol.name, new SField((uint)dataSymbol.offset, (uint)dataSymbol.type.length, module, DiaHelpers.GetTypeName(dataSymbol.type), bitOffset, bitCount)); } else if (location == DiaHelpers.LocationType.LocIsThisRel) { fields.Add(dataSymbol.name, new SField((uint)dataSymbol.offset, (uint)dataSymbol.type.length, module, DiaHelpers.GetTypeName(dataSymbol.type), 0, 0)); } else if (location == DiaHelpers.LocationType.LocIsConstant) { try { constants.Add(dataSymbol.name, (ulong)dataSymbol.value); } catch { // If the cast failed, just ignore the constant for now. } } } IDiaEnumSymbols enumSymbols; symbol.findChildren(SymTagEnum.SymTagEnum, null, 0, out enumSymbols); List <string> names = new List <string>(); foreach (IDiaSymbol enumSymbol in enumSymbols) { if (enumSymbol.name.IndexOf("<unnamed-enum") == 0) { // Anonymous enum. Include the constants in the outer type. IDiaEnumSymbols anonymousEnumDataSymbols; enumSymbol.findChildren(SymTagEnum.SymTagData, null, 0, out anonymousEnumDataSymbols); foreach (IDiaSymbol dataSymbol in anonymousEnumDataSymbols) { DiaHelpers.LocationType location = (DiaHelpers.LocationType)dataSymbol.locationType; if (location == DiaHelpers.LocationType.LocIsConstant) { try { constants.Add(dataSymbol.name, (ulong)dataSymbol.value); } catch { // If the cast failed, just ignore the constant for now. } } } } } // Get the base types. List <SBaseType> baseTypes = new List <SBaseType>(); IDiaEnumSymbols baseClassSymbols; symbol.findChildren(SymTagEnum.SymTagBaseClass, null, 0, out baseClassSymbols); foreach (IDiaSymbol baseClassSymbol in baseClassSymbols) { string baseTypename = DiaHelpers.GetTypeName(baseClassSymbol.type); Type baseType; try { baseType = await this.LoadType(module, baseTypename); } catch (DebuggerException) { // Sometimes types will refer to a base type that doesn't resolve; just ignore that type. baseType = null; } if (baseType != null) { baseTypes.Add(new SBaseType(baseType, baseClassSymbol.offset)); } else { System.Diagnostics.Debug.WriteLine("Unable to retrieve base type: {0}", baseTypename); } } // Construct the type. Type type = new Type(module, typename, typeSize, symTag == SymTagEnum.SymTagEnum, fields, constants, baseTypes); return(type); } } return(null); }