Add arm/arm64 support to dotnet-dump (#411)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 30 Jul 2019 17:03:16 +0000 (10:03 -0700)
committerGitHub <noreply@github.com>
Tue, 30 Jul 2019 17:03:16 +0000 (10:03 -0700)
Add arm/arm64 support

Using new CLRMD version 1.1.37504

Add Microsoft.Diagnostics.DebugServices project containing the
new RegisterService and what's left of the AnalyzeContext.

Add ServiceProvider and refactor adding/creating the services.

Made OutputVaList global so we don't allocate 8K every line of output

Fixed that the "mask" (determines if error/normal/warning) is pasted on
to the debugger in OutputVaList.

Removed the formatting/buffer allocating in the OutputVaList in lldb services

Always use C++ runtime to format output now.

SOS_PTR keeps the architecture pointer size (size_t).

On x86, dotnet-dump had problems with %p formatting because the
C++ runtime was used and the pointer was converted to 64 bit by
the SOS_PTR macro.

Add arm64 registers to lldb service GetContextFromFrame

Enable tests on arm.

Added IConsoleService and removed the dependencies on System.CommandLine
from SOS.Hosting and MS.D.DebugServices.

IConsole is no longer exposed as a service.

38 files changed:
diagnostics.sln
eng/Build-Native.cmd
eng/Versions.props
eng/build-native.sh
src/Microsoft.Diagnostics.DebugServices/AnalyzeContext.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices/RegisterService.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices/ServiceProvider.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.Repl/Command/CommandBase.cs
src/Microsoft.Diagnostics.Repl/Command/CommandProcessor.cs
src/Microsoft.Diagnostics.Repl/Console/ConsoleProvider.cs
src/Microsoft.Diagnostics.Repl/Microsoft.Diagnostics.Repl.csproj
src/SOS/SOS.Hosting/Amd64Context.cs [deleted file]
src/SOS/SOS.Hosting/ISOSHostContext.cs [deleted file]
src/SOS/SOS.Hosting/LLDBServices.cs
src/SOS/SOS.Hosting/SOS.Hosting.csproj
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/SOS.InstallHelper/InstallHelper.cs
src/SOS/SOS.UnitTests/SOS.cs
src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script
src/SOS/SOS.UnitTests/Scripts/StackTests.script
src/SOS/Strike/exts.cpp
src/SOS/Strike/strike.h
src/SOS/Strike/util.cpp
src/SOS/Strike/xplat/dbgeng.h
src/SOS/lldbplugin/inc/lldbservices.h
src/SOS/lldbplugin/services.cpp
src/Tools/dotnet-dump/AnalyzeContext.cs [deleted file]
src/Tools/dotnet-dump/Analyzer.cs
src/Tools/dotnet-dump/Commands/ClrModulesCommand.cs
src/Tools/dotnet-dump/Commands/ExitCommand.cs
src/Tools/dotnet-dump/Commands/HelpCommand.cs
src/Tools/dotnet-dump/Commands/ModulesCommand.cs
src/Tools/dotnet-dump/Commands/RegistersCommand.cs [new file with mode: 0644]
src/Tools/dotnet-dump/Commands/SOSCommand.cs
src/Tools/dotnet-dump/Commands/SetThreadCommand.cs
src/Tools/dotnet-dump/dotnet-dump.csproj

index 257e4c17a94fcc54872be463e61b7d10742418a0..65c8d5402f0ad621c17cb3d4fb29d892eb833deb 100644 (file)
@@ -45,6 +45,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Tools
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SOS.Package", "src\SOS\SOS.Package\SOS.Package.csproj", "{234416E9-EA5F-4018-AC34-67682C5D3E04}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.DebugServices", "src\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj", "{A1CE682A-12C4-4FF9-B864-A9A15A8726D2}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Checked|Any CPU = Checked|Any CPU
@@ -719,6 +721,46 @@ Global
                {234416E9-EA5F-4018-AC34-67682C5D3E04}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
                {234416E9-EA5F-4018-AC34-67682C5D3E04}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
                {234416E9-EA5F-4018-AC34-67682C5D3E04}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|Any CPU.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|ARM.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|ARM.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|ARM64.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|ARM64.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|x64.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|x64.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|x86.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Checked|x86.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|ARM.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|ARM64.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|x64.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Debug|x86.Build.0 = Debug|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|Any CPU.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|ARM.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|ARM.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|ARM64.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|ARM64.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|x64.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|x64.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|x86.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.Release|x86.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|ARM.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|ARM.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|ARM64.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|ARM64.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -744,6 +786,7 @@ Global
                {2A9B5988-982F-4E26-9E44-D38AC5978C30} = {B62728C8-1267-4043-B46F-5537BBAEC692}
                {54C240C5-7932-4421-A5FB-75205DE0B824} = {19FAB78C-3351-4911-8F0C-8C6056401740}
                {234416E9-EA5F-4018-AC34-67682C5D3E04} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
+               {A1CE682A-12C4-4FF9-B864-A9A15A8726D2} = {19FAB78C-3351-4911-8F0C-8C6056401740}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0}
index 378c486e16e198c24ff3feff3cdec3138778549e..690ac763371c7485b680f34d82089b8bc226f873 100644 (file)
@@ -332,8 +332,7 @@ REM ============================================================================
 echo %__MsgPrefix%Repo successfully built. Finished at %TIME%
 echo %__MsgPrefix%Product binaries are available at !__BinDir!
 
