private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) { OpenedReader result = null; MetadataReaderProvider provider = null; try { CodeViewDebugDirectoryData data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); string pdbPath = data.Path; Stream pdbStream = null; if (assemblyPath != null) { try { pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return(null); } pdbStream = TryOpenFile(pdbPath); } if (pdbStream == null) { if (s_symbolStore == null) { return(null); } Debug.Assert(codeViewEntry.MinorVersion == ImageDebugDirectory.PortablePDBMinorVersion); SymbolStoreKey key = PortablePDBFileKeyGenerator.GetKey(pdbPath, data.Guid); pdbStream = GetSymbolStoreFile(key)?.Stream; } provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); MetadataReader reader = provider.GetMetadataReader(); // Validate that the PDB matches the assembly version if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) { result = new OpenedReader(provider, reader); } } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
public async Task DirectorySymbolStore() { using (Stream pdb = File.OpenRead("TestBinaries/dir1/System.Threading.Thread.pdb")) { var inputFile = new SymbolStoreFile(pdb, "System.Threading.Thread.pdb"); var generator = new PortablePDBFileKeyGenerator(_tracer, inputFile); IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey); Assert.True(keys.Count() == 1); SymbolStoreKey key = keys.First(); var dir1store = new DirectorySymbolStore(_tracer, null, "TestBinaries/dir1"); var dir2store = new DirectorySymbolStore(_tracer, dir1store, "TestBinaries/dir2"); SymbolStoreFile outputFile = await dir2store.GetFile(key, CancellationToken.None); Assert.True(outputFile != null); // Should NOT be the exact same SymbolStoreFile instance Assert.True(inputFile != outputFile); 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); }