From: Mike McLaughlin Date: Thu, 12 Sep 2019 07:34:56 +0000 (-0700) Subject: Fix dumpmd/ip2md commands for < 3.x runtimes (#462) X-Git-Tag: submit/tizen/20191015.063341~10^2~1^2~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b5f90f7cad144e2d58e587f3e0f63614693f23cb;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Fix dumpmd/ip2md commands for < 3.x runtimes (#462) Fix dumpmd/ip2md commands for < 3.x runtimes Implement GetEEVersion for xplat using the embedded "@(#)Version" string. Enabled/add the "eeversion" command for xplat. Added LLDBService2::GetModuleVersion to get the version string via the "sccid" symbol. Fallback to using search the data sections to the version string. Added same to SOSHost so eeversion works in dotnet-dump. Fixed initializing g_moduleInfo for Linux. It is used by dumpmt. Added new LLDBService2::GetModuleInfo api to do this. Added "dumparray" alias to lldb command aliases. Add testing for the eeversion command. Fixed desktop SOS tests. The recent change adding the MAJOR_RUNTIME_VERSION_X SOS runner define silently broke the "desktop" SOS. Made the SOS runner more robust to these silent failures. --- diff --git a/eng/Versions.props b/eng/Versions.props index 0efd7a0b4..6ac5419fe 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -23,7 +23,7 @@ 1.0.41901 - 1.1.37504 + 1.1.46104 1.7.0 2.0.44 0.2.0-alpha.19254.1 diff --git a/eng/build.yml b/eng/build.yml index 1800afc72..42c03e97f 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -130,7 +130,7 @@ phases: inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/$(_PublishArtifacts)' artifactName: $(_PhaseName)_$(_BuildArch)_$(_BuildConfig) - condition: and(succeeded(), ne(variables['_PublishArtifacts'], '')) + condition: ne(variables['_PublishArtifacts'], '') - task: CopyFiles@2 displayName: Gather Build Logs diff --git a/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs b/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs index 98c16a333..001028d36 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs @@ -480,6 +480,7 @@ namespace Microsoft.Diagnostics.TestHelpers /// /// The major portion of the runtime framework version /// + /// the RuntimeFrameworkVersion property doesn't exist public int RuntimeFrameworkVersionMajor { get { diff --git a/src/SOS/SOS.Hosting/LLDBServices.cs b/src/SOS/SOS.Hosting/LLDBServices.cs index 8f5425bdf..554b43b3f 100644 --- a/src/SOS/SOS.Hosting/LLDBServices.cs +++ b/src/SOS/SOS.Hosting/LLDBServices.cs @@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Runtime.Utilities; using System; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -79,6 +80,8 @@ namespace SOS builder = AddInterface(IID_ILLDBServices2, validate: false); builder.AddMethod(new LoadNativeSymbolsDelegate2(LoadNativeSymbols2)); builder.AddMethod(new AddModuleSymbolDelegate(AddModuleSymbol)); + builder.AddMethod(new GetModuleInfoDelegate(GetModuleInfo)); + builder.AddMethod(new GetModuleVersionInformationDelegate(soshost.GetModuleVersionInformation)); builder.Complete(); AddRef(); @@ -194,6 +197,28 @@ namespace SOS return S_OK; } + unsafe int GetModuleInfo( + IntPtr self, + uint index, + ulong *moduleBase, + ulong *moduleSize) + { + try + { + ModuleInfo module = _soshost.DataReader.EnumerateModules().ElementAt((int)index); + if (module == null) { + return E_FAIL; + } + SOSHost.Write(moduleBase, module.ImageBase); + SOSHost.Write(moduleSize, module.FileSize); + } + catch (ArgumentOutOfRangeException) + { + return E_FAIL; + } + return S_OK; + } + #endregion #region ILLDBServices delegates @@ -462,21 +487,38 @@ namespace SOS /// public delegate void ModuleLoadCallback( IntPtr parameter, - [MarshalAs(UnmanagedType.LPStr)] string moduleFilePath, - ulong moduleAddress, - int moduleSize); + [In, MarshalAs(UnmanagedType.LPStr)] string moduleFilePath, + [In] ulong moduleAddress, + [In] int moduleSize); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int LoadNativeSymbolsDelegate2( IntPtr self, - bool runtimeOnly, - ModuleLoadCallback callback); + [In] bool runtimeOnly, + [In] ModuleLoadCallback callback); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int AddModuleSymbolDelegate( IntPtr self, - IntPtr parameter, - [MarshalAs(UnmanagedType.LPStr)] string symbolFilename); + [In] IntPtr parameter, + [In, MarshalAs(UnmanagedType.LPStr)] string symbolFilename); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private unsafe delegate int GetModuleInfoDelegate( + IntPtr self, + [In] uint index, + [Out] ulong *moduleBase, + [Out] ulong *moduleSize); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + private delegate int GetModuleVersionInformationDelegate( + IntPtr self, + [In] uint Index, + [In] ulong Base, + [In][MarshalAs(UnmanagedType.LPStr)] string Item, + [Out] byte* Buffer, + [In] uint BufferSize, + [Out] uint* VerInfoSize); #endregion } diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs index e19e4e69b..e0a7c5a25 100644 --- a/src/SOS/SOS.Hosting/SOSHost.cs +++ b/src/SOS/SOS.Hosting/SOSHost.cs @@ -164,6 +164,7 @@ namespace SOS private readonly IConsoleService _console; private readonly COMCallableIUnknown _ccw; private readonly IntPtr _interface; + private readonly ReadVirtualCache _versionCache; private IntPtr _sosLibrary = IntPtr.Zero; private Dictionary _pathToPeReader = new Dictionary(); @@ -202,6 +203,7 @@ namespace SOS _console = serviceProvider.GetService(); _analyzeContext = serviceProvider.GetService(); _registerService = serviceProvider.GetService(); + _versionCache = new ReadVirtualCache(this); string rid = InstallHelper.GetRid(); SOSPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), rid); @@ -593,7 +595,7 @@ namespace SOS uint* nameSize, ulong* displacement) { - nameBuffer.Clear(); + nameBuffer?.Clear(); Write(nameSize); Write(displacement); return E_NOTIMPL; @@ -689,17 +691,13 @@ namespace SOS uint i = 0; foreach (ModuleInfo module in DataReader.EnumerateModules()) { - if (index != uint.MaxValue && i == index || index == uint.MaxValue && baseAddress == module.ImageBase) + if ((index != uint.MaxValue && i == index) || (index == uint.MaxValue && baseAddress == module.ImageBase)) { - if (imageNameBuffer != null) { - imageNameBuffer.Append(module.FileName); - } + imageNameBuffer?.Append(module.FileName); Write(imageNameSize, (uint)module.FileName.Length + 1); string moduleName = GetModuleName(module); - if (moduleNameBuffer != null) { - moduleNameBuffer.Append(moduleName); - } + moduleNameBuffer?.Append(moduleName); Write(moduleNameSize, (uint)moduleName.Length + 1); return S_OK; } @@ -747,6 +745,158 @@ namespace SOS return S_OK; } + internal unsafe int GetModuleVersionInformation( + IntPtr self, + uint index, + ulong baseAddress, + [MarshalAs(UnmanagedType.LPStr)] string item, + byte* buffer, + uint bufferSize, + uint* verInfoSize) + { + Debug.Assert(buffer != null); + Debug.Assert(verInfoSize == null); + + uint i = 0; + foreach (ModuleInfo module in DataReader.EnumerateModules()) + { + if ((index != uint.MaxValue && i == index) || (index == uint.MaxValue && baseAddress == module.ImageBase)) + { + if (item == "\\") + { + uint versionSize = (uint)Marshal.SizeOf(typeof(VS_FIXEDFILEINFO)); + Write(verInfoSize, versionSize); + if (bufferSize < versionSize) + { + return E_INVALIDARG; + } + VS_FIXEDFILEINFO* fileInfo = (VS_FIXEDFILEINFO*)buffer; + fileInfo->dwSignature = 0; + fileInfo->dwStrucVersion = 0; + fileInfo->dwFileFlagsMask = 0; + fileInfo->dwFileFlags = 0; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + VersionInfo versionInfo = module.Version; + fileInfo->dwFileVersionMS = (uint)versionInfo.Minor | (uint)versionInfo.Major << 16; + fileInfo->dwFileVersionLS = (uint)versionInfo.Patch | (uint)versionInfo.Revision << 16; + return S_OK; + } + else + { + if (SearchVersionString(module, out string versionString)) + { + int spaceIndex = versionString.IndexOf(' '); + if (spaceIndex > 0) + { + if (versionString[spaceIndex - 1] == '.') + { + spaceIndex--; + } + string versionToParse = versionString.Substring(0, spaceIndex); + try + { + Version versionInfo = Version.Parse(versionToParse); + fileInfo->dwFileVersionMS = (uint)versionInfo.Minor | (uint)versionInfo.Major << 16; + fileInfo->dwFileVersionLS = (uint)versionInfo.Revision | (uint)versionInfo.Build << 16; + return S_OK; + } + catch (ArgumentException ex) + { + Trace.TraceError($"GetModuleVersion FAILURE: '{versionToParse}' '{versionString}' {ex.ToString()}"); + } + } + } + break; + } + } + else if (item == "\\StringFileInfo\\040904B0\\FileVersion") + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return E_INVALIDARG; + } + else + { + if (SearchVersionString(module, out string versionString)) + { + byte[] source = Encoding.ASCII.GetBytes(versionString + '\0'); + Marshal.Copy(source, 0, new IntPtr(buffer), Math.Min(source.Length, (int)bufferSize)); + return S_OK; + } + break; + } + } + else + { + return E_INVALIDARG; + } + } + i++; + } + + return E_FAIL; + } + + private static readonly byte[] s_versionString = Encoding.ASCII.GetBytes("@(#)Version "); + private static readonly uint s_versionLength = (uint)s_versionString.Length; + + private bool SearchVersionString(ModuleInfo moduleInfo, out string fileVersion) + { + byte[] buffer = new byte[s_versionString.Length]; + ulong address = moduleInfo.ImageBase; + uint size = moduleInfo.FileSize; + + _versionCache.Clear(); + + while (size > 0) { + bool result = _versionCache.Read(address, buffer, s_versionString.Length, out int cbBytesRead); + if (result && cbBytesRead >= s_versionLength) + { + if (s_versionString.SequenceEqual(buffer)) + { + address += s_versionLength; + size -= s_versionLength; + + var sb = new StringBuilder(); + byte[] ch = new byte[1]; + while (true) + { + // Now read the version string a char/byte at a time + result = _versionCache.Read(address, ch, ch.Length, out cbBytesRead); + + // Return not found if there are any failures or problems while reading the version string. + if (!result || cbBytesRead < ch.Length || size <= 0) { + break; + } + + // Found the end of the string + if (ch[0] == '\0') { + fileVersion = sb.ToString(); + return true; + } + sb.Append(Encoding.ASCII.GetChars(ch)); + address++; + size--; + } + // Return not found if overflowed the fileVersionBuffer (not finding a null). + break; + } + address++; + size--; + } + else + { + address += s_versionLength; + size -= s_versionLength; + } + } + + fileVersion = null; + return false; + } + internal unsafe int GetLineByOffset( IntPtr self, ulong offset, @@ -1070,4 +1220,57 @@ namespace SOS #endregion } + + class ReadVirtualCache + { + private const int CACHE_SIZE = 4096; + + private readonly SOSHost _soshost; + private readonly byte[] _cache = new byte[CACHE_SIZE]; + private ulong _startCache; + private bool _cacheValid; + private int _cacheSize; + + internal ReadVirtualCache(SOSHost soshost) + { + _soshost = soshost; + Clear(); + } + + internal bool Read(ulong address, byte[] buffer, int bufferSize, out int bytesRead) + { + bytesRead = 0; + + if (bufferSize == 0) { + return true; + } + + if (bufferSize > CACHE_SIZE) + { + // Don't even try with the cache + return _soshost.DataReader.ReadMemory(address, buffer, bufferSize, out bytesRead); + } + + if (!_cacheValid || (address < _startCache) || (address > (_startCache + (ulong)(_cacheSize - bufferSize)))) + { + _cacheValid = false; + _startCache = address; + if (!_soshost.DataReader.ReadMemory(_startCache, _cache, CACHE_SIZE, out int cbBytesRead)) { + return false; + } + _cacheSize = cbBytesRead; + _cacheValid = true; + } + + Array.Copy(_cache, (int)(address - _startCache), buffer, 0, bufferSize); + bytesRead = bufferSize; + return true; + } + + internal void Clear() + { + _cacheValid = false; + _cacheSize = CACHE_SIZE; + } + } } diff --git a/src/SOS/SOS.Hosting/dbgeng/DebugSymbols.cs b/src/SOS/SOS.Hosting/dbgeng/DebugSymbols.cs index 259a160b1..cde29143b 100644 --- a/src/SOS/SOS.Hosting/dbgeng/DebugSymbols.cs +++ b/src/SOS/SOS.Hosting/dbgeng/DebugSymbols.cs @@ -83,7 +83,7 @@ namespace SOS private static void AddDebugSymbols2(VTableBuilder builder, SOSHost soshost) { AddDebugSymbols(builder, soshost); - builder.AddMethod(new GetModuleVersionInformationDelegate((self, index, baseAddress, item, buffer, bufferSize, verInfoSize) => DebugClient.NotImplemented)); + builder.AddMethod(new GetModuleVersionInformationDelegate(soshost.GetModuleVersionInformation)); builder.AddMethod(new GetModuleNameStringDelegate((self, which, index, baseAddress, buffer, bufferSize, nameSize) => DebugClient.NotImplemented)); builder.AddMethod(new GetConstantNameDelegate((self, module, typeId, value, buffer, bufferSize, nameSize) => DebugClient.NotImplemented)); builder.AddMethod(new GetFieldNameDelegate((self, module, typeId, fieldIndex, buffer, bufferSize, nameSize) => DebugClient.NotImplemented)); diff --git a/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs b/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs index 95f223366..6cb8511c7 100644 --- a/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs +++ b/src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs @@ -49,7 +49,7 @@ class GCWhere Debugger.Break(); // GCWhere should temp in Gen2 PrintIt(temp); GC.KeepAlive(temp); - return 100; + return 0; } // This is here because without calling something with the object as an argument it'll get optimized away diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index 614575659..24205b8fe 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -12,6 +12,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Xunit.Abstractions; +using Xunit.Extensions; public class SOSRunner : IDisposable { @@ -158,6 +159,12 @@ public class SOSRunner : IDisposable WithEnvironmentVariable("COMPlus_DbgEnableMiniDump", "1"). WithEnvironmentVariable("COMPlus_DbgMiniDumpName", ReplaceVariables(variables,"%DUMP_NAME%")); + // Exit codes on Windows should always be 0, but not on Linux/OSX for the faulting test apps. + if (OS.Kind == OSKind.Windows) + { + processRunner.WithExpectedExitCode(0); + } + processRunner.Start(); // Wait for the debuggee to finish @@ -377,6 +384,12 @@ public class SOSRunner : IDisposable WithLog(scriptLogger). WithTimeout(TimeSpan.FromMinutes(10)); + // Exit codes on Windows should always be 0, but not on Linux/OSX for the faulting test apps. + if (OS.Kind == OSKind.Windows) + { + processRunner.WithExpectedExitCode(0); + } + // Create the sos runner instance sosRunner = new SOSRunner(debugger, config, outputHelper, variables, scriptLogger, processRunner, options == Options.LoadDump || options == Options.LoadDumpWithDotNetDump); @@ -411,104 +424,111 @@ public class SOSRunner : IDisposable public async Task RunScript(string scriptRelativePath) { - string scriptFile = Path.Combine(_config.ScriptRootDir, scriptRelativePath); - if (!File.Exists(scriptFile)) - { - throw new FileNotFoundException("Script file does not exist: " + scriptFile); - } - HashSet enabledDefines = GetEnabledDefines(); - LogProcessingReproInfo(scriptFile, enabledDefines); - string[] scriptLines = File.ReadAllLines(scriptFile); - Dictionary activeDefines = new Dictionary(); - bool isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); - int i = 0; try { - for (; i < scriptLines.Length; i++) + string scriptFile = Path.Combine(_config.ScriptRootDir, scriptRelativePath); + if (!File.Exists(scriptFile)) { - string line = scriptLines[i].TrimStart(); - if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) - { - continue; - } - else if (line.StartsWith("IFDEF:")) - { - string define = line.Substring("IFDEF:".Length); - activeDefines.Add(define, true); - isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); - } - else if (line.StartsWith("!IFDEF:")) - { - string define = line.Substring("!IFDEF:".Length); - activeDefines.Add(define, false); - isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); - } - else if (line.StartsWith("ENDIF:")) + throw new FileNotFoundException("Script file does not exist: " + scriptFile); + } + HashSet enabledDefines = GetEnabledDefines(); + LogProcessingReproInfo(scriptFile, enabledDefines); + string[] scriptLines = File.ReadAllLines(scriptFile); + Dictionary activeDefines = new Dictionary(); + bool isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); + int i = 0; + try + { + for (; i < scriptLines.Length; i++) { - string define = line.Substring("ENDIF:".Length); - if (!activeDefines.Last().Key.Equals(define)) + string line = scriptLines[i].TrimStart(); + if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) { - throw new Exception("Mismatched IFDEF/ENDIF. IFDEF: " + activeDefines.Last().Key + " ENDIF: " + define); + continue; } - activeDefines.Remove(define); - isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); - } - else if (!isActiveDefineRegionEnabled) - { - WriteLine(" SKIPPING: {0}", line); - continue; - } - else if (line.StartsWith("LOADSOS")) - { - await LoadSosExtension(); - } - else if (line.StartsWith("CONTINUE")) - { - await ContinueExecution(); - } - else if (line.StartsWith("SOSCOMMAND:")) - { - string input = line.Substring("SOSCOMMAND:".Length).TrimStart(); - if (!await RunSosCommand(input)) + else if (line.StartsWith("IFDEF:")) { - throw new Exception($"SOS command FAILED: {input}"); + string define = line.Substring("IFDEF:".Length); + activeDefines.Add(define, true); + isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); } - } - else if (line.StartsWith("COMMAND:")) - { - string input = line.Substring("COMMAND:".Length).TrimStart(); - if (!await RunCommand(input)) + else if (line.StartsWith("!IFDEF:")) { - throw new Exception($"Debugger command FAILED: {input}"); + string define = line.Substring("!IFDEF:".Length); + activeDefines.Add(define, false); + isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); + } + else if (line.StartsWith("ENDIF:")) + { + string define = line.Substring("ENDIF:".Length); + if (!activeDefines.Last().Key.Equals(define)) + { + throw new Exception("Mismatched IFDEF/ENDIF. IFDEF: " + activeDefines.Last().Key + " ENDIF: " + define); + } + activeDefines.Remove(define); + isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines); + } + else if (!isActiveDefineRegionEnabled) + { + WriteLine(" SKIPPING: {0}", line); + continue; + } + else if (line.StartsWith("LOADSOS")) + { + await LoadSosExtension(); + } + else if (line.StartsWith("CONTINUE")) + { + await ContinueExecution(); + } + else if (line.StartsWith("SOSCOMMAND:")) + { + string input = line.Substring("SOSCOMMAND:".Length).TrimStart(); + if (!await RunSosCommand(input)) + { + throw new Exception($"SOS command FAILED: {input}"); + } + } + else if (line.StartsWith("COMMAND:")) + { + string input = line.Substring("COMMAND:".Length).TrimStart(); + if (!await RunCommand(input)) + { + throw new Exception($"Debugger command FAILED: {input}"); + } + } + else if (line.StartsWith("VERIFY:")) + { + string verifyLine = line.Substring("VERIFY:".Length); + VerifyOutput(verifyLine); + } + else + { + continue; } } - else if (line.StartsWith("VERIFY:")) - { - string verifyLine = line.Substring("VERIFY:".Length); - VerifyOutput(verifyLine); - } - else + + if (activeDefines.Count != 0) { - continue; + throw new Exception("Error unbalanced IFDEFs. " + activeDefines.First().Key + " has no ENDIF."); } - } - if (activeDefines.Count != 0) + await QuitDebugger(); + } + catch (Exception) { - throw new Exception("Error unbalanced IFDEFs. " + activeDefines.First().Key + " has no ENDIF."); + WriteLine("SOSRunner error at " + scriptFile + ":" + (i + 1)); + WriteLine("Excerpt from " + scriptFile + ":"); + for (int j = Math.Max(0, i - 2); j < Math.Min(i + 3, scriptLines.Length); j++) + { + WriteLine((j + 1).ToString().PadLeft(5) + " " + scriptLines[j]); + } + throw; } - - await QuitDebugger(); } - catch (Exception e) + catch (Exception ex) { - WriteLine("SOSRunner error at " + scriptFile + ":" + (i + 1)); - WriteLine("Excerpt from " + scriptFile + ":"); - for (int j = Math.Max(0, i - 2); j < Math.Min(i + 3, scriptLines.Length); j++) - { - WriteLine((j + 1).ToString().PadLeft(5) + " " + scriptLines[j]); - } - WriteLine(e.ToString()); + WriteLine(ex.ToString()); throw; } } @@ -863,8 +883,14 @@ public class SOSRunner : IDisposable OS.Kind.ToString().ToUpperInvariant(), _config.TestProduct.ToUpperInvariant(), _config.TargetArchitecture.ToUpperInvariant(), - "MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString() }; + try + { + defines.Add("MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString()); + } + catch (SkipTestException) + { + } if (_isDump) { defines.Add("DUMP"); diff --git a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script index e57aad271..6f8e24aa7 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script @@ -23,6 +23,10 @@ VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Foo1\(.*\)\s+\[(?i:.*[\\ VERIFY:\s+\s+\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s* SOSCOMMAND:SetSymbolServer -disable +# Test eeversion command +SOSCOMMAND:EEVersion +VERIFY:\s+....* + # Verify that ClrStack with managed/native mixed works IFDEF:PROJECTK SOSCOMMAND:ClrStack -f diff --git a/src/SOS/SOS.UnitTests/Scripts/StackTests.script b/src/SOS/SOS.UnitTests/Scripts/StackTests.script index 6670639aa..ca21ffc2e 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackTests.script @@ -7,6 +7,10 @@ IFDEF:LIVE CONTINUE ENDIF:LIVE +# Test eeversion command +SOSCOMMAND:EEVersion +VERIFY:\s+....* + # 1) Verifying that ClrStack with no options works SOSCOMMAND:ClrStack VERIFY:.*OS Thread Id:\s+0x\s+.* diff --git a/src/SOS/Strike/exts.cpp b/src/SOS/Strike/exts.cpp index ef84f7469..69c77acae 100644 --- a/src/SOS/Strike/exts.cpp +++ b/src/SOS/Strike/exts.cpp @@ -31,7 +31,6 @@ DWORD_PTR g_filterHint = 0; PDEBUG_CLIENT g_ExtClient; PDEBUG_DATA_SPACES2 g_ExtData2; -PDEBUG_SYMBOLS2 g_ExtSymbols2; PDEBUG_ADVANCED g_ExtAdvanced; PDEBUG_CLIENT g_pCallbacksClient; @@ -39,6 +38,7 @@ PDEBUG_CLIENT g_pCallbacksClient; DebugClient* g_DebugClient; ILLDBServices* g_ExtServices; +ILLDBServices2* g_ExtServices2; bool g_palInitialized = false; #endif // FEATURE_PAL @@ -50,6 +50,7 @@ PDEBUG_CONTROL2 g_ExtControl; PDEBUG_DATA_SPACES g_ExtData; PDEBUG_REGISTERS g_ExtRegisters; PDEBUG_SYMBOLS g_ExtSymbols; +PDEBUG_SYMBOLS2 g_ExtSymbols2; PDEBUG_SYSTEM_OBJECTS g_ExtSystem; #define SOS_ExtQueryFailGo(var, riid) \ @@ -80,7 +81,9 @@ ExtQuery(ILLDBServices* services) g_palInitialized = true; } g_ExtServices = services; - DebugClient* client = new DebugClient(services); + services->QueryInterface(__uuidof(ILLDBServices2), (void**)&g_ExtServices2); + + DebugClient* client = new DebugClient(services, g_ExtServices2); g_DebugClient = client; #endif HRESULT Status; @@ -88,10 +91,10 @@ ExtQuery(ILLDBServices* services) SOS_ExtQueryFailGo(g_ExtData, IDebugDataSpaces); SOS_ExtQueryFailGo(g_ExtRegisters, IDebugRegisters); SOS_ExtQueryFailGo(g_ExtSymbols, IDebugSymbols); + SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2); SOS_ExtQueryFailGo(g_ExtSystem, IDebugSystemObjects); #ifndef FEATURE_PAL SOS_ExtQueryFailGo(g_ExtData2, IDebugDataSpaces2); - SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2); SOS_ExtQueryFailGo(g_ExtAdvanced, IDebugAdvanced); #endif // FEATURE_PAL return S_OK; @@ -160,14 +163,15 @@ ExtRelease(void) EXT_RELEASE(g_ExtData); EXT_RELEASE(g_ExtRegisters); EXT_RELEASE(g_ExtSymbols); + EXT_RELEASE(g_ExtSymbols2); EXT_RELEASE(g_ExtSystem); #ifndef FEATURE_PAL EXT_RELEASE(g_ExtData2); - EXT_RELEASE(g_ExtSymbols2); EXT_RELEASE(g_ExtAdvanced); g_ExtClient = NULL; #else EXT_RELEASE(g_DebugClient); + EXT_RELEASE(g_ExtServices2); g_ExtServices = NULL; #endif // FEATURE_PAL } @@ -328,6 +332,7 @@ DebugClient::QueryInterface( InterfaceId == __uuidof(IDebugControl4) || InterfaceId == __uuidof(IDebugDataSpaces) || InterfaceId == __uuidof(IDebugSymbols) || + InterfaceId == __uuidof(IDebugSymbols2) || InterfaceId == __uuidof(IDebugSystemObjects) || InterfaceId == __uuidof(IDebugRegisters)) { @@ -356,6 +361,9 @@ DebugClient::Release() if (ref == 0) { m_lldbservices->Release(); + if (m_lldbservices2 != nullptr) { + m_lldbservices2->Release(); + } delete this; } return ref; diff --git a/src/SOS/Strike/exts.h b/src/SOS/Strike/exts.h index 46a5916f4..61b29e148 100644 --- a/src/SOS/Strike/exts.h +++ b/src/SOS/Strike/exts.h @@ -133,6 +133,7 @@ private: extern PDEBUG_CONTROL2 g_ExtControl; extern PDEBUG_DATA_SPACES g_ExtData; extern PDEBUG_SYMBOLS g_ExtSymbols; +extern PDEBUG_SYMBOLS2 g_ExtSymbols2; extern PDEBUG_SYSTEM_OBJECTS g_ExtSystem; extern PDEBUG_REGISTERS g_ExtRegisters; @@ -141,7 +142,6 @@ extern PDEBUG_REGISTERS g_ExtRegisters; // Global variables initialized by query. extern PDEBUG_CLIENT g_ExtClient; extern PDEBUG_DATA_SPACES2 g_ExtData2; -extern PDEBUG_SYMBOLS2 g_ExtSymbols2; extern PDEBUG_ADVANCED g_ExtAdvanced; bool @@ -150,6 +150,7 @@ IsInitializedByDbgEng(); #else // FEATURE_PAL extern ILLDBServices* g_ExtServices; +extern ILLDBServices2* g_ExtServices2; #define IsInitializedByDbgEng() false diff --git a/src/SOS/Strike/hostcoreclr.cpp b/src/SOS/Strike/hostcoreclr.cpp index 41dfe1b78..339898c09 100644 --- a/src/SOS/Strike/hostcoreclr.cpp +++ b/src/SOS/Strike/hostcoreclr.cpp @@ -246,7 +246,7 @@ static HRESULT GetCoreClrDirectory(std::string& coreClrDirectory) } #else ULONG index; - HRESULT Status = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, NULL); + HRESULT Status = GetRuntimeModuleInfo(&index, NULL); if (FAILED(Status)) { ExtErr("Error: Runtime module (%s) not loaded yet\n", MAKEDLLNAME_A("coreclr")); @@ -519,7 +519,7 @@ LPCSTR GetDacFilePath() dacModulePath.append(DIRECTORY_SEPARATOR_STR_A); dacModulePath.append(MAKEDLLNAME_A("mscordaccore")); #ifdef FEATURE_PAL - // if DAC file exists + // If DAC file exists in the runtime directory if (access(dacModulePath.c_str(), F_OK) == 0) #endif { @@ -573,7 +573,7 @@ LPCSTR GetDbiFilePath() dbiModulePath.append(DIRECTORY_SEPARATOR_STR_A); dbiModulePath.append(MAKEDLLNAME_A("mscordbi")); #ifdef FEATURE_PAL - // if DBI file exists + // If DBI file exists in the runtime directory if (access(dbiModulePath.c_str(), F_OK) == 0) #endif { @@ -843,11 +843,9 @@ static void SymbolFileCallback(void* param, const char* moduleFileName, const ch return; } #ifdef FEATURE_PAL - ToRelease services2(NULL); - HRESULT Status = g_ExtServices->QueryInterface(__uuidof(ILLDBServices2), (void**)&services2); - if (SUCCEEDED(Status)) + if (g_ExtServices2 != nullptr) { - services2->AddModuleSymbol(param, symbolFilePath); + g_ExtServices2->AddModuleSymbol(param, symbolFilePath); } #endif } @@ -873,18 +871,13 @@ HRESULT LoadNativeSymbols(bool runtimeOnly) if (g_symbolStoreInitialized) { #ifdef FEATURE_PAL - ToRelease services2(NULL); - hr = g_ExtServices->QueryInterface(__uuidof(ILLDBServices2), (void**)&services2); - if (SUCCEEDED(hr)) - { - hr = services2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback); - } + hr = g_ExtServices2 ? g_ExtServices2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback) : E_NOINTERFACE; #else if (runtimeOnly) { ULONG index; ULONG64 moduleAddress; - HRESULT hr = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, &moduleAddress); + HRESULT hr = GetRuntimeModuleInfo(&index, &moduleAddress); if (SUCCEEDED(hr)) { ArrayHolder moduleFilePath = new char[MAX_LONGPATH + 1]; diff --git a/src/SOS/Strike/sos_unixexports.src b/src/SOS/Strike/sos_unixexports.src index 979c279f1..6533ce9c2 100644 --- a/src/SOS/Strike/sos_unixexports.src +++ b/src/SOS/Strike/sos_unixexports.src @@ -25,6 +25,7 @@ DumpStack DumpStackObjects DumpVC EEHeap +EEVersion GCWhere EEStack EHInfo diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 439fd5e92..4f3546154 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -440,6 +440,7 @@ void DumpStackInternal(DumpStackFlag *pDSFlag) DumpStackWorker(*pDSFlag); } + DECLARE_API(DumpStack) { INIT_API_NO_RET_ON_FAILURE(); @@ -1276,6 +1277,14 @@ DECLARE_API(DumpClass) ExtOut("NumThreadStaticFields: %x\n", vMethodTableFields.wNumThreadStaticFields); } + + if (vMethodTableFields.wContextStaticsSize) + { + ExtOut("ContextStaticOffset: %x\n", vMethodTableFields.wContextStaticOffset); + ExtOut("ContextStaticsSize: %x\n", vMethodTableFields.wContextStaticsSize); + } + + if (vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0) { DisplayFields(methodTable, &mtdata, &vMethodTableFields, NULL, TRUE, FALSE); @@ -7996,11 +8005,7 @@ DECLARE_API(bpmd) // did we get dll and type name or file:line#? Search for a colon in the first arg // to see if it is in fact a file:line# CHAR* pColon = strchr(DllName.data, ':'); -#ifndef FEATURE_PAL - if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, NULL, NULL))) { -#else - if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, NULL))) { -#endif + if (FAILED(GetRuntimeModuleInfo(NULL, NULL))) { ExtOut("%s not loaded yet\n", MAIN_CLR_DLL_NAME_A); return Status; } @@ -10028,7 +10033,6 @@ DECLARE_API(DumpGCData) #endif //GC_CONFIG_DRIVEN } -#ifndef FEATURE_PAL /**********************************************************************\ * Routine Description: * * * @@ -10045,39 +10049,42 @@ DECLARE_API (EEVersion) ExtOut("CLR not loaded\n"); return Status; } - - if (g_ExtSymbols2) { - VS_FIXEDFILEINFO version; - - BOOL ret = GetEEVersion(&version); - - if (ret) - { - if (version.dwFileVersionMS != (DWORD)-1) - { - ExtOut("%u.%u.%u.%u", - HIWORD(version.dwFileVersionMS), - LOWORD(version.dwFileVersionMS), - HIWORD(version.dwFileVersionLS), - LOWORD(version.dwFileVersionLS)); - if (version.dwFileFlags & VS_FF_DEBUG) - { - ExtOut(" Checked or debug build"); - } - else - { - BOOL fRet = IsRetailBuild ((size_t)g_moduleInfo[eef].baseAddr); + static const int fileVersionBufferSize = 1024; + ArrayHolder fileVersionBuffer = new char[fileVersionBufferSize]; + VS_FIXEDFILEINFO version; - if (fRet) - ExtOut(" retail"); - else - ExtOut(" free"); - } + BOOL ret = GetEEVersion(&version, fileVersionBuffer.GetPtr(), fileVersionBufferSize); + if (ret) + { + if (version.dwFileVersionMS != (DWORD)-1) + { + ExtOut("%u.%u.%u.%u", + HIWORD(version.dwFileVersionMS), + LOWORD(version.dwFileVersionMS), + HIWORD(version.dwFileVersionLS), + LOWORD(version.dwFileVersionLS)); +#ifndef FEATURE_PAL + if (version.dwFileFlags & VS_FF_DEBUG) + { + ExtOut(" Checked or debug build"); + } + else + { + BOOL fRet = IsRetailBuild ((size_t)g_moduleInfo[eef].baseAddr); + if (fRet) + ExtOut(" retail"); + else + ExtOut(" free"); + } +#endif + ExtOut("\n"); - ExtOut("\n"); + if (fileVersionBuffer[0] != '\0') + { + ExtOut("%s\n", fileVersionBuffer.GetPtr()); } } - } + } if (!InitializeHeapData ()) ExtOut("GC Heap not initialized, so GC mode is not determined yet.\n"); @@ -10091,6 +10098,7 @@ DECLARE_API (EEVersion) ExtOut("In plan phase of garbage collection\n"); } +#ifndef FEATURE_PAL // Print SOS version VS_FIXEDFILEINFO sosVersion; if (GetSOSVersion(&sosVersion)) @@ -10102,6 +10110,7 @@ DECLARE_API (EEVersion) LOWORD(sosVersion.dwFileVersionMS), HIWORD(sosVersion.dwFileVersionLS), LOWORD(sosVersion.dwFileVersionLS)); + if (sosVersion.dwFileFlags & VS_FF_DEBUG) { ExtOut(" Checked or debug build"); @@ -10110,13 +10119,12 @@ DECLARE_API (EEVersion) { ExtOut(" retail build"); } - ExtOut("\n"); } } +#endif // FEATURE_PAL return Status; } -#endif // FEATURE_PAL #ifndef FEATURE_PAL /**********************************************************************\ @@ -11386,8 +11394,7 @@ DECLARE_API(TraceToCode) { if(g_clrBaseAddr == 0) { - g_ExtSymbols->GetModuleByModuleName (MAIN_CLR_MODULE_NAME_A,0,NULL, - &g_clrBaseAddr); + GetRuntimeModuleInfo(NULL, &g_clrBaseAddr); } if(g_clrBaseAddr == base) { @@ -11522,7 +11529,7 @@ DECLARE_API(GetCodeTypeFlags) else if(g_ExtSymbols->GetModuleByOffset (ip, 0, NULL, &base) == S_OK) { ULONG64 clrBaseAddr = 0; - if(SUCCEEDED(g_ExtSymbols->GetModuleByModuleName (MAIN_CLR_MODULE_NAME_A,0,NULL, &clrBaseAddr)) && base==clrBaseAddr) + if(SUCCEEDED(GetRuntimeModuleInfo(NULL, &clrBaseAddr)) && base==clrBaseAddr) { ExtOut("Compiled code in CLR"); codeType = 4; diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index d80ae8881..9a87e46eb 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -150,45 +150,63 @@ DWORD_PTR GetValueFromExpression(___in __in_z const char *const instr) #endif // FEATURE_PAL -ModuleInfo g_moduleInfo[MSCOREND] = {{0, FALSE, 0}, {0, FALSE, 0}, {0, FALSE, 0}}; +ModuleInfo g_moduleInfo[MSCOREND] = {{0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}}; void ReportOOM() { ExtOut("SOS Error: Out of memory\n"); } +HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase) +{ +#ifdef FEATURE_PAL + return g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, moduleIndex, moduleBase); +#else + return g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, moduleIndex, moduleBase); +#endif +} + HRESULT CheckEEDll() { -#ifndef FEATURE_PAL - // Do we have coreclr.dll + HRESULT hr = S_OK; + + // Do we have runtime module info? if (g_moduleInfo[MSCORWKS].baseAddr == 0) { - DEBUG_MODULE_PARAMETERS Params; - - g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, NULL, &g_moduleInfo[MSCORWKS].baseAddr); - if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE) + hr = GetRuntimeModuleInfo(&g_moduleInfo[MSCORWKS].index, &g_moduleInfo[MSCORWKS].baseAddr); +#ifdef FEATURE_PAL + if (SUCCEEDED(hr)) { - g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &Params); - if (Params.SymbolType == SymDeferred) + if (g_ExtServices2 != nullptr) { - g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A); - g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &Params); + g_ExtServices2->GetModuleInfo(g_moduleInfo[MSCORWKS].index, nullptr, &g_moduleInfo[MSCORWKS].size); } - if (Params.SymbolType == SymPdb || Params.SymbolType == SymDia) + } +#else + if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE) + { + DEBUG_MODULE_PARAMETERS params; + if (SUCCEEDED(g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, ¶ms))) { - g_moduleInfo[MSCORWKS].hasPdb = TRUE; + if (params.SymbolType == SymDeferred) + { + g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A); + g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, ¶ms); + } + if (params.SymbolType == SymPdb || params.SymbolType == SymDia) + { + g_moduleInfo[MSCORWKS].hasPdb = TRUE; + } + g_moduleInfo[MSCORWKS].size = params.Size; } - g_moduleInfo[MSCORWKS].size = Params.Size; } if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE) { ExtOut("PDB symbol for coreclr.dll not loaded\n"); } - } - return (g_moduleInfo[MSCORWKS].baseAddr != 0) ? S_OK : E_FAIL; -#else - return S_OK; #endif // FEATURE_PAL + } + return hr; } EEFLAVOR GetEEFlavor() @@ -197,8 +215,7 @@ EEFLAVOR GetEEFlavor() return MSCORWKS; #else // FEATUER_PAL EEFLAVOR flavor = UNKNOWNEE; - - if (SUCCEEDED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A,0,NULL,NULL))) { + if (SUCCEEDED(GetRuntimeModuleInfo(NULL, NULL))) { flavor = MSCORWKS; } return flavor; @@ -2796,42 +2813,72 @@ const char *EHTypeName(EHClauseType et) return "UNKNOWN"; } -void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData, - const UINT cTieredVersionData, ULONG rejitID, CLRDATA_ADDRESS ilAddr, CLRDATA_ADDRESS ilNodeAddr) +// 2.x version +void DumpTieredNativeCodeAddressInfo_2x(struct DacpTieredVersionData_2x * pTieredVersionData, const UINT cTieredVersionData) { for(int i = cTieredVersionData - 1; i >= 0; --i) { - ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr)); - const char *descriptor = NULL; - switch(pTieredVersionData[i].OptimizationTier) + switch(pTieredVersionData[i].TieredInfo) { - case DacpTieredVersionData::OptimizationTier_Unknown: + case DacpTieredVersionData_2x::TIERED_UNKNOWN: default: descriptor = "Unknown Tier"; break; - case DacpTieredVersionData::OptimizationTier_MinOptJitted: - descriptor = "MinOptJitted"; - break; - case DacpTieredVersionData::OptimizationTier_Optimized: - descriptor = "Optimized"; + case DacpTieredVersionData_2x::NON_TIERED: + descriptor = "Non-Tiered"; break; - case DacpTieredVersionData::OptimizationTier_QuickJitted: - descriptor = "QuickJitted"; + case DacpTieredVersionData_2x::TIERED_0: + descriptor = "Tier 0"; break; - case DacpTieredVersionData::OptimizationTier_OptimizedTier1: - descriptor = "OptimizedTier1"; - break; - case DacpTieredVersionData::OptimizationTier_ReadyToRun: - descriptor = "ReadyToRun"; + case DacpTieredVersionData_2x::TIERED_1: + descriptor = "Tier 1"; break; } + DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor); + ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr)); + } +} - ExtOut(" ReJIT ID: %d\n", rejitID); - DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor); - DMLOut(" IL Addr: %s\n", DMLIL(ilAddr)); - ExtOut(" ILCodeVersion: %p\n", SOS_PTR(ilNodeAddr)); +void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData, const UINT cTieredVersionData, + ULONG rejitID, CLRDATA_ADDRESS ilAddr, CLRDATA_ADDRESS ilNodeAddr) +{ + ExtOut(" ILCodeVersion: %p\n", SOS_PTR(ilNodeAddr)); + ExtOut(" ReJIT ID: %d\n", rejitID); + DMLOut(" IL Addr: %s\n", DMLIL(ilAddr)); + if (IsRuntimeVersion(3)) { + for(int i = cTieredVersionData - 1; i >= 0; --i) + { + const char *descriptor = NULL; + switch(pTieredVersionData[i].OptimizationTier) + { + case DacpTieredVersionData::OptimizationTier_Unknown: + default: + descriptor = "Unknown Tier"; + break; + case DacpTieredVersionData::OptimizationTier_MinOptJitted: + descriptor = "MinOptJitted"; + break; + case DacpTieredVersionData::OptimizationTier_Optimized: + descriptor = "Optimized"; + break; + case DacpTieredVersionData::OptimizationTier_QuickJitted: + descriptor = "QuickJitted"; + break; + case DacpTieredVersionData::OptimizationTier_OptimizedTier1: + descriptor = "OptimizedTier1"; + break; + case DacpTieredVersionData::OptimizationTier_ReadyToRun: + descriptor = "ReadyToRun"; + break; + } + DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor); + ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr)); + } + } + else { + DumpTieredNativeCodeAddressInfo_2x((DacpTieredVersionData_2x*)pTieredVersionData, cTieredVersionData); } } @@ -2967,8 +3014,8 @@ void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, DacpReJi { // Special case, there is no jitted code yet but still need to output the IL information ExtOut(" ILCodeVersion: %p (pending)\n", SOS_PTR(pendingRejitData.ilCodeVersionNodePtr)); - ExtOut(" ReJIT ID: %d\n", pendingRejitID); - DMLOut(" IL Addr: %s\n", DMLIL(pendingRejitData.il)); + ExtOut(" ReJIT ID: %d\n", pendingRejitID); + DMLOut(" IL Addr: %s\n", DMLIL(pendingRejitData.il)); } } @@ -3225,21 +3272,65 @@ size_t FunctionType (size_t EIP) return (size_t) pMD; } -#ifndef FEATURE_PAL - // // Gets version info for the CLR in the debuggee process. // -BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo) +BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int fileVersionBufferSizeInBytes) { - _ASSERTE(g_ExtSymbols2); _ASSERTE(pFileInfo); + if (g_ExtSymbols2 == nullptr) { + return FALSE; + } + ModuleInfo moduleInfo = g_moduleInfo[GetEEFlavor()]; + _ASSERTE(moduleInfo.index != DEBUG_ANY_ID); + +#ifdef FEATURE_PAL + // Load the symbols for runtime. On Linux we are looking for the "sccsid" + // global so "libcoreclr.so/.dylib" symbols need to be loaded. + LoadNativeSymbols(true); +#endif + + HRESULT hr = g_ExtSymbols2->GetModuleVersionInformation(moduleInfo.index, 0, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL); + + // Attempt to get the the FileVersion string that contains version and the "built by" and commit id info + if (fileVersionBuffer != nullptr) + { + if (fileVersionBufferSizeInBytes > 0) { + fileVersionBuffer[0] = '\0'; + } + // We can assume the English/CP_UNICODE lang/code page for the runtime modules + g_ExtSymbols2->GetModuleVersionInformation( + moduleInfo.index, 0, "\\StringFileInfo\\040904B0\\FileVersion", fileVersionBuffer, fileVersionBufferSizeInBytes, NULL); + } - // Grab the version info directly from the module. - return g_ExtSymbols2->GetModuleVersionInformation( - DEBUG_ANY_ID, g_moduleInfo[GetEEFlavor()].baseAddr, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL) == S_OK; + return SUCCEEDED(hr); +} + +// +// Return true if major runtime version (logical product version like 2.1, +// 3.0 or 5.x). Currently only major versions of 3 or 5 are supported. +// +bool IsRuntimeVersion(DWORD major) +{ + VS_FIXEDFILEINFO fileInfo; + if (GetEEVersion(&fileInfo, nullptr, 0)) + { + switch (major) + { + case 5: + return HIWORD(fileInfo.dwFileVersionMS) == 5; + case 3: + return HIWORD(fileInfo.dwFileVersionMS) == 4 && LOWORD(fileInfo.dwFileVersionMS) == 700; + default: + _ASSERTE(FALSE); + break; + } + } + return false; } +#ifndef FEATURE_PAL + BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo) { _ASSERTE(pFileInfo); @@ -4450,7 +4541,7 @@ HRESULT InitCorDebugInterface() return E_FAIL; #else ULONG64 ulBase; - hr = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, &ulBase); + hr = GetRuntimeModuleInfo(NULL, &ulBase); if (SUCCEEDED(hr)) { hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging); @@ -6141,4 +6232,4 @@ HRESULT GetMetadataMemory(CLRDATA_ADDRESS address, ULONG32 bufferSize, BYTE* buf return E_ACCESSDENIED; } -#endif // FEATURE_PAL \ No newline at end of file +#endif // FEATURE_PAL diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 80797f559..054d5b950 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -1536,6 +1536,7 @@ struct ModuleInfo { ULONG64 baseAddr; ULONG64 size; + ULONG index; BOOL hasPdb; }; extern ModuleInfo g_moduleInfo[]; @@ -1551,12 +1552,14 @@ HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr); void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize); void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray); -BOOL IsRetailBuild (size_t base); +HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase); EEFLAVOR GetEEFlavor (); HRESULT InitCorDebugInterface(); VOID UninitCorDebugInterface(); +BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int fileVersionBufferSizeInBytes); +bool IsRuntimeVersion(DWORD major); #ifndef FEATURE_PAL -BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo); +BOOL IsRetailBuild (size_t base); BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo); #endif diff --git a/src/SOS/Strike/xplat/dbgeng.h b/src/SOS/Strike/xplat/dbgeng.h index 13f37988e..42a506042 100644 --- a/src/SOS/Strike/xplat/dbgeng.h +++ b/src/SOS/Strike/xplat/dbgeng.h @@ -24,14 +24,19 @@ class DebugClient { private: LONG m_ref; - ILLDBServices *m_lldbservices; + ILLDBServices* m_lldbservices; + ILLDBServices2* m_lldbservices2; public: - DebugClient(ILLDBServices *lldbservices) : + DebugClient(ILLDBServices* lldbservices, ILLDBServices2* lldbservices2) : m_ref(1), - m_lldbservices(lldbservices) + m_lldbservices(lldbservices), + m_lldbservices2(lldbservices2) { m_lldbservices->AddRef(); + if (m_lldbservices2 != nullptr) { + m_lldbservices2->AddRef(); + } } //---------------------------------------------------------------------------- @@ -267,6 +272,21 @@ public: moduleNameBufferSize, moduleNameSize, loadedImageNameBuffer, loadedImageNameBufferSize, loadedImageNameSize); } + HRESULT + GetModuleVersionInformation( + ULONG index, + ULONG64 base, + PCSTR item, + PVOID buffer, + ULONG bufferSize, + PULONG versionInfoSize) + { + if (m_lldbservices2 == nullptr) { + return E_NOINTERFACE; + } + return m_lldbservices2->GetModuleVersionInformation(index, base, item, buffer, bufferSize, versionInfoSize); + } + HRESULT GetLineByOffset( ULONG64 offset, @@ -407,6 +427,11 @@ IDebugSymbols : DebugClient { }; +MIDL_INTERFACE("3a707211-afdd-4495-ad4f-56fecdf8163f") +IDebugSymbols2 : DebugClient +{ +}; + MIDL_INTERFACE("6b86fe2c-2c4f-4f0c-9da2-174311acc327") IDebugSystemObjects : DebugClient { @@ -422,6 +447,7 @@ typedef interface IDebugControl2* PDEBUG_CONTROL2; typedef interface IDebugControl4* PDEBUG_CONTROL4; typedef interface IDebugDataSpaces* PDEBUG_DATA_SPACES; typedef interface IDebugSymbols* PDEBUG_SYMBOLS; +typedef interface IDebugSymbols2* PDEBUG_SYMBOLS2; typedef interface IDebugSystemObjects* PDEBUG_SYSTEM_OBJECTS; typedef interface IDebugRegisters* PDEBUG_REGISTERS; diff --git a/src/SOS/lldbplugin/inc/lldbservices.h b/src/SOS/lldbplugin/inc/lldbservices.h index 881e4387e..a8bd87bd6 100644 --- a/src/SOS/lldbplugin/inc/lldbservices.h +++ b/src/SOS/lldbplugin/inc/lldbservices.h @@ -562,6 +562,19 @@ public: virtual HRESULT AddModuleSymbol( void* param, const char* symbolFilePath) = 0; + + virtual HRESULT GetModuleInfo( + ULONG index, + PULONG64 base, + PULONG64 size) = 0; + + virtual HRESULT GetModuleVersionInformation( + ULONG index, + ULONG64 base, + PCSTR item, + PVOID buffer, + ULONG bufferSize, + PULONG versionInfoSize) = 0; }; #ifdef __cplusplus diff --git a/src/SOS/lldbplugin/services.cpp b/src/SOS/lldbplugin/services.cpp index 76e2e792a..0cbeacc88 100644 --- a/src/SOS/lldbplugin/services.cpp +++ b/src/SOS/lldbplugin/services.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #define CONVERT_FROM_SIGN_EXTENDED(offset) ((ULONG_PTR)(offset)) @@ -24,6 +25,7 @@ LLDBServices::LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObje m_currentProcess(process), m_currentThread(thread) { + ClearCache(); returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult); } @@ -968,31 +970,31 @@ HRESULT LLDBServices::GetModuleByIndex( ULONG index, PULONG64 base) { - ULONG64 moduleBase = UINT64_MAX; - lldb::SBTarget target; lldb::SBModule module; target = m_debugger.GetSelectedTarget(); if (!target.IsValid()) { - goto exit; + return E_INVALIDARG; } module = target.GetModuleAtIndex(index); if (!module.IsValid()) { - goto exit; + return E_INVALIDARG; } - moduleBase = GetModuleBase(target, module); - -exit: if (base) { + ULONG64 moduleBase = GetModuleBase(target, module); + if (moduleBase == UINT64_MAX) + { + return E_INVALIDARG; + } *base = moduleBase; } - return moduleBase == UINT64_MAX ? E_FAIL : S_OK; + return S_OK; } HRESULT @@ -1002,9 +1004,6 @@ LLDBServices::GetModuleByModuleName( PULONG index, PULONG64 base) { - ULONG64 moduleBase = UINT64_MAX; - ULONG moduleIndex = UINT32_MAX; - lldb::SBTarget target; lldb::SBModule module; lldb::SBFileSpec fileSpec; @@ -1013,16 +1012,24 @@ LLDBServices::GetModuleByModuleName( target = m_debugger.GetSelectedTarget(); if (!target.IsValid()) { - goto exit; + return E_INVALIDARG; } module = target.FindModule(fileSpec); if (!module.IsValid()) { - goto exit; + return E_INVALIDARG; } - moduleBase = GetModuleBase(target, module); + if (base) + { + ULONG64 moduleBase = GetModuleBase(target, module); + if (moduleBase == UINT64_MAX) + { + return E_INVALIDARG; + } + *base = moduleBase; + } if (index) { @@ -1032,22 +1039,13 @@ LLDBServices::GetModuleByModuleName( lldb::SBModule mod = target.GetModuleAtIndex(mi); if (module == mod) { - moduleIndex = mi; + *index = mi; break; } } } -exit: - if (index) - { - *index = moduleIndex; - } - if (base) - { - *base = moduleBase; - } - return moduleBase == UINT64_MAX ? E_FAIL : S_OK; + return S_OK; } HRESULT @@ -1057,9 +1055,6 @@ LLDBServices::GetModuleByOffset( PULONG index, PULONG64 base) { - ULONG64 moduleBase = UINT64_MAX; - ULONG moduleIndex = UINT32_MAX; - lldb::SBTarget target; int numModules; @@ -1069,7 +1064,7 @@ LLDBServices::GetModuleByOffset( target = m_debugger.GetSelectedTarget(); if (!target.IsValid()) { - goto exit; + return E_INVALIDARG; } numModules = target.GetNumModules(); @@ -1086,13 +1081,19 @@ LLDBServices::GetModuleByOffset( lldb::addr_t baseAddress = section.GetLoadAddress(target); if (baseAddress != LLDB_INVALID_ADDRESS) { - if (offset > baseAddress) + if (offset >= baseAddress) { if ((offset - baseAddress) < section.GetByteSize()) { - moduleIndex = mi; - moduleBase = baseAddress - section.GetFileOffset(); - goto exit; + if (index) + { + *index = mi; + } + if (base) + { + *base = baseAddress - section.GetFileOffset(); + } + return S_OK; } } } @@ -1100,16 +1101,7 @@ LLDBServices::GetModuleByOffset( } } -exit: - if (index) - { - *index = moduleIndex; - } - if (base) - { - *base = moduleBase; - } - return moduleBase == UINT64_MAX ? E_FAIL : S_OK; + return E_FAIL; } HRESULT @@ -1128,7 +1120,6 @@ LLDBServices::GetModuleNames( { lldb::SBTarget target; lldb::SBFileSpec fileSpec; - HRESULT hr = S_OK; // lldb doesn't expect sign-extended address base = CONVERT_FROM_SIGN_EXTENDED(base); @@ -1136,10 +1127,8 @@ LLDBServices::GetModuleNames( target = m_debugger.GetSelectedTarget(); if (!target.IsValid()) { - hr = E_FAIL; - goto exit; + return E_INVALIDARG; } - if (index != DEBUG_ANY_ID) { lldb::SBModule module = target.GetModuleAtIndex(index); @@ -1165,14 +1154,10 @@ LLDBServices::GetModuleNames( } } } - if (!fileSpec.IsValid()) { - hr = E_FAIL; - goto exit; + return E_INVALIDARG; } - -exit: if (imageNameBuffer) { int size = fileSpec.GetPath(imageNameBuffer, imageNameBufferSize); @@ -1202,7 +1187,7 @@ exit: *loadedImageNameSize = size; } } - return hr; + return S_OK; } HRESULT @@ -1348,6 +1333,26 @@ LLDBServices::GetModuleBase( return UINT64_MAX; } +ULONG64 +LLDBServices::GetModuleSize( + /* const */ lldb::SBModule& module) +{ + ULONG64 size = 0; + + // Find the first section with an valid base address + int numSections = module.GetNumSections(); + for (int si = 0; si < numSections; si++) + { + lldb::SBSection section = module.GetSectionAtIndex(si); + if (section.IsValid()) + { + size += section.GetByteSize(); + } + } + + return size; +} + //---------------------------------------------------------------------------- // IDebugSystemObjects //---------------------------------------------------------------------------- @@ -1777,13 +1782,14 @@ LLDBServices::LoadNativeSymbols( if (directory != nullptr && filename != nullptr) { ULONG64 moduleAddress = GetModuleBase(target, module); - int moduleSize = INT32_MAX; if (moduleAddress != UINT64_MAX) { std::string path(directory); path.append("/"); path.append(filename); + int moduleSize = GetModuleSize(module); + callback(&module, path.c_str(), moduleAddress, moduleSize); } } @@ -1840,6 +1846,141 @@ LLDBServices::AddModuleSymbol( return Execute(DEBUG_EXECUTE_NOT_LOGGED, command.c_str(), 0); } +HRESULT LLDBServices::GetModuleInfo( + ULONG index, + PULONG64 pBase, + PULONG64 pSize) +{ + lldb::SBTarget target; + lldb::SBModule module; + + target = m_debugger.GetSelectedTarget(); + if (!target.IsValid()) + { + return E_INVALIDARG; + } + + module = target.GetModuleAtIndex(index); + if (!module.IsValid()) + { + return E_INVALIDARG; + } + + if (pBase) + { + ULONG64 moduleBase = GetModuleBase(target, module); + if (moduleBase == UINT64_MAX) + { + return E_INVALIDARG; + } + *pBase = moduleBase; + } + + if (pSize) + { + *pSize = GetModuleSize(module); + } + + return S_OK; +} + +#define VersionBufferSize 1024 + +HRESULT +LLDBServices::GetModuleVersionInformation( + ULONG index, + ULONG64 base, + PCSTR item, + PVOID buffer, + ULONG bufferSize, + PULONG versionInfoSize) +{ + // Only support a narrow set of argument values + if (index == DEBUG_ANY_ID || buffer == nullptr || versionInfoSize != nullptr) + { + return E_INVALIDARG; + } + lldb::SBTarget target = m_debugger.GetSelectedTarget(); + if (!target.IsValid()) + { + return E_INVALIDARG; + } + lldb::SBModule module = target.GetModuleAtIndex(index); + if (!module.IsValid()) + { + return E_INVALIDARG; + } + const char* versionString = nullptr; + lldb::SBValue value; + lldb::SBData data; + + value = module.FindFirstGlobalVariable(target, "sccsid"); + if (value.IsValid()) + { + data = value.GetData(); + if (data.IsValid()) + { + lldb::SBError error; + versionString = data.GetString(error, 0); + if (error.Fail()) + { + versionString = nullptr; + } + } + } + + ArrayHolder versionBuffer = nullptr; + if (versionString == nullptr) + { + versionBuffer = new char[VersionBufferSize]; + + int numSections = module.GetNumSections(); + for (int si = 0; si < numSections; si++) + { + lldb::SBSection section = module.GetSectionAtIndex(si); + if (GetVersionStringFromSection(target, section, versionBuffer.GetPtr())) + { + versionString = versionBuffer; + break; + } + } + } + + if (versionString == nullptr) + { + return E_FAIL; + } + + if (strcmp(item, "\\") == 0) + { + if (bufferSize < sizeof(VS_FIXEDFILEINFO)) + { + return E_INVALIDARG; + } + DWORD major, minor, build, revision; + if (sscanf(versionString, "@(#)Version %u.%u.%u.%u", &major, &minor, &build, &revision) != 4) + { + return E_FAIL; + } + memset(buffer, 0, sizeof(VS_FIXEDFILEINFO)); + ((VS_FIXEDFILEINFO*)buffer)->dwFileVersionMS = MAKELONG(minor, major); + ((VS_FIXEDFILEINFO*)buffer)->dwFileVersionLS = MAKELONG(revision, build); + } + else if (strcmp(item, "\\StringFileInfo\\040904B0\\FileVersion") == 0) + { + if (bufferSize < (strlen(versionString) - sizeof("@(#)Version"))) + { + return E_INVALIDARG; + } + stpncpy((char*)buffer, versionString + sizeof("@(#)Version"), bufferSize); + } + else + { + return E_INVALIDARG; + } + return S_OK; +} + //---------------------------------------------------------------------------- // Helper functions //---------------------------------------------------------------------------- @@ -1927,3 +2068,128 @@ LLDBServices::GetPluginModuleDirectory() } return g_pluginModuleDirectory; } + +bool +LLDBServices::GetVersionStringFromSection(lldb::SBTarget& target, lldb::SBSection& section, char* versionBuffer) +{ + if (section.IsValid()) + { + lldb::SectionType sectionType = section.GetSectionType(); + + if (sectionType == lldb::eSectionTypeContainer) + { + int numSubSections = section.GetNumSubSections(); + for (int subsi = 0; subsi < numSubSections; subsi++) + { + lldb::SBSection subSection = section.GetSubSectionAtIndex(subsi); + if (GetVersionStringFromSection(target, subSection, versionBuffer)) { + return true; + } + } + } + else if (sectionType == lldb::eSectionTypeData) + { + lldb::addr_t address = section.GetLoadAddress(target); + uint32_t size = section.GetByteSize(); + if (SearchVersionString(address, size, versionBuffer, VersionBufferSize)) { + return true; + } + } + } + return false; +} + +#define VersionLength 12 +static const char* g_versionString = "@(#)Version "; + +bool +LLDBServices::SearchVersionString( + ULONG64 address, + ULONG64 size, + char* versionBuffer, + int versionBufferSize) +{ + BYTE buffer[VersionLength]; + ULONG cbBytesRead; + bool result; + + ClearCache(); + + while (size > 0) + { + result = ReadVirtualCache(address, buffer, VersionLength, &cbBytesRead); + if (result && cbBytesRead >= VersionLength) + { + if (memcmp(buffer, g_versionString, VersionLength) == 0) + { + for (int i = 0; i < versionBufferSize; i++) + { + // Now read the version string a char/byte at a time + result = ReadVirtualCache(address, &versionBuffer[i], 1, &cbBytesRead); + + // Return not found if there are any failures or problems while reading the version string. + if (!result || cbBytesRead < 1 || size <= 0) { + break; + } + // Found the end of the string + if (versionBuffer[i] == '\0') { + return true; + } + address++; + size--; + } + // Return not found if overflowed the versionBuffer (not finding a null). + break; + } + address++; + size--; + } + else + { + address += VersionLength; + size -= VersionLength; + } + } + + return false; +} + +bool +LLDBServices::ReadVirtualCache(ULONG64 address, PVOID buffer, ULONG bufferSize, PULONG pcbBytesRead) +{ + if (bufferSize == 0) + { + return true; + } + + if (bufferSize > CACHE_SIZE) + { + // Don't even try with the cache + return ReadVirtual(address, buffer, bufferSize, pcbBytesRead) == S_OK; + } + + if (!m_cacheValid || (address < m_startCache) || (address > (m_startCache + m_cacheSize - bufferSize))) + { + m_cacheValid = false; + m_startCache = address; + + ULONG cbBytesRead = 0; + HRESULT hr = ReadVirtual(m_startCache, m_cache, CACHE_SIZE, &cbBytesRead); + if (hr != S_OK) + { + return false; + } + + m_cacheSize = cbBytesRead; + m_cacheValid = true; + } + + memcpy(buffer, (LPVOID)((ULONG64)m_cache + (address - m_startCache)), bufferSize); + + if (pcbBytesRead != NULL) + { + *pcbBytesRead = bufferSize; + } + + return true; +} diff --git a/src/SOS/lldbplugin/services.h b/src/SOS/lldbplugin/services.h index 8eb79f6a1..ff06c9e25 100644 --- a/src/SOS/lldbplugin/services.h +++ b/src/SOS/lldbplugin/services.h @@ -4,6 +4,8 @@ #include +#define CACHE_SIZE 4096 + class LLDBServices : public ILLDBServices, public ILLDBServices2 { private: @@ -14,12 +16,28 @@ private: lldb::SBProcess *m_currentProcess; lldb::SBThread *m_currentThread; + BYTE m_cache[CACHE_SIZE]; + ULONG64 m_startCache; + bool m_cacheValid; + ULONG m_cacheSize; + void OutputString(ULONG mask, PCSTR str); ULONG64 GetModuleBase(lldb::SBTarget& target, lldb::SBModule& module); + ULONG64 GetModuleSize(lldb::SBModule& module); DWORD_PTR GetExpression(lldb::SBFrame& frame, lldb::SBError& error, PCSTR exp); void GetContextFromFrame(lldb::SBFrame& frame, DT_CONTEXT *dtcontext); DWORD_PTR GetRegister(lldb::SBFrame& frame, const char *name); + bool GetVersionStringFromSection(lldb::SBTarget& target, lldb::SBSection& section, char* versionBuffer); + bool SearchVersionString(ULONG64 address, ULONG64 size, char* versionBuffer, int versionBufferSize); + bool ReadVirtualCache(ULONG64 address, PVOID buffer, ULONG bufferSize, PULONG pcbBytesRead); + + void ClearCache() + { + m_cacheValid = false; + m_cacheSize = CACHE_SIZE; + } + lldb::SBProcess GetCurrentProcess(); lldb::SBThread GetCurrentThread(); lldb::SBFrame GetCurrentFrame(); @@ -277,6 +295,19 @@ public: void* param, const char* symbolFileName); + HRESULT GetModuleInfo( + ULONG index, + PULONG64 base, + PULONG64 size); + + HRESULT GetModuleVersionInformation( + ULONG index, + ULONG64 base, + PCSTR item, + PVOID buffer, + ULONG bufferSize, + PULONG versionInfoSize); + //---------------------------------------------------------------------------- // LLDBServices (internal) //---------------------------------------------------------------------------- diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index b6a4edc8f..725731196 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -134,6 +134,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) interpreter.AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only."); interpreter.AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running."); interpreter.AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method."); + interpreter.AddCommand("dumparray", new sosCommand("DumpArray"), "Displays details about a managed array."); interpreter.AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays info about async state machines on the garbage-collected heap."); interpreter.AddCommand("dumpassembly", new sosCommand("DumpAssembly"), "Displays details about an assembly."); interpreter.AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address."); @@ -150,6 +151,7 @@ sosCommandInitialize(lldb::SBDebugger debugger) interpreter.AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack."); interpreter.AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures."); interpreter.AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process."); + interpreter.AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime version."); interpreter.AddCommand("finalizequeue", new sosCommand("FinalizeQueue"), "Displays all objects registered for finalization."); interpreter.AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address."); interpreter.AddCommand("gcwhere", new sosCommand("GCWhere"), "Displays the location in the GC heap of the argument passed in."); diff --git a/src/Tools/dotnet-dump/Commands/SOSCommand.cs b/src/Tools/dotnet-dump/Commands/SOSCommand.cs index e9317ae44..35b6958d0 100644 --- a/src/Tools/dotnet-dump/Commands/SOSCommand.cs +++ b/src/Tools/dotnet-dump/Commands/SOSCommand.cs @@ -30,6 +30,7 @@ namespace Microsoft.Diagnostics.Tools.Dump [Command(Name = "dumpstackobjects", AliasExpansion = "DumpStackObjects", Help = "Displays all managed objects found within the bounds of the current stack.")] [CommandAlias(Name = "dso")] [Command(Name = "eeheap", AliasExpansion = "EEHeap", Help = "Displays info about process memory consumed by internal runtime data structures.")] + [Command(Name = "eeversion", AliasExpansion = "EEVersion", Help = "Displays information about the runtime version.")] [Command(Name = "finalizequeue", AliasExpansion = "FinalizeQueue", Help = "Displays all objects registered for finalization.")] [Command(Name = "gcroot", AliasExpansion = "GCRoot", Help = "Displays info about references (or roots) to an object at the specified address.")] [Command(Name = "gcwhere", AliasExpansion = "GCWhere", Help = "Displays the location in the GC heap of the argument passed in.")] diff --git a/src/Tools/dotnet-dump/Commands/SOSCommandForWindows.cs b/src/Tools/dotnet-dump/Commands/SOSCommandForWindows.cs index 560693d3c..27f690559 100644 --- a/src/Tools/dotnet-dump/Commands/SOSCommandForWindows.cs +++ b/src/Tools/dotnet-dump/Commands/SOSCommandForWindows.cs @@ -18,7 +18,6 @@ namespace Microsoft.Diagnostics.Tools.Dump [Command(Name = "watsonbuckets", AliasExpansion = "WatsonBuckets", Help = "Displays the Watson buckets.")] [Command(Name = "threadpool", AliasExpansion = "ThreadPool", Help = "Lists basic information about the thread pool.")] [Command(Name = "comstate", AliasExpansion = "COMState", Help = "Lists the COM apartment model for each thread.")] - [Command(Name = "eeversion", AliasExpansion = "EEVersion", Help = "This prints the runtiem and SOS versions.")] [Command(Name = "gchandles", AliasExpansion = "GCHandles", Help = "Provides statistics about GCHandles in the process.")] [Command(Name = "objsize", AliasExpansion = "ObjSize", Help = "Lists the sizes of the all the objects found on managed threads.")] [Command(Name = "gchandleleaks", AliasExpansion = "GCHandleLeaks", Help = "Helps in tracking down GCHandle leaks")] diff --git a/src/inc/dacprivate.h b/src/inc/dacprivate.h index 02ec2eb69..ac74bfdff 100644 --- a/src/inc/dacprivate.h +++ b/src/inc/dacprivate.h @@ -631,8 +631,8 @@ struct MSLAYOUT DacpTieredVersionData CLRDATA_ADDRESS NativeCodeVersionNodePtr; }; -// 2.1 version -struct MSLAYOUT DacpTieredVersionData_21 +// 2.x version +struct MSLAYOUT DacpTieredVersionData_2x { enum TieredState {