// 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 static void HandleTsvStacktrace(string tsvPath, IDiaSession pdbSession)
        {
            var lines = File.ReadAllLines(tsvPath);

            for (int i = 1; i < lines.Length; i++)
            {
                string[] frags      = lines[i].Split('\t');
                string   methodName = "";
                string   module     = "";
                if (frags.Length >= 4)
                {
                    module = frags[1];
                    string rvaStr = frags[3];
                    string rva    = rvaStr.Replace("0x", "");
                    if (frags[2] != "null")
                    {
                        methodName = frags[2];
                    }
                    uint offset = HexToUint(rva);
                    if (pdbSession != null && offset != 0)
                    {
                        string tmpMethodName = DiaHelper.GetMethodName(pdbSession, offset);
                        if (!String.IsNullOrEmpty(tmpMethodName))
                        {
                            methodName = tmpMethodName;
                        }
                    }
                }
                _writer.WriteLine($"at {module}!{methodName}");
            }
        }
예제 #3
0
        private void AddEntry(IDiaSession session, IDiaEnumSymbolsByAddr symbolsByAddr, ulong eip, uint rva)
        {
            session.findSymbolByRVA(rva, SymTagEnum.SymTagPublicSymbol, out var symbol);
            if (symbol == null)
            {
                session.findSymbolByRVA(rva, SymTagEnum.SymTagFunction, out symbol);
                if (symbol == null)
                {
                    symbol = symbolsByAddr.symbolByRVA(rva);
                }
            }

            string functionName;

            if (symbol != null)
            {
                symbol.get_undecoratedNameEx(0x1000, out var unmangled);
                if (!string.IsNullOrEmpty(unmangled))
                {
                    functionName = unmangled;
                }
                else
                {
                    functionName = !string.IsNullOrEmpty(symbol.name) ? symbol.name : eip.ToString("x");
                }
            }
            else
            {
                functionName = eip.ToString("x");
            }

            this.rvaToFunctionNameMap.Add(rva, functionName);
        }
예제 #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DiaModule"/> class.
 /// </summary>
 /// <param name="name">The module name.</param>
 /// <param name="nameSpace">The default namespace.</param>
 /// <param name="dia">The DIA data source.</param>
 /// <param name="session">The DIA session.</param>
 private DiaModule(string name, string nameSpace, IDiaDataSource dia, IDiaSession session)
 {
     this.session = session;
     this.dia     = dia;
     Name         = name;
     Namespace    = nameSpace;
 }
예제 #5
0
        private async Task <Type> LoadType(string module, string typename)
        {
            // Try to load the type from DIA.
            IDiaSession session = await this.debuggerEngine.DiaLoader.LoadDiaSession(module);

            bool foundType;
            Type type = this.typeCache.GetCachedType(session, module, typename, out foundType);

            if (foundType)
            {
                if (type != null)
                {
                    return(type);
                }
                else
                {
                    // We previously tried to load the type but were unable to.
                    throw new DebuggerException(String.Format("Unable to load type: {0}!{1}", module, typename));
                }
            }

            this.DebuggerMessage?.Invoke(this, String.Format("Loading type information for {0}!{1}...", module, typename));

            if (session != null)
            {
                type = await this.LoadTypeFromDiaSession(session, module, typename, DiaHelpers.NameSearchOptions.nsCaseSensitive);

                if (type == null)
                {
                    type = await this.LoadTypeFromDiaSession(session, module, typename, DiaHelpers.NameSearchOptions.nsCaseInsensitive);
                }

                if (type != null)
                {
                    this.typeCache.AddType(type);
                    return(type);
                }
                else
                {
                    // We have a DIA session but couldn't find the type.  Assume the type is invalid rather than falling back to the debugger.
                    this.typeCache.AddInvalidType(module, typename);
                    throw new DebuggerException(String.Format("Unable to load type: {0}!{1}", module, typename));
                }
            }

            this.DebuggerMessage?.Invoke(this, String.Format("WARNING: Unable to load {0}!{1} from PDBs. Falling back to the debugger, which could be slow...", module, typename));

            type = await this.debuggerEngine.GetTypeFromDebugger(module, typename);

            if (type != null)
            {
                this.typeCache.AddType(type);
                return(type);
            }
            else
            {
                this.typeCache.AddInvalidType(module, typename);
                throw new DebuggerException(String.Format("Unable to load type: {0}!{1}", module, typename));
            }
        }
예제 #6
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);
        }