-if /i "%__BuildArch%" == "arm" goto Done
-if /i "%__BuildArch%" == "arm64" goto Done
+if /i %__BuildCrossArch% EQU 1 goto Done
 
 :: Test components
 if %__Test% EQU 1 (
index 4c5748f1428938b6d3ab8a26ebafda04cc981d3d..47309088f9c986c37bdd22c503a53f2ee3e2fb08 100644 (file)
@@ -2,7 +2,7 @@
 <Project>
   <PropertyGroup>
     <RepositoryUrl>https://github.com/dotnet/diagnostics</RepositoryUrl>
-    <PreReleaseVersionLabel>preview7</PreReleaseVersionLabel>
+    <PreReleaseVersionLabel>preview8</PreReleaseVersionLabel>
     <VersionPrefix>3.0.0</VersionPrefix>
     <DotNetUseShippingVersions>true</DotNetUseShippingVersions>
     <AutoGenerateAssemblyVersion>true</AutoGenerateAssemblyVersion>
@@ -23,7 +23,7 @@
 
     <!-- Other libs -->
     <MicrosoftSymbolStoreVersion>1.0.0-dev-64131-02</MicrosoftSymbolStoreVersion>
-    <MicrosoftDiagnosticsRuntimeVersion>1.1.35902</MicrosoftDiagnosticsRuntimeVersion>
+    <MicrosoftDiagnosticsRuntimeVersion>1.1.37504</MicrosoftDiagnosticsRuntimeVersion>
     <MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
     <MicrosoftDiagnosticsTracingTraceEventVersion>2.0.43</MicrosoftDiagnosticsTracingTraceEventVersion>
     <SystemCommandLineExperimentalVersion>0.2.0-alpha.19254.1</SystemCommandLineExperimentalVersion>
index 81e8926ea37c3a33dd1c7e36335112c0f1107871..b4932f8a538eb52362b47cb6f23ffb1f1a40a55d 100755 (executable)
@@ -364,7 +364,7 @@ initTargetDistroRid()
     local passedRootfsDir=""
 
     # Only pass ROOTFS_DIR if cross is specified.
-    if [ "$__CrossBuild" == true ]; then
+    if [ $__CrossBuild == true ]; then
         passedRootfsDir=${ROOTFS_DIR}
     fi
 
@@ -438,7 +438,7 @@ fi
 
 # Run SOS/lldbplugin tests
 if [ $__Test == true ]; then
-   if [[ "$__BuildArch" != "arm" && "$__BuildArch" != "armel" && "$__BuildArch" != "arm64" ]]; then
+   if [ $__CrossBuild != true ]; then
 
       # Install the other versions of .NET Core runtime we are going to test on
       "$__ProjectRoot/eng/install-test-runtimes.sh" --dotnet-directory "$__ProjectRoot/.dotnet" --runtime-version-21 "$__DotNetRuntimeVersion" --temp-directory "$__IntermediatesDir" --architecture "$__BuildArch" $__DailyTest
diff --git a/src/Microsoft.Diagnostics.DebugServices/AnalyzeContext.cs b/src/Microsoft.Diagnostics.DebugServices/AnalyzeContext.cs
new file mode 100644 (file)
index 0000000..e1f4e27
--- /dev/null
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace Microsoft.Diagnostics.DebugServices
+{
+    /// <summary>
+    /// Common context for commands
+    /// </summary>
+    public class AnalyzeContext
+    {
+        public AnalyzeContext()
+        {
+        }
+
+        /// <summary>
+        /// Current OS thread Id
+        /// </summary>
+        public int CurrentThreadId { get; set; }
+
+        /// <summary>
+        /// Cancellation token for current command
+        /// </summary>
+        public CancellationToken CancellationToken { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs b/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs
new file mode 100644 (file)
index 0000000..2990d37
--- /dev/null
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Diagnostics.DebugServices
+{
+    /// <summary>
+    /// Console output service
+    /// </summary>
+    public interface IConsoleService
+    {
+        /// <summary>
+        /// Write text to console's standard out
+        /// </summary>
+        /// <param name="value">text</param>
+        void Write(string value);
+
+        /// <summary>
+        /// Write text to console's standard error
+        /// </summary>
+        /// <param name="value"></param>
+        void WriteError(string value);
+
+        /// <summary>
+        /// Exit the interactive console 
+        /// </summary>
+        void Exit();
+    }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj b/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj
new file mode 100644 (file)
index 0000000..098bc45
--- /dev/null
@@ -0,0 +1,15 @@
+<!-- Copyright (c)  Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information. -->
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <NoWarn>;1591;1701</NoWarn>
+    <Description>Diagnostics debug services</Description>
+    <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="$(MicrosoftDiagnosticsRuntimeVersion)" />
+  </ItemGroup>
+</Project>
diff --git a/src/Microsoft.Diagnostics.DebugServices/RegisterService.cs b/src/Microsoft.Diagnostics.DebugServices/RegisterService.cs
new file mode 100644 (file)
index 0000000..3bd96d6
--- /dev/null
@@ -0,0 +1,216 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.Runtime;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Architecture = Microsoft.Diagnostics.Runtime.Architecture;
+
+namespace Microsoft.Diagnostics.DebugServices
+{
+    /// <summary>
+    /// Provides register info and values
+    /// </summary>
+    public class RegisterService
+    {
+        public struct RegisterInfo
+        {
+            public readonly int RegisterIndex;
+            public readonly int RegisterOffset;
+            public readonly int RegisterSize;
+            public readonly string RegisterName;
+
+            internal RegisterInfo(int registerIndex, int registerOffset, int registerSize, string registerName)
+            {
+                RegisterIndex = registerIndex;
+                RegisterOffset = registerOffset;
+                RegisterSize = registerSize;
+                RegisterName = registerName;
+            }
+        }
+
+        private readonly DataTarget _target;
+        private readonly int _contextSize;
+        private readonly uint _contextFlags;
+        private readonly Dictionary<string, RegisterInfo> _lookupByName;
+        private readonly Dictionary<int, RegisterInfo> _lookupByIndex;
+        private readonly Dictionary<uint, byte[]> _threadContextCache = new Dictionary<uint, byte[]>();
+
+        public IEnumerable<RegisterInfo> Registers { get; }
+
+        public int InstructionPointerIndex { get; }
+
+        public int FramePointerIndex { get; }
+
+        public int StackPointerIndex { get; }
+
+        public RegisterService(DataTarget target)
+        {
+            _target = target;
+
+            Type contextType;
+            switch (target.Architecture)
+            {
+                case Architecture.Amd64:
+                    _contextSize = AMD64Context.Size;
+                    _contextFlags = AMD64Context.ContextControl | AMD64Context.ContextInteger | AMD64Context.ContextSegments;
+                    contextType = typeof(AMD64Context);
+                    break;
+
+                case Architecture.X86:
+                    _contextSize = X86Context.Size;
+                    _contextFlags = X86Context.ContextControl | X86Context.ContextInteger | X86Context.ContextSegments;
+                    contextType = typeof(X86Context);
+                    break;
+
+                case Architecture.Arm64:
+                    _contextSize = Arm64Context.Size;
+                    _contextFlags = Arm64Context.ContextControl | Arm64Context.ContextInteger;
+                    contextType = typeof(Arm64Context);
+                    break;
+
+                case Architecture.Arm:
+                    _contextSize = ArmContext.Size;
+                    _contextFlags = ArmContext.ContextControl | ArmContext.ContextInteger;
+                    contextType = typeof(ArmContext);
+                    break;
+
+                default:
+                    throw new PlatformNotSupportedException($"Unsupported architecture: {target.Architecture}");
+            }
+
+            var registers = new List<RegisterInfo>();
+            int index = 0;
+
+            FieldInfo[] fields = contextType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);
+            foreach (FieldInfo field in fields) {
+                RegisterAttribute registerAttribute = field.GetCustomAttributes<RegisterAttribute>(inherit: false).SingleOrDefault();
+                if (registerAttribute == null) {
+                    continue;
+                }
+                RegisterType registerType = registerAttribute.RegisterType & RegisterType.TypeMask;
+                switch (registerType)
+                {
+                    case RegisterType.Control:
+                    case RegisterType.General:
+                    case RegisterType.Segments:
+                        break;
+                    default:
+                        continue;
+                }
+                if ((registerAttribute.RegisterType & RegisterType.ProgramCounter) != 0) {
+                    InstructionPointerIndex = index;
+                }
+                if ((registerAttribute.RegisterType & RegisterType.StackPointer) != 0) {
+                    StackPointerIndex = index;
+                }
+                if ((registerAttribute.RegisterType & RegisterType.FramePointer) != 0) {
+                    FramePointerIndex = index;
+                }
+                FieldOffsetAttribute offsetAttribute = field.GetCustomAttributes<FieldOffsetAttribute>(inherit: false).Single();
+                var registerInfo = new RegisterInfo(index, offsetAttribute.Value, Marshal.SizeOf(field.FieldType), registerAttribute.Name ?? field.Name.ToLower());
+                registers.Add(registerInfo);
+                index++;
+            }
+
+            _lookupByName = registers.ToDictionary((info) => info.RegisterName);
+            _lookupByIndex = registers.ToDictionary((info) => info.RegisterIndex);
+
+            Registers = registers;
+        }
+
+        /// <summary>
+        /// Return the register index for the register name
+        /// </summary>
+        /// <param name="name">register name</param>
+        /// <param name="index">returns register index or -1</param>
+        /// <returns>true if name found</returns>
+        public bool GetRegisterIndexByName(string name, out int index)
+        {
+            if (_lookupByName.TryGetValue(name, out RegisterInfo info))
+            {
+                index = info.RegisterIndex;
+                return true;
+            }
+            index = int.MaxValue;
+            return false;
+        }
+
+        /// <summary>
+        /// Returns the register info (name, offset, size, etc).
+        /// </summary>
+        /// <param name="index">register index</param>
+        /// <param name="info">RegisterInfo</param>
+        /// <returns>true if index found</returns>
+        public bool GetRegisterInfo(int index, out RegisterInfo info)
+        {
+            return _lookupByIndex.TryGetValue(index, out info);
+        }
+
+        /// <summary>
+        /// Returns the register value for the thread and register index. This function
+        /// can only return register values that are 64 bits or less and currently the
+        /// clrmd data targets don't return any floating point or larger registers.
+        /// </summary>
+        /// <param name="threadId">thread id</param>
+        /// <param name="index">register index</param>
+        /// <param name="value">value returned</param>
+        /// <returns>true if value found</returns>
+        public unsafe bool GetRegisterValue(uint threadId, int index, out ulong value)
+        {
+            value = 0;
+
+            if (_lookupByIndex.TryGetValue(index, out RegisterInfo info))
+            {
+                byte[] threadContext = GetThreadContext(threadId);
+                if (threadContext != null)
+                {
+                    fixed (byte* ptr = threadContext)
+                    {
+                        switch (info.RegisterSize)
+                        {
+                            case 1:
+                                value = *((byte*)(ptr + info.RegisterOffset));
+                                return true;
+                            case 2:
+                                value = *((ushort*)(ptr + info.RegisterOffset));
+                                return true;
+                            case 4:
+                                value = *((uint*)(ptr + info.RegisterOffset));
+                                return true;
+                            case 8:
+                                value = *((ulong*)(ptr + info.RegisterOffset));
+                                return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        private unsafe byte[] GetThreadContext(uint threadId)
+        {
+            if (_threadContextCache.TryGetValue(threadId, out byte[] threadContext))
+            {
+                return threadContext;
+            }
+            else
+            {
+                threadContext = new byte[_contextSize];
+                fixed (byte* ptr = threadContext)
+                {
+                    if (_target.DataReader.GetThreadContext(threadId, _contextFlags, (uint)_contextSize, new IntPtr(ptr)))
+                    {
+                        _threadContextCache.Add(threadId, threadContext);
+                        return threadContext;
+                    }
+                }
+            }
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Diagnostics.DebugServices/ServiceProvider.cs b/src/Microsoft.Diagnostics.DebugServices/ServiceProvider.cs
new file mode 100644 (file)
index 0000000..c455629
--- /dev/null
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.Diagnostics.DebugServices
+{
+    public class ServiceProvider : IServiceProvider
+    {
+        readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
+        readonly Dictionary<Type, Func<object>> _factories = new Dictionary<Type, Func<object>>();
+
+        /// <summary>
+        /// Create a service provider instance
+        /// </summary>
+        public ServiceProvider()
+        {
+        }
+
+        /// <summary>
+        /// Add service factory
+        /// </summary>
+        /// <param name="type">service type</param>
+        /// <param name="factory">function to create service instance</param>
+        public void AddServiceFactory(Type type, Func<object> factory) => _factories.Add(type, factory);
+
+        /// <summary>
+        /// Adds a service or context to inject into an command.
+        /// </summary>
+        /// <typeparam name="T">type of service</typeparam>
+        /// <param name="instance">service instance</param>
+        public void AddService<T>(T instance) => AddService(typeof(T), instance);
+
+        /// <summary>
+        /// Add a service instance.
+        /// </summary>
+        /// <param name="type">service type</param>
+        /// <param name="service">instance</param>
+        public void AddService(Type type, object service) => _services.Add(type, service);
+
+        /// <summary>
+        /// Returns the instance of the service or returns null if service doesn't exist
+        /// </summary>
+        /// <param name="type">service type</param>
+        /// <returns>service instance or null</returns>
+        public object GetService(Type type)
+        {
+            if (!_services.TryGetValue(type, out object service))
+            {
+                if (_factories.TryGetValue(type, out Func<object> factory))
+                {
+                    service = factory();
+                    _services.Add(type, service);
+                }
+            }
+            return service;
+        }
+    }
+
+    public static class ServiceProviderExtensions
+    {
+        /// <summary>
+        /// Returns the instance of the service or returns null if service doesn't exist
+        /// </summary>
+        /// <typeparam name="T">service type</typeparam>
+        /// <returns>service instance or null</returns>
+        public static T GetService<T>(this IServiceProvider serviceProvider)
+        {
+            return (T)serviceProvider.GetService(typeof(T));
+        }
+    }
+}
index cf6238cec3a87cf215b36aa9318a648b69ca0c3d..5537cd031549e7d590d6c1823ab2b4045136ae03 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using System;
 using System.CommandLine;
 using System.CommandLine.Invocation;
@@ -21,9 +22,9 @@ namespace Microsoft.Diagnostics.Repl
         public InvocationContext InvocationContext { get; set; }
 
         /// <summary>
-        /// Console instance
+        /// Console service
         /// </summary>
-        public IConsole Console { get; set; }
+        public IConsoleService Console { get; set; }
 
         /// <summary>
         /// The AliasExpansion value from the CommandAttribute or null if none.
@@ -42,7 +43,7 @@ namespace Microsoft.Diagnostics.Repl
         /// <param name="message">text message</param>
         protected void WriteLine(string message)
         {
-            Console.Out.WriteLine(message);
+            Console.Write(message + Environment.NewLine);
         }
 
         /// <summary>
@@ -52,7 +53,17 @@ namespace Microsoft.Diagnostics.Repl
         /// <param name="args">arguments</param>
         protected void WriteLine(string format, params object[] args)
         {
-            Console.Out.WriteLine(string.Format(format, args));
+            Console.Write(string.Format(format, args) + Environment.NewLine);
+        }
+
+        /// <summary>
+        /// Display formatted error text
+        /// </summary>
+        /// <param name="format">format string</param>
+        /// <param name="args">arguments</param>
+        protected void WriteLineError(string format, params object[] args)
+        {
+            Console.WriteError(string.Format(format, args) + Environment.NewLine);
         }
     }
 }
\ No newline at end of file
index 4efec289e27cc90f58b1e5c0e608165314b099e0..745bca2a5472177bbb683a057e6cf2fe2cb9f28b 100644 (file)
@@ -3,10 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
-using System.Collections;
 using System.Collections.Generic;
 using System.CommandLine;
-using System.CommandLine.Binding;
 using System.CommandLine.Builder;
 using System.CommandLine.Invocation;
 using System.Diagnostics;
@@ -20,22 +18,24 @@ namespace Microsoft.Diagnostics.Repl
     {
         private readonly Parser _parser;
         private readonly Command _rootCommand;
-        private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
+        private readonly IServiceProvider _serviceProvider;
+        private readonly IConsole _console;
         private readonly Dictionary<string, Handler> _commandHandlers = new Dictionary<string, Handler>();
 
         /// <summary>
         /// Create an instance of the command processor;
         /// </summary>
-        /// <param name="console">console instance to use for commands</param>
+        /// <param name="serviceProvider">service provider interface</param>
+        /// <param name="console">console instance</param>
         /// <param name="assemblies">Optional list of assemblies to look for commands</param>
         /// <param name="types">Optional list of types to look for commands</param>
-        public CommandProcessor(IConsole console, IEnumerable<Assembly> assemblies = null, IEnumerable<Type> types = null)
+        public CommandProcessor(IServiceProvider serviceProvider, IConsole console, IEnumerable<Assembly> assemblies = null, IEnumerable<Type> types = null)
         {
-            Debug.Assert(console != null);
+            Debug.Assert(serviceProvider != null);
             Debug.Assert(assemblies != null);
-            _services.Add(typeof(CommandProcessor), this);
-            _services.Add(typeof(IConsole), console);
-            _services.Add(typeof(IHelpBuilder), new LocalHelpBuilder(this));
+            _serviceProvider = serviceProvider;
+            _console = console;
+
             var rootBuilder = new CommandLineBuilder(new Command(">"));
             rootBuilder.UseHelp()
                        .UseHelpBuilder((bindingContext) => GetService<IHelpBuilder>())
@@ -43,6 +43,7 @@ namespace Microsoft.Diagnostics.Repl
                        .UseSuggestDirective()
                        .UseParseErrorReporting()
                        .UseExceptionHandler();
+
             if (assemblies != null) {
                 BuildCommands(rootBuilder, assemblies);
             }
@@ -54,23 +55,11 @@ namespace Microsoft.Diagnostics.Repl
         }
 
         /// <summary>
-        /// Adds a service or context to inject into an command.
-        /// </summary>
-        /// <typeparam name="T">type of service</typeparam>
-        /// <param name="instance">service instance</param>
-        public void AddService<T>(T instance)
-        {
-            AddService(typeof(T), instance);
-        }
-
-        /// <summary>
-        /// Adds a service or context to inject into an command.
+        /// Creates a new instance of the command help builder
         /// </summary>
-        /// <param name="type">service type</param>
-        /// <param name="instance">service instance</param>
-        public void AddService(Type type, object instance)
+        public IHelpBuilder CreateHelpBuilder()
         {
-            _services.Add(type, instance);
+            return new LocalHelpBuilder(this);
         }
 
         /// <summary>
@@ -81,7 +70,7 @@ namespace Microsoft.Diagnostics.Repl
         public Task<int> Parse(string commandLine)
         {
             ParseResult result = _parser.Parse(commandLine);
-            return _parser.InvokeAsync(result, GetService<IConsole>());
+            return _parser.InvokeAsync(result, _console);
         }
 
         /// <summary>
@@ -188,11 +177,16 @@ namespace Microsoft.Diagnostics.Repl
             }
         }
 
+        private object GetService(Type serviceType)
+        {
+            return _serviceProvider.GetService(serviceType);
+        }
+
         private T GetService<T>()
         {
-            _services.TryGetValue(typeof(T), out object service);
+            T service = (T)_serviceProvider.GetService(typeof(T));
             Debug.Assert(service != null);
-            return (T)service;
+            return service;
         }
 
         private static string BuildAlias(string parameterName)
@@ -293,7 +287,8 @@ namespace Microsoft.Diagnostics.Repl
                     else 
                     {
                         Type propertyType = property.Property.PropertyType;
-                        if (TryGetService(propertyType, context, out object service)) {
+                        object service = GetService(propertyType, context);
+                        if (service != null) {
                             value = service;
                         }
                         else if (context != null && property.Option != null)
@@ -330,23 +325,23 @@ namespace Microsoft.Diagnostics.Repl
                 object[] arguments = new object[parameters.Length];
                 for (int i = 0; i < parameters.Length; i++) {
                     Type parameterType = parameters[i].ParameterType;
-                    // Ignoring false: the parameter will passed as null to allow for "optional"
-                    // services. The invoked method needs to check for possible null parameters.
-                    TryGetService(parameterType, context, out arguments[i]);
+                    // The parameter will passed as null to allow for "optional" services. The invoked 
+                    // method needs to check for possible null parameters.
+                    arguments[i] = GetService(parameterType, context);
                 }
                 return arguments;
             }
 
-            private bool TryGetService(Type type, InvocationContext context, out object service)
+            private object GetService(Type type, InvocationContext context)
             {
+                object service;
                 if (type == typeof(InvocationContext)) {
                     service = context;
                 }
-                else if (!_commandProcessor._services.TryGetValue(type, out service)) {
-                    service = null;
-                    return false;
+                else {
+                    service = _commandProcessor.GetService(type);
                 }
-                return true;
+                return service;
             }
         }
 
@@ -367,7 +362,7 @@ namespace Microsoft.Diagnostics.Repl
                         return;
                     }
                 }
-                var helpBuilder = new HelpBuilder(_commandProcessor.GetService<IConsole>(), maxWidth: Console.WindowWidth);
+                var helpBuilder = new HelpBuilder(_commandProcessor._console, maxWidth: Console.WindowWidth);
                 helpBuilder.Write(command);
             }
         }
index 71958b91736b0ed406f0beb6ea3c40d63d4dad34..c5399a1fa0e2f612a9f142b6df6133d782f4b75a 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using System;
 using System.Collections.Generic;
 using System.CommandLine;
@@ -12,7 +13,7 @@ using System.Threading.Tasks;
 
 namespace Microsoft.Diagnostics.Repl
 {
-    public sealed class ConsoleProvider : IConsole
+    public sealed class ConsoleProvider : IConsole, IConsoleService
     {
         private readonly List<StringBuilder> m_history;
 
@@ -120,12 +121,20 @@ namespace Microsoft.Diagnostics.Repl
             RefreshLine();
         }
 
+        /// <summary>
+        /// Writes a message with a new line to console.
+        /// </summary>
+        public void WriteLine(string format, params object[] parameters)
+        {
+            WriteLine(OutputType.Normal, format, parameters);
+        }
+
         /// <summary>
         /// Writes a message with a new line to console.
         /// </summary>
         public void WriteLine(OutputType type, string format, params object[] parameters)
         {
-            WriteOutput(type, string.Format(format + Environment.NewLine, parameters));
+            WriteOutput(type, string.Format(format, parameters) + Environment.NewLine);
         }
 
         /// <summary>
@@ -506,5 +515,15 @@ namespace Microsoft.Diagnostics.Repl
         }
 
         #endregion
+
+        #region IConsoleService
+
+        void IConsoleService.Write(string text) => WriteOutput(OutputType.Normal, text);
+
+        void IConsoleService.WriteError(string text) => WriteOutput(OutputType.Error, text);
+
+        void IConsoleService.Exit() => Stop();
+
+        #endregion
     }
 }
index caeb36fa6c68bd9630ede24b7ce55165f8d7b67a..a209fe5d32df45d228f57e690e6b9916e3359d2d 100644 (file)
@@ -13,4 +13,8 @@
     <PackageReference Include="System.CommandLine.Experimental" Version="$(SystemCommandLineExperimentalVersion)" />
   </ItemGroup>
   
+  <ItemGroup>
+    <ProjectReference Include="..\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj" />
+  </ItemGroup>
+  
 </Project>
diff --git a/src/SOS/SOS.Hosting/Amd64Context.cs b/src/SOS/SOS.Hosting/Amd64Context.cs
deleted file mode 100644 (file)
index 9eb3b26..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-namespace SOS
-{
-    [StructLayout(LayoutKind.Explicit)]
-    internal struct AMD64Context
-    {
-        [FieldOffset(0x0)]
-        public ulong P1Home;
-        [FieldOffset(0x8)]
-        public ulong P2Home;
-        [FieldOffset(0x10)]
-        public ulong P3Home;
-        [FieldOffset(0x18)]
-        public ulong P4Home;
-        [FieldOffset(0x20)]
-        public ulong P5Home;
-        [FieldOffset(0x28)]
-        public ulong P6Home;
-
-        [FieldOffset(0x30)]
-        public int ContextFlags;
-
-        [FieldOffset(0x34)]
-        public int MxCsr;
-
-        [FieldOffset(0x38)]
-        public short Cs;
-        [FieldOffset(0x3a)]
-        public short Ds;
-        [FieldOffset(0x3c)]
-        public short Es;
-        [FieldOffset(0x3e)]
-        public short Fs;
-        [FieldOffset(0x40)]
-        public short Gs;
-        [FieldOffset(0x42)]
-        public short Ss;
-        [FieldOffset(0x44)]
-        public int EFlags;
-
-        [FieldOffset(0x48)]
-        public ulong Dr0;
-        [FieldOffset(0x50)]
-        public ulong Dr1;
-        [FieldOffset(0x58)]
-        public ulong Dr2;
-        [FieldOffset(0x60)]
-        public ulong Dr3;
-        [FieldOffset(0x68)]
-        public ulong Dr6;
-        [FieldOffset(0x70)]
-        public ulong Dr7;
-
-        [FieldOffset(0x78)]
-        public ulong Rax;
-        [FieldOffset(0x80)]
-        public ulong Rcx;
-        [FieldOffset(0x88)]
-        public ulong Rdx;
-        [FieldOffset(0x90)]
-        public ulong Rbx;
-        [FieldOffset(0x98)]
-        public ulong Rsp;
-        [FieldOffset(0xa0)]
-        public ulong Rbp;
-        [FieldOffset(0xa8)]
-        public ulong Rsi;
-        [FieldOffset(0xb0)]
-        public ulong Rdi;
-        [FieldOffset(0xb8)]
-        public ulong R8;
-        [FieldOffset(0xc0)]
-        public ulong R9;
-        [FieldOffset(0xc8)]
-        public ulong R10;
-        [FieldOffset(0xd0)]
-        public ulong R11;
-        [FieldOffset(0xd8)]
-        public ulong R12;
-        [FieldOffset(0xe0)]
-        public ulong R13;
-        [FieldOffset(0xe8)]
-        public ulong R14;
-        [FieldOffset(0xf0)]
-        public ulong R15;
-
-        [FieldOffset(0xf8)]
-        public ulong Rip;
-
-        //[FieldOffset(0x100)]
-        //public XmmSaveArea FltSave;
-
-        //[FieldOffset(0x300)]
-        //public VectorRegisterArea VectorRegisters;
-
-        [FieldOffset(0x4a8)]
-        public ulong DebugControl;
-        [FieldOffset(0x4b0)]
-        public ulong LastBranchToRip;
-        [FieldOffset(0x4b8)]
-        public ulong LastBranchFromRip;
-        [FieldOffset(0x4c0)]
-        public ulong LastExceptionToRip;
-        [FieldOffset(0x4c8)]
-        public ulong LastExceptionFromRip;
-
-        public static int Size => Marshal.SizeOf(typeof(AMD64Context));
-    }
-}
\ No newline at end of file
diff --git a/src/SOS/SOS.Hosting/ISOSHostContext.cs b/src/SOS/SOS.Hosting/ISOSHostContext.cs
deleted file mode 100644 (file)
index 3157a30..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-
-namespace SOS
-{
-    /// <summary>
-    /// Context/services provided to the SOS host.
-    /// </summary>
-    public interface ISOSHostContext
-    {
-        /// <summary>
-        /// Display text on the console
-        /// </summary>
-        /// <param name="text">message</param>
-        void Write(string text);
-
-        /// <summary>
-        /// Get/set the current native thread id
-        /// </summary>
-        int CurrentThreadId { get; set; }
-
-        /// <summary>
-        /// Cancellation token for current operation
-        /// </summary>
-        CancellationToken CancellationToken { get; }
-    }
-}
\ No newline at end of file
index 2423e3f9fd66d8c0df51df4f168d7db1e442b202..8f5425bdfc6c38d18717d982d04dc349f2129405 100644 (file)
@@ -152,9 +152,11 @@ namespace SOS
         int GetValueByName(
             IntPtr self,
             string name,
-            out ulong value)
+            out UIntPtr value)
         {
-            return _soshost.GetRegister(name, out value);
+            int hr = _soshost.GetRegister(name, out ulong register);
+            value = new UIntPtr(register);
+            return hr;
         }
 
         #endregion 
@@ -202,7 +204,7 @@ namespace SOS
             IntPtr self);
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        private delegate ulong GetExpressionDelegate(
+        private delegate UIntPtr GetExpressionDelegate(
             IntPtr self,
             [In][MarshalAs(UnmanagedType.LPStr)] string text);
 
@@ -434,7 +436,7 @@ namespace SOS
         private delegate int GetValueByNameDelegate(
             IntPtr self,
             [In, MarshalAs(UnmanagedType.LPStr)] string name,
-            out ulong value);
+            out UIntPtr value);
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
         private delegate int GetInstructionOffsetDelegate(
index a3d1587468809d561d3a9421b74bb1962c3b910e..8cb3f77efa9b246b28f311a30a2d2807622d8aff 100644 (file)
@@ -15,5 +15,6 @@
   <ItemGroup>
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\SOS.NETCore\SOS.NETCore.csproj" />
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\SOS.InstallHelper\SOS.InstallHelper.csproj" />
+    <ProjectReference Include="..\..\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj" />
   </ItemGroup>
 </Project>
index 6491c83e314b78bd36dd3ce063e1f4d5f42c2e2e..6425ec1db56c9cac96dd15a90d2b3bf1aec1f524 100644 (file)
@@ -2,11 +2,11 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Runtime;
 using Microsoft.Diagnostics.Runtime.Interop;
 using Microsoft.Diagnostics.Runtime.Utilities;
 using System;
-using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO;
@@ -43,7 +43,7 @@ namespace SOS
             bool symbolStoreEnabled);
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        private delegate ulong GetExpressionDelegate(
+        private delegate UIntPtr GetExpressionDelegate(
             [In, MarshalAs(UnmanagedType.LPStr)] string expression);
 
         private const string SOSInitialize = "SOSInitializeByHost";
@@ -149,12 +149,12 @@ namespace SOS
         };
 
         internal readonly IDataReader DataReader;
-        internal readonly ISOSHostContext SOSHostContext;
 
         private static readonly string s_coreclrModuleName;
-        private static readonly Dictionary<string, int> s_registersByName;
-        private static readonly int[] s_registerOffsets;
 
+        private readonly AnalyzeContext _analyzeContext;
+        private readonly RegisterService _registerService;
+        private readonly IConsoleService _console;
         private readonly COMCallableIUnknown _ccw;  
         private readonly IntPtr _interface;
         private IntPtr _sosLibrary = IntPtr.Zero;
@@ -176,23 +176,6 @@ namespace SOS
             else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
                 s_coreclrModuleName = "libcoreclr.dylib";
             }
-
-            // TODO: Support other architectures
-            Type contextType = typeof(AMD64Context);
-            var registerNames = new Dictionary<string, int>();
-            var offsets = new List<int>();
-            int index = 0;
-
-            FieldInfo[] fields = contextType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);
-            foreach (FieldInfo field in fields) {
-                registerNames.Add(field.Name.ToLower(), index);
-
-                FieldOffsetAttribute attribute = field.GetCustomAttributes<FieldOffsetAttribute>(inherit: false).Single();
-                offsets.Insert(index, attribute.Value);
-                index++;
-            }
-            s_registersByName = registerNames;
-            s_registerOffsets = offsets.ToArray();
         }
 
         /// <summary>
