Beispiel #1
0
        // 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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        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;
        }
Beispiel #7
0
        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);
        }