예제 #7
0
        /// <summary>
        /// Loads symbol provider module from the specified module.
        /// </summary>
        /// <param name="module">The module.</param>
        /// <returns>Interface for symbol provider module</returns>
        public override ISymbolProviderModule LoadModule(Module module)
        {
            // Try to get debugger DIA session
            IDiaSessionProvider diaSessionProvider = Context.Debugger as IDiaSessionProvider;
            IDiaSession         diaSession         = diaSessionProvider?.GetModuleDiaSession(module);

            if (diaSession != null)
            {
                return(new DiaModule(diaSession, module));
            }

            // Try to load PDB file into our own DIA session
            string pdb = module.SymbolFileName;

            if (!string.IsNullOrEmpty(pdb) && Path.GetExtension(pdb).ToLower() == ".pdb")
            {
                try
                {
                    return(new DiaModule(pdb, module));
                }
                catch
                {
                }
            }

            return(null);
        }
        private static void TryGetILOffsetInfo(IDiaSession session, int rva, out int ilOffset)
        {
            IDiaEnumLineNumbers lineNumbers;
            int hr = session.FindILOffsetsByRVA(rva, 1, out lineNumbers);

            if (hr == S_OK)
            {
                int numLineNumbers;
                hr = lineNumbers.Count(out numLineNumbers);
                if (hr == S_OK && numLineNumbers > 0)
                {
                    IDiaLineNumber ln;
                    hr = lineNumbers.Item(0, out ln);
                    if (hr == S_OK)
                    {
                        hr = ln.LineNumber(out ilOffset);
                        if (hr == S_OK)
                        {
                            return;
                        }
                    }
                }
            }
            ilOffset = StackFrame.OFFSET_UNKNOWN;
        }
예제 #9
0
        internal DiaResolver(string binary, string pathExtension, ILogger logger)
        {
            _binary = binary;
            _logger = logger;

            string pdb = FindPdbFile(binary, pathExtension);

            if (pdb == null)
            {
                _logger.LogWarning($"Couldn't find the .pdb file of file '{binary}'. You will not get any source locations for your tests.");
                return;
            }

            if (!TryCreateDiaInstance(Dia140) && !TryCreateDiaInstance(Dia120) && !TryCreateDiaInstance(Dia110))
            {
                _logger.LogError("Couldn't find the msdia.dll to parse *.pdb files. You will not get any source locations for your tests.");
                return;
            }

            _logger.DebugInfo($"Parsing pdb file \"{pdb}\"");

            _fileStream = File.Open(pdb, FileMode.Open, FileAccess.Read, FileShare.Read);
            _diaDataSource.loadDataFromIStream(new DiaMemoryStream(_fileStream));

            dynamic diaSession110Or140;

            _diaDataSource.openSession(out diaSession110Or140);
            _diaSession = new DiaSessionAdapter(diaSession110Or140);
        }
예제 #10
0
 /// <summary>
 /// Clears the symbol map and creates a new Dia source class. Sets Dia session to null
 /// </summary>
 private void Reset()
 {
     m_SymbolMap.Clear();
     // If the creation of the DiaSourceClass fails, then you likely need
     // to register the MSDIA1xx.dll on your machine. See readme for more details
     m_DiaSource  = new DiaSourceClass();
     m_DiaSession = null;
 }
예제 #11
0
 public void Dispose()
 {
     if (m_session != null)
     {
         Marshal.ReleaseComObject(m_session);
         m_session = null;
     }
 }
예제 #12
0
        static PdbSession()
        {
            var module = Process.GetCurrentProcess().MainModule;
            var pdb    = DiaSourceFactory.CreateInstance();

            pdb.loadDataForExe(module.FileName, null, null);
            pdb.openSession(out IDiaSession session);
            Current = session;
        }