@@ -203,10 +186,14 @@ namespace SOS
         /// <summary>
         /// Create an instance of the hosting class
         /// </summary>
-        public SOSHost(IDataReader dataReader, ISOSHostContext context)
+        public SOSHost(IServiceProvider serviceProvider)
         {
-            DataReader = dataReader;
-            SOSHostContext = context;
+            DataTarget dataTarget = serviceProvider.GetService<DataTarget>();
+            DataReader = dataTarget.DataReader;
+            _console = serviceProvider.GetService<IConsoleService>();
+            _analyzeContext = serviceProvider.GetService<AnalyzeContext>();
+            _registerService = serviceProvider.GetService<RegisterService>();
+
             string rid = InstallHelper.GetRid();
             SOSPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), rid);
             if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -325,23 +312,23 @@ namespace SOS
 
         #region Reverse PInvoke Implementations
 
-        internal static ulong GetExpression(
+        internal static UIntPtr GetExpression(
             string expression)
         {
             if (expression != null)
             {
                 if (ulong.TryParse(expression.Replace("0x", ""), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong result))
                 {
-                    return result;
+                    return new UIntPtr(result);
                 }
             }
-            return 0;
+            return UIntPtr.Zero;
         }
 
         internal int GetInterrupt(
             IntPtr self)
         {
-            return SOSHostContext.CancellationToken.IsCancellationRequested ? S_OK : E_FAIL;
+            return _analyzeContext.CancellationToken.IsCancellationRequested ? S_OK : E_FAIL;
         }
 
         internal int OutputVaList(
@@ -353,7 +340,7 @@ namespace SOS
             try
             {
                 // The text has already been formated by sos
-                SOSHostContext.Write(format);
+                _console.Write(format);
             }
             catch (OperationCanceledException)
             {
@@ -401,7 +388,10 @@ namespace SOS
                     *type = IMAGE_FILE_MACHINE.I386;
                     break;
                 case Microsoft.Diagnostics.Runtime.Architecture.Arm:
-                    *type = IMAGE_FILE_MACHINE.ARM;
+                    *type = IMAGE_FILE_MACHINE.THUMB2;
+                    break;
+                case Microsoft.Diagnostics.Runtime.Architecture.Arm64:
+                    *type = IMAGE_FILE_MACHINE.ARM64;
                     break;
                 default:
                     *type = IMAGE_FILE_MACHINE.UNKNOWN;
@@ -706,7 +696,7 @@ namespace SOS
             IntPtr context,
             uint contextSize)
         {
-            uint threadId = (uint)SOSHostContext.CurrentThreadId;
+            uint threadId = (uint)_analyzeContext.CurrentThreadId;
             if (!DataReader.GetThreadContext(threadId, uint.MaxValue, contextSize, context)) {
                 return E_FAIL;
             }
@@ -754,7 +744,7 @@ namespace SOS
             IntPtr self,
             out uint id)
         {
-            return GetThreadIdBySystemId(self, (uint)SOSHostContext.CurrentThreadId, out id);
+            return GetThreadIdBySystemId(self, (uint)_analyzeContext.CurrentThreadId, out id);
         }
 
         internal int SetCurrentThreadId(
@@ -764,7 +754,7 @@ namespace SOS
             try
             {
                 unchecked {
-                    SOSHostContext.CurrentThreadId = (int)DataReader.EnumerateAllThreads().ElementAt((int)id);
+                    _analyzeContext.CurrentThreadId = (int)DataReader.EnumerateAllThreads().ElementAt((int)id);
                 }
             }
             catch (ArgumentOutOfRangeException)
@@ -778,7 +768,7 @@ namespace SOS
             IntPtr self,
             out uint sysId)
         {
-            sysId = (uint)SOSHostContext.CurrentThreadId;
+            sysId = (uint)_analyzeContext.CurrentThreadId;
             return S_OK;
         }
 
@@ -834,7 +824,7 @@ namespace SOS
             IntPtr self,
             ulong* offset)
         {
-            uint threadId = (uint)SOSHostContext.CurrentThreadId;
+            uint threadId = (uint)_analyzeContext.CurrentThreadId;
             ulong teb = DataReader.GetThreadTeb(threadId);
             Write(offset, teb);
             return S_OK;
@@ -844,24 +834,21 @@ namespace SOS
             IntPtr self,
             out ulong offset)
         {
-            // TODO: Support other architectures
-            return GetRegister("rip", out offset);
+            return GetRegister(_registerService.InstructionPointerIndex, out offset);
         }
 
         internal int GetStackOffset(
             IntPtr self,
             out ulong offset)
         {
-            // TODO: Support other architectures
-            return GetRegister("rsp", out offset);
+            return GetRegister(_registerService.StackPointerIndex, out offset);
         }
 
         internal int GetFrameOffset(
             IntPtr self,
             out ulong offset)
         {
-            // TODO: Support other architectures
-            return GetRegister("rbp", out offset);
+            return GetRegister(_registerService.FramePointerIndex, out offset);
         }
 
         internal int GetIndexByName(
@@ -869,7 +856,7 @@ namespace SOS
             string name,
             out uint index)
         {
-            if (!s_registersByName.TryGetValue(name, out int value)) {
+            if (_registerService.GetRegisterIndexByName(name, out int value)) {
                 index = 0;
                 return E_INVALIDARG;
             }
@@ -882,46 +869,52 @@ namespace SOS
             uint register,
             out DEBUG_VALUE value)
         {
-            return GetRegister((int)register, out value);
+            int hr = GetRegister((int)register, out ulong offset);
+
+            // SOS expects the DEBUG_VALUE field to be set based on the 
+            // processor architecture instead of the register size.
+            switch (DataReader.GetPointerSize())
+            {
+                case 8:
+                    value = new DEBUG_VALUE {
+                        Type = DEBUG_VALUE_TYPE.INT64,
+                        I64 = offset
+                    };
+                    break;
+
+                case 4:
+                    value = new DEBUG_VALUE {
+                        Type = DEBUG_VALUE_TYPE.INT32,
+                        I32 = (uint)offset
+                    };
+                    break;
+
+                default:
+                    value = new DEBUG_VALUE();
+                    hr = E_FAIL;
+                    break;
+            }
+            return hr;
         }
 
-        internal unsafe int GetRegister(
+        internal int GetRegister(
             string register,
             out ulong value)
         {
             value = 0;
-            if (!s_registersByName.TryGetValue(register, out int index)) {
+            if (!_registerService.GetRegisterIndexByName(register, out int index)) {
                 return E_INVALIDARG;
             }
-            int hr = GetRegister(index, out DEBUG_VALUE debugValue);
-            if (hr != S_OK) {
-                return hr;
-            }
-            // TODO: Support other architectures
-            value = debugValue.I64;
-            return S_OK;
+            return GetRegister(index, out value);
         }
 
-        internal unsafe int GetRegister(
+        internal int GetRegister(
             int index, 
-            out DEBUG_VALUE value)
+            out ulong value)
         {
-            value = new DEBUG_VALUE();
-
-            if (index >= s_registerOffsets.Length) {
-                return E_INVALIDARG;
-            }
-            uint threadId = (uint)SOSHostContext.CurrentThreadId;
-
-            // TODO: Support other architectures
-            byte[] buffer = new byte[AMD64Context.Size];
-            fixed (byte* ptr = buffer)
-            {
-                if (!DataReader.GetThreadContext(threadId, uint.MaxValue, (uint)AMD64Context.Size, new IntPtr(ptr))) {
-                    return E_FAIL;
-                }
-                int offset = s_registerOffsets[index];
-                value.I64 = *((ulong*)(ptr + offset));
+            uint threadId = (uint)_analyzeContext.CurrentThreadId;
+            if (!_registerService.GetRegisterValue(threadId, index, out value)) {
+                return E_FAIL;
             }
             return S_OK;
         }
index c0eb3e897debf074aeaa82cf57d22af9fdf2aef9..731e2742937fbaf4a57022bf1834b02a9f560f76 100644 (file)
@@ -330,7 +330,7 @@ namespace SOS
             {
                 throw new SOSInstallerException($"Unsupported operating system {RuntimeInformation.OSDescription}");
             }
-            string architecture = RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant();
+            string architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
             return $"{os}-{architecture}";
         }
 
index 8db30a6c6c4a2c54bfc4bce68033cb79478d97a6..4dcb14146aa9b52ff655ddd031b4828a83fe9b91 100644 (file)
@@ -22,7 +22,6 @@ public class SOS
     ITestOutputHelper Output { get; set; }
 
     public static IEnumerable<object[]> Configurations => TestRunConfiguration.Instance.Configurations.Select(c => new[] { c });
-
     private void SkipIfArm(TestConfiguration config)
     {
         if (config.TargetArchitecture == "arm" || config.TargetArchitecture == "arm64")
@@ -48,8 +47,6 @@ public class SOS
 
     private async Task RunTest(TestConfiguration config, string testName, string debuggeeName, string scriptName, string debuggeeArguments = null, bool useCreateDump = true)
     {
-        SkipIfArm(config);
-
         if (!SOSRunner.IsAlpine())
         {
             // Live
@@ -101,8 +98,9 @@ public class SOS
     [SkippableTheory, MemberData(nameof(Configurations))]
     public async Task GCTests(TestConfiguration config)
     {
-        // Live only
         SkipIfArm(config);
+
+        // Live only
         if (SOSRunner.IsAlpine())
         {
             throw new SkipTestException("lldb tests not supported on Alpine");
@@ -153,7 +151,6 @@ public class SOS
     [SkippableTheory, MemberData(nameof(Configurations))]
     public async Task StackAndOtherTests(TestConfiguration config)
     {
-        SkipIfArm(config);
         if (config.RuntimeFrameworkVersionMajor == 1)
         {
             throw new SkipTestException("The debuggee (SymbolTestApp) doesn't work on .NET Core 1.1 because of a AssemblyLoadContext problem");
index ac2ec47fedfb33cc115c8b699e6c0ce912f0527c..51d3cdc826ae6f8a2f425ec8b39a05140fc77afe 100644 (file)
@@ -54,12 +54,37 @@ IFDEF:PROJECTK
 SOSCOMMAND:ClrStack -r
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
 VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo4\(System\.String\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 54\]\s*
-VERIFY:\s+[r|e]sp=<HEXVAL>\s+[r|e]bp=<HEXVAL>\s+[r|e]ip=<HEXVAL>\s+
-VERIFY:\s+|r|e]ax=<HEXVAL>\s+[r|e]bx=<HEXVAL>\s+[r|e]cx=<HEXVAL>\s+
+IFDEF:arm
+VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
+ENDIF:arm
+IFDEF:arm64
+VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
+ENDIF:arm64
+VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
+IFDEF:x64
+VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
+ENDIF:x64
+IFDEF:x86
+VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
+ENDIF:x86
+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo2\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 29\]\s*
-VERIFY:\s+[r|e]sp=<HEXVAL>\s+[r|e]bp=<HEXVAL>\s+[r|e]ip=<HEXVAL>\s+
-VERIFY:\s+[r|e]ax=<HEXVAL>\s+[r|e]bx=<HEXVAL>\s+[r|e]cx=<HEXVAL>\s+
+IFDEF:arm
+VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
+ENDIF:arm
+IFDEF:arm64
+VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
+ENDIF:arm64
+VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
+IFDEF:x64
+VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
+ENDIF:x64
+IFDEF:x86
+VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
+ENDIF:x86
+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Foo1\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 24\]\s*
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s*
 ENDIF:PROJECTK
@@ -100,7 +125,7 @@ ENDIF:PROJECTK
 IFDEF:PROJECTK
 SOSCOMMAND:DumpStackObjects
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:\s+[R|E]SP/REG\s+Object\s+Name\s+
+VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String\[\].*
 ENDIF:PROJECTK
@@ -109,7 +134,7 @@ ENDIF:PROJECTK
 IFDEF:PROJECTK
 SOSCOMMAND:DumpStackObjects -verify
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:\s+[R|E]SP/REG\s+Object\s+Name\s+
+VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String\[\].*
 ENDIF:PROJECTK
@@ -117,26 +142,28 @@ ENDIF:PROJECTK
 ENDIF:ALPINE
 
 !IFDEF:DOTNETDUMP
+!IFDEF:arm
 IFDEF:PROJECTK
 
 # Verify DumpStack works
 SOSCOMMAND:DumpStack
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo4\(System\.String\)\),\s+calling.*\s+)|(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo2\(Int32, System\.String\)\),\s+calling.*\s+)
 
 # Verify DumpStack -EE works
 SOSCOMMAND:DumpStack -EE
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo4\(System\.String\)\)\s+)|(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo2\(Int32, System\.String\)\)\s+)
 
 # Verify EEStack works
 SOSCOMMAND:EEStack
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo4\(System\.String\)\),\s+calling.*\s+)|(.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+(\+\s*0x<HEXVAL>\s+)?SymbolTestApp\.Program\.Foo2\(Int32, System\.String\)\),\s+calling.*\s+)
 
 ENDIF:PROJECTK
