src\SOS\inc\lldbservices.h = src\SOS\inc\lldbservices.h
src\SOS\inc\remotememoryservice.h = src\SOS\inc\remotememoryservice.h
src\SOS\inc\runtime.h = src\SOS\inc\runtime.h
+ src\SOS\inc\specialdiaginfo.h = src\SOS\inc\specialdiaginfo.h
src\SOS\inc\specialthreadinfo.h = src\SOS\inc\specialthreadinfo.h
src\SOS\inc\symbolservice.h = src\SOS\inc\symbolservice.h
src\SOS\inc\target.h = src\SOS\inc\target.h
}
#endregion
-
- public override string ToString()
- {
- StringBuilder sb = new();
- if (_runtimes is not null)
- {
- IRuntime currentRuntime = _services.GetService<IContextService>()?.GetCurrentRuntime();
- foreach (IRuntime runtime in _runtimes)
- {
- string current = _runtimes.Count > 1 ? runtime == currentRuntime ? "*" : " " : "";
- sb.Append(current);
- sb.AppendLine(runtime.ToString());
- }
- }
- return sb.ToString();
- }
}
}
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
+using Microsoft.FileFormats;
using Architecture = System.Runtime.InteropServices.Architecture;
namespace Microsoft.Diagnostics.DebugServices.Implementation
// Initialize the per-target services.
_serviceContainerFactory = host.Services.GetService<IServiceManager>().CreateServiceContainerFactory(ServiceScope.Target, host.Services);
_serviceContainerFactory.AddServiceFactory<ITarget>((_) => this);
+ _serviceContainerFactory.AddServiceFactory<Reader>(CreateReader);
}
protected void Finished()
#endregion
+ /// <summary>
+ /// Create the file format reader used to read and layout TStruct derived structures from memory
+ /// </summary>
+ private static Reader CreateReader(IServiceProvider services)
+ {
+ IMemoryService memoryService = services.GetService<IMemoryService>();
+ Stream stream = memoryService.CreateMemoryStream();
+ LayoutManager layoutManager = new LayoutManager()
+ .AddPrimitives()
+ .AddEnumTypes()
+ .AddSizeT(memoryService.PointerSize)
+ .AddPointerTypes()
+ .AddNullTerminatedString()
+ .AddTStructTypes();
+ return new Reader(new StreamAddressSpace(stream), layoutManager);
+ }
+
private void CleanupTempDirectory()
{
if (_tempDirectory != null)
{
StringBuilder sb = new();
string process = ProcessId.HasValue ? string.Format("{0} (0x{0:X})", ProcessId.Value) : "<none>";
- sb.AppendLine($"Target OS: {OperatingSystem} Architecture: {Architecture} ProcessId: {process}");
- if (_tempDirectory != null)
- {
- sb.AppendLine($"Temp path: {_tempDirectory}");
- }
+ sb.Append($"Target OS: {OperatingSystem} Architecture: {Architecture} ProcessId: {process}");
if (_dumpPath != null)
{
- sb.AppendLine($"Dump path: {_dumpPath}");
+ sb.Append($" {_dumpPath}");
}
- IRuntimeService runtimeService = Services.GetService<IRuntimeService>();
- if (runtimeService != null)
+ if (_tempDirectory != null)
{
- sb.AppendLine(runtimeService.ToString());
+ sb.Append($" {_tempDirectory}");
}
return sb.ToString();
}
/// </summary>
public abstract class CommandBase
{
+ /// <summary>
+ /// The services provided to this command
+ /// </summary>
+ [ServiceImport]
+ public IServiceProvider Services { get; set; }
+
/// <summary>
/// Console service
/// </summary>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+ /// <summary>
+ /// Native CLR_DEBUG_RESOURCE struct
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ClrDebugResource
+ {
+ public uint dwVersion;
+ public Guid signature;
+ public int dwDacTimeStamp;
+ public int dwDacSizeOfImage;
+ public int dwDbiTimeStamp;
+ public int dwDbiSizeOfImage;
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.FileFormats;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+ public class ClrEngineMetrics : TStruct
+ {
+ public const string Symbol = "g_CLREngineMetrics";
+
+ public readonly int Size;
+ public readonly int DbiVersion;
+ public readonly SizeT ContinueStartupEvent;
+
+ public static bool TryRead(IServiceProvider services, ulong address, out ClrEngineMetrics metrics)
+ {
+ metrics = default;
+
+ Reader reader = services.GetService<Reader>();
+ if (reader is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ metrics = reader.Read<ClrEngineMetrics>(address);
+ }
+ catch (Exception ex) when (ex is InvalidVirtualAddressException or BadInputFormatException)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.ExtensionCommands.Output;
+using Microsoft.Diagnostics.Runtime;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+ public static class CommandFormatHelpers
+ {
+ public const string DacTableSymbol = "g_dacTable";
+ public const string DebugHeaderSymbol = "DotNetRuntimeDebugHeader";
+
+ /// <summary>
+ /// Displays the special diagnostics info header memory block (.NET Core 8 or later on Linux/MacOS)
+ /// </summary>
+ public static void DisplaySpecialInfo(this CommandBase command, string indent = "")
+ {
+ if (command.Services.GetService<ITarget>().OperatingSystem != OSPlatform.Windows)
+ {
+ ulong address = SpecialDiagInfoHeader.GetAddress(command.Services);
+ command.Console.Write($"{indent}SpecialDiagInfoHeader : {address:X16}");
+ if (SpecialDiagInfoHeader.TryRead(command.Services, address, out SpecialDiagInfoHeader info))
+ {
+ command.Console.WriteLine(info.IsValid ? "" : " <INVALID>");
+ command.Console.WriteLine($"{indent} Signature: {info.Signature}");
+ command.Console.WriteLine($"{indent} Version: {info.Version}");
+ command.Console.WriteLine($"{indent} ExceptionRecordAddress: {info.ExceptionRecordAddress:X16}");
+ command.Console.WriteLine($"{indent} RuntimeBaseAddress: {info.RuntimeBaseAddress:X16}");
+
+ if (info.Version >= SpecialDiagInfoHeader.SPECIAL_DIAGINFO_RUNTIME_BASEADDRESS)
+ {
+ IModule runtimeModule = command.Services.GetService<IModuleService>().GetModuleFromBaseAddress(info.RuntimeBaseAddress);
+ if (runtimeModule != null)
+ {
+ command.DisplayRuntimeExports(runtimeModule, error: true, indent + " ");
+ }
+ }
+ }
+ else
+ {
+ command.Console.WriteLine(" <NONE>");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Display the module's resources. The ClrDebugResource is pretty formatted.
+ /// </summary>
+ /// <exception cref="DiagnosticsException"></exception>
+ public static void DisplayResources(this CommandBase command, IModule module, bool all, string indent)
+ {
+ if (module.IsPEImage)
+ {
+ command.Console.WriteLine($"{indent}Resources:");
+ IDataReader reader = command.Services.GetService<IDataReader>() ?? throw new DiagnosticsException("IDataReader service needed");
+ IResourceNode resourceRoot = ModuleInfo.TryCreateResourceRoot(reader, module.ImageBase, module.ImageSize, module.IsFileLayout.GetValueOrDefault(false));
+ if (resourceRoot != null)
+ {
+ foreach (IResourceNode child in resourceRoot.Children)
+ {
+ DisplayResources(command.Console, child, all, indent + " ");
+ }
+ }
+ }
+ }
+
+ private static void DisplayResources(IConsoleService console, IResourceNode resourceNode, bool all, string indent)
+ {
+ if (resourceNode.Name.StartsWith("CLRDEBUGINFO"))
+ {
+ console.WriteLine($"{indent}Name: {resourceNode.Name}");
+ IResourceNode node = resourceNode.Children.FirstOrDefault();
+ if (node is not null)
+ {
+ ClrDebugResource clrDebugResource = node.Read<ClrDebugResource>(0);
+ console.WriteLine($"{indent} Size: {node.Size:X8}");
+ console.WriteLine($"{indent} Version: {clrDebugResource.dwVersion:X8}");
+ console.WriteLine($"{indent} Signature: {clrDebugResource.signature}");
+ console.WriteLine($"{indent} DacTimeStamp: {clrDebugResource.dwDacTimeStamp:X8}");
+ console.WriteLine($"{indent} DacSizeOfImage: {clrDebugResource.dwDacSizeOfImage:X8}");
+ console.WriteLine($"{indent} DbiTimeStamp: {clrDebugResource.dwDbiTimeStamp:X8}");
+ console.WriteLine($"{indent} DbiSizeOfImage: {clrDebugResource.dwDbiSizeOfImage:X8}");
+ }
+ }
+ else
+ {
+ if (all)
+ {
+ console.WriteLine($"{indent}Name: {resourceNode.Name}");
+ int size = resourceNode.Size;
+ if (size > 0)
+ {
+ console.WriteLine($"{indent}Size: {size:X8}");
+ }
+ indent += " ";
+ }
+ foreach (IResourceNode child in resourceNode.Children)
+ {
+ DisplayResources(console, child, all, indent);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Displays the module's special runtime exports
+ /// </summary>
+ public static void DisplayRuntimeExports(this CommandBase command, IModule module, bool error, string indent)
+ {
+ bool header = false;
+ IConsoleService Console()
+ {
+ if (!header)
+ {
+ header = true;
+ command.Console.WriteLine($"{indent}Exports:");
+ indent += " ";
+ }
+ return command.Console;
+ }
+ // Print the runtime info (.NET Core single-file)
+ IExportSymbols symbols = module.Services.GetService<IExportSymbols>();
+ if (symbols != null && symbols.TryGetSymbolAddress(RuntimeInfo.RUNTIME_INFO_SYMBOL, out ulong infoAddress))
+ {
+ Console().Write($"{indent}{RuntimeInfo.RUNTIME_INFO_SYMBOL,-24}: {infoAddress:X16}");
+ if (RuntimeInfo.TryRead(command.Services, infoAddress, out RuntimeInfo info))
+ {
+ Console().WriteLine(info.IsValid ? "" : " <INVALID>");
+ Console().WriteLine($"{indent} Signature: {info.Signature}");
+ Console().WriteLine($"{indent} Version: {info.Version}");
+ Console().WriteLine($"{indent} RuntimeModuleIndex: {info.RawRuntimeModuleIndex.ToHex()}");
+ Console().WriteLine($"{indent} DacModuleIndex: {info.RawDacModuleIndex.ToHex()}");
+ Console().WriteLine($"{indent} DbiModuleIndex: {info.RawDbiModuleIndex.ToHex()}");
+ if (module.IsPEImage)
+ {
+ Console().WriteLine($"{indent} RuntimePEIndex: {info.RuntimePEIIndex.timeStamp:X8}/{info.RuntimePEIIndex.fileSize:X}");
+ Console().WriteLine($"{indent} DacPEIndex: {info.DacPEIndex.timeStamp:X8}/{info.DacPEIndex.fileSize:X}");
+ Console().WriteLine($"{indent} DbiPEIndex: {info.DbiPEIndex.timeStamp:X8}/{info.DbiPEIndex.fileSize:X}");
+ }
+ else
+ {
+ Console().WriteLine($"{indent} RuntimeBuildId: {info.RuntimeBuildId.ToHex()}");
+ Console().WriteLine($"{indent} DacBuildId: {info.DacBuildId.ToHex()}");
+ Console().WriteLine($"{indent} DbiBuildId: {info.DbiBuildId.ToHex()}");
+ }
+ Console().WriteLine($"{indent} RuntimeVersion: {info.RuntimeVersion?.ToString() ?? "<none>"}");
+ }
+ else
+ {
+ Console().WriteLineError(" <NONE>");
+ }
+ }
+ else if (error)
+ {
+ Console().WriteLineError($"{indent}{RuntimeInfo.RUNTIME_INFO_SYMBOL,-24}: <NO SYMBOL>");
+ }
+
+ // Print the Windows runtime engine metrics (.NET Core and .NET Framework)
+ if (command.Services.GetService<ITarget>().OperatingSystem == OSPlatform.Windows)
+ {
+ if (symbols != null && symbols.TryGetSymbolAddress(ClrEngineMetrics.Symbol, out ulong metricsAddress))
+ {
+ Console().Write($"{indent}{ClrEngineMetrics.Symbol,-24}: ({metricsAddress:X16})");
+ if (ClrEngineMetrics.TryRead(command.Services, metricsAddress, out ClrEngineMetrics metrics))
+ {
+ Console().WriteLine();
+ Console().WriteLine($"{indent} Size: {metrics.Size} (0x{metrics.Size:X2})");
+ Console().WriteLine($"{indent} DbiVersion: {metrics.DbiVersion}");
+ Console().WriteLine($"{indent} ContinueStartupEvent: {((ulong)metrics.ContinueStartupEvent):X16}");
+ }
+ else
+ {
+ Console().WriteLineError(" <NONE>");
+ }
+ }
+ else if (error)
+ {
+ Console().WriteLineError($"{indent}{ClrEngineMetrics.Symbol,-24}: <NO SYMBOL>");
+ }
+ }
+
+ // Print the DAC table address (g_dacTable)
+ if (symbols != null && symbols.TryGetSymbolAddress(DacTableSymbol, out ulong dacTableAddress))
+ {
+ Console().WriteLine($"{indent}{DacTableSymbol,-24}: {dacTableAddress:X16}");
+ }
+ else if (error)
+ {
+ Console().WriteLineError($"{indent}{DacTableSymbol,-24}: <NO SYMBOL>");
+ }
+
+ // Print the Native AOT contract data address (DotNetRuntimeDebugHeader)
+ if (symbols != null && symbols.TryGetSymbolAddress(DebugHeaderSymbol, out ulong debugHeaderAddress))
+ {
+ Console().WriteLine($"{indent}{DebugHeaderSymbol,-24}: {debugHeaderAddress:X16}");
+ }
+ else if (error)
+ {
+ Console().WriteLineError($"{indent}{DebugHeaderSymbol,-24}: <NO SYMBOL>");
+ }
+ }
+ }
+}
[ServiceImport]
public ICommandService CommandService { get; set; }
- [ServiceImport]
- public IServiceProvider Services { get; set; }
-
public override void Invoke()
{
if (string.IsNullOrWhiteSpace(Command))
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Runtime;
using Microsoft.FileFormats;
using Microsoft.FileFormats.ELF;
using Microsoft.FileFormats.MachO;
[Option(Name = "--segments", Aliases = new string[] { "-s" }, Help = "Displays the module segments.")]
public bool Segment { get; set; }
+ [Option(Name = "--resources", Aliases = new string[] { "-r" }, Help = "Displays the module resources.")]
+ public bool Resources { get; set; }
+
[Option(Name = "--name", Aliases = new string[] { "-n" }, Help = "RegEx filter on module name (path not included).")]
public string ModuleName { get; set; }
[Option(Name = "--address", Aliases = new string[] { "-a" }, Help = "Lookup address in module list.")]
public ulong? Address { get; set; }
+ [ServiceImport]
+ public ITarget Target { get; set; }
+
[ServiceImport]
public IModuleService ModuleService { get; set; }
+ [ServiceImport]
+ public IMemoryService MemoryService { get; set; }
+
public override void Invoke()
{
if (Address.HasValue)
WriteLine(" PdbInfo: {0}", pdbFileInfo);
}
WriteLine(" BuildId: {0}", !module.BuildId.IsDefaultOrEmpty ? string.Concat(module.BuildId.Select((b) => b.ToString("x2"))) : "<none>");
+
+ this.DisplayRuntimeExports(module, error: false, indent: " ");
}
else
{
{
DisplaySegments(module);
}
+ if (Resources)
+ {
+ this.DisplayResources(module, all: true, indent: " ");
+ }
}
- [ServiceImport]
- public ITarget Target { get; set; }
-
- [ServiceImport]
- public IMemoryService MemoryService { get; set; }
-
private void DisplaySegments(IModule module)
{
try
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.FileFormats;
+
+namespace Microsoft.Diagnostics.Runtime
+{
+ public class RuntimeInfo : TStruct
+ {
+ public const string RUNTIME_INFO_SYMBOL = "DotNetRuntimeInfo";
+ public const string RUNTIME_INFO_SIGNATURE = "DotNetRuntimeInfo";
+ public const int RUNTIME_INFO_RUNTIME_VERSION = 2;
+ public const int RUNTIME_INFO_LATEST = 2;
+
+ [ArraySize(18)]
+ public readonly byte[] RawSignature;
+ public readonly int Version;
+ [ArraySize(24)]
+ public readonly byte[] RawRuntimeModuleIndex;
+ [ArraySize(24)]
+ public readonly byte[] RawDacModuleIndex;
+ [ArraySize(24)]
+ public readonly byte[] RawDbiModuleIndex;
+ [ArraySize(4)]
+ public readonly int[] RawRuntimeVersion; // major, minor, build, revision - added in version RUNTIME_INFO_RUNTIME_VERSION
+
+ public static unsafe bool TryRead(IServiceProvider services, ulong address, out RuntimeInfo info)
+ {
+ info = default;
+
+ Reader reader = services.GetService<Reader>();
+ if (reader is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ info = reader.Read<RuntimeInfo>(address);
+ }
+ catch (Exception ex) when (ex is InvalidVirtualAddressException or BadInputFormatException)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public string Signature => Encoding.ASCII.GetString(RawSignature.Take(RUNTIME_INFO_SIGNATURE.Length).ToArray());
+
+ public bool IsValid => Version > 0 && Signature == RUNTIME_INFO_SIGNATURE;
+
+ public (int timeStamp, int fileSize) RuntimePEIIndex => GetPEIndex(RawRuntimeModuleIndex);
+
+ public (int timeStamp, int fileSize) DacPEIndex => GetPEIndex(RawDacModuleIndex);
+
+ public (int timeStamp, int fileSize) DbiPEIndex => GetPEIndex(RawDbiModuleIndex);
+
+ private static (int timeStamp, int fileSize) GetPEIndex(byte[] index)
+ {
+ if (index[0] < 2 * sizeof(int))
+ {
+ return (0, 0);
+ }
+ return (BitConverter.ToInt32(index, 1), BitConverter.ToInt32(index, 1 + sizeof(int)));
+ }
+
+ public ImmutableArray<byte> RuntimeBuildId => GetBuildId(RawRuntimeModuleIndex);
+
+ public ImmutableArray<byte> DacBuildId => GetBuildId(RawDacModuleIndex);
+
+ public ImmutableArray<byte> DbiBuildId => GetBuildId(RawDbiModuleIndex);
+
+ private static ImmutableArray<byte> GetBuildId(byte[] index) => index.Skip(1).Take(index[0]).ToImmutableArray();
+
+ public Version RuntimeVersion => Version >= RUNTIME_INFO_RUNTIME_VERSION ? new Version(RawRuntimeVersion[0], RawRuntimeVersion[1], RawRuntimeVersion[2], RawRuntimeVersion[3]) : null;
+ }
+}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Collections.Immutable;
+using System;
using System.Linq;
using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.ExtensionCommands.Output;
using Microsoft.Diagnostics.Runtime;
namespace Microsoft.Diagnostics.ExtensionCommands
WriteLine($" {library.Kind} {library.FileName} {library.Platform} {library.TargetArchitecture} {library.ArchivedUnder} {index}");
}
}
+ this.DisplayResources(runtime.RuntimeModule, all: false, indent: " ");
+ this.DisplayRuntimeExports(runtime.RuntimeModule, error: true, indent: " ");
}
}
}
}
-
- public static class CommandUtilities
- {
- public static string ToHex(this ImmutableArray<byte> array) => string.Concat(array.Select((b) => b.ToString("x2")));
- }
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.FileFormats;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+ public class SpecialDiagInfoHeader : TStruct
+ {
+ public const string SPECIAL_DIAGINFO_SIGNATURE = "DIAGINFOHEADER";
+ public const int SPECIAL_DIAGINFO_RUNTIME_BASEADDRESS = 2;
+ public const int SPECIAL_DIAGINFO_LATEST = 2;
+
+ public const ulong SpecialDiagInfoAddress_OSX = 0x7fffffff10000000UL;
+ public const ulong SpecialDiagInfoAddress_64BIT = 0x00007ffffff10000UL;
+ public const ulong SpecialDiagInfoAddress_32BIT = 0x000000007fff1000UL;
+ public const int SpecialDiagInfoSize = 0x1000;
+
+ [ArraySize(16)]
+ public readonly byte[] RawSignature;
+ public readonly int Version;
+ public readonly ulong ExceptionRecordAddress;
+ public readonly ulong RuntimeBaseAddress; // Exists in version SPECIAL_DIAGINFO_RUNTIME_BASEADDRESS
+
+ public static bool TryRead(IServiceProvider services, ulong address, out SpecialDiagInfoHeader info)
+ {
+ info = default;
+
+ Reader reader = services.GetService<Reader>();
+ if (reader is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ info = reader.Read<SpecialDiagInfoHeader>(address);
+ }
+ catch (Exception ex) when (ex is InvalidVirtualAddressException or BadInputFormatException)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static ulong GetAddress(IServiceProvider services)
+ {
+ ITarget target = services.GetService<ITarget>();
+ IMemoryService memoryService = services.GetService<IMemoryService>();
+ return target.OperatingSystem == OSPlatform.OSX ? SpecialDiagInfoAddress_OSX : (memoryService.PointerSize == 4 ? SpecialDiagInfoAddress_32BIT : SpecialDiagInfoAddress_64BIT);
+ }
+
+ public string Signature => Encoding.ASCII.GetString(RawSignature.Take(SPECIAL_DIAGINFO_SIGNATURE.Length).ToArray());
+
+ public bool IsValid => Version > 0 && Signature == SPECIAL_DIAGINFO_SIGNATURE;
+ }
+}
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Linq;
using Microsoft.Diagnostics.DebugServices;
namespace Microsoft.Diagnostics.ExtensionCommands
public class StatusCommand : CommandBase
{
[ServiceImport]
- public ITarget Target { get; set; }
+ public IHost Host { get; set; }
[ServiceImport]
public ISymbolService SymbolService { get; set; }
+ [ServiceImport]
+ public IContextService ContextService { get; set; }
+
[Option(Name = "--reset", Aliases = new[] { "-reset" }, Help = "Resets the internal cached state.")]
public bool Reset { get; set; }
{
if (Reset)
{
- Target.Flush();
+ foreach (ITarget target in Host.EnumerateTargets())
+ {
+ target.Flush();
+ }
WriteLine("Internal cached state reset");
}
else
{
- Write(Target.ToString());
+ IRuntime currentRuntime = ContextService.GetCurrentRuntime();
+ foreach (ITarget target in Host.EnumerateTargets())
+ {
+ WriteLine(target.ToString());
+
+ IRuntimeService runtimeService = target.Services.GetService<IRuntimeService>();
+
+ // Display the current runtime star ("*") only if there is more than one runtime
+ bool displayStar = runtimeService.EnumerateRuntimes().Count() > 1;
+
+ foreach (IRuntime runtime in runtimeService.EnumerateRuntimes())
+ {
+ string current = displayStar ? (runtime == currentRuntime ? "*" : " ") : "";
+ Write($" {current}");
+ WriteLine(runtime.ToString());
+ string indent = new(' ', 8);
+ this.DisplayResources(runtime.RuntimeModule, all: false, indent);
+ this.DisplayRuntimeExports(runtime.RuntimeModule, error: true, indent);
+ }
+ }
+ this.DisplaySpecialInfo();
Write(SymbolService.ToString());
long memoryUsage = GC.GetTotalMemory(forceFullCollection: true);
WriteLine($"GC memory usage for managed SOS components: {memoryUsage:##,#} bytes");
namespace Microsoft.Diagnostics.ExtensionCommands
{
- [Command(Name = "threads", Aliases = new string[] { "setthread" }, Help = "Displays threads or sets the current thread.")]
+ [Command(Name = "threads", Aliases = new string[] { "setthread" }, Help = "Lists the threads in the target or sets the current thread.")]
public class ThreadsCommand : CommandBase
{
[Argument(Help = "The thread index or id to set, otherwise displays the list of threads.")]
[Option(Name = "--verbose", Aliases = new string[] { "-v" }, Help = "Displays more details.")]
public bool Verbose { get; set; }
- [ServiceImport(Optional = true)]
- public IThread CurrentThread { get; set; }
-
[ServiceImport]
public IThreadService ThreadService { get; set; }
}
else
{
- uint currentThreadId = CurrentThread != null ? CurrentThread.ThreadId : uint.MaxValue;
+ IThread currentThread = ContextService.GetCurrentThread();
foreach (IThread thread in ThreadService.EnumerateThreads())
{
- WriteLine("{0}{1} 0x{2:X4} ({2})", thread.ThreadId == currentThreadId ? "*" : " ", thread.ThreadIndex, thread.ThreadId);
+ WriteLine("{0}{1} 0x{2:X4} ({2})", thread == currentThread ? "*" : " ", thread.ThreadIndex, thread.ThreadId);
if (Verbose)
{
thread.TryGetRegisterValue(ThreadService.InstructionPointerIndex, out ulong ip);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Microsoft.Diagnostics.ExtensionCommands.Output
+{
+ public static class ArrayExtensions
+ {
+ public static string ToHex(this ImmutableArray<byte> array) => string.Concat(array.Select((b) => b.ToString("x2")));
+
+ public static string ToHex(this byte[] array) => string.Concat(array.Select((b) => b.ToString("x2")));
+ }
+}
[ServiceImport]
public CommandService CommandService { get; set; }
- [ServiceImport]
- public IServiceProvider Services { get; set; }
-
[ServiceImport(Optional = true)]
public SOSHost SOSHost { get; set; }
[Command(Name = "writetestdata", Help = "Writes the test data xml file.")]
public class WriteTestDataCommand : CommandBase
{
- [ServiceImport]
- public IServiceProvider Services { get; set; }
-
[Argument(Name = "FileName", Help = "Test data file path.")]
public string FileName { get; set; }