예제 #13
0
        /// <summary>
        /// Opens the image and reads information about the symbols file, associated
        /// to this image.
        /// </summary>
        /// <param name="imagePath">The full path to executable or DLL.</param>
        /// <returns>Full path to corresponding symbols file or null if the image does
        /// not contain symbols file information.</returns>
        public static string GetSymbolsFileName(string imagePath)
        {
            Debug.Assert(!string.IsNullOrEmpty(imagePath), "imagePath");

            IDiaDataSource source;

            try
            {
                source = (IDiaDataSource) new DiaSourceClass();
            }
            catch (COMException ex)
            {
                EqtTrace.ErrorIf(EqtTrace.IsErrorEnabled, "DIA initialization threw:\n" + ex.ToString());

                // Let things go fine if we can find a local file, return
                // null if we can't.  This is needed to support xcopy deployment.
                string pdbFile = Path.ChangeExtension(imagePath, ".pdb");
                if (File.Exists(pdbFile))
                {
                    return(pdbFile);
                }

                return(null);
            }

            IDiaSession session = null;
            IDiaSymbol  global  = null;

            try
            {
                // Load the image:
                source.loadDataForExe(imagePath, null, null);

                // Extract the main symbol via session:
                source.openSession(out session);
                global = session.globalScope;

                Debug.Assert(global != null, "globalScope Symbol");
                return(global.symbolsFileName);
            }
            catch (COMException ex)
            {
                // If exception is thrown the image does not contain symbols or the symbols found
                // are not correct.
                EqtTrace.ErrorIf(EqtTrace.IsErrorEnabled, "DIA thew in retrieving symbols: " + ex.ToString());
                return(null);
            }
            finally
            {
                // Ensure that the resources allocated by DIA get cleaned up.
                // In particular, after loadDataForExe, the PDB will be locked
                // until CDiaDataSource::~CDiaDataSource is called.
                ReleaseComObject(global);
                ReleaseComObject(session);
                ReleaseComObject(source);
            }
        }
예제 #14
0
        public static void ReleaseSession(IDiaSession session)
        {
            IDiaDataSource source;

            if (sessionMap.TryGetValue(session, out source))
            {
                sessionMap.Remove(session);
                Marshal.FinalReleaseComObject(session);
                Marshal.FinalReleaseComObject(source);
            }
        }
예제 #15
0
        public async Task <IDiaSession> LoadDiaSession(string module)
        {
            module = module.ToLowerInvariant();

            if (this.activeSessions.ContainsKey(module))
            {
                return(this.activeSessions[module]);
            }

            // Try each of the sources until we're able to get one.
            foreach (IDiaSessionSource source in this.sources)
            {
                int attempts = 1;
                while (attempts <= 3)
                {
                    if (attempts > 1)
                    {
                        await source.WaitUntilReady();
                    }
                    ++attempts;

                    try {
                        IDiaDataSource dataSource = this.CreateDataSource();
                        if (dataSource == null)
                        {
                            // Without a data source we can't use DIA at all.
                            break;
                        }
                        IDiaSession session = source.LoadSessionForModule(dataSource, module);
                        if (session != null)
                        {
                            this.activeSessions[module] = session;
                            return(session);
                        }
                        break;
                    } catch (DebuggerException) {
                        throw;
                    } catch (DiaSourceNotReadyException) {
                        // Try again.
                        continue;
                    } catch {
                        // Try the next source.
                        break;
                    }
                }
            }

            // The session load failed.
            this.activeSessions[module] = null;

            return(null);
        }
 /// <summary>
 /// Makes reasonable effort to find the IL offset corresponding to the given address within a method.
 /// Returns StackFrame.OFFSET_UNKNOWN if not available.
 /// </summary>
 public static void TryGetILOffsetWithinMethod(IntPtr ip, out int ilOffset)
 {
     ilOffset = StackFrame.OFFSET_UNKNOWN;
     if (!IsDiaStackTraceResolutionDisabled())
     {
         int         rva;
         IDiaSession session = GetDiaSession(ip, out rva);
         if (session != null)
         {
             TryGetILOffsetInfo(session, rva, out ilOffset);
         }
     }
 }
        //
        // Makes reasonable effort to get source info. Returns null sourceFile and 0 lineNumber/columnNumber if it can't.
        //
        public static void TryGetSourceLineInfo(IntPtr ip, out string fileName, out int lineNumber, out int columnNumber)
        {
            fileName     = null;
            lineNumber   = 0;
            columnNumber = 0;
            int         rva;
            IDiaSession session = GetDiaSession(ip, out rva);

            if (session == null)
            {
                return;
            }
            TryGetSourceLineInfo(session, rva, out fileName, out lineNumber, out columnNumber);
        }