+ENDIF:arm
 ENDIF:DOTNETDUMP
 
 # Verify that IP2MD works (uses IP from ClrStack)
index 115509c26d3ee82730b4a20e0ecde666f95de4bb..c4535a5be939a0bf9e6a4a2a840dd976f22a8248 100644 (file)
@@ -56,13 +56,37 @@ IFDEF:PROJECTK
 SOSCOMMAND:ClrStack -r
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
 VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
+
 VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 8\s*\]\s+
-VERIFY:\s+[r|e]sp=<HEXVAL>\s+[r|e]bp=<HEXVAL>\s+[r|e]ip=<HEXVAL>\s+
-VERIFY:\s+[r|e]ax=<HEXVAL>\s+[r|e]bx=<HEXVAL>\s+[r|e]cx=<HEXVAL>\s+
+IFDEF:arm
+VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
+ENDIF:arm
+IFDEF:arm64
+VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
+ENDIF:arm64
+VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
+IFDEF:x64
+VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
+ENDIF:x64
+IFDEF:x86
+VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
+ENDIF:x86
+
 IFDEF:64BIT
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]NestedExceptionTest\.cs) @ 13\s*\]\s+
-VERIFY:\s+[r|e]sp=<HEXVAL>\s+[r|e]bp=<HEXVAL>\s+[r|e]ip=<HEXVAL>\s+
-VERIFY:\s+[r|e]ax=<HEXVAL>\s+[r|e]bx=<HEXVAL>\s+[r|e]cx=<HEXVAL>\s+
+IFDEF:arm
+VERIFY:\s+r0=<HEXVAL>\s+r1=<HEXVAL>\s+r2=<HEXVAL>\s+
+ENDIF:arm
+IFDEF:arm64
+VERIFY:\s+x0=<HEXVAL>\s+x1=<HEXVAL>\s+x2=<HEXVAL>\s+
+ENDIF:arm64
+VERIFY:\s+([r|e]sp|sp)=<HEXVAL>\s+([r|e]bp|lr)=<HEXVAL>\s+([r|e]ip|pc)=<HEXVAL>\s+
+IFDEF:x64
+VERIFY:\s+rax=<HEXVAL>\s+rbx=<HEXVAL>\s+rcx=<HEXVAL>\s+
+ENDIF:x64
+IFDEF:x86
+VERIFY:\s+eax=<HEXVAL>\s+ebx=<HEXVAL>\s+ecx=<HEXVAL>\s+
+ENDIF:x86
 ENDIF:64BIT
 ENDIF:PROJECTK
 
