internal async Task DownloadFiles() { using (SymbolStore symbolStore = BuildSymbolStore()) { bool verifyPackages = Packages && OutputDirectory == null; KeyTypeFlags flags = KeyTypeFlags.None; if (Symbols) { flags |= KeyTypeFlags.SymbolKey; } if (Modules) { flags |= KeyTypeFlags.IdentityKey; } if (Debugging) { flags |= KeyTypeFlags.ClrKeys; } if (flags == KeyTypeFlags.None) { if (verifyPackages) { // If we are verifing symbol packages then only check the identity and clr keys. flags = KeyTypeFlags.IdentityKey | KeyTypeFlags.ClrKeys; } else { // The default is to download everything flags = KeyTypeFlags.IdentityKey | KeyTypeFlags.SymbolKey | KeyTypeFlags.ClrKeys; } } if (ForceWindowsPdbs) { flags |= KeyTypeFlags.ForceWindowsPdbs; } foreach (SymbolStoreKeyWrapper wrapper in GetKeys(flags).Distinct()) { SymbolStoreKey key = wrapper.Key; Tracer.Information("Key: {0} - {1}{2}", key.Index, key.FullPathName, key.IsClrSpecialFile ? "*" : ""); if (symbolStore != null) { using (SymbolStoreFile symbolFile = await symbolStore.GetFile(key, CancellationToken.None)) { if (symbolFile != null) { await WriteFile(symbolFile, wrapper); } // If there is no output directory verify the file exists in the symbol store if (OutputDirectory == null) { Tracer.WriteLine("Key {0}found {1} - {2}", symbolFile != null ? "" : "NOT ", key.Index, key.FullPathName); } } } } } }
/// <summary> /// Load native symbols and modules (i.e. dac, dbi). /// </summary> /// <param name="callback">called back for each symbol file loaded</param> /// <param name="parameter">callback parameter</param> /// <param name="tempDirectory">temp directory unique to this instance of SOS</param> /// <param name="moduleFilePath">module path</param> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <param name="readMemory">read memory callback delegate</param> public static void LoadNativeSymbols(SymbolFileCallback callback, IntPtr parameter, string tempDirectory, string moduleFilePath, ulong address, int size, ReadMemoryDelegate readMemory) { if (IsSymbolStoreEnabled()) { Debug.Assert(s_tracer != null); Stream stream = new TargetStream(address, size, readMemory); KeyTypeFlags flags = KeyTypeFlags.SymbolKey | KeyTypeFlags.ClrKeys; KeyGenerator generator = null; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); generator = new ELFFileKeyGenerator(s_tracer, elfFile, moduleFilePath); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); generator = new MachOFileKeyGenerator(s_tracer, machOFile, moduleFilePath); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var peFile = new PEFile(new StreamAddressSpace(stream), true); generator = new PEFileKeyGenerator(s_tracer, peFile, moduleFilePath); } else { return; } try { IEnumerable <SymbolStoreKey> keys = generator.GetKeys(flags); foreach (SymbolStoreKey key in keys) { string moduleFileName = Path.GetFileName(key.FullPathName); s_tracer.Verbose("{0} {1}", key.FullPathName, key.Index); // Don't download the sos binaries that come with the runtime if (moduleFileName != "SOS.NETCore.dll" && !moduleFileName.StartsWith("libsos.")) { string downloadFilePath = GetSymbolFile(key, tempDirectory); if (downloadFilePath != null) { s_tracer.Information("{0}: {1}", moduleFileName, downloadFilePath); callback(parameter, moduleFileName, downloadFilePath); } } } } catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException) { s_tracer.Error("{0}/{1:X16}: {2}", moduleFilePath, address, ex.Message); } } }
private async Task ScanFileAsync([NotNull] string sourceDir, [NotNull] string sourceFile, [NotNull] ITracer tracer) { var srcFile = Path.GetRelativePath(sourceDir, sourceFile); tracer.Information($" Scanning {srcFile}..."); foreach (var key in GetKeyInfos(tracer, sourceFile)) { var index = key.Item1.Index; if (!SymbolStoreKey.IsKeyValid(index)) { tracer.Error($"Invalid key index in file {index}"); } else if (key.Item2 == KeyType.Elf && Path.GetExtension(sourceFile) == ".debug" && !index.EndsWith("/_.debug")) { // Bug: Check that ELF .debug was processed right way! See https://github.com/dotnet/symstore/issues/158 tracer.Error($"ELF file {sourceFile} was processed incorrectly because Microsoft.SymbolStore doesn't support .debug extension"); } else { var dstFile = index.NormalizeSystem(); if ( myCompressWPdb && key.Item2 == KeyType.WPdb || myCompressPe && key.Item2 == KeyType.Pe) { await myProcessCompressed(sourceDir, srcFile, Path.ChangeExtension(dstFile, PathUtil.GetPackedExtension(Path.GetExtension(dstFile)))); if (myIsKeepNonCompressed) { await myProcessNormal(sourceDir, srcFile, dstFile); } } else { await myProcessNormal(sourceDir, srcFile, dstFile); } } } }
/// <summary> /// Load native symbols and modules (i.e. dac, dbi). /// </summary> /// <param name="callback">called back for each symbol file loaded</param> /// <param name="parameter">callback parameter</param> /// <param name="moduleDirectory">module path</param> /// <param name="moduleFileName">module file name</param> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <param name="readMemory">read memory callback delegate</param> internal static void LoadNativeSymbols(SymbolFileCallback callback, IntPtr parameter, string tempDirectory, string moduleDirectory, string moduleFileName, ulong address, int size, ReadMemoryDelegate readMemory) { if (s_symbolStore != null) { Debug.Assert(s_tracer != null); string path = Path.Combine(moduleDirectory, moduleFileName); Stream stream = new TargetStream(address, size, readMemory); KeyTypeFlags flags = KeyTypeFlags.SymbolKey | KeyTypeFlags.ClrKeys; KeyGenerator generator = null; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); generator = new ELFFileKeyGenerator(s_tracer, elfFile, path); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); generator = new MachOFileKeyGenerator(s_tracer, machOFile, path); } else { return; } try { IEnumerable <SymbolStoreKey> keys = generator.GetKeys(flags); foreach (SymbolStoreKey key in keys) { string symbolFileName = Path.GetFileName(key.FullPathName); s_tracer.Verbose("{0} {1}", key.FullPathName, key.Index); // Don't download the sos binaries that come with the runtime if (symbolFileName != "SOS.NETCore.dll" && !symbolFileName.StartsWith("libsos.")) { using (SymbolStoreFile file = GetSymbolStoreFile(key)) { if (file != null) { try { string downloadFileName = file.FileName; // If the downloaded doesn't already exists on disk in the cache, then write it to a temporary location. if (!File.Exists(downloadFileName)) { downloadFileName = Path.Combine(tempDirectory, symbolFileName); using (Stream destinationStream = File.OpenWrite(downloadFileName)) { file.Stream.CopyTo(destinationStream); } s_tracer.WriteLine("Downloaded symbol file {0}", key.FullPathName); } s_tracer.Information("{0}: {1}", symbolFileName, downloadFileName); callback(parameter, symbolFileName, downloadFileName); } catch (Exception ex) when(ex is UnauthorizedAccessException || ex is DirectoryNotFoundException) { s_tracer.Error("{0}", ex.Message); } } } } } } catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException) { s_tracer.Error("Exception: {0}/{1}: {2:X16}", moduleDirectory, moduleFileName, address); } } }
internal static void Validate(ITracer tracer, Stream pdbStream, IEnumerable <PdbChecksum> pdbChecksums) { uint offset = 0; byte[] bytes = new byte[pdbStream.Length]; byte[] pdbId = new byte[pdbIdSize]; if (pdbStream.Read(bytes, offset: 0, count: bytes.Length) != bytes.Length) { throw new InvalidChecksumException("Unexpected stream length"); } try { offset = GetPdbStreamOffset(pdbStream); } catch (Exception ex) { tracer.Error(ex.Message); throw; } // Make a copy of the pdb Id Array.Copy(bytes, offset, pdbId, 0, pdbIdSize); // Zero out the pdb Id for (int i = 0; i <= pdbIdSize; i++) { bytes[i + offset] = 0; } bool algorithmNameKnown = false; foreach (var checksum in pdbChecksums) { tracer.Information($"Testing checksum: {checksum}"); var algorithm = HashAlgorithm.Create(checksum.AlgorithmName); if (algorithm != null) { algorithmNameKnown = true; var hash = algorithm.ComputeHash(bytes); if (hash.SequenceEqual(checksum.Checksum)) { // If any of the checksums are OK, we're good tracer.Information($"Found checksum match {checksum}"); // Restore the pdb Id Array.Copy(pdbId, 0, bytes, offset, pdbIdSize); // Restore the steam position pdbStream.Seek(0, SeekOrigin.Begin); return; } } } if (!algorithmNameKnown) { var algorithmNames = string.Join(" ", pdbChecksums.Select(c => c.AlgorithmName)); throw new InvalidChecksumException($"Unknown hash algorithm: {algorithmNames}"); } throw new InvalidChecksumException("PDB checksum mismatch"); }