예제 #18
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         // free the state of any contained objects
         // we don't contain any other objects!
     }
     // free my own state
     if (session != null)
     {
         Marshal.ReleaseComObject(session);
         session = null;
     }
 }
        //
        // Makes reasonable effort to construct one useful line of a stack trace. Returns null if it can't.
        //
        public static String CreateStackTraceString(IntPtr ip, bool includeFileInfo)
        {
            if (IsDiaStackTraceResolutionDisabled())
            {
                return(null);
            }

            try
            {
                int hr;

                int         rva;
                IDiaSession session = GetDiaSession(ip, out rva);
                if (session == null)
                {
                    return(null);
                }

                StringBuilder sb = new StringBuilder();
                IDiaSymbol    symbol;
                hr = session.FindSymbolByRVA(rva, SymTagEnum.SymTagFunction, out symbol);
                if (hr != S_OK)
                {
                    return(null);
                }
                String functionName;
                hr = symbol.GetName(out functionName);
                if (hr == S_OK)
                {
                    sb.Append(functionName.Demanglify());
                }
                else
                {
                    sb.Append("<Function Name Not Available>");
                }

                sb.Append(CreateParameterListString(session, symbol));

                if (includeFileInfo)
                {
                    sb.Append(CreateSourceInfoString(session, rva));
                }

                return(sb.ToString());
            }
            catch
            {
                return(null);
            }
        }
 //
 // Makes reasonable effort to get source info. Returns null sourceFile and 0 lineNumber/columnNumber if it can't.
 //
 public static void TryGetSourceLineInfo(IntPtr ip, out string fileName, out int lineNumber, out int columnNumber)
 {
     fileName     = null;
     lineNumber   = 0;
     columnNumber = 0;
     if (!IsDiaStackTraceResolutionDisabled())
     {
         int         rva;
         IDiaSession session = GetDiaSession(ip, out rva);
         if (session != null)
         {
             TryGetSourceLineInfo(session, rva, out fileName, out lineNumber, out columnNumber);
         }
     }
 }
        //
        // Generate the " in <filename>:line <line#>" section.
        //
        private static String CreateSourceInfoString(IDiaSession session, int rva)
        {
            StringBuilder sb = new StringBuilder();
            string        fileName;
            int           lineNumber, columnNumber;

            TryGetSourceLineInfo(session, rva, out fileName, out lineNumber, out columnNumber);
            if (!string.IsNullOrEmpty(fileName))
            {
                sb.Append(" in ").Append(fileName);
                if (lineNumber >= 0)
                {
                    sb.Append(":line ").Append(lineNumber);
                }
            }
            return(sb.ToString());
        }
 private static void HandleCrash(string hash, IDiaSession pdbSession, int crashCount)
 {
     if (!String.IsNullOrEmpty(hash))
     {
         var crashDetails   = GetCrashDetails(hash);
         int crashOccurence = 0;
         foreach (var crashDetail in crashDetails)
         {
             crashOccurence++;
             string cabId = crashDetail.cabId;
             if (!String.IsNullOrEmpty(cabId))
             {
                 var stackTrace = GetCrashStacktrace(cabId);
                 _writer.WriteLine();
                 _writer.WriteLine();
                 _writer.WriteLine();
                 _writer.WriteLine($"Crash #{crashCount}.{crashOccurence}: {crashDetail.failureName}");
                 _writer.WriteLine();
                 if (stackTrace != null)
                 {
                     foreach (var stackLine in stackTrace)
                     {
                         string methodName = stackLine.function;
                         if (String.IsNullOrEmpty(methodName) || methodName == "null")
                         {
                             string fullOffset = stackLine.offset;
                             string hexOffset  = fullOffset.Replace("0x", "");
                             uint   offset     = HexToUint(hexOffset);
                             if (pdbSession != null && offset != 0)
                             {
                                 methodName = DiaHelper.GetMethodName(pdbSession, offset);
                             }
                         }
                         _writer.WriteLine($"at {stackLine.image}!{methodName}");
                     }
                     if (_preventDuplication)
                     {
                         break;
                     }
                 }
             }
         }
     }
 }
예제 #23
0
        /// <summary>
        /// Initializes this instance of the <see cref="DiaModule"/> class.
        /// </summary>
        /// <param name="diaSession">The DIA session.</param>
        /// <param name="module">The module.</param>
        private void Initialize(IDiaSession diaSession, Module module)
        {
            Module        = module;
            session       = diaSession;
            globalScope   = session.globalScope;
            typeAllFields = new DictionaryCache <uint, List <Tuple <string, uint, int> > >(GetTypeAllFields);
            typeFields    = new DictionaryCache <uint, List <Tuple <string, uint, int> > >(GetTypeFields);
            basicTypes    = SimpleCache.Create(() =>
            {
                var types      = new Dictionary <string, IDiaSymbol>();
                var basicTypes = globalScope.GetChildren(SymTagEnum.BaseType);

                foreach (var type in basicTypes)
                {
                    try
                    {
                        string typeString = TypeToString.GetTypeString(type);

                        if (!types.ContainsKey(typeString))
                        {
                            types.Add(typeString, type);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                return(types);
            });
            symbolNamesByAddress = new DictionaryCache <uint, Tuple <string, ulong> >((distance) =>
            {
                IDiaSymbol symbol;
                int displacement;
                string name;

                session.findSymbolByRVAEx(distance, SymTagEnum.Null, out symbol, out displacement);
                name = symbol.get_undecoratedNameEx(UndecoratedNameOptions.NameOnly | UndecoratedNameOptions.NoEscu);
                return(Tuple.Create(name, (ulong)displacement));
            });

            session.loadAddress = module.Address;
            enumTypeNames       = new DictionaryCache <uint, Dictionary <ulong, string> >(GetEnumName);
        }
예제 #24
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));
        }
