public async Task CacheSymbolStore() { using (Stream pdb = File.OpenRead("TestBinaries/HelloWorld.pdb")) { // Clean up any previous cache directories string cacheDirectory = "TestSymbolCache"; try { Directory.Delete(cacheDirectory, recursive: true); } catch (DirectoryNotFoundException) { } var inputFile = new SymbolStoreFile(pdb, "HelloWorld.pdb"); var generator = new PDBFileKeyGenerator(_tracer, inputFile); IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey); Assert.True(keys.Count() == 1); SymbolStoreKey key = keys.First(); var backingStore = new TestSymbolStore(_tracer, key, inputFile); var cacheSymbolStore = new CacheSymbolStore(_tracer, backingStore, cacheDirectory); // This should put HelloWorld.pdb into the cache SymbolStoreFile outputFile = await cacheSymbolStore.GetFile(key, CancellationToken.None); Assert.True(outputFile != null); // Should be the exact same instance given to TestSymbolStore Assert.True(inputFile == outputFile); // This should get it from the cache and not the backingStore backingStore.Dispose(); outputFile = await cacheSymbolStore.GetFile(key, CancellationToken.None); Assert.True(outputFile != null); // Should NOT be the exact same SymbolStoreFile instance given to TestSymbolStore Assert.True(inputFile != outputFile); // Now make sure the output file from the cache is the same as the pdb we opened above CompareStreams(pdb, outputFile.Stream); } }
/// <summary> /// Finds or downloads the PE module /// </summary> /// <param name="module">module instance</param> /// <param name="flags"></param> /// <returns>module path or null</returns> private string DownloadPE(IModule module, KeyTypeFlags flags) { SymbolStoreKey fileKey = null; string fileName = null; if ((flags & KeyTypeFlags.IdentityKey) != 0) { if (!module.IndexTimeStamp.HasValue || !module.IndexFileSize.HasValue) { return(null); } fileName = module.FileName; fileKey = PEFileKeyGenerator.GetKey(Path.GetFileName(fileName), module.IndexTimeStamp.Value, module.IndexFileSize.Value); if (fileKey is null) { Trace.TraceWarning($"DownLoadPE: no key generated for module {fileName} "); return(null); } } else if ((flags & KeyTypeFlags.SymbolKey) != 0) { IEnumerable <PdbFileInfo> pdbInfos = module.GetPdbFileInfos(); if (!pdbInfos.Any()) { return(null); } foreach (PdbFileInfo pdbInfo in pdbInfos) { if (pdbInfo.IsPortable) { fileKey = PortablePDBFileKeyGenerator.GetKey(pdbInfo.Path, pdbInfo.Guid); if (fileKey is not null) { fileName = pdbInfo.Path; break; } } } if (fileKey is null) { foreach (PdbFileInfo pdbInfo in pdbInfos) { if (!pdbInfo.IsPortable) { fileKey = PDBFileKeyGenerator.GetKey(pdbInfo.Path, pdbInfo.Guid, pdbInfo.Revision); if (fileKey is not null) { fileName = pdbInfo.Path; break; } } } } if (fileKey is null) { Trace.TraceWarning($"DownLoadPE: no key generated for module PDB {module.FileName} "); return(null); } } else { throw new ArgumentException($"Key flag not supported {flags}"); } // Check if the file is local and the key matches the module if (File.Exists(fileName)) { using Stream stream = Utilities.TryOpenFile(fileName); if (stream is not null) { var peFile = new PEFile(new StreamAddressSpace(stream), false); var generator = new PEFileKeyGenerator(Tracer.Instance, peFile, fileName); foreach (SymbolStoreKey key in generator.GetKeys(flags)) { if (fileKey.Equals(key)) { Trace.TraceInformation($"DownloadPE: local file match {fileName}"); return(fileName); } } } } // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key string downloadFilePath = DownloadFile(fileKey); if (!string.IsNullOrEmpty(downloadFilePath)) { Trace.TraceInformation("DownloadPE: downloaded {0}", downloadFilePath); return(downloadFilePath); } return(null); }