Fix dumpmd/ip2md commands for < 3.x runtimes (#462)
authorMike McLaughlin <mikem@microsoft.com>
Thu, 12 Sep 2019 07:34:56 +0000 (00:34 -0700)
committerGitHub <noreply@github.com>
Thu, 12 Sep 2019 07:34:56 +0000 (00:34 -0700)
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.

25 files changed:
eng/Versions.props
eng/build.yml
src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs
src/SOS/SOS.Hosting/LLDBServices.cs
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/SOS.Hosting/dbgeng/DebugSymbols.cs
src/SOS/SOS.UnitTests/Debuggees/GCWhere/GCWhere.cs
src/SOS/SOS.UnitTests/SOSRunner.cs
src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script
src/SOS/SOS.UnitTests/Scripts/StackTests.script
src/SOS/Strike/exts.cpp
src/SOS/Strike/exts.h
src/SOS/Strike/hostcoreclr.cpp
src/SOS/Strike/sos_unixexports.src
src/SOS/Strike/strike.cpp
src/SOS/Strike/util.cpp
src/SOS/Strike/util.h
src/SOS/Strike/xplat/dbgeng.h
src/SOS/lldbplugin/inc/lldbservices.h
src/SOS/lldbplugin/services.cpp
src/SOS/lldbplugin/services.h
src/SOS/lldbplugin/soscommand.cpp
src/Tools/dotnet-dump/Commands/SOSCommand.cs
src/Tools/dotnet-dump/Commands/SOSCommandForWindows.cs
src/inc/dacprivate.h

index 0efd7a0b4c5975059ab4b97440282bbd145b111d..6ac5419fe47d52c381b454c5216bece1d536fe72 100644 (file)
@@ -23,7 +23,7 @@
 
     <!-- Other libs -->
     <MicrosoftSymbolStoreVersion>1.0.41901</MicrosoftSymbolStoreVersion>
-    <MicrosoftDiagnosticsRuntimeVersion>1.1.37504</MicrosoftDiagnosticsRuntimeVersion>
+    <MicrosoftDiagnosticsRuntimeVersion>1.1.46104</MicrosoftDiagnosticsRuntimeVersion>
     <MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
     <MicrosoftDiagnosticsTracingTraceEventVersion>2.0.44</MicrosoftDiagnosticsTracingTraceEventVersion>
     <SystemCommandLineExperimentalVersion>0.2.0-alpha.19254.1</SystemCommandLineExperimentalVersion>
index 1800afc72445275c40c76d22ef3a8336fd03bace..42c03e97ff16df80eda8632d3c65f5f2061e2219 100644 (file)
@@ -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
index 98c16a333855f292eed3fed1053ebedbba487f58..001028d368386caeb6e4310313ecfb6b993d4388 100644 (file)
@@ -480,6 +480,7 @@ namespace Microsoft.Diagnostics.TestHelpers
         /// <summary>
         /// The major portion of the runtime framework version
         /// </summary>
+        /// <exception cref="SkipTestException">the RuntimeFrameworkVersion property doesn't exist</exception>
         public int RuntimeFrameworkVersionMajor
         {
             get {
index 8f5425bdfc6c38d18717d982d04dc349f2129405..554b43b3fbcf86e04656e2e603ccda7c1f7bb6d6 100644 (file)
@@ -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
         /// </summary>
         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
     }
index e19e4e69bec0cb6ff86017dd95452ee64b2b06c1..e0a7c5a25c552bd18bedde36459f770d1b68fb23 100644 (file)
@@ -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<string, PEReader> _pathToPeReader = new Dictionary<string, PEReader>();
 
@@ -202,6 +203,7 @@ namespace SOS
             _console = serviceProvider.GetService<IConsoleService>();
             _analyzeContext = serviceProvider.GetService<AnalyzeContext>();
             _registerService = serviceProvider.GetService<RegisterService>();
+            _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;
+        }
+    }
 }