예제 #25
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Module"/> class.
        /// </summary>
        /// <param name="name">The module name.</param>
        /// <param name="nameSpace">The default namespace.</param>
        /// <param name="dia">The DIA data source.</param>
        /// <param name="session">The DIA session.</param>
        private Module(string name, string nameSpace, IDiaDataSource dia, IDiaSession session)
        {
            this.session = session;
            this.dia = dia;
            Name = name;
            Namespace = nameSpace;
            GlobalScope = GetSymbol(session.globalScope);

            PublicSymbols = new HashSet<string>(session.globalScope.GetChildren(SymTagEnum.SymTagPublicSymbol).Select((type) =>
            {
                if (type.code != 0 || type.function != 0 || (LocationType)type.locationType != LocationType.Static)
                    return string.Empty;

                string undecoratedName;

                type.get_undecoratedNameEx(0x1000, out undecoratedName);
                return undecoratedName ?? type.name;
            }));
        }
예제 #26
0
        private async Task <ConstantCache> LoadConstants(string module)
        {
            if (this.constantCaches.ContainsKey(module))
            {
                return(this.constantCaches[module]);
            }

            IDiaSession session = await this.debuggerEngine.DiaLoader.LoadDiaSession(module);

            if (session != null)
            {
                this.constantCaches[module] = this.LoadGlobalConstantsFromDiaSession(session);
                return(this.constantCaches[module]);
            }
            else
            {
                return(null);
            }
        }
예제 #27
0
파일: Module.cs 프로젝트: d4nnyk/WinDbgCs
        /// <summary>
        /// Initializes a new instance of the <see cref="Module"/> class.
        /// </summary>
        /// <param name="name">The module name.</param>
        /// <param name="nameSpace">The default namespace.</param>
        /// <param name="dia">The DIA data source.</param>
        /// <param name="session">The DIA session.</param>
        private Module(string name, string nameSpace, IDiaDataSource dia, IDiaSession session)
        {
            this.session = session;
            this.dia     = dia;
            Name         = name;
            Namespace    = nameSpace;
            GlobalScope  = GetSymbol(session.globalScope);

            PublicSymbols = new HashSet <string>(session.globalScope.GetChildren(SymTagEnum.SymTagPublicSymbol).Select((type) =>
            {
                if (type.code != 0 || type.function != 0 || (LocationType)type.locationType != LocationType.Static)
                {
                    return(string.Empty);
                }

                string undecoratedName;

                type.get_undecoratedNameEx(0x1000, out undecoratedName);
                return(undecoratedName ?? type.name);
            }));
        }
예제 #28
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);
            }
        }
        private static void HandleCrashTxtStacktrace(string crashTxt, IDiaSession pdbSession)
        {
            var lines = File.ReadAllLines(crashTxt);

            for (int i = 0; i < lines.Length; i++)
            {
                var currentLine = lines[i];
                if (currentLine.Contains("<BaseAddress>"))
                {
                    string   outputLine = "";
                    string[] splitted   = currentLine.Split(new string[] { "<BaseAddress>" }, StringSplitOptions.None);
                    outputLine += splitted[0];
                    string rva    = splitted[1].Replace("+0x", "");
                    uint   offset = HexToUint(rva);
                    if (pdbSession != null && offset != 0)
                    {
                        string tmpMethodName = DiaHelper.GetMethodName(pdbSession, offset);
                        if (!String.IsNullOrEmpty(tmpMethodName))
                        {
                            outputLine += tmpMethodName;
                        }
                        else
                        {
                            outputLine += "<BaseAddress>" + splitted[1];
                        }
                    }
                    else
                    {
                        outputLine += "<BaseAddress>" + splitted[1];
                    }
                    _writer.WriteLine(outputLine);
                }
                else
                {
                    _writer.WriteLine(currentLine);
                }
            }
        }
