/// <summary> /// Load native modules (i.e. DAC, DBI) from the runtime build id. /// </summary> /// <param name="callback">called back for each symbol file loaded</param> /// <param name="parameter">callback parameter</param> /// <param name="config">Target configuration: Windows, Linux or OSX</param> /// <param name="moduleFilePath">module path</param> /// <param name="specialKeys">if true, returns the DBI/DAC keys, otherwise the identity key</param> /// <param name="moduleIndexSize">build id size</param> /// <param name="moduleIndex">pointer to build id</param> private void LoadNativeSymbolsFromIndex( IntPtr self, SymbolFileCallback callback, IntPtr parameter, RuntimeConfiguration config, string moduleFilePath, bool specialKeys, int moduleIndexSize, IntPtr moduleIndex) { if (_symbolService.IsSymbolStoreEnabled) { try { KeyTypeFlags flags = specialKeys ? KeyTypeFlags.DacDbiKeys : KeyTypeFlags.IdentityKey; byte[] id = new byte[moduleIndexSize]; Marshal.Copy(moduleIndex, id, 0, moduleIndexSize); IEnumerable <SymbolStoreKey> keys = null; switch (config) { case RuntimeConfiguration.UnixCore: keys = ELFFileKeyGenerator.GetKeys(flags, moduleFilePath, id, symbolFile: false, symbolFileName: null); break; case RuntimeConfiguration.OSXCore: keys = MachOFileKeyGenerator.GetKeys(flags, moduleFilePath, id, symbolFile: false, symbolFileName: null); break; case RuntimeConfiguration.WindowsCore: case RuntimeConfiguration.WindowsDesktop: uint timeStamp = BitConverter.ToUInt32(id, 0); uint fileSize = BitConverter.ToUInt32(id, 4); SymbolStoreKey key = PEFileKeyGenerator.GetKey(moduleFilePath, timeStamp, fileSize); keys = new SymbolStoreKey[] { key }; break; default: Trace.TraceError("LoadNativeSymbolsFromIndex: unsupported platform {0}", config); return; } foreach (SymbolStoreKey key in keys) { string moduleFileName = Path.GetFileName(key.FullPathName); Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index); string downloadFilePath = _symbolService.DownloadFile(key); if (downloadFilePath != null) { Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath); callback(parameter, moduleFileName, downloadFilePath); } } } catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException || ex is TaskCanceledException) { Trace.TraceError("{0} - {1}", ex.Message, moduleFilePath); } } }
/// <summary> /// Creates a key generator for the runtime module pointed to by the address/size. /// </summary> /// <param name="memoryService">memory service instance</param> /// <param name="config">Target configuration: Windows, Linux or OSX</param> /// <param name="moduleFilePath">module path</param> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <returns>KeyGenerator or null if error</returns> public static KeyGenerator GetKeyGenerator(this IMemoryService memoryService, OSPlatform config, string moduleFilePath, ulong address, ulong size) { Stream stream = memoryService.CreateMemoryStream(address, size); KeyGenerator generator = null; if (config == OSPlatform.Linux) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath); } else if (config == OSPlatform.OSX) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath); } else if (config == OSPlatform.Windows) { var peFile = new PEFile(new StreamAddressSpace(stream), true); generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath); } else { Trace.TraceError("GetKeyGenerator: unsupported platform {0}", config); } return(generator); }
/// <summary> /// Finds or downloads the ELF module and creates a MachOFile instance for it. /// </summary> /// <param name="module">module instance</param> /// <returns>MachO file instance or null</returns> internal MachOFile GetMachOFile(IModule module) { string downloadFilePath = null; MachOFile machoFile = null; if (File.Exists(module.FileName)) { // TODO - Need to verify the build id matches this local file downloadFilePath = module.FileName; } else { if (SymbolService.IsSymbolStoreEnabled) { if (!module.BuildId.IsDefaultOrEmpty) { var key = MachOFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault(); if (key != null) { // Now download the module from the symbol server downloadFilePath = SymbolService.DownloadFile(key); } } } } if (!string.IsNullOrEmpty(downloadFilePath)) { Trace.TraceInformation("GetMachOFile: downloaded {0}", downloadFilePath); Stream stream; try { stream = File.OpenRead(downloadFilePath); } catch (Exception ex) when(ex is DirectoryNotFoundException || ex is FileNotFoundException || ex is UnauthorizedAccessException || ex is IOException) { Trace.TraceError($"GetMachOFile: OpenRead exception {ex.Message}"); return(null); } try { machoFile = new MachOFile(new StreamAddressSpace(stream), position: 0, dataSourceIsVirtualAddressSpace: false); if (!machoFile.IsValid()) { return(null); } } catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException) { Trace.TraceError($"GetMachOFile: exception {ex.Message}"); return(null); } } return(machoFile); }
/// <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); } } }
/// <summary> /// Finds or downloads the MachO module. /// </summary> /// <param name="module">module instance</param> /// <param name="flags"></param> /// <returns>module path or null</returns> private string DownloadMachO(IModule module, KeyTypeFlags flags) { if ((flags & (KeyTypeFlags.IdentityKey | KeyTypeFlags.SymbolKey)) == 0) { throw new ArgumentException($"Key flag not supported {flags}"); } if (module.BuildId.IsDefaultOrEmpty) { Trace.TraceWarning($"DownloadMachO: module {module.FileName} has no build id"); return(null); } SymbolStoreKey fileKey = MachOFileKeyGenerator.GetKeys(flags, module.FileName, module.BuildId.ToArray(), symbolFile: false, module.GetSymbolFileName()).SingleOrDefault(); if (fileKey is null) { Trace.TraceWarning($"DownloadMachO: no index generated for module {module.FileName} "); return(null); } // Check if the file is local and the key matches the module string fileName = fileKey.FullPathName; if (File.Exists(fileName)) { using MachOModule machOModule = MachOModule.OpenFile(fileName); if (machOModule is not null) { var generator = new MachOFileKeyGenerator(Tracer.Instance, machOModule, fileName); IEnumerable <SymbolStoreKey> keys = generator.GetKeys(flags); foreach (SymbolStoreKey key in keys) { if (fileKey.Equals(key)) { Trace.TraceInformation("DownloadMachO: local file match {0}", 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("DownloadMachO: downloaded {0}", downloadFilePath); return(downloadFilePath); } return(null); }
/// <summary> /// Finds or downloads the ELF module and creates a MachOFile instance for it. /// </summary> /// <param name="module">module instance</param> /// <returns>MachO file instance or null</returns> internal MachOFile GetMachOFile(IModule module) { if (module.BuildId.IsDefaultOrEmpty) { Trace.TraceWarning($"GetMachOFile: module {module.FileName} has no build id"); return(null); } SymbolStoreKey moduleKey = MachOFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault(); if (moduleKey is null) { Trace.TraceWarning($"GetMachOFile: no index generated for module {module.FileName} "); return(null); } if (File.Exists(module.FileName)) { MachOFile machOFile = OpenMachOFile(module.FileName); if (machOFile is not null) { var generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, module.FileName); IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey); foreach (SymbolStoreKey key in keys) { if (moduleKey.Equals(key)) { Trace.TraceInformation("GetMachOFile: local file match {0}", module.FileName); return(machOFile); } } } } // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key string downloadFilePath = SymbolService.DownloadFile(moduleKey); if (!string.IsNullOrEmpty(downloadFilePath)) { Trace.TraceInformation("GetMachOFile: downloaded {0}", downloadFilePath); return(OpenMachOFile(downloadFilePath)); } return(null); }
private string DownloadModule(string moduleName, byte[] buildId) { Assert.True(buildId.Length > 0); SymbolStoreKey key = null; OSPlatform platform; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // This is the cross-DAC case when OpenVirtualProcess calls on a Linux/MacOS dump. Should never // get here for a Windows dump or for live sessions (RegisterForRuntimeStartup, etc). platform = _targetOS; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { platform = OSPlatform.Linux; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { platform = OSPlatform.OSX; } else { throw new NotSupportedException($"OS not supported {RuntimeInformation.OSDescription}"); } if (platform == OSPlatform.Linux) { key = ELFFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, moduleName, buildId, symbolFile: false, symbolFileName: null).SingleOrDefault(); } else if (platform == OSPlatform.OSX) { key = MachOFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, moduleName, buildId, symbolFile: false, symbolFileName: null).SingleOrDefault(); } Assert.NotNull(key); string downloadedPath = SymbolService.DownloadFile(key); Assert.NotNull(downloadedPath); return(downloadedPath); }
/// <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); } } }
/// <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="config">Target configuration: Windows, Linux or OSX</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> private void LoadNativeSymbols( IntPtr self, SymbolFileCallback callback, IntPtr parameter, RuntimeConfiguration config, string moduleFilePath, ulong address, uint size) { if (_symbolService.IsSymbolStoreEnabled) { try { Stream stream = MemoryService.CreateMemoryStream(address, size); KeyGenerator generator = null; if (config == RuntimeConfiguration.UnixCore) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath); } else if (config == RuntimeConfiguration.OSXCore) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath); } else if (config == RuntimeConfiguration.WindowsCore || config == RuntimeConfiguration.WindowsDesktop) { var peFile = new PEFile(new StreamAddressSpace(stream), true); generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath); } else { Trace.TraceError("LoadNativeSymbols: unsupported config {0}", config); } if (generator != null) { IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.SymbolKey | KeyTypeFlags.DacDbiKeys); foreach (SymbolStoreKey key in keys) { string moduleFileName = Path.GetFileName(key.FullPathName); Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index); string downloadFilePath = _symbolService.DownloadFile(key); if (downloadFilePath != null) { Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath); callback(parameter, moduleFileName, downloadFilePath); } } } } catch (Exception ex) when (ex is DiagnosticsException || ex is BadInputFormatException || ex is InvalidVirtualAddressException || ex is ArgumentOutOfRangeException || ex is IndexOutOfRangeException || ex is TaskCanceledException) { Trace.TraceError("{0} address {1:X16}: {2}", moduleFilePath, address, ex.Message); } } }
private string DownloadFile(string fileName) { OSPlatform platform = _target.OperatingSystem; string filePath = null; if (SymbolService.IsSymbolStoreEnabled) { SymbolStoreKey key = null; if (platform == OSPlatform.Windows) { // It is the coreclr.dll's id (timestamp/filesize) in the DacInfo used to download the the dac module. if (_clrInfo.DacInfo.IndexTimeStamp != 0 && _clrInfo.DacInfo.IndexFileSize != 0) { key = PEFileKeyGenerator.GetKey(fileName, (uint)_clrInfo.DacInfo.IndexTimeStamp, (uint)_clrInfo.DacInfo.IndexFileSize); } else { Trace.TraceError($"DownloadFile: {fileName}: key not generated - no index timestamp/filesize"); } } else { // Use the runtime's build id to download the the dac module. if (!_clrInfo.DacInfo.ClrBuildId.IsDefaultOrEmpty) { byte[] buildId = _clrInfo.DacInfo.ClrBuildId.ToArray(); IEnumerable <SymbolStoreKey> keys = null; if (platform == OSPlatform.Linux) { keys = ELFFileKeyGenerator.GetKeys(KeyTypeFlags.DacDbiKeys, "libcoreclr.so", buildId, symbolFile: false, symbolFileName: null); } else if (platform == OSPlatform.OSX) { keys = MachOFileKeyGenerator.GetKeys(KeyTypeFlags.DacDbiKeys, "libcoreclr.dylib", buildId, symbolFile: false, symbolFileName: null); } else { Trace.TraceError($"DownloadFile: {fileName}: platform not supported - {platform}"); } key = keys?.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == fileName); } else { Trace.TraceError($"DownloadFile: {fileName}: key not generated - no index time stamp or file size"); } } if (key is not null) { // Now download the DAC module from the symbol server filePath = SymbolService.DownloadFile(key); } } else { Trace.TraceInformation($"DownLoadFile: {fileName}: symbol store not enabled"); } return(filePath); }