index 259a160b12cfda9be5dab20a3d567b62254df915..cde29143bab3b3e814cb56f4bd3b651d33f28e41 100644 (file)
@@ -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));
index 95f2233668669f653d08d95e452acef37813839b..6cb8511c76759bf36d86cad9e8b29cf4b20aa776 100644 (file)
@@ -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
index 6145756592522e47058a2c469a70b392cbb88a0d..24205b8fe444d734f59d008212b3116530e0adee 100644 (file)
@@ -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<string> enabledDefines = GetEnabledDefines();
-        LogProcessingReproInfo(scriptFile, enabledDefines);
-        string[] scriptLines = File.ReadAllLines(scriptFile);
-        Dictionary<string, bool> activeDefines = new Dictionary<string, bool>();
-        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<string> enabledDefines = GetEnabledDefines();
+            LogProcessingReproInfo(scriptFile, enabledDefines);
+            string[] scriptLines = File.ReadAllLines(scriptFile);
+            Dictionary<string, bool> activeDefines = new Dictionary<string, bool>();
+            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");
index e57aad271ccecb8632e37a5cc1a05332a93ed7fe..6f8e24aa78eaa1dcff1789d538901925c6b11acf 100644 (file)
@@ -23,6 +23,10 @@ VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo1\(.*\)\s+\[(?i:.*[\\
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s*
 SOSCOMMAND:SetSymbolServer -disable
 
+# Test eeversion command
+SOSCOMMAND:EEVersion
+VERIFY:\s+<DECVAL>.<DECVAL>.<DECVAL>.<DECVAL>.*
+
 # Verify that ClrStack with managed/native mixed works
 IFDEF:PROJECTK
 SOSCOMMAND:ClrStack -f
index 6670639aa1eec6562dd2631505cc85f46e1f14ff..ca21ffc2ee454703619763bfb59130061fcb6fac 100644 (file)
@@ -7,6 +7,10 @@ IFDEF:LIVE
 CONTINUE
 ENDIF:LIVE
 
+# Test eeversion command
+SOSCOMMAND:EEVersion
+VERIFY:\s+<DECVAL>.<DECVAL>.<DECVAL>.<DECVAL>.*
+
 # 1) Verifying that ClrStack with no options works
 SOSCOMMAND:ClrStack
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
index ef84f746906ef080ae74d8fbeb227d24d2b8d428..69c77acaee851615835aa7e5387534895e226919 100644 (file)
@@ -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;
index 46a5916f45f5534d214d3042d08a19752274fc4b..61b29e1483567a9cc370ad4c4b56c6d2605ed0b0 100644 (file)
@@ -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
 
index 41dfe1b78d4eb01db13cc0141d99916afb8bb93d..339898c09bd10bbc6fbe197db66ae18eb1a5c29e 100644 (file)
@@ -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<ILLDBServices2> 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<ILLDBServices2> 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<char> moduleFilePath = new char[MAX_LONGPATH + 1];
index 979c279f1cbec8fd5c9b5d00093c3f890564e26b..6533ce9c2444d15e425e45baf0af3035b2cecb67 100644 (file)
@@ -25,6 +25,7 @@ DumpStack
 DumpStackObjects
 DumpVC
 EEHeap
+EEVersion
 GCWhere
 EEStack
 EHInfo
index 439fd5e922a2d52a337bcf2e67a8ae897b18cea1..4f3546154f29ac0a34adf96792d227ee1b45aa81 100644 (file)
@@ -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<char> 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;
index d80ae8881e4f24d90c8a3a69e99ec87959144c16..9a87e46ebf3a1676e703997241141e8bbca43ad7 100644 (file)
@@ -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, &params)))
             {
-                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, &params);
+                }
+                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
index 80797f559ce2c28958096d1a8d17bdb2c248ce89..054d5b9500d1ed0b23580cea4e857841c4d4758a 100644 (file)
@@ -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
 
index 13f37988ef8de4e01cc64e6e5e055c93a61c1051..42a5060427169a531f9725940fc9b27970d9ebd3 100644 (file)
@@ -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;
 
index 881e4387e7c92ef3c32b134523dae6ca32be4c4b..a8bd87bd695317373cdc6f56807fc36bb0c1f7cf 100644 (file)
@@ -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
index 76e2e792a615dc5bbf11c21f5ebd1111c4e689f9..0cbeacc88f7091f696b2415edd88967f3cf06163 100644 (file)
@@ -9,6 +9,7 @@
 #include <string>
 #include <dlfcn.h>
 #include <pthread.h>
+#include <arrayholder.h>
 
 #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<char> 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;
+}
index 8eb79f6a140811228446f5565bb458218b4896d5..ff06c9e25ab0a2737bb5062c4362660fb1468a2a 100644 (file)
@@ -4,6 +4,8 @@
 
 #include <cstdarg>
 
+#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)
     //----------------------------------------------------------------------------
index b6a4edc8f5c570bf4193a8422b530bc5a54fdf3d..725731196caac858d828e8ab487bb4002a9d21d3 100644 (file)
@@ -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.");
index e9317ae4425f1d5de94aa9aa5e61001c320e5e0d..35b6958d0ed83a9b73bc67470a3f370b422b9ccb 100644 (file)
@@ -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.")]
index 560693d3c1478e18c1d1e854b1fc9a811273afad..27f69055982f67579233a259382f8b7316bff50b 100644 (file)
@@ -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")]
index 02ec2eb698ceee1d0d3babf3dd7b172c85641dc0..ac74bfdffca0e18ac33fef41e15a94a0193c23cf 100644 (file)
@@ -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 
     {