@@ -96,7 +120,7 @@ ENDIF:ALPINE
 IFDEF:PROJECTK
 SOSCOMMAND:DumpStackObjects
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:\s+[R|E]SP/REG\s+Object\s+Name\s+
+VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.FormatException\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.InvalidOperationException\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*
@@ -106,29 +130,31 @@ ENDIF:PROJECTK
 IFDEF:PROJECTK
 SOSCOMMAND:DumpStackObjects -verify
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:\s+[R|E]SP/REG\s+Object\s+Name\s+
+VERIFY:\s+([R|E])*SP/REG\s+Object\s+Name\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.FormatException\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.InvalidOperationException\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+System\.String.*
 ENDIF:PROJECTK
 
 !IFDEF:DOTNETDUMP
+!IFDEF:arm
 
 # 9) Verify DumpStack works
 SOSCOMMAND:DumpStack
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+\+\s*0x<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(System\.String\[\]\)\),\s+calling.*
 
 # 10) Verify DumpStack -EE works
 SOSCOMMAND:DumpStack -EE
 VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+\+\s*0x<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(System\.String\[\]\)\)\s+
 
 # 11) Verify EEStack works
 SOSCOMMAND:EEStack
-VERIFY:.*Child(-SP|EBP)\s+RetAddr\s+Caller, Callee\s+
+VERIFY:.*Child(-SP|EBP|FP)\s+RetAddr\s+Caller, Callee\s+
 VERIFY:.*\s+<HEXVAL>\s+<HEXVAL>\s+\(MethodDesc\s+<HEXVAL>\s+\+\s*0x<HEXVAL>\s+NestedExceptionTest\.Program\.Main\(System\.String\[\]\)\),\s+calling.*
 
+ENDIF:arm
 ENDIF:DOTNETDUMP
index ed40770d0c26fce244b636c52eb9d86a733f24d3..ef84f746906ef080ae74d8fbeb227d24d2b8d428 100644 (file)
@@ -125,9 +125,13 @@ ArchQuery(void)
     }
 #endif // SOS_TARGET_X86
 #ifdef SOS_TARGET_ARM
