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
{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
{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}
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 (
<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>
<!-- 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>
local passedRootfsDir=""
# Only pass ROOTFS_DIR if cross is specified.
- if [ "$__CrossBuild" == true ]; then
+ if [ $__CrossBuild == true ]; then
passedRootfsDir=${ROOTFS_DIR}
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
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+<!-- 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>
--- /dev/null
+// 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
--- /dev/null
+// 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));
+ }
+ }
+}
// 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;
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.
/// <param name="message">text message</param>
protected void WriteLine(string message)
{
- Console.Out.WriteLine(message);
+ Console.Write(message + Environment.NewLine);
}
/// <summary>
/// <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
// 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;
{
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>())
.UseSuggestDirective()
.UseParseErrorReporting()
.UseExceptionHandler();
+
if (assemblies != null) {
BuildCommands(rootBuilder, assemblies);
}
}
/// <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>
public Task<int> Parse(string commandLine)
{
ParseResult result = _parser.Parse(commandLine);
- return _parser.InvokeAsync(result, GetService<IConsole>());
+ return _parser.InvokeAsync(result, _console);
}
/// <summary>
}
}
+ 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)
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)
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;
}
}
return;
}
}
- var helpBuilder = new HelpBuilder(_commandProcessor.GetService<IConsole>(), maxWidth: Console.WindowWidth);
+ var helpBuilder = new HelpBuilder(_commandProcessor._console, maxWidth: Console.WindowWidth);
helpBuilder.Write(command);
}
}
// 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;
namespace Microsoft.Diagnostics.Repl
{
- public sealed class ConsoleProvider : IConsole
+ public sealed class ConsoleProvider : IConsole, IConsoleService
{
private readonly List<StringBuilder> m_history;
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>
}
#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
}
}
<PackageReference Include="System.CommandLine.Experimental" Version="$(SystemCommandLineExperimentalVersion)" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj" />
+ </ItemGroup>
+
</Project>
+++ /dev/null
-// 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
+++ /dev/null
-// 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
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
IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
- private delegate ulong GetExpressionDelegate(
+ private delegate UIntPtr GetExpressionDelegate(
IntPtr self,
[In][MarshalAs(UnmanagedType.LPStr)] string text);
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(
<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>
// 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;
bool symbolStoreEnabled);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
- private delegate ulong GetExpressionDelegate(
+ private delegate UIntPtr GetExpressionDelegate(
[In, MarshalAs(UnmanagedType.LPStr)] string expression);
private const string SOSInitialize = "SOSInitializeByHost";
};
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;
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>
/// <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))
#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(
try
{
// The text has already been formated by sos
- SOSHostContext.Write(format);
+ _console.Write(format);
}
catch (OperationCanceledException)
{
*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;
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;
}
IntPtr self,
out uint id)
{
- return GetThreadIdBySystemId(self, (uint)SOSHostContext.CurrentThreadId, out id);
+ return GetThreadIdBySystemId(self, (uint)_analyzeContext.CurrentThreadId, out id);
}
internal int SetCurrentThreadId(
try
{
unchecked {
- SOSHostContext.CurrentThreadId = (int)DataReader.EnumerateAllThreads().ElementAt((int)id);
+ _analyzeContext.CurrentThreadId = (int)DataReader.EnumerateAllThreads().ElementAt((int)id);
}
}
catch (ArgumentOutOfRangeException)
IntPtr self,
out uint sysId)
{
- sysId = (uint)SOSHostContext.CurrentThreadId;
+ sysId = (uint)_analyzeContext.CurrentThreadId;
return S_OK;
}
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;
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(
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;
}
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;
}
{
throw new SOSInstallerException($"Unsupported operating system {RuntimeInformation.OSDescription}");
}
- string architecture = RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant();
+ string architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
return $"{os}-{architecture}";
}
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")
private async Task RunTest(TestConfiguration config, string testName, string debuggeeName, string scriptName, string debuggeeArguments = null, bool useCreateDump = true)
{
- SkipIfArm(config);
-
if (!SOSRunner.IsAlpine())
{
// Live
[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");
[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");
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
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
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
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)
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
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.*
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
}
#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
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;
}
#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"
#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
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
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);
}
void IfDMLOut(PCSTR format, ...)
{
-#ifndef FEATURE_PAL
if (Output::IsOutputSuppressed() || !IsDMLEnabled())
return;
ExtOutIndent();
g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
va_end(args);
-#endif
}
void ExtOut(PCSTR Format, ...)
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,
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,
// 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
{
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))
// 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);
}
}
- 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
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();
+++ /dev/null
-// 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
// 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;
{
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
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
{
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);
}
// 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);
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;
+ }
}
}
[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);
}
[CommandAlias(Name = "quit")]
public class ExitCommand : CommandBase
{
- public ConsoleProvider ConsoleProvider { get; set; }
-
public override void Invoke()
{
- ConsoleProvider.Stop();
+ Console.Exit();
}
}
}
HelpBuilder.Write(command);
}
else {
- Console.Error.WriteLine($"Help for {Command} not found.");
+ WriteLineError($"Help for {Command} not found.");
}
}
}
[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)
{
--- /dev/null
+// 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);
+ }
+ }
+ }
+ }
+}
// 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;
[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()
{
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);
}
}
}
// 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;
[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}");
}
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++;
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeFrameworkVersion>2.1.0</RuntimeFrameworkVersion>
<ToolCommandName>dotnet-dump</ToolCommandName>
<RootNamespace>Microsoft.Diagnostic.Tools.Dump</RootNamespace>
<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" />