/// <summary> /// Adds a file to this project, ignoring dupes /// </summary> /// <param name="FilePath">Path to the file on disk</param> /// <param name="BaseFolder">The directory the path within the project will be relative to</param> public void AddFileToProject(FileReference FilePath, DirectoryReference BaseFolder) { // Check if hasn't already been added as an aliased file if (AliasedFilesSet.Contains(FilePath)) { return; } // Don't add duplicates SourceFile ExistingFile = null; if (SourceFileMap.TryGetValue(FilePath, out ExistingFile)) { if (ExistingFile.BaseFolder != BaseFolder) { throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but with a different relative base folder '" + BaseFolder + "' is different than the current file's '" + ExistingFile.BaseFolder + "'!"); } } else { SourceFile File = AllocSourceFile(FilePath, BaseFolder); if (File != null) { SourceFileMap[FilePath] = File; SourceFiles.Add(File); } } }
/// <summary> /// Adds a file to this project, ignoring dupes /// </summary> /// <param name="FilePath">Path to the file on disk</param> /// <param name="RelativeBaseFolder">The directory the path within the project will be relative to</param> public void AddFileToProject(string FilePath, string RelativeBaseFolder) { // Don't add duplicates SourceFile ExistingFile = null; if (SourceFileMap.TryGetValue(FilePath, out ExistingFile)) { if (ExistingFile.RelativeBaseFolder != RelativeBaseFolder) { if ((ExistingFile.RelativeBaseFolder != null) != (RelativeBaseFolder != null) || !ExistingFile.RelativeBaseFolder.Equals(RelativeBaseFolder, StringComparison.InvariantCultureIgnoreCase)) { throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but with a different relative base folder '" + RelativeBaseFolder + "' is different than the current file's '" + ExistingFile.RelativeBaseFolder + "'!"); } else { throw new BuildException("Trying to add file '" + FilePath + "' to project '" + ProjectFilePath + "' when the file already exists, but the specified project relative base folder is different than the current file's!"); } } } else { SourceFile File = AllocSourceFile(FilePath, RelativeBaseFolder); if (File != null) { SourceFileMap[FilePath] = File; SourceFiles.Add(File); } } }
private static async Task <bool> DownloadSourceFiles(SourceFileMap map, string pdbCacheDirectory, bool force) { int countDownloaded = 0; int countPreviouslyDownloaded = 0; int countFailed = 0; int countPreviouslyFailed = 0; foreach (SourceFileDetails sfd in map.Files) { string fileCachePath = Path.Combine(pdbCacheDirectory, sfd.CachedPathSuffix); string fileCacheFolderPath = Path.GetDirectoryName(fileCachePath); // If the folder where the file would be downloaded exists, stop (that's the marker we tried already) if (!force) { if (File.Exists(fileCachePath)) { countPreviouslyDownloaded++; continue; } if (Directory.Exists(fileCacheFolderPath)) { countPreviouslyFailed++; continue; } } // Try to download the file Console.WriteLine("Downloading {0}...", sfd.SourceUrl); try { await SourceFileMap.Download(map.PdbPath, sfd.SourceUrl, TimeSpan.FromSeconds(5)); countDownloaded++; } catch (WebException ex) { countFailed++; // On download failure, create a marker so we know we tried previously Console.WriteLine("Download failed. Writing do not retry marker. Error: {0}", ex.Message); if (!String.IsNullOrEmpty(fileCacheFolderPath)) { Directory.CreateDirectory(fileCacheFolderPath); } } } // Log download result if (map.Files.Count > 0) { Console.WriteLine("Source Download completed. {1:n0} newly downloaded, {2:n0} previously downloaded, {3:n0} failed, {4:n0} previously failed.", map.Files.Count, countDownloaded, countPreviouslyDownloaded, countFailed, countPreviouslyFailed); } return(countFailed == 0); }
private PdbSymbolProvider(string binaryFilePath, string pdbFilePath = "") { _binaryFilePath = binaryFilePath; _pdbFilePath = pdbFilePath; if (String.IsNullOrEmpty(_pdbFilePath)) { _pdbFilePath = Path.ChangeExtension(binaryFilePath, ".pdb"); } // Create a COM Metadata dispenser Guid dispenserClassID = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); // CLSID_CorMetaDataDispenser Guid dispenserIID = new Guid(0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 0x00, 0xa0, 0xc9, 0xb4, 0xd5, 0x0c); // IID_IMetaDataDispenser object objDispenser; Marshal.ThrowExceptionForHR(NativeMethods.MetaDataGetDispenser(ref dispenserClassID, ref dispenserIID, out objDispenser)); _metadataDispenser = (IMetaDataDispenser)objDispenser; // Create a symbol binder [?] Guid symBinderClassID = new Guid(0x0A29FF9E, 0x7F9C, 0x4437, 0x8B, 0x11, 0xF4, 0x24, 0x49, 0x1E, 0x39, 0x31); // CLSID_CorSymBinder Guid symBinderIID = new Guid(0xAA544d42, 0x28CB, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd); // IID_ISymUnmanagedBinder object objBinder; if (NativeMethods.CoCreateInstance(ref symBinderClassID, IntPtr.Zero, // pUnkOuter 1, // CLSCTX_INPROC_SERVER ref symBinderIID, out objBinder) < 0) { throw new InvalidComObjectException("PdbSymbolProvider unable to construct an ISymUnmanagedBinder."); } _symBinder = (ISymUnmanagedBinder)objBinder; // Create a symbol reader Guid importerIID = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); // IID_IMetaDataImport // Open an metadata importer on the given filename. We'll end up passing this importer straight // through to the Binder. object objImporter; Marshal.ThrowExceptionForHR(_metadataDispenser.OpenScope(binaryFilePath, 0x00000010 /* read only */, ref importerIID, out objImporter)); string pdbFolderPath = Path.GetDirectoryName(pdbFilePath); ISymUnmanagedReader reader; Marshal.ThrowExceptionForHR(_symBinder.GetReaderForFile(objImporter, binaryFilePath, pdbFolderPath, out reader)); _symReader = reader; // Create a source file map [if we can find the map file] _sourceFileMap = SourceFileMap.Load(pdbFilePath); }
private void OpenSymbol(Symbol matchToOpen) { string localPath = SourceFileMap.GetLocalPath(matchToOpen); if (String.IsNullOrEmpty(localPath)) { Console.WriteLine("ERROR: File Path unknown for '{0}'.", matchToOpen.Name.ToString()); } else { Console.WriteLine("OPEN: {0}({1})", localPath, matchToOpen.Line); VS.OpenFileToLine(localPath, matchToOpen.Line, Options.DatabasePath); } }
public string CacheLocation(string url) { if (_sourceFileMap == null) { return(url); } SourceFileDetails details = _sourceFileMap.Details(url); if (details == null) { return(url); } return(SourceFileMap.ComputeCachedPath(_pdbFilePath, details.SourceUrl)); }
public SyntaxTree ParseFile(string filePath, string pdbPath) { // Determine the local path to the file (if it's a URL) string localPath = filePath; if (filePath.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { localPath = SourceFileMap.ComputeCachedPath(pdbPath, filePath); } if (!File.Exists(localPath)) { return(null); } // Much like Roslyn CSharpCompiler.CreateCompilation SourceText fileContent = null; using (var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 1, options: FileOptions.None)) { fileContent = SourceText.From(stream); } // Parse the file but keep the original path or URL as the path (so locations from Roslyn point to it) string extension = Path.GetExtension(filePath).ToLowerInvariant(); switch (extension) { case ".cs": return(CSharpSyntaxTree.ParseText(fileContent, path: filePath)); case ".vb": return(VisualBasicSyntaxTree.ParseText(fileContent, path: filePath)); default: return(null); } }
private static int Run(Options arguments) { if (!String.IsNullOrEmpty(arguments.SymbolCachePath)) { SymbolCache.Path = arguments.SymbolCachePath; } if (!File.Exists(arguments.BinaryPath)) { Console.WriteLine("Error: Unable to find \"{0}\". Stopping.", arguments.BinaryPath); return(ExitCodes.BinaryNotFound); } // Get Hash of Binary RsDsSignature signature = Assembly.ReadRsDsSignature(arguments.BinaryPath); if (signature == null) { Console.WriteLine("Unable to read binary signature. It may not be a managed binary."); return(ExitCodes.BinarySignatureNotFound); } Console.WriteLine("Signature: {0}", signature); // File Structure Map: // C:\SymbolCache\Elfie.pdb => All known Elfie.pdb copies // \671497fb11a04a8f9fc2c64bd82b4a201\Elfie.pdb => All content related to Elfie.dll with debug signature 671...201 // Elfie.pdb => Elfie.pdb matching Elfie.dll with debug signature 671...201 // FilePaths.map => Tab delimited file with source file path in PDB, download URL, cached path under \SymbolCache\Elfie.pdb // \src\fc2c64bd\Program.cs => Source Code 'Program.cs' with remote URL hash fc2c64bd string pdbFileName = Path.ChangeExtension(Path.GetFileName(arguments.BinaryPath), ".pdb"); string pdbNameDirectory = Path.Combine(Environment.ExpandEnvironmentVariables(SymbolCache.Path), pdbFileName); string pdbCacheDirectory = Path.Combine(pdbNameDirectory, signature.ToString()); string pdbPath = Path.Combine(pdbCacheDirectory, pdbFileName); string sourceCacheDirectory = Path.Combine(pdbNameDirectory, "src"); if (File.Exists(pdbPath)) { Console.WriteLine("PDB: {0}", pdbPath); } else if (File.Exists(Path.ChangeExtension(arguments.BinaryPath, ".pdb"))) { pdbPath = Path.GetFullPath(Path.ChangeExtension(arguments.BinaryPath, ".pdb")); Console.WriteLine("PDB: {0}", pdbPath); } else if (Directory.Exists(pdbCacheDirectory) && !arguments.Force) { Console.WriteLine("PDB download previously failed. Stopping. Use '-f' to force retry."); return(ExitCodes.SymbolsNotFoundAtAnySymbolServer); } else { // Get symbols, if we haven't previously tried DownloadSymbols(arguments, pdbPath); if (!File.Exists(pdbPath)) { // TODO: Ping the symbol servers; don't write the "don't try again" if we couldn't reach the server at all // Create a stub indicating we tried but could not download the PDB if (!String.IsNullOrEmpty(pdbCacheDirectory)) { Directory.CreateDirectory(pdbCacheDirectory); } Console.WriteLine("No configured symbol server had symbols. Stopping. Use '-f' to force retry."); return(ExitCodes.SymbolsNotFoundAtAnySymbolServer); } } // Extract or reload the PDB path to source URL map SourceFileMap map = SourceFileMap.BuildOrLoad(pdbPath); // Write map next to binary as well as PDB [so either can be indexed safely] map.Save(Path.ChangeExtension(arguments.BinaryPath, ".map")); if (map.Files.Count == 0) { Console.WriteLine("No Source File URLs found in PDB. It may not be source server registered."); return(ExitCodes.SourceUrlsNotFoundInPdb); } else { Console.WriteLine("PDB references {0:n0} source file URLs.", map.Files.Count); } // Download source files not already downloaded (or failed) bool allFilesDownloaded = DownloadSourceFiles(map, sourceCacheDirectory, arguments.Force).Result; return(allFilesDownloaded ? ExitCodes.Success : ExitCodes.FailedDownloadingSomeSourceFiles); }
public string RenderCoverageReport(SourceFileMap sourceFileMap) { return(_viewRender.Render("CoveragePage", sourceFileMap)); }