-    if (targetArchitecture == IMAGE_FILE_MACHINE_ARMNT)
+    switch (targetArchitecture)
     {
-        targetMachine = ARMMachine::GetInstance();
+        case IMAGE_FILE_MACHINE_ARM:
+        case IMAGE_FILE_MACHINE_THUMB:
+        case IMAGE_FILE_MACHINE_ARMNT:
+            targetMachine = ARMMachine::GetInstance();
+            break;
     }
 #endif // SOS_TARGET_ARM
 #ifdef SOS_TARGET_ARM64
@@ -140,7 +144,7 @@ ArchQuery(void)
     if (targetMachine == NULL)
     {
         g_targetMachine = NULL;
-        ExtErr("SOS does not support the current target architecture 0x%llx.\n", targetArchitecture);
+        ExtErr("SOS does not support the current target architecture 0x%08x\n", targetArchitecture);
         return E_FAIL;
     }
 
index dfc0dcfea411fb9f962fe51f91ddf684529d4524..13e62f39a045c32b117aca5e8fec14da7f178ded 100644 (file)
 #define INITGUID
 #include "guiddef.h"
 
-#ifdef FEATURE_PAL
 #define SOS_PTR(x) (size_t)(x)
-#else // FEATURE_PAL
-#define SOS_PTR(x) (unsigned __int64)(x)
-#endif // FEATURE_PAL else
 
 #include "exts.h"
 
index 651950af0506151af858c87a46294f41ac0eb2d3..049f5e81e1b3470b08a385e91e8844aac852d26f 100644 (file)
 #define STRESS_LOG_READONLY
 #include "stresslog.h"
 
-#ifndef FEATURE_PAL
-#define MAX_SYMBOL_LEN 4096
-#define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL) + MAX_SYMBOL_LEN)
-char symBuffer[SYM_BUFFER_SIZE];
-PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) symBuffer;
-#else
+#ifdef FEATURE_PAL
 #include <sys/stat.h>
 #include <dlfcn.h>
 #endif // !FEATURE_PAL
@@ -4805,28 +4800,44 @@ size_t CountHexCharacters(CLRDATA_ADDRESS val)
     return ret;
 } 
 
+// SOS is single threaded so a global buffer doesn't need any locking
+char g_printBuffer[8192];
+
+//---------------------------------------------------------------------
+// Because debuggers and hosts SOS runs on now output formatting always
+// happens with the C++ runtime functions and not dbgeng. This means
+// the special dbgeng formatting charaters are not supported: %N, %I,
+// %ma, %mu, %msa, %msu, %y, %ly and %p takes an architecture size 
+// pointer (size_t) instead of always a 64bit one.
+//---------------------------------------------------------------------
+
 HRESULT 
 OutputVaList(
     ULONG mask,
     PCSTR format,
     va_list args)
 {
-#ifndef FEATURE_PAL
-    if (IsInitializedByDbgEng())
+    int length = _vsnprintf_s((char* const)&g_printBuffer, sizeof(g_printBuffer), _TRUNCATE, format, args);
+    if (length > 0)
     {
-        return g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, format, args);
+        return g_ExtControl->OutputVaList(mask, (char* const)&g_printBuffer, args);
     }
-    else
-#endif
+    return E_FAIL;
+}
+
+HRESULT 
+ControlledOutputVaList(
+    ULONG outputControl,
+    ULONG mask,
+    PCSTR format,
+    va_list args)
+{
+    int length = _vsnprintf_s((char* const)&g_printBuffer, sizeof(g_printBuffer), _TRUNCATE, format, args);
+    if (length > 0)
     {
-        ArrayHolder<char> str = new char[8192];
-        int length = _vsnprintf_s(str, 8192, _TRUNCATE, format, args);
-        if (length > 0)
-        {
-            return g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, str, args);
-        }
-        return E_FAIL;
+        return g_ExtControl->ControlledOutputVaList(outputControl, mask, (char* const)&g_printBuffer, args);
     }
+    return E_FAIL;
 }
 
 HRESULT 
@@ -4870,13 +4881,11 @@ void DMLOut(PCSTR format, ...)
     va_start(args, format);
     ExtOutIndent();
 
-#ifndef FEATURE_PAL
     if (IsDMLEnabled() && !Output::IsDMLExposed())
     {
-        g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
+        ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
     }
     else
-#endif
     {
         OutputVaList(DEBUG_OUTPUT_NORMAL, format, args);
     }
@@ -4886,7 +4895,6 @@ void DMLOut(PCSTR format, ...)
 
 void IfDMLOut(PCSTR format, ...)
 {
-#ifndef FEATURE_PAL
     if (Output::IsOutputSuppressed() || !IsDMLEnabled())
         return;
 
@@ -4896,7 +4904,6 @@ void IfDMLOut(PCSTR format, ...)
     ExtOutIndent();
     g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
     va_end(args);
-#endif
 }
 
 void ExtOut(PCSTR Format, ...)
index 4379aabb2a2332bb00cac831941b9d6612789e08..13f37988ef8de4e01cc64e6e5e055c93a61c1051 100644 (file)
@@ -60,24 +60,6 @@ public:
         return m_lldbservices->GetInterrupt();
     }
 
-    // Sends output through clients
-    // output callbacks if the mask is allowed
-    // by the current output control mask and
-    // according to the output distribution
-    // settings.
-    HRESULT 
-    Output(
-        ULONG mask,
-        PCSTR format,
-        ...)
-    {
-        va_list args;
-        va_start (args, format);
-        HRESULT result = OutputVaList(mask, format, args);
-        va_end (args);
-        return result;
-    }
-
     HRESULT 
     OutputVaList(
         ULONG mask,
@@ -87,26 +69,6 @@ public:
         return m_lldbservices->OutputVaList(mask, format, args);
     }
 
