Exemple #1
0
        /// <summary>
        /// Parses a PEFile from a given stream. If it is valid, a new PEFile object is
        /// constructed and returned. Otherwise, null is returned.
        /// </summary>
        public static PEFile TryLoad(Stream stream, bool virt)
        {
            PEBuffer headerBuff = new PEBuffer(stream);
            PEHeader hdr = PEHeader.FromBuffer(headerBuff, virt);

            if (hdr == null)
                return null;

            PEFile pefile = new PEFile();
            pefile.Init(stream, "stream", virt, headerBuff, hdr);
            return pefile;
        }
Exemple #2
0
        public override bool IsMatchingPdb(string pdbPath)
        {
            if (m_peFile == null)
                m_peFile = new PEFile(new ReadVirtualStream(m_runtime.DataReader, (long)m_imageBase, (long)m_size), true);

            string pdbName;
            Guid pdbGuid;
            int rev;
            if (!m_peFile.GetPdbSignature(out pdbName, out pdbGuid, out rev))
                throw new ClrDiagnosticsException("Failed to get PDB signature from module.", ClrDiagnosticsException.HR.DataRequestError);
                
            IDiaDataSource source = DiaLoader.GetDiaSourceObject();
            IDiaSession session;
            source.loadDataFromPdb(pdbPath);
            source.openSession(out session);
            return pdbGuid == session.globalScope.guid;
        }
        /// <summary>
        /// Helper function to load a DLL and then lookup exported functions. For this we use CLRMD and specifically the PEHeader class
        /// </summary>
        /// <param name="DLLPath"></param>
        /// <returns></returns>
        public unsafe Dictionary <int, ExportedSymbol> GetExports(string DLLPath)
        {
            PEHeader Header = new Microsoft.Diagnostics.Runtime.Utilities.PEFile(DLLPath).Header;

            var dir    = Header.ExportDirectory;
            var offset = Header.RvaToFileOffset(dir.VirtualAddress);

            // this is the placeholder for the final mapping of ordinal # to address map
            Dictionary <int, ExportedSymbol> exports = null;

            using (var mmf = MemoryMappedFile.CreateFromFile(new FileStream(DLLPath, FileMode.Open, FileAccess.Read, FileShare.Read), null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false))
            {
                using (var _accessor = mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read))
                {
                    IMAGE_EXPORT_DIRECTORY exportDirectory;
                    _accessor.Read(offset, out exportDirectory);

                    var count = exportDirectory.NumberOfFunctions;
                    exports = new Dictionary <int, ExportedSymbol>(count);

                    var namesOffset     = exportDirectory.AddressOfNames != 0 ? Header.RvaToFileOffset(exportDirectory.AddressOfNames) : 0;
                    var ordinalOffset   = exportDirectory.AddressOfOrdinals != 0 ? Header.RvaToFileOffset(exportDirectory.AddressOfOrdinals) : 0;
                    var functionsOffset = Header.RvaToFileOffset(exportDirectory.AddressOfFunctions);

                    var ordinalBase = (int)exportDirectory.Base;

                    var name = new sbyte[64];
                    fixed(sbyte *p = name)
                    {
                        for (uint i = 0; i < count; i++)
                        {
                            // read function address
                            var address = _accessor.ReadUInt32(functionsOffset + i * 4);

                            exports.Add((int)(ordinalBase + i), new ExportedSymbol
                            {
                                Name    = string.Format("Ordinal{0}", ordinalBase + i),
                                Address = address
                            });
                        }
                    }
                }
            }

            return(exports);
        }
        public void PdbGuidAgeTest()
        {
            int pdbAge;
            Guid pdbSignature;
            PdbReader.GetPdbProperties(TestTargets.NestedException.Pdb, out pdbSignature, out pdbAge);
            
            // Ensure we get the same answer a different way.
            using (PdbReader pdbReader = new PdbReader(TestTargets.NestedException.Pdb))
            {
                Assert.AreEqual(pdbAge, pdbReader.Age);
                Assert.AreEqual(pdbSignature, pdbReader.Signature);
            }

            // Ensure the PEFile has the same signature/age.
            using (PEFile peFile = new PEFile(TestTargets.NestedException.Executable))
            {
                Assert.AreEqual(peFile.PdbInfo.Guid, pdbSignature);
                Assert.AreEqual(peFile.PdbInfo.Revision, pdbAge);
            }
        }
Exemple #5
0
        internal ResourceNode(string name, int nodeFileOffset, PEFile file, bool isLeaf, bool isTop = false)
        {
            _file = file;
            _nodeFileOffset = nodeFileOffset;
            _isTop = isTop;
            IsLeaf = isLeaf;
            Name = name;

            if (isLeaf)
            {
                var buff = _file.AllocBuff();
                IMAGE_RESOURCE_DATA_ENTRY* dataDescr = (IMAGE_RESOURCE_DATA_ENTRY*)buff.Fetch(nodeFileOffset, sizeof(IMAGE_RESOURCE_DATA_ENTRY));

                _dataLen = dataDescr->Size;
                _dataFileOffset = file.Header.RvaToFileOffset(dataDescr->RvaToData);
                var data = FetchData(0, _dataLen, buff);
                _file.FreeBuff(buff);
            }
        }
Exemple #6
0
 internal static bool TryGetIndexProperties(Stream stream, bool virt, out int timestamp, out int filesize)
 {
     try
     {
         using (PEFile pefile = new PEFile(stream, virt))
         {
             var header = pefile.Header;
             timestamp = header.TimeDateStampSec;
             filesize = (int)header.SizeOfImage;
             return true;
         }
     }
     catch
     {
         timestamp = 0;
         filesize = 0;
         return false;
     }
 }
Exemple #7
0
        /// <summary>
        /// This API looks up an executable file, by its build-timestamp and size (on a symbol server),  'fileName' should be 
        /// a simple name (no directory), and you need the buildTimeStamp and sizeOfImage that are found in the PE header.
        /// 
        /// Returns null if it cannot find anything.  
        /// </summary>
        public string FindExecutableFilePath(string fileName, int buildTimeStamp, int sizeOfImage, ISymbolNotification notification)
        {
            Debug.Assert(notification != null);

            string exeIndexPath = null;
            foreach (SymPathElement element in SymbolPath.Elements)
            {
                if (element.IsSymServer)
                {
                    if (exeIndexPath == null)
                        exeIndexPath = fileName + @"\" + buildTimeStamp.ToString("x") + sizeOfImage.ToString("x") + @"\" + fileName;

                    string cache = element.Cache;
                    if (cache == null)
                        cache = SymbolPath.DefaultSymbolCache;

                    string targetPath = GetFileFromServer(element.Target, exeIndexPath, cache, notification);
                    if (targetPath != null)
                        return targetPath;
                }
                else
                {
                    string filePath = Path.Combine(element.Target, fileName);
                    _log.WriteLine("Probing file {0}", filePath);
                    if (File.Exists(filePath))
                    {
                        using (PEFile file = new PEFile(filePath))
                        {
                            // TODO: This is incorrect.
                            //if ((file.Header.TimeDateStampSec == buildTimeStamp) && (file.Header.SizeOfImage == sizeOfImage))
                            {
                                notification.FoundSymbolOnPath(filePath);
                                return filePath;
                            }

                            //m_log.WriteLine("Found file {0} but file timstamp:size {1}:{2} != desired {3}:{4}, rejecting.",
                            //    filePath, file.Header.TimeDateStampSec, file.Header.SizeOfImage, buildTimeStamp, sizeOfImage);
                        }
                    }

                    notification.ProbeFailed(filePath);
                }
            }
            return null;
        }
Exemple #8
0
        public string FindSymbolFilePath(string pdbSimpleName, Guid pdbIndexGuid, int pdbIndexAge, ISymbolNotification notification)
        {
            string pdbIndexPath = null;
            foreach (SymPathElement element in SymbolPath.Elements)
            {
                if (element.IsSymServer)
                {
                    pdbSimpleName = Path.GetFileName(pdbSimpleName);
                    if (pdbIndexPath == null)
                        pdbIndexPath = pdbSimpleName + @"\" + pdbIndexGuid.ToString().Replace("-", "") + pdbIndexAge.ToString("x") + @"\" + pdbSimpleName;

                    string cache = element.Cache;
                    if (cache == null)
                        cache = SymbolPath.DefaultSymbolCache;

                    string targetPath = GetFileFromServer(element.Target, pdbIndexPath, cache, notification);
                    if (targetPath != null)
                        return targetPath;
                }
                else
                {
                    string filePath = Path.Combine(element.Target, pdbSimpleName);
                    _log.WriteLine("Probing file {0}", filePath);
                    if (File.Exists(filePath))
                    {
                        using (PEFile file = new PEFile(filePath))
                        {
                            IDiaDataSource source = DiaLoader.GetDiaSourceObject();
                            IDiaSession session;
                            source.loadDataFromPdb(filePath);
                            source.openSession(out session);

                            if (pdbIndexGuid == session.globalScope.guid)
                            {
                                notification.FoundSymbolOnPath(filePath);
                                return filePath;
                            }

                            _log.WriteLine("Found file {0} but guid {1} != desired {2}, rejecting.", filePath, session.globalScope.guid, pdbIndexGuid);
                        }
                    }

                    notification.ProbeFailed(filePath);
                }
            }

            return null;
        }
Exemple #9
0
        public override string TryDownloadPdb(ISymbolNotification notification)
        {
            var dataTarget = m_runtime.DataTarget;
            if (notification == null)
                notification = dataTarget.DefaultSymbolNotification ?? new NullSymbolNotification();

            if (m_peFile == null)
                m_peFile = new PEFile(new ReadVirtualStream(m_runtime.DataReader, (long)m_imageBase, (long)m_size), true);
            
            string pdbName;
            Guid pdbGuid;
            int rev;
            if (!m_peFile.GetPdbSignature(out pdbName, out pdbGuid, out rev))
                throw new ClrDiagnosticsException("Failed to get PDB signature from module.", ClrDiagnosticsException.HR.DataRequestError);

            if (File.Exists(pdbName))
                return pdbName;

            var reader = dataTarget.SymbolReader;
            return reader.FindSymbolFilePath(pdbName, pdbGuid, rev, notification);
        }
        private string FindImage(string image, uint imageTimestamp, uint imageSize)
        {
            // Test file on disk.
            if (File.Exists(image))
            {
                try
                {
                    using (PEFile file = new PEFile(image))
                    {
                        var header = file.Header;
                        if (header.TimeDateStampSec == (int)imageTimestamp && header.SizeOfImage == imageSize)
                            return image;
                    }
                }
                catch
                {
                    // Ignore any exceptions when trying to determine image and file timestamp.
                    Debug.Assert(false);
                }
            }

            try
            {
                image = Path.GetFileName(image);
            }
            catch (ArgumentException)
            {
                return null;
            }

            // Try symbol server instead.
            return m_dataTarget.TryDownloadFile(image, (int)imageTimestamp, (int)imageSize, null);
        }
        SymbolModule FindPdbForModule(ModuleInfo module)
        {
            if (module == null)
                return null;

            string pdbName;
            Guid pdbGuid;
            int rev;
            using (PEFile pefile = new PEFile(new ReadVirtualStream(m_dataReader, (long)module.ImageBase, (long)module.FileSize), true))
                if (!pefile.GetPdbSignature(out pdbName, out pdbGuid, out rev))
                    return null;

            if (!File.Exists(pdbName))
            {
                ISymbolNotification notification = DefaultSymbolNotification ?? new NullSymbolNotification();
                pdbName = Path.GetFileName(pdbName);
                pdbName = SymbolReader.FindSymbolFilePath(pdbName, pdbGuid, rev, notification);

                if (string.IsNullOrEmpty(pdbName) || !File.Exists(pdbName))
                    return null;
            }

            if (pdbName == null)
            {
                m_symbols[module] = null;
                return null;
            }

            SymbolModule symbols = null;
            try
            {
                symbols = new SymbolModule(SymbolReader, pdbName);
                m_symbols[module] = symbols;
            }
            catch
            {
                m_symbols[module] = null;
                return null;
            }

            return symbols;
        }
Exemple #12
0
        // These routines find a PDB based on something (either an DLL or a pdb 'signature')
        /// <summary>
        /// Finds the symbol file for 'exeFilePath' that exists on the current machine (we open
        /// it to find the needed info).   Uses the SymbolReader.SymbolPath (including Symbol servers) to 
        /// look up the PDB, and will download the PDB to the local cache if necessary.   It will also
        /// generate NGEN pdbs unless SymbolReaderFlags.NoNGenPDB is set.   
        /// 
        /// returns null if the pdb can't be found.  
        /// </summary>
        public string FindSymbolFilePathForModule(string dllFilePath)
        {
            Debug.Assert(!IsDisposed);
            try
            {
                dllFilePath = BypassSystem32FileRedirection(dllFilePath);
                if (File.Exists(dllFilePath))
                {
                    using (var peFile = new PEFile(dllFilePath))
                    {
                        string pdbName;
                        Guid pdbGuid;
                        int pdbAge;
                        if (peFile.GetPdbSignature(out pdbName, out pdbGuid, out pdbAge, true))
                        {
                            string fileVersionString = null;
                            var fileVersion = peFile.GetFileVersionInfo();
                            if (fileVersion != null)
                                fileVersionString = fileVersion.FileVersion;

                            // TODO FIX NOW should this be here? 
                            m_log.WriteLine("Exe {0} has pdb {1} GUID {2} age {3}", dllFilePath, pdbName, pdbGuid, pdbAge);

                            var ret = FindSymbolFilePath(pdbName, pdbGuid, pdbAge, dllFilePath, fileVersionString);
                            if (ret == null && (Flags & SymbolReaderFlags.NoNGenPDB) == 0 &&
                                (dllFilePath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) ||
                                 dllFilePath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase)))
                            {
                                m_log.WriteLine("Could not find PDB for NGEN image, Trying to genereate it.");
                                ret = GenerateNGenPdbForModule(Path.GetFullPath(dllFilePath));
                            }
                            m_log.WriteLine("FindSymbolFilePathForModule returns {0}", ret ?? "NULL");
                            return ret;
                        }
                        else
                            m_log.WriteLine("File does not have a codeview debug signature.");
                    }
                }
                else
                    m_log.WriteLine("File does not exist.");
            }
            catch (Exception e)
            {
                m_log.WriteLine("Failure opening PE file: {0}", e.Message);
            }

            m_log.WriteLine("[Failed to find PDB file for {0}]", dllFilePath);
            return null;
        }
Exemple #13
0
        /// <summary>
        /// Given a full filename path to an NGEN image, insure that there is an NGEN image for it
        /// in the symbol cache.  If one already exists, this method simply returns that.   If not
        /// it is generated and placed in the symbol cache.  When generating the PDB this routine
        /// attempt to resolve line numbers, which DOES require looking up the PDB for the IL image. 
        /// Thus routine may do network accesses (to download IL PDBs).  
        /// 
        /// Note that FindSymbolFilePathForModule calls this, so normally you don't need to call 
        /// this method directly.  
        /// </summary>
        public string GenerateNGenPdbForModule(string ngenImageFullPath)
        {
            SymbolReader symReader = this;

            var log = symReader.m_log;
            if (!File.Exists(ngenImageFullPath))
            {
                log.WriteLine("Warning, NGEN image does not exist: {0}", ngenImageFullPath);
                return null;
            }

            // When V4.5 shipped, NGEN CreatePdb did not support looking up the IL pdb using symbol servers.  
            // We work around by explicitly fetching the IL PDB and pointing NGEN CreatePdb at that.  
            string ilPdbName = null;
            Guid ilPdbGuid = Guid.Empty;
            int ilPdbAge = 0;

            string pdbName;
            Guid pdbGuid;
            int pdbAge;
            using (var peFile = new PEFile(ngenImageFullPath))
            {
                if (!peFile.GetPdbSignature(out pdbName, out pdbGuid, out pdbAge, true))
                {
                    log.WriteLine("Could not get PDB signature for {0}", ngenImageFullPath);
                    return null;
                }

                // Also get the IL pdb information
                peFile.GetPdbSignature(out ilPdbName, out ilPdbGuid, out ilPdbAge, false);
            }

            // Fast path, the file already exists.
            pdbName = Path.GetFileName(pdbName);
            var relPath = pdbName + "\\" + pdbGuid.ToString("N") + pdbAge.ToString() + "\\" + pdbName;
            var pdbPath = Path.Combine(symReader.SymbolCacheDirectory, relPath);
            if (File.Exists(pdbPath))
                return pdbPath;

            var clrDir = GetClrDirectoryForNGenImage(ngenImageFullPath, log);
            if (clrDir == null)
                return null;

            // See if this is a V4.5 CLR, if so we can do line numbers too.l  
            var lineNumberArg = "";
            var ngenexe = Path.Combine(clrDir, "ngen.exe");
            log.WriteLine("Checking for V4.5 for NGEN image {0}", ngenexe);
            if (!File.Exists(ngenexe))
                return null;
            var isV4_5Runtime = false;

            Match m;
            using (var peFile = new PEFile(ngenexe))
            {
                var fileVersionInfo = peFile.GetFileVersionInfo();
                if (fileVersionInfo != null)
                {
                    var clrFileVersion = fileVersionInfo.FileVersion;
                    m = Regex.Match(clrFileVersion, @"^[\d.]+\.(\d+) ");       // Fetch the build number (last number)
                    if (m.Success)
                    {
                        // Is this a V4.5 runtime?
                        var buildNumber = int.Parse(m.Groups[1].Value);
                        log.WriteLine("Got NGEN.exe Build number: {0}", buildNumber);
                        if (buildNumber > 16000)
                        {
                            if (ilPdbName != null)
                            {
                                var ilPdbPath = symReader.FindSymbolFilePath(ilPdbName, ilPdbGuid, ilPdbAge);
                                if (ilPdbPath != null)
                                    lineNumberArg = "/lines " + Command.Quote(Path.GetDirectoryName(ilPdbPath));
                                else
                                    log.WriteLine("Could not find IL PDB {0} Guid {1} Age {2}.", ilPdbName, ilPdbGuid, ilPdbAge);
                            }
                            else
                                log.WriteLine("NGEN image did not have IL PDB information, giving up on line number info.");
                            isV4_5Runtime = true;
                        }
                    }
                }
            }

            var options = new CommandOptions();
            options.AddEnvironmentVariable("COMPLUS_NGenEnableCreatePdb", "1");

            // NGenLocalWorker is needed for V4.0 runtims but interferes on V4.5 runtimes.  
            if (!isV4_5Runtime)
                options.AddEnvironmentVariable("COMPLUS_NGenLocalWorker", "1");
            options.AddEnvironmentVariable("_NT_SYMBOL_PATH", symReader.SymbolPath.ToString());
            var newPath = "%PATH%;" + clrDir;
            options.AddEnvironmentVariable("PATH", newPath);
            options.AddOutputStream(log);
            options.AddNoThrow();

            // For Metro Auto-NGEN images we need to use a location where the app can write the PDB file
            var outputDirectory = symReader.SymbolCacheDirectory;
            var outputPdbPath = pdbPath;

            // Find the tempDir where we can write.  
            string tempDir = null;
            m = Regex.Match(ngenImageFullPath, @"(.*)\\Microsoft\\CLR_v(\d+)\.\d+(_(\d\d))?\\NativeImages", RegexOptions.IgnoreCase);
            if (m.Success)
            {
                tempDir = Path.Combine(m.Groups[1].Value, @"Temp\NGenPdb");
                DirectoryUtilities.Clean(tempDir);
                Directory.CreateDirectory(tempDir);
                outputDirectory = tempDir;
                outputPdbPath = Path.Combine(tempDir, relPath);
                log.WriteLine("Updating NGEN createPdb output file to {0}", outputPdbPath); // TODO FIX NOW REMOVE (for debugging)
            }
            try
            {

                for (; ; ) // Loop for retrying without /lines 
                {
                    // TODO FIX NOW: there is a and ugly problem with persistance of suboptimial PDB files
                    // This is made pretty bad because the not finding the IL pdbs is enough to make it fail.  

                    // TODO we need to figure out a convention show we know that we have fallen back to no-lines
                    // and we should regenerate it if we ultimately get the PDB information 
                    var cmdLine = string.Format(@"{0}\ngen.exe createpdb {1} {2} {3}",
                        clrDir, Command.Quote(ngenImageFullPath), Command.Quote(outputDirectory), lineNumberArg);
                    // TODO FIX NOW REMOVE after V4.5 is out a while
                    log.WriteLine("set COMPLUS_NGenEnableCreatePdb=1");
                    if (!isV4_5Runtime)
                        log.WriteLine("set COMPLUS_NGenLocalWorker=1");
                    log.WriteLine("set PATH=" + newPath);
                    log.WriteLine("set _NT_SYMBOL_PATH={0}", symReader.SymbolPath);
                    log.WriteLine("*** NGEN  CREATEPDB cmdline: {0}\r\n", cmdLine);
                    options.AddOutputStream(log);
                    var cmd = Command.Run(cmdLine, options);
                    log.WriteLine("*** NGEN CREATEPDB returns: {0}", cmd.ExitCode);

                    if (cmd.ExitCode != 0)
                    {
                        // ngen might make a bad PDB, so if it returns failure delete it.  
                        if (File.Exists(outputPdbPath))
                            File.Delete(outputPdbPath);

                        // We may have failed because we could not get the PDB.  
                        if (lineNumberArg.Length != 0)
                        {
                            log.WriteLine("Ngen failed to generate pdb for {0}, trying again without /lines", ngenImageFullPath);
                            lineNumberArg = "";
                            continue;
                        }
                    }

                    if (cmd.ExitCode != 0 || !File.Exists(outputPdbPath))
                    {
                        log.WriteLine("ngen failed to generate pdb for {0} at expected location {1}", ngenImageFullPath, outputPdbPath);
                        return null;
                    }

                    // Copy the file to where we want the PDB to live.  
                    if (outputPdbPath != pdbPath)
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(pdbPath));        // Make sure the destination directory exists.
                        File.Copy(outputPdbPath, pdbPath);
                    }
                    return pdbPath;
                }
            }
            finally
            {
                // Insure we have cleaned up any temporary files.  
                if (tempDir != null)
                    DirectoryUtilities.Clean(tempDir);
            }
        }