예제 #30
0
        public Type GetCachedType(IDiaSession session, string module, string typename, out bool foundType)
        {
            string key = TypeKey(module, typename);

            if (this.types.ContainsKey(key))
            {
                foundType = true;
                return(this.types[key]);
            }

            // Is it a built-in type?
            Type builtinType = this.GetBuiltinType(session, module, typename);

            if (builtinType != null)
            {
                this.types.Add(key, builtinType);
                foundType = true;
                return(builtinType);
            }

            foundType = false;
            return(null);
        }
        //
        // Retrieve the source fileName, line number, and column
        //
        private static void TryGetSourceLineInfo(IDiaSession session, int rva, out string fileName, out int lineNumber, out int columnNumber)
        {
            fileName     = null;
            lineNumber   = 0;
            columnNumber = 0;
            IDiaEnumLineNumbers lineNumbers;
            int hr = session.FindLinesByRVA(rva, 1, out lineNumbers);

            if (hr == S_OK)
            {
                int numLineNumbers;
                hr = lineNumbers.Count(out numLineNumbers);
                if (hr == S_OK && numLineNumbers > 0)
                {
                    IDiaLineNumber ln;
                    hr = lineNumbers.Item(0, out ln);
                    if (hr == S_OK)
                    {
                        IDiaSourceFile sourceFile;
                        hr = ln.SourceFile(out sourceFile);
                        if (hr == S_OK)
                        {
                            hr = sourceFile.FileName(out fileName);
                            if (hr == S_OK)
                            {
                                hr = ln.LineNumber(out lineNumber);
                                if (hr == S_OK)
                                {
                                    hr = ln.ColumnNumber(out columnNumber);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #32
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DiaModule"/> class.
 /// </summary>
 /// <param name="diaSession">The DIA session.</param>
 /// <param name="module">The module.</param>
 public DiaModule(IDiaSession diaSession, Module module)
 {
     Initialize(diaSession, module);
 }
예제 #33
0
        //
        // Create the method parameter list.
        //
        private static String CreateParameterListString(IDiaSession session, IDiaSymbol symbol)
        {
            StringBuilder sb = new StringBuilder("(");

            // find the parameters
            IDiaEnumSymbols dataSymbols;
            int hr = session.FindChildren(symbol, SymTagEnum.SymTagData, null, NameSearchOptions.nsNone, out dataSymbols);
            if (hr == S_OK)
            {
                int count;
                hr = dataSymbols.Count(out count);
                if (hr == S_OK)
                {
                    for (int i = 0, iParam = 0; i < count; i++)
                    {
                        IDiaSymbol dataSym;
                        hr = dataSymbols.Item(i, out dataSym);
                        if (hr != S_OK)
                            continue;

                        DataKind dataKind;
                        hr = dataSym.GetDataKind(out dataKind);
                        if (hr != S_OK || dataKind != DataKind.DataIsParam)
                            continue;

                        string paramName;
                        hr = dataSym.GetName(out paramName);
                        if (hr != S_OK)
                        {
                            continue;
                        }

                        //this approximates the way C# displays methods by not including these hidden arguments
                        if (paramName == "InstParam" || paramName == "this")
                        {
                            continue;
                        }

                        IDiaSymbol parameterType;
                        hr = dataSym.GetType(out parameterType);
                        if (hr != S_OK)
                        {
                            continue;
                        }

                        if (iParam++ != 0)
                            sb.Append(", ");

                        sb.Append(parameterType.ToTypeString(session));
                        sb.Append(' ');
                        sb.Append(paramName);
                    }
                }
            }
            sb.Append(')');
            return sb.ToString();
        }
예제 #34
0
 //
 // Retrieve the source fileName, line number, and column
 //
 private static void TryGetSourceLineInfo(IDiaSession session, int rva, out string fileName, out int lineNumber, out int columnNumber)
 {
     fileName = null;
     lineNumber = 0;
     columnNumber = 0;
     IDiaEnumLineNumbers lineNumbers;
     int hr = session.FindLinesByRVA(rva, 1, out lineNumbers);
     if (hr == S_OK)
     {
         int numLineNumbers;
         hr = lineNumbers.Count(out numLineNumbers);
         if (hr == S_OK && numLineNumbers > 0)
         {
             IDiaLineNumber ln;
             hr = lineNumbers.Item(0, out ln);
             if (hr == S_OK)
             {
                 IDiaSourceFile sourceFile;
                 hr = ln.SourceFile(out sourceFile);
                 if (hr == S_OK)
                 {
                     hr = sourceFile.FileName(out fileName);
                     if (hr == S_OK)
                     {
                         hr = ln.LineNumber(out lineNumber);
                         if (hr == S_OK)
                         {
                             hr = ln.ColumnNumber(out columnNumber);
                         }
                     }
                 }
             }
         }
     }
 }
예제 #35
0
        internal DiaResolver(string binary, string pathExtension, ILogger logger, bool debugMode)
        {
            _binary = binary;
            _logger = logger;
            _debugMode = debugMode;

            string pdb = FindPdbFile(binary, pathExtension);
            if (pdb == null)
            {
                _logger.LogWarning($"Couldn't find the .pdb file of file '{binary}'. You will not get any source locations for your tests.");
                return;
            }

            if (!TryCreateDiaInstance(Dia140) && !TryCreateDiaInstance(Dia120) && !TryCreateDiaInstance(Dia110))
            {
                _logger.LogError("Couldn't find the msdia.dll to parse *.pdb files. You will not get any source locations for your tests.");
                return;
            }

            if (_debugMode)
                _logger.LogInfo($"Parsing pdb file \"{pdb}\"");

            _fileStream = File.Open(pdb, FileMode.Open, FileAccess.Read, FileShare.Read);
            _diaDataSource.loadDataFromIStream(new DiaMemoryStream(_fileStream));

            dynamic diaSession110Or140;
            _diaDataSource.openSession(out diaSession110Or140);
            _diaSession = new DiaSessionAdapter(diaSession110Or140);
        }
예제 #36
0
 //
 // Generate the " in <filename>:line <line#>" section.
 //
 private static String CreateSourceInfoString(IDiaSession session, int rva)
 {
     StringBuilder sb = new StringBuilder();
     string fileName;
     int lineNumber, columnNumber;
     TryGetSourceLineInfo(session, rva, out fileName, out lineNumber, out columnNumber);
     if(!string.IsNullOrEmpty(fileName))
     {
         sb.Append(" in ").Append(fileName);
         if(lineNumber >= 0)
         {
             sb.Append(":line ").Append(lineNumber);
         }
     }
     return sb.ToString();
 }
예제 #37
0
 private static String ToTypeString(this IDiaSymbol parameterType, IDiaSession session)
 {
     bool ignore;
     return parameterType.ToTypeStringWorker(session, 0, out ignore);
 }
예제 #38
0
        private static String ToTypeStringWorker(this IDiaSymbol parameterType, IDiaSession session, int recursionLevel, out bool isValueTypeOrByRef)
        {
            int hr;
            isValueTypeOrByRef = false;

            // Block runaway recursions.
            if (recursionLevel++ > 10)
                return "?";

            SymTagEnum symTag;
            hr = parameterType.GetSymTag(out symTag);
            if (hr != S_OK)
                return "?";
            if (symTag == SymTagEnum.SymTagPointerType)
            {
                bool isReference;
                hr = parameterType.GetReference(out isReference);
                if (hr != S_OK)
                    return "?";

                if (isReference)
                {
                    // An isReference pointer can mean one of two things:
                    //   1. ELEMENT_TYPE_BYREF
                    //   2. An indication that the UDT that follows is actually a class, not a struct. 
                    //
                    isValueTypeOrByRef = true;
                    IDiaSymbol targetType;
                    hr = parameterType.GetType(out targetType);
                    if (hr != S_OK)
                        return "?";
                    bool targetIsValueTypeOrByRef;
                    String targetTypeString = targetType.ToTypeStringWorker(session, recursionLevel, out targetIsValueTypeOrByRef);
                    if (targetIsValueTypeOrByRef)
                        return targetTypeString + "&";
                    else
                        return targetTypeString;
                }
                else
                {
                    // A non-isReference pointer means an ELEMENT_TYPE_PTR
                    IDiaSymbol targetType;
                    hr = parameterType.GetType(out targetType);
                    if (hr != S_OK)
                        return "?";
                    bool ignore;
                    return targetType.ToTypeStringWorker(session, recursionLevel, out ignore) + "*";
                }
            }
            else if (symTag == SymTagEnum.SymTagArrayType)
            {
                // Note: We don't actually hit this case in NUTC-generated PDB's as NUTC emits arrays as if they were UDT's with square brackets in the name.
                // But just in case NUTC ever changes its PDB emission, we'll print out the most obvious interpretation and hope we're right.
                IDiaSymbol elementType;
                hr = parameterType.GetType(out elementType);
                if (hr != S_OK)
                    return "?";
                bool ignore;
                return elementType.ToTypeStringWorker(session, recursionLevel, out ignore) + "[]";
            }
            else if (symTag == SymTagEnum.SymTagUDT || symTag == SymTagEnum.SymTagEnum)
            {
                // Need to figure out whether this is a value type as our recursive caller needs to know whether the "byref pointer" that wrapped this
                // is a true managed byref or just the "byref pointer" that wraps all non-valuetypes.
                if (symTag == SymTagEnum.SymTagEnum)
                {
                    isValueTypeOrByRef = true;
                }
                else
                {
                    IDiaEnumSymbols baseClasses;
                    hr = session.FindChildren(parameterType, SymTagEnum.SymTagBaseClass, null, 0, out baseClasses);
                    if (hr != S_OK)
                        return "?";
                    int count;
                    hr = baseClasses.Count(out count);
                    if (hr != S_OK)
                        return "?";
                    for (int i = 0; i < count; i++)
                    {
                        IDiaSymbol baseClass;
                        if (S_OK == baseClasses.Item(i, out baseClass))
                        {
                            String baseClassName;
                            if (S_OK == baseClass.GetName(out baseClassName))
                            {
                                if (baseClassName == "System::ValueType")
                                    isValueTypeOrByRef = true;
                            }
                        }
                    }
                }

                String name;
                hr = parameterType.GetName(out name);
                if (hr != S_OK)
                    return "?";
                return name.RemoveNamespaces().Demanglify();
            }
            else if (symTag == SymTagEnum.SymTagBaseType)
            {
                // Certain "primitive" types are encoded specially.
                BasicType basicType;
                hr = parameterType.GetBaseType(out basicType);
                if (hr != S_OK)
                    return "?";
                long length;
                hr = parameterType.GetLength(out length);
                if (hr != S_OK)
                    return "?";
                return ConvertBasicTypeToTypeString(basicType, length, out isValueTypeOrByRef);
            }
            else
            {
                return "?";
            }
        }
예제 #39
0
        /// <summary>
        /// Locate and lazily load debug info for the native app module overlapping given
        /// virtual address.
        /// </summary>
        /// <param name="ip">Instruction pointer address (code address for the lookup)</param>
        /// <param name="rva">Output VA relative to module base</param>
        private static IDiaSession GetDiaSession(IntPtr ip, out int rva)
        {
            if (ip == IntPtr.Zero)
            {
                rva = -1;
                return null;
            }

            IntPtr moduleBase = RuntimeAugments.GetModuleFromPointer(ip);
            if (moduleBase == IntPtr.Zero)
            {
                rva = -1;
                return null;
            }

            rva = (int)(ip.ToInt64() - moduleBase.ToInt64());

            if (s_loadedModules == null)
            {
                // Lazily create the parallel arrays s_loadedModules and s_perModuleDebugInfo
                int moduleCount = RuntimeAugments.GetLoadedModules(null);

                s_loadedModules = new IntPtr[moduleCount];
                s_perModuleDebugInfo = new IDiaSession[moduleCount];

                // Actually read the module addresses into the array
                RuntimeAugments.GetLoadedModules(s_loadedModules);
            }

            // Locate module index based on base address
            int moduleIndex = s_loadedModules.Length;
            do
            {
                if (--moduleIndex < 0)
                {
                    return null;
                }
            }
            while(s_loadedModules[moduleIndex] != moduleBase);

            IDiaSession diaSession = s_perModuleDebugInfo[moduleIndex];
            if (diaSession != null)
            {
                return diaSession;
            }
            
            string modulePath = RuntimeAugments.TryGetFullPathToApplicationModule(moduleBase);
            if (modulePath == null)
            {
                return null;
            }

            int indexOfLastDot = modulePath.LastIndexOf('.');
            if (indexOfLastDot == -1)
            {
                return null;
            }

            IDiaDataSource diaDataSource = GetDiaDataSource();
            if (diaDataSource == null)
            {
                return null;
            }

            // Look for .pdb next to .exe / dll - if it's not there, bail.
            String pdbPath = modulePath.Substring(0, indexOfLastDot) + ".pdb";
            int hr = diaDataSource.LoadDataFromPdb(pdbPath);
            if (hr != S_OK)
            {
                return null;
            }

            hr = diaDataSource.OpenSession(out diaSession);
            if (hr != S_OK)
            {
                return null;
            }

            s_perModuleDebugInfo[moduleIndex] = diaSession;
            return diaSession;
        }