-    // The following methods allow direct control
-    // over the distribution of the given output
-    // for situations where something other than
-    // the default is desired.  These methods require
-    // extra work in the engine so they should
-    // only be used when necessary.
-    HRESULT 
-    ControlledOutput(
-        ULONG outputControl,
-        ULONG mask,
-        PCSTR format,
-        ...)
-    {
-        va_list args;
-        va_start (args, format);
-        HRESULT result = ControlledOutputVaList(outputControl, mask, format, args);
-        va_end (args);
-        return result;
-    }
-
     HRESULT 
     ControlledOutputVaList(
         ULONG outputControl,
index 69c78e62f7d0a353283d157425479aed92f3de87..881e4387e7c92ef3c32b134523dae6ca32be4c4b 100644 (file)
@@ -41,6 +41,9 @@ extern "C" {
 // Symbol messages, such as for !sym noisy.
 #define DEBUG_OUTPUT_SYMBOLS           0x00000200
 
+#define DEBUG_OUTCTL_DML               0x00000020
+#define DEBUG_OUTCTL_AMBIENT_DML       0xfffffffe
+
 // Execute and ExecuteCommandFile flags.
 // These flags only apply to the command
 // text itself; output from the executed
index 22eb1cda53263a74747228d69d01ff770602062e..76e2e792a615dc5bbf11c21f5ebd1111c4e689f9 100644 (file)
@@ -336,23 +336,10 @@ LLDBServices::Output(
 {
     va_list args;
     va_start (args, format);
-    HRESULT result = OutputVaList(mask, format, args);
-    va_end (args);
-    return result;
-}
 
-HRESULT 
-LLDBServices::OutputVaList(
-    ULONG mask,
-    PCSTR format,
-    va_list args)
-{
     HRESULT result = S_OK;
     char str[1024];
 
-    va_list args_copy;
-    va_copy (args_copy, args);
-
     // Try and format our string into a fixed buffer first and see if it fits
     size_t length = ::vsnprintf(str, sizeof(str), format, args);
     if (length < sizeof(str))
@@ -364,7 +351,7 @@ LLDBServices::OutputVaList(
         // Our stack buffer wasn't big enough to contain the entire formatted
         // string, so lets let vasprintf create the string for us!
         char *str_ptr = nullptr;
-        length = ::vasprintf(&str_ptr, format, args_copy);
+        length = ::vasprintf(&str_ptr, format, args);
         if (str_ptr)
         {
             OutputString(mask, str_ptr);
@@ -376,11 +363,21 @@ LLDBServices::OutputVaList(
         }
     }
 
-    va_end (args_copy);
-
+    va_end (args);
     return result;
 }
 
+HRESULT 
+LLDBServices::OutputVaList(
+    ULONG mask,
+    PCSTR format,
+    va_list args)
+{
+    // Just output the string; ignore args. It is always formatted by SOS.
+    OutputString(mask, format);
+    return S_OK;
+}
+
 // The following methods allow direct control
 // over the distribution of the given output
 // for situations where something other than
@@ -1603,6 +1600,42 @@ LLDBServices::GetContextFromFrame(
     dtcontext->R10 = GetRegister(frame, "r10");
     dtcontext->R11 = GetRegister(frame, "r11");
     dtcontext->R12 = GetRegister(frame, "r12");
+#elif DBG_TARGET_ARM64
+    dtcontext->Pc = frame.GetPC();
+    dtcontext->Sp = frame.GetSP();
+    dtcontext->Lr = GetRegister(frame, "x30");
+    dtcontext->Fp = GetRegister(frame, "x29");
+    dtcontext->Cpsr = GetRegister(frame, "cpsr");
+
+    dtcontext->X0 = GetRegister(frame, "x0");
+    dtcontext->X1 = GetRegister(frame, "x1");
+    dtcontext->X2 = GetRegister(frame, "x2");
+    dtcontext->X3 = GetRegister(frame, "x3");
+    dtcontext->X4 = GetRegister(frame, "x4");
+    dtcontext->X5 = GetRegister(frame, "x5");
+    dtcontext->X6 = GetRegister(frame, "x6");
+    dtcontext->X7 = GetRegister(frame, "x7");
+    dtcontext->X8 = GetRegister(frame, "x8");
+    dtcontext->X9 = GetRegister(frame, "x9");
+    dtcontext->X10 = GetRegister(frame, "x10");
+    dtcontext->X11 = GetRegister(frame, "x11");
+    dtcontext->X12 = GetRegister(frame, "x12");
+    dtcontext->X13 = GetRegister(frame, "x13");
+    dtcontext->X14 = GetRegister(frame, "x14");
+    dtcontext->X15 = GetRegister(frame, "x15");
+    dtcontext->X16 = GetRegister(frame, "x16");
+    dtcontext->X17 = GetRegister(frame, "x17");
+    dtcontext->X18 = GetRegister(frame, "x18");
+    dtcontext->X19 = GetRegister(frame, "x19");
+    dtcontext->X20 = GetRegister(frame, "x20");
+    dtcontext->X21 = GetRegister(frame, "x21");
+    dtcontext->X22 = GetRegister(frame, "x22");
+    dtcontext->X23 = GetRegister(frame, "x23");
+    dtcontext->X24 = GetRegister(frame, "x24");
+    dtcontext->X25 = GetRegister(frame, "x25");
+    dtcontext->X26 = GetRegister(frame, "x26");
+    dtcontext->X27 = GetRegister(frame, "x27");
+    dtcontext->X28 = GetRegister(frame, "x28");
 #elif DBG_TARGET_X86
     dtcontext->Eip = frame.GetPC();
     dtcontext->Esp = frame.GetSP();
diff --git a/src/Tools/dotnet-dump/AnalyzeContext.cs b/src/Tools/dotnet-dump/AnalyzeContext.cs
deleted file mode 100644 (file)
index fae01c0..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Runtime;
-using Microsoft.SymbolStore;
-using Microsoft.SymbolStore.KeyGenerators;
-using SOS;
-using System;
-using System.Collections.Generic;
-using System.CommandLine;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-namespace Microsoft.Diagnostics.Tools.Dump
-{
-    /// <summary>
-    /// The the common context for analyze commands
-    /// </summary>
-    public class AnalyzeContext: ISOSHostContext
-    {
-        private readonly IConsole _console;
-        private ClrRuntime _runtime;
-
-        private static SOSHost s_sosHost;
-        private static string s_tempDirectory;
-        private static string s_dacFilePath;
-
-        public AnalyzeContext(IConsole console, DataTarget target)
-        {
-            _console = console;
-            Target = target;
-        }
-
-        /// <summary>
-        /// ClrMD data target
-        /// </summary>
-        public DataTarget Target { get; }
-
-        /// <summary>
-        /// ClrMD runtime info
-        /// </summary>
-        public ClrRuntime Runtime
-        {
-            get 
-            {
-                if (_runtime == null)
-                {
-                    if (Target.ClrVersions.Count != 1) {
-                        throw new InvalidOperationException("More or less than 1 CLR version is present");
-                    }
-                    ClrInfo clrInfo = Target.ClrVersions[0];
-                    string dacFilePath = GetDacFile(clrInfo);
-                    try
-                    {
-                        _runtime = clrInfo.CreateRuntime(dacFilePath);
-                    }
-                    catch (DllNotFoundException ex)
-                    {
-                        // This is a workaround for the Microsoft SDK docker images. Can fail when clrmd uses libdl.so 
-                        // to create a symlink to and load the DAC module.
-                        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
-                        {
-                            throw new DllNotFoundException("Problem initializing CLRMD. Try installing libc6-dev (apt-get install libc6-dev) to work around this problem.", ex);
-                        }
-                        else
-                        {
-                            throw;
-                        }
-                    }
-                }
-                return _runtime;
-            }
-        }
-
-        private string GetDacFile(ClrInfo clrInfo)
-        {
-            if (s_dacFilePath == null)
-            {
-                string dac = clrInfo.LocalMatchingDac;
-                if (dac != null && File.Exists(dac))
-                {
-                    s_dacFilePath = dac;
-                }
-                else if (SymbolReader.IsSymbolStoreEnabled())
-                {
-                    string dacFileName = Path.GetFileName(dac ?? clrInfo.DacInfo.FileName);
-                    if (dacFileName != null)
-                    {
-                        SymbolStoreKey key = null;
-
-                        if (clrInfo.ModuleInfo.BuildId != null)
-                        {
-                            IEnumerable<SymbolStoreKey> keys = ELFFileKeyGenerator.GetKeys(
-                                KeyTypeFlags.ClrKeys, clrInfo.ModuleInfo.FileName, clrInfo.ModuleInfo.BuildId, symbolFile: false, symbolFileName: null);
-
-                            key = keys.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == dacFileName);
-                        }
-                        else
-                        {
-                            // Use the coreclr.dll's id (timestamp/filesize) to download the the dac module.
-                            key = PEFileKeyGenerator.GetKey(dacFileName, clrInfo.ModuleInfo.TimeStamp, clrInfo.ModuleInfo.FileSize);
-                        }
-
-                        if (key != null)
-                        {
-                            if (s_tempDirectory == null)
-                            {
-                                int processId = Process.GetCurrentProcess().Id;
-                                s_tempDirectory = Path.Combine(Path.GetTempPath(), "analyze" + processId.ToString());
-                            }
-                            // Now download the DAC module from the symbol server
-                            s_dacFilePath = SymbolReader.GetSymbolFile(key, s_tempDirectory);
-                        }
-                    }
-                }
-
-                if (s_dacFilePath == null)
-                {
-                    throw new FileNotFoundException("Could not find matching DAC for this runtime: {0}", clrInfo.ModuleInfo.FileName);
-                }
-            }
-
-            return s_dacFilePath;
-        }
-
-        /// <summary>
-        /// Returns the SOS host instance
-        /// </summary>
-        public SOSHost SOSHost
-        {
-            get 
-            {
-                if (s_sosHost == null) {
-                    s_sosHost = new SOSHost(Target.DataReader, this);
-                    s_sosHost.InitializeSOSHost(s_tempDirectory, s_dacFilePath, dbiFilePath: null);
-                }
-                return s_sosHost;
-            }
-        }
-
-        /// <summary>
-        /// Current OS thread Id
-        /// </summary>
-        public int CurrentThreadId { get; set; }
-
-        /// <summary>
-        /// Cancellation token for current command
-        /// </summary>
-        public CancellationToken CancellationToken { get; set; }
-
-        /// <summary>
-        /// Console write function
-        /// </summary>
-        /// <param name="text"></param>
-        void ISOSHostContext.Write(string text)
-        {
-            _console.Out.Write(text);
-        }
-    }
-}
\ No newline at end of file
index f92d79eddcd12f6f7c1eae0df3d1ec48c6250f65..839f734ccfdfb01195dc4ba54e3153cc56ce0b91 100644 (file)
@@ -2,15 +2,19 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Repl;
 using Microsoft.Diagnostics.Runtime;
+using Microsoft.SymbolStore;
+using Microsoft.SymbolStore.KeyGenerators;
 using SOS;
 using System;
+using System.Collections.Generic;
 using System.CommandLine;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using System.Reflection.Metadata;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
@@ -19,8 +23,12 @@ namespace Microsoft.Diagnostics.Tools.Dump
 {
     public class Analyzer
     {
+        private readonly ServiceProvider _serviceProvider;
         private readonly ConsoleProvider _consoleProvider;
         private readonly CommandProcessor _commandProcessor;
+        private string _dacFilePath;
+
+        private static string s_tempDirectory;
 
         /// <summary>
         /// Enable the assembly resolver to get the right SOS.NETCore version (the one
@@ -33,15 +41,15 @@ namespace Microsoft.Diagnostics.Tools.Dump
 
         public Analyzer()
         {
+            _serviceProvider = new ServiceProvider();
             _consoleProvider = new ConsoleProvider();
             Type type = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? typeof(SOSCommandForWindows) : typeof(SOSCommand);
-            _commandProcessor = new CommandProcessor(_consoleProvider, new Assembly[] { typeof(Analyzer).Assembly }, new Type[] { type });
-            _commandProcessor.AddService(_consoleProvider);
+            _commandProcessor = new CommandProcessor(_serviceProvider, _consoleProvider, new Assembly[] { typeof(Analyzer).Assembly }, new Type[] { type });
         }
 
         public async Task<int> Analyze(FileInfo dump_path, string[] command)
         {
-            _consoleProvider.Out.WriteLine($"Loading core dump: {dump_path} ...");
+            _consoleProvider.WriteLine($"Loading core dump: {dump_path} ...");
 
             try
             { 
@@ -58,14 +66,11 @@ namespace Microsoft.Diagnostics.Tools.Dump
 
                 using (target)
                 {
-                    _consoleProvider.Out.WriteLine("Ready to process analysis commands. Type 'help' to list available commands or 'help [command]' to get detailed help on a command.");
-                    _consoleProvider.Out.WriteLine("Type 'quit' or 'exit' to exit the session.");
+                    _consoleProvider.WriteLine("Ready to process analysis commands. Type 'help' to list available commands or 'help [command]' to get detailed help on a command.");
+                    _consoleProvider.WriteLine("Type 'quit' or 'exit' to exit the session.");
 
-                    // Create common analyze context for commands
-                    var analyzeContext = new AnalyzeContext(_consoleProvider, target) {
-                        CurrentThreadId = unchecked((int)target.DataReader.EnumerateAllThreads().FirstOrDefault())
-                    };
-                    _commandProcessor.AddService(analyzeContext);
+                    // Add all the services needed by commands and other services
+                    AddServices(target);
 
                     // Automatically enable symbol server support
                     SymbolReader.InitializeSymbolStore(logging: false, msdl: true, symweb: false, symbolServerPath: null, symbolCachePath: null, windowsSymbolPath: null);
@@ -79,6 +84,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                     }
 
                     // Start interactive command line processing
+                    var analyzeContext = _serviceProvider.GetService<AnalyzeContext>();
                     await _consoleProvider.Start(async (string commandLine, CancellationToken cancellation) => {
                         analyzeContext.CancellationToken = cancellation;
                         await _commandProcessor.Parse(commandLine);
@@ -95,11 +101,121 @@ namespace Microsoft.Diagnostics.Tools.Dump
                  ex is InvalidOperationException ||
                  ex is NotSupportedException)
             {
-                _consoleProvider.Error.WriteLine($"{ex.Message}");
+                _consoleProvider.WriteLine(OutputType.Error, $"{ex.Message}");
                 return 1;
             }
 
             return 0;
         }
+
+        /// <summary>
+        /// Add all the services needed by commands
+        /// </summary>
+        private void AddServices(DataTarget target)
+        {
+            _serviceProvider.AddService(target);
+            _serviceProvider.AddService<IConsoleService>(_consoleProvider);
+            _serviceProvider.AddService(_commandProcessor);
+            _serviceProvider.AddServiceFactory(typeof(IHelpBuilder), _commandProcessor.CreateHelpBuilder);
+
+            // Create common analyze context for commands
+            var analyzeContext = new AnalyzeContext() {
+                CurrentThreadId = unchecked((int)target.DataReader.EnumerateAllThreads().FirstOrDefault())
+            };
+            _serviceProvider.AddService(analyzeContext);
+
+            // Add the register, SOSHost and ClrRuntime services
+            var registerService = new RegisterService(target);
+            _serviceProvider.AddService(registerService);
+
+            _serviceProvider.AddServiceFactory(typeof(ClrRuntime), () => CreateRuntime(target));
+
+            _serviceProvider.AddServiceFactory(typeof(SOSHost), () => {
+                var sosHost = new SOSHost(_serviceProvider);
+                sosHost.InitializeSOSHost(s_tempDirectory, _dacFilePath, dbiFilePath: null);
+                return sosHost;
+            });
+        }
+
+        /// <summary>
+        /// ClrRuntime service factory
+        /// </summary>
+        private ClrRuntime CreateRuntime(DataTarget target)
+        {
+            ClrRuntime runtime;
+            if (target.ClrVersions.Count != 1) {
+                throw new InvalidOperationException("More or less than 1 CLR version is present");
+            }
+            ClrInfo clrInfo = target.ClrVersions[0];
+            string dacFilePath = GetDacFile(clrInfo);
+            try
+            {
+                runtime = clrInfo.CreateRuntime(dacFilePath);
+            }
+            catch (DllNotFoundException ex)
+            {
+                // This is a workaround for the Microsoft SDK docker images. Can fail when clrmd uses libdl.so 
+                // to create a symlink to and load the DAC module.
+                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+                {
+                    throw new DllNotFoundException("Problem initializing CLRMD. Try installing libc6-dev (apt-get install libc6-dev) to work around this problem.", ex);
+                }
+                else
+                {
+                    throw;
+                }
+            }
+            return runtime;
+        }
+
+        private string GetDacFile(ClrInfo clrInfo)
+        {
+            if (_dacFilePath == null)
+            {
+                string dac = clrInfo.LocalMatchingDac;
+                if (dac != null && File.Exists(dac))
+                {
+                    _dacFilePath = dac;
+                }
+                else if (SymbolReader.IsSymbolStoreEnabled())
+                {
+                    string dacFileName = Path.GetFileName(dac ?? clrInfo.DacInfo.FileName);
+                    if (dacFileName != null)
+                    {
+                        SymbolStoreKey key = null;
+
+                        if (clrInfo.ModuleInfo.BuildId != null)
+                        {
+                            IEnumerable<SymbolStoreKey> keys = ELFFileKeyGenerator.GetKeys(
+                                KeyTypeFlags.ClrKeys, clrInfo.ModuleInfo.FileName, clrInfo.ModuleInfo.BuildId, symbolFile: false, symbolFileName: null);
+
+                            key = keys.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == dacFileName);
+                        }
+                        else
+                        {
+                            // Use the coreclr.dll's id (timestamp/filesize) to download the the dac module.
+                            key = PEFileKeyGenerator.GetKey(dacFileName, clrInfo.ModuleInfo.TimeStamp, clrInfo.ModuleInfo.FileSize);
+                        }
+
+                        if (key != null)
+                        {
+                            if (s_tempDirectory == null)
+                            {
+                                int processId = Process.GetCurrentProcess().Id;
+                                s_tempDirectory = Path.Combine(Path.GetTempPath(), "analyze" + processId.ToString());
+                            }
+                            // Now download the DAC module from the symbol server
+                            _dacFilePath = SymbolReader.GetSymbolFile(key, s_tempDirectory);
+                        }
+                    }
+                }
+
+                if (_dacFilePath == null)
+                {
+                    throw new FileNotFoundException("Could not find matching DAC for this runtime: {0}", clrInfo.ModuleInfo.FileName);
+                }
+            }
+            return _dacFilePath;
+        }
     }
 }
index 9c2a3228702bd49225cfcdf44f5f55e1e455d117..fe44d534dca75c238a318119314df0d37a0011ed 100644 (file)
@@ -12,11 +12,11 @@ namespace Microsoft.Diagnostics.Tools.Dump
     [Command(Name = "clrmodules", Help = "Lists the managed modules in the process.")]
     public class ClrModulesCommand : CommandBase
     {
-        public AnalyzeContext AnalyzeContext { get; set; }
+        public ClrRuntime Runtime { get; set; }
 
         public override void Invoke()
         {
-            foreach (ClrModule module in AnalyzeContext.Runtime.Modules)
+            foreach (ClrModule module in Runtime.Modules)
             {
                 WriteLine("{0:X16} {1}", module.Address, module.FileName);
             }
index a7dcaa592de0f11eb7bbadd9ed596a6e6dd065da..1c249c42420d2177442d16abd9fd4d3e1b956d56 100644 (file)
@@ -12,11 +12,9 @@ namespace Microsoft.Diagnostics.Tools.Dump
     [CommandAlias(Name = "quit")]
     public class ExitCommand : CommandBase
     {
-        public ConsoleProvider ConsoleProvider { get; set; }
-
         public override void Invoke()
         {
-            ConsoleProvider.Stop();
+            Console.Exit();
         }
     }
 }
index 2a12890905138c2df808d641e0a9b80e94e55094..d2f3ce8507de673f3e62d69c314947af5b46dffb 100644 (file)
@@ -24,7 +24,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                 HelpBuilder.Write(command);
             }
             else {
-                Console.Error.WriteLine($"Help for {Command} not found.");
+                WriteLineError($"Help for {Command} not found.");
             }
         }
     }
index 6d0b0a9d11204aa542a04a7c83d5032ae2256b60..ecf97ff19802f1812448465d686a7cb6660c2ba1 100644 (file)
@@ -18,11 +18,11 @@ namespace Microsoft.Diagnostics.Tools.Dump
         [OptionAlias(Name = "-v")]
         public bool Verbose { get; set; }
 
-        public AnalyzeContext AnalyzeContext { get; set; }
+        public DataTarget DataTarget { get; set; }
 
         public override void Invoke()
         {
-            foreach (ModuleInfo module in AnalyzeContext.Target.DataReader.EnumerateModules())
+            foreach (ModuleInfo module in DataTarget.DataReader.EnumerateModules())
             {
                 if (Verbose)
                 {
diff --git a/src/Tools/dotnet-dump/Commands/RegistersCommand.cs b/src/Tools/dotnet-dump/Commands/RegistersCommand.cs
new file mode 100644 (file)
index 0000000..441613b
--- /dev/null
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Repl;
+using Microsoft.Diagnostics.Runtime;
+using System;
+using System.Collections.Generic;
+using System.CommandLine;
+using System.Linq;
+
+namespace Microsoft.Diagnostics.Tools.Dump
+{
+    [Command(Name = "registers", Help = "Displays the thread's registers.")]
+    public class RegistersCommand : CommandBase
+    {
+        [Argument(Help = "The thread index to display, otherwise use the current thread.")]
+        public int? ThreadIndex { get; set; } = null;
+
+        public DataTarget DataTarget { get; set; }
+
+        public AnalyzeContext AnalyzeContext { get; set; }
+
+        public RegisterService RegisterService { get; set; }
+
+        public override void Invoke()
+        {
+            IEnumerable<uint> threads = DataTarget.DataReader.EnumerateAllThreads();
+            uint threadId;
+
+            if (ThreadIndex.HasValue)
+            {
+                if (ThreadIndex.Value >= threads.Count()) {
+                    throw new InvalidOperationException($"Invalid thread index {ThreadIndex.Value}");
+                }
+                threadId = threads.ElementAt(ThreadIndex.Value);
+            }
+            else
+            {
+                threadId = (uint)AnalyzeContext.CurrentThreadId;
+            }
+
+            foreach (RegisterService.RegisterInfo register in RegisterService.Registers)
+            {
+                if (RegisterService.GetRegisterValue(threadId, register.RegisterIndex, out ulong value))
+                {
+                    switch (register.RegisterSize)
+                    {
+                        case 1:
+                            WriteLine("{0} = {1:X1}", register.RegisterName, value);
+                            break;
+                        case 2:
+                            WriteLine("{0} = {1:X4}", register.RegisterName, value);
+                            break;
+                        case 4:
+                            WriteLine("{0} = {1:X8}", register.RegisterName, value);
+                            break;
+                        case 8:
+                            WriteLine("{0} = {1:X16}", register.RegisterName, value);
+                            break;
+                    }
+                }
+                else
+                {
+                    WriteLine("{0} = ", register.RegisterName);
+                }
+            }
+        }
+    }
+}
index 40cf8b45c8e249aa717d5786550d7cb387972819..2e622abb7f18b53c2cfde905de21f487dc38f7c2 100644 (file)
@@ -2,7 +2,9 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Repl;
+using SOS;
 using System;
 using System.CommandLine;
 using System.IO;
@@ -46,7 +48,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
         [Argument(Name = "arguments", Help = "Arguments to SOS command.")]
         public string[] Arguments { get; set; }
 
-        public AnalyzeContext AnalyzeContext { get; set; }
+        public SOSHost SOSHost { get; set; }
 
         public override void Invoke()
         {
@@ -55,17 +57,17 @@ namespace Microsoft.Diagnostics.Tools.Dump
                 if (Arguments.Length > 0) {
                     arguments = string.Concat(Arguments.Select((arg) => arg + " "));
                 }
-                AnalyzeContext.SOSHost.ExecuteCommand(AliasExpansion, arguments);
+                SOSHost.ExecuteCommand(AliasExpansion, arguments);
             }
             catch (Exception ex) when (ex is FileNotFoundException || ex is EntryPointNotFoundException || ex is InvalidOperationException) {
-                Console.Error.WriteLine(ex.Message);
+                WriteLineError(ex.Message);
             }
         }
 
         [HelpInvoke]
         public void InvokeHelp()
         {
-            AnalyzeContext.SOSHost.ExecuteCommand("Help", AliasExpansion);
+            SOSHost.ExecuteCommand("Help", AliasExpansion);
         }
     }
 }
index c08dd307c34ba5ef8927d3231d52ea87b35b59c8..c13ac1cb6966d43675da9b738a998b97a1e58663 100644 (file)
@@ -2,7 +2,9 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Repl;
+using Microsoft.Diagnostics.Runtime;
 using System;
 using System.Collections.Generic;
 using System.CommandLine;
@@ -17,13 +19,15 @@ namespace Microsoft.Diagnostics.Tools.Dump
         [Argument(Help = "The thread index to set, otherwise displays the list of threads.")]
         public int? ThreadIndex { get; set; } = null;
 
+        public DataTarget DataTarget { get; set; }
+
         public AnalyzeContext AnalyzeContext { get; set; }
 
         public override void Invoke()
         {
             if (ThreadIndex.HasValue)
             {
-                IEnumerable<uint> threads = AnalyzeContext.Target.DataReader.EnumerateAllThreads();
+                IEnumerable<uint> threads = DataTarget.DataReader.EnumerateAllThreads();
                 if (ThreadIndex.Value >= threads.Count()) {
                     throw new InvalidOperationException($"Invalid thread index {ThreadIndex.Value}");
                 }
@@ -32,7 +36,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
             else
             {
                 int index = 0;
-                foreach (uint threadId in AnalyzeContext.Target.DataReader.EnumerateAllThreads())
+                foreach (uint threadId in DataTarget.DataReader.EnumerateAllThreads())
                 {
                     WriteLine("{0}{1} 0x{2:X4} ({2})", threadId == AnalyzeContext.CurrentThreadId ? "*" : " ", index, threadId);
                     index++;
index 22008e22411fb8c957adde1340bcc5666757dfda..f1aa20e8e0882d1daf8e82c0f40b445b386b2c57 100644 (file)
@@ -2,6 +2,7 @@
 
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <RuntimeFrameworkVersion>2.1.0</RuntimeFrameworkVersion>
     <ToolCommandName>dotnet-dump</ToolCommandName>
     <RootNamespace>Microsoft.Diagnostic.Tools.Dump</RootNamespace>
@@ -21,6 +22,7 @@
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\SOS\SOS.Hosting\SOS.Hosting.csproj" />
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\SOS\SOS.NETCore\SOS.NETCore.csproj" />
+    <ProjectReference Include="..\..\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj" />
   </ItemGroup>
 
   <Import Project="$(MSBuildThisFileDirectory)..\..\sos-packaging.props" />