diff --git a/eng/Versions.props b/eng/Versions.props index 73b7b137bb..407a6f1743 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -28,12 +28,12 @@ - 3.1.25 + 3.1.28 $(MicrosoftNETCoreApp31Version) - 6.0.6 + 6.0.8 $(MicrosoftNETCoreApp60Version) - 6.0.6 + 6.0.8 7.0.0-rc.1.22403.8 diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs index bfb2bc5720..7585f33b90 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs @@ -42,8 +42,8 @@ public CommandService(string commandPrompt = null) /// /// command line text /// services for the command - /// exit code - public int Execute(string commandLine, IServiceProvider services) + /// true success, false failure + public bool Execute(string commandLine, IServiceProvider services) { // Parse the command line and invoke the command ParseResult parseResult = Parser.Parse(commandLine); @@ -70,7 +70,7 @@ public int Execute(string commandLine, IServiceProvider services) { context.Console.Error.WriteLine($"Command '{command.Name}' needs a target"); } - return 1; + return false; } try { @@ -78,14 +78,27 @@ public int Execute(string commandLine, IServiceProvider services) } catch (Exception ex) { - OnException(ex, context); + if (ex is NullReferenceException || + ex is ArgumentException || + ex is ArgumentNullException || + ex is ArgumentOutOfRangeException || + ex is NotImplementedException) + { + context.Console.Error.WriteLine(ex.ToString()); + } + else + { + context.Console.Error.WriteLine(ex.Message); + } + Trace.TraceError(ex.ToString()); + return false; } } } } context.InvocationResult?.Apply(context); - return context.ResultCode; + return context.ResultCode == 0; } /// @@ -137,6 +150,13 @@ public bool DisplayHelp(string commandName, IServiceProvider services) return true; } + /// + /// Does this command or alias exists? + /// + /// command or alias name + /// true if command exists + public bool IsCommand(string commandName) => _rootBuilder.Command.Children.Contains(commandName); + /// /// Enumerates all the command's name and help /// @@ -149,28 +169,31 @@ public bool DisplayHelp(string commandName, IServiceProvider services) /// function to create command instance public void AddCommands(Type type, Func factory) { - for (Type baseType = type; baseType != null; baseType = baseType.BaseType) + if (type.IsClass) { - if (baseType == typeof(CommandBase)) { - break; - } - var commandAttributes = (CommandAttribute[])baseType.GetCustomAttributes(typeof(CommandAttribute), inherit: false); - foreach (CommandAttribute commandAttribute in commandAttributes) + for (Type baseType = type; baseType != null; baseType = baseType.BaseType) { - if (factory == null) + if (baseType == typeof(CommandBase)) { - // Assumes zero parameter constructor - ConstructorInfo constructor = type.GetConstructors().SingleOrDefault((info) => info.GetParameters().Length == 0) ?? - throw new ArgumentException($"No eligible constructor found in {type}"); - - factory = (services) => constructor.Invoke(Array.Empty()); + break; + } + var commandAttributes = (CommandAttribute[])baseType.GetCustomAttributes(typeof(CommandAttribute), inherit: false); + foreach (CommandAttribute commandAttribute in commandAttributes) + { + if ((commandAttribute.Flags & CommandFlags.Manual) == 0 || factory != null) + { + if (factory == null) + { + factory = (services) => Utilities.InvokeConstructor(type, services, optional: true); + } + CreateCommand(baseType, commandAttribute, factory); + } } - CreateCommand(baseType, commandAttribute, factory); } - } - // Build or re-build parser instance after all these commands and aliases are added - FlushParser(); + // Build or re-build parser instance after all these commands and aliases are added + FlushParser(); + } } private void CreateCommand(Type type, CommandAttribute commandAttribute, Func factory) @@ -234,27 +257,6 @@ private void CreateCommand(Type type, CommandAttribute commandAttribute, Func _parser = null; - private void OnException(Exception ex, InvocationContext context) - { - if (ex is TargetInvocationException) - { - ex = ex.InnerException; - } - if (ex is NullReferenceException || - ex is ArgumentException || - ex is ArgumentNullException || - ex is ArgumentOutOfRangeException || - ex is NotImplementedException) - { - context.Console.Error.WriteLine(ex.ToString()); - } - else - { - context.Console.Error.WriteLine(ex.Message); - } - Trace.TraceError(ex.ToString()); - } - private static string BuildOptionAlias(string parameterName) { if (string.IsNullOrWhiteSpace(parameterName)) { @@ -319,7 +321,7 @@ Task ICommandHandler.InvokeAsync(InvocationContext context) /// internal bool IsValidPlatform(ITarget target) { - if ((_commandAttribute.Platform & CommandPlatform.Global) != 0) + if ((_commandAttribute.Flags & CommandFlags.Global) != 0) { return true; } @@ -327,15 +329,15 @@ internal bool IsValidPlatform(ITarget target) { if (target.OperatingSystem == OSPlatform.Windows) { - return (_commandAttribute.Platform & CommandPlatform.Windows) != 0; + return (_commandAttribute.Flags & CommandFlags.Windows) != 0; } if (target.OperatingSystem == OSPlatform.Linux) { - return (_commandAttribute.Platform & CommandPlatform.Linux) != 0; + return (_commandAttribute.Flags & CommandFlags.Linux) != 0; } if (target.OperatingSystem == OSPlatform.OSX) { - return (_commandAttribute.Platform & CommandPlatform.OSX) != 0; + return (_commandAttribute.Flags & CommandFlags.OSX) != 0; } } return false; @@ -372,9 +374,7 @@ private void Invoke(MethodInfo methodInfo, InvocationContext context, Parser par { object instance = _factory(services); SetProperties(context, parser, services, instance); - - object[] arguments = BuildArguments(methodInfo, services); - methodInfo.Invoke(instance, arguments); + Utilities.Invoke(methodInfo, instance, services, optional: true); } private void SetProperties(InvocationContext context, Parser parser, IServiceProvider services, object instance) @@ -461,21 +461,6 @@ private void SetProperties(InvocationContext context, Parser parser, IServicePro argument.Property.SetValue(instance, array != null ? array.ToArray() : value); } } - - private object[] BuildArguments(MethodBase methodBase, IServiceProvider services) - { - ParameterInfo[] parameters = methodBase.GetParameters(); - object[] arguments = new object[parameters.Length]; - for (int i = 0; i < parameters.Length; i++) - { - Type parameterType = parameters[i].ParameterType; - - // The parameter will passed as null to allow for "optional" services. The invoked - // method needs to check for possible null parameters. - arguments[i] = services.GetService(parameterType); - } - return arguments; - } } /// diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs index d1d71c81e1..0876574724 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Reflection.PortableExecutable; namespace Microsoft.Diagnostics.DebugServices.Implementation @@ -107,5 +108,65 @@ public static Stream TryOpenFile(string path) return null; } + + /// + /// Call the constructor of the type and return the instance binding any + /// services in the constructor parameters. + /// + /// type to create + /// services + /// if true, the service is not required + /// type instance + public static object InvokeConstructor(Type type, IServiceProvider provider, bool optional) + { + ConstructorInfo constructor = type.GetConstructors().Single(); + object[] arguments = BuildArguments(constructor, provider, optional); + try + { + return constructor.Invoke(arguments); + } + catch (TargetInvocationException ex) + { + throw ex.InnerException; + } + } + + /// + /// Call the method and bind any services in the constructor parameters. + /// + /// method to invoke + /// class instance or null if static + /// services + /// if true, the service is not required + /// method return value + public static object Invoke(MethodBase method, object instance, IServiceProvider provider, bool optional) + { + object[] arguments = BuildArguments(method, provider, optional); + try + { + return method.Invoke(instance, arguments); + } + catch (TargetInvocationException ex) + { + throw ex.InnerException; + } + } + + private static object[] BuildArguments(MethodBase methodBase, IServiceProvider services, bool optional) + { + ParameterInfo[] parameters = methodBase.GetParameters(); + object[] arguments = new object[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + // The parameter will passed as null to allow for "optional" services. The invoked + // method needs to check for possible null parameters. + arguments[i] = services.GetService(parameters[i].ParameterType); + if (arguments[i] is null && !optional) + { + throw new DiagnosticsException($"The {parameters[i].ParameterType} service is required by the {parameters[i].Name} parameter"); + } + } + return arguments; + } } } diff --git a/src/Microsoft.Diagnostics.DebugServices/CommandAttributes.cs b/src/Microsoft.Diagnostics.DebugServices/CommandAttributes.cs index a02161eb70..a41d076712 100644 --- a/src/Microsoft.Diagnostics.DebugServices/CommandAttributes.cs +++ b/src/Microsoft.Diagnostics.DebugServices/CommandAttributes.cs @@ -7,10 +7,10 @@ namespace Microsoft.Diagnostics.DebugServices { /// - /// OS Platforms to add command + /// Command flags to filter by OS Platforms, control scope and how the command is registered. /// [Flags] - public enum CommandPlatform : byte + public enum CommandFlags : byte { Windows = 0x01, Linux = 0x02, @@ -21,6 +21,11 @@ public enum CommandPlatform : byte /// Global = 0x08, + /// + /// Command is not added through reflection, but manually with command service API. + /// + Manual = 0x10, + /// /// Default. All operating system, but target is required /// @@ -49,9 +54,9 @@ public class CommandAttribute : Attribute public string[] Aliases = Array.Empty(); /// - /// Optional OS platform for the command + /// Command flags to filter by OS Platforms, control scope and how the command is registered. /// - public CommandPlatform Platform = CommandPlatform.Default; + public CommandFlags Flags = CommandFlags.Default; /// /// A string of options that are parsed before the command line options diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs index b5d2c54556..8f1bb430e7 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs @@ -13,7 +13,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands { - [Command(Name = CommandName, Help = "Displays information about async \"stacks\" on the garbage-collected heap.")] + [Command(Name = CommandName, Aliases = new string[] { "DumpAsync" }, Help = "Displays information about async \"stacks\" on the garbage-collected heap.")] public sealed class DumpAsyncCommand : ExtensionCommandBase { /// The name of the command. diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Host/LoggingCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Host/LoggingCommand.cs index 10ec2d68d1..974a796816 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Host/LoggingCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Host/LoggingCommand.cs @@ -8,7 +8,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands { - [Command(Name = "logging", Help = "Enable/disable internal logging", Platform = CommandPlatform.Global)] + [Command(Name = "logging", Help = "Enable/disable internal logging", Flags = CommandFlags.Global)] public class LoggingCommand : CommandBase { [Option(Name = "enable", Help = "Enable internal logging.")] diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs index 756b302c00..eaf0797af8 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs @@ -10,7 +10,12 @@ namespace Microsoft.Diagnostics.ExtensionCommands Name = "setsymbolserver", Aliases = new string[] { "SetSymbolServer" }, Help = "Enable and set symbol server support for symbols and module download", - Platform = CommandPlatform.Global)] + Flags = CommandFlags.Global)] + [Command( + Name = "loadsymbols", + DefaultOptions = "--loadsymbols", + Help = "Load symbols for all modules", + Flags = CommandFlags.Global)] public class SetSymbolServerCommand : CommandBase { public ISymbolService SymbolService { get; set; } diff --git a/src/Microsoft.Diagnostics.Repl/ExitCommand.cs b/src/Microsoft.Diagnostics.Repl/ExitCommand.cs index c7678c3f1f..4d4eb4eee1 100644 --- a/src/Microsoft.Diagnostics.Repl/ExitCommand.cs +++ b/src/Microsoft.Diagnostics.Repl/ExitCommand.cs @@ -7,7 +7,7 @@ namespace Microsoft.Diagnostics.Repl { - [Command(Name = "exit", Aliases = new string[] { "quit", "q" }, Help = "Exit interactive mode.", Platform = CommandPlatform.Global)] + [Command(Name = "exit", Aliases = new string[] { "quit", "q" }, Help = "Exit interactive mode.", Flags = CommandFlags.Global | CommandFlags.Manual)] public class ExitCommand : CommandBase { private readonly Action _exit; diff --git a/src/Microsoft.Diagnostics.Repl/HelpCommand.cs b/src/Microsoft.Diagnostics.Repl/HelpCommand.cs index cbf3699f4f..b4153706f4 100644 --- a/src/Microsoft.Diagnostics.Repl/HelpCommand.cs +++ b/src/Microsoft.Diagnostics.Repl/HelpCommand.cs @@ -7,7 +7,7 @@ namespace Microsoft.Diagnostics.Repl { - [Command(Name = "help", Help = "Display help for a command.", Platform = CommandPlatform.Global)] + [Command(Name = "help", Help = "Display help for a command.", Flags = CommandFlags.Global | CommandFlags.Manual)] public class HelpCommand : CommandBase { [Argument(Help = "Command to find help.")] diff --git a/src/SOS/SOS.Extensions/HostServices.cs b/src/SOS/SOS.Extensions/HostServices.cs index 41b9947ac8..91308b8945 100644 --- a/src/SOS/SOS.Extensions/HostServices.cs +++ b/src/SOS/SOS.Extensions/HostServices.cs @@ -13,6 +13,7 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; +using System.Text; namespace SOS.Extensions { @@ -128,7 +129,7 @@ private HostServices() builder.AddMethod(new FlushTargetDelegate(FlushTarget)); builder.AddMethod(new DestroyTargetDelegate(DestroyTarget)); builder.AddMethod(new DispatchCommandDelegate(DispatchCommand)); - builder.AddMethod(new DispatchCommandDelegate(DisplayHelp)); + builder.AddMethod(new DisplayHelpDelegate(DisplayHelp)); builder.AddMethod(new UninitializeDelegate(Uninitialize)); IHostServices = builder.Complete(); @@ -325,15 +326,30 @@ private void DestroyTarget( private HResult DispatchCommand( IntPtr self, - string commandLine) + string commandName, + string commandArguments) { - if (commandLine == null) + if (string.IsNullOrWhiteSpace(commandName)) { return HResult.E_INVALIDARG; } + if (!_commandService.IsCommand(commandName)) + { + return HResult.E_NOTIMPL; + } try { - return _commandService.Execute(commandLine, _contextService.Services); + StringBuilder sb = new(); + sb.Append(commandName); + if (!string.IsNullOrWhiteSpace(commandArguments)) + { + sb.Append(' '); + sb.Append(commandArguments); + } + if (_commandService.Execute(sb.ToString(), _contextService.Services)) + { + return HResult.S_OK; + } } catch (Exception ex) { @@ -344,11 +360,11 @@ private HResult DispatchCommand( private HResult DisplayHelp( IntPtr self, - string command) + string commandName) { try { - if (!_commandService.DisplayHelp(command, _contextService.Services)) + if (!_commandService.DisplayHelp(commandName, _contextService.Services)) { return HResult.E_INVALIDARG; } @@ -424,12 +440,13 @@ private delegate void DestroyTargetDelegate( [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate HResult DispatchCommandDelegate( [In] IntPtr self, - [In, MarshalAs(UnmanagedType.LPStr)] string commandLine); + [In, MarshalAs(UnmanagedType.LPStr)] string commandName, + [In, MarshalAs(UnmanagedType.LPStr)] string commandArguments); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate HResult DisplayHelpDelegate( [In] IntPtr self, - [In, MarshalAs(UnmanagedType.LPStr)] string command); + [In, MarshalAs(UnmanagedType.LPStr)] string commandName); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate void UninitializeDelegate( diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index c37b4f7b1e..d4e5f38570 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -60,13 +60,13 @@ namespace SOS.Hosting [Command(Name = "threadpool", DefaultOptions = "ThreadPool", Help = "Lists basic information about the thread pool.")] [Command(Name = "verifyheap", DefaultOptions = "VerifyHeap", Help = "Checks the GC heap for signs of corruption.")] [Command(Name = "verifyobj", DefaultOptions = "VerifyObj", Help = "Checks the object for signs of corruption.")] - [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Platform = CommandPlatform.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] - [Command(Name = "dumpccw", DefaultOptions = "DumpCCW", Platform = CommandPlatform.Windows, Help = "Displays information about a COM Callable Wrapper.")] - [Command(Name = "dumppermissionset",DefaultOptions = "DumpPermissionSet", Platform = CommandPlatform.Windows, Help = "Displays a PermissionSet object (debug build only).")] - [Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Platform = CommandPlatform.Windows, Help = "Writes out a file in a format understood by the CLR Profiler.")] - [Command(Name = "watsonbuckets", DefaultOptions = "WatsonBuckets", Platform = CommandPlatform.Windows, Help = "Displays the Watson buckets.")] - [Command(Name = "comstate", DefaultOptions = "COMState", Platform = CommandPlatform.Windows, Help = "Lists the COM apartment model for each thread.")] - [Command(Name = "gchandleleaks", DefaultOptions = "GCHandleLeaks", Platform = CommandPlatform.Windows, Help = "Helps in tracking down GCHandle leaks")] + [Command(Name = "comstate", DefaultOptions = "COMState", Flags = CommandFlags.Windows, Help = "Lists the COM apartment model for each thread.")] + [Command(Name = "dumprcw", DefaultOptions = "DumpRCW", Flags = CommandFlags.Windows, Help = "Displays information about a Runtime Callable Wrapper.")] + [Command(Name = "dumpccw", DefaultOptions = "DumpCCW", Flags = CommandFlags.Windows, Help = "Displays information about a COM Callable Wrapper.")] + [Command(Name = "dumppermissionset",DefaultOptions = "DumpPermissionSet", Flags = CommandFlags.Windows, Help = "Displays a PermissionSet object (debug build only).")] + [Command(Name = "gchandleleaks", DefaultOptions = "GCHandleLeaks", Flags = CommandFlags.Windows, Help = "Helps in tracking down GCHandle leaks")] + [Command(Name = "traverseheap", DefaultOptions = "TraverseHeap", Flags = CommandFlags.Windows, Help = "Writes out a file in a format understood by the CLR Profiler.")] + [Command(Name = "watsonbuckets", DefaultOptions = "WatsonBuckets", Flags = CommandFlags.Windows, Help = "Displays the Watson buckets.")] public class SOSCommand : CommandBase { [Argument(Name = "arguments", Help = "Arguments to SOS command.")] @@ -78,7 +78,7 @@ public override void Invoke() { try { Debug.Assert(Arguments != null && Arguments.Length > 0); - string arguments = string.Concat(Arguments.Skip(1).Select((arg) => arg + " ")); + string arguments = string.Concat(Arguments.Skip(1).Select((arg) => arg + " ")).Trim(); SOSHost.ExecuteCommand(Arguments[0], arguments); } catch (Exception ex) when (ex is FileNotFoundException || ex is EntryPointNotFoundException || ex is InvalidOperationException) { diff --git a/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs b/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs index 0954470bc5..058cdb4dfb 100644 --- a/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs +++ b/src/SOS/SOS.Hosting/CorDebugDataTargetWrapper.cs @@ -125,13 +125,17 @@ private unsafe int ReadVirtual( uint bytesRequested, uint* pbytesRead) { - address &= _ignoreAddressBitsMask; - if (!_memoryService.ReadMemory(address, buffer, unchecked((int)bytesRequested), out int bytesRead)) + int read = 0; + if (bytesRequested > 0) { - Trace.TraceError("CorDebugDataTargetWrappter.ReadVirtual FAILED address {0:X16} size {1:X8}", address, bytesRequested); - return HResult.E_FAIL; + address &= _ignoreAddressBitsMask; + if (!_memoryService.ReadMemory(address, buffer, unchecked((int)bytesRequested), out read)) + { + Trace.TraceError("CorDebugDataTargetWrappter.ReadVirtual FAILED address {0:X16} size {1:X8}", address, bytesRequested); + return HResult.E_FAIL; + } } - SOSHost.Write(pbytesRead, (uint)bytesRead); + SOSHost.Write(pbytesRead, (uint)read); return HResult.S_OK; } diff --git a/src/SOS/SOS.Hosting/DataTargetWrapper.cs b/src/SOS/SOS.Hosting/DataTargetWrapper.cs index 826143d224..a5a9d4992e 100644 --- a/src/SOS/SOS.Hosting/DataTargetWrapper.cs +++ b/src/SOS/SOS.Hosting/DataTargetWrapper.cs @@ -149,17 +149,21 @@ private int ReadVirtual( ulong address, IntPtr buffer, uint bytesRequested, - uint* bytesRead) + uint* pbytesRead) { Debug.Assert(address != MagicCallbackConstant); - address &= _ignoreAddressBitsMask; - if (!_memoryService.ReadMemory(address, buffer, unchecked((int)bytesRequested), out int read)) + int read = 0; + if (bytesRequested > 0) { - Trace.TraceError("DataTargetWrapper.ReadVirtual FAILED address {0:X16} size {1:X8}", address, bytesRequested); - SOSHost.Write(bytesRead); - return HResult.E_FAIL; + address &= _ignoreAddressBitsMask; + if (!_memoryService.ReadMemory(address, buffer, unchecked((int)bytesRequested), out read)) + { + Trace.TraceError("DataTargetWrapper.ReadVirtual FAILED address {0:X16} size {1:X8}", address, bytesRequested); + SOSHost.Write(pbytesRead); + return HResult.E_FAIL; + } } - SOSHost.Write(bytesRead, (uint)read); + SOSHost.Write(pbytesRead, (uint)read); return HResult.S_OK; } diff --git a/src/SOS/SOS.Hosting/SOSLibrary.cs b/src/SOS/SOS.Hosting/SOSLibrary.cs index 1009e5a7be..a43683f7c3 100644 --- a/src/SOS/SOS.Hosting/SOSLibrary.cs +++ b/src/SOS/SOS.Hosting/SOSLibrary.cs @@ -159,7 +159,7 @@ public void ExecuteCommand(IntPtr client, string command, string arguments) var commandFunc = SOSHost.GetDelegateFunction(_sosLibrary, command); if (commandFunc == null) { - throw new EntryPointNotFoundException($"Can not find SOS command: {command}"); + throw new DiagnosticsException($"SOS command not found: {command}"); } int result = commandFunc(client, arguments ?? ""); if (result != HResult.S_OK) diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index 2b6c697e17..616733bfae 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -924,6 +924,8 @@ public async Task LoadSosExtension() { commands.Add($"sethostruntime {setHostRuntime}"); } + // Disabled until https://github.com/dotnet/diagnostics/issues/3265 is fixed. +#if DISABLED // If a single-file app, add the path to runtime so SOS can find DAC/DBI locally. if (_config.PublishSingleFile) { @@ -932,6 +934,7 @@ public async Task LoadSosExtension() commands.Add($"setclrpath {runtimeSymbolsPath}"); } } +#endif if (!isHostRuntimeNone && !string.IsNullOrEmpty(setSymbolServer)) { commands.Add($"setsymbolserver {setSymbolServer}"); @@ -1015,7 +1018,7 @@ public async Task RunSosCommand(string command, bool extensionCommand = fa case NativeDebugger.Cdb: if (extensionCommand) { - command = "!ext " + command; + command = "!sos " + command; } else { @@ -1023,20 +1026,26 @@ public async Task RunSosCommand(string command, bool extensionCommand = fa } break; case NativeDebugger.Lldb: - if (!extensionCommand) - { - command = "sos " + command; - } + command = "sos " + command; break; case NativeDebugger.DotNetDump: - int index = command.IndexOf(' '); - if (index != -1) { - // lowercase just the command name not the rest of the command line - command = command.Substring(0, index).ToLowerInvariant() + command.Substring(index); + if (extensionCommand) + { + command = "sos " + command; } - else { - // it is only the command name - command = command.ToLowerInvariant(); + else + { + int index = command.IndexOf(' '); + if (index != -1) + { + // lowercase just the command name not the rest of the command line + command = command.Substring(0, index).ToLowerInvariant() + command.Substring(index); + } + else + { + // it is only the command name + command = command.ToLowerInvariant(); + } } break; default: diff --git a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script index 76470093ed..32fb62b9eb 100644 --- a/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script +++ b/src/SOS/SOS.UnitTests/Scripts/OtherCommands.script @@ -68,9 +68,11 @@ VERIFY:\s*\s+0x\s+\(\)\s+ EXTCOMMAND:registers VERIFY:\s*([r|e]ip|pc) = 0x\s+ -SOSCOMMAND:ThreadPool +EXTCOMMAND:ClrStack -SOSCOMMAND:VerifyHeap +EXTCOMMAND:ThreadPool + +EXTCOMMAND:VerifyHeap SOSCOMMAND:DumpHeap VERIFY:\s+Address\s+MT\s+Size\s+ diff --git a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script index e4afc5c497..3cf92dd763 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackAndOtherTests.script @@ -197,7 +197,6 @@ VERIFY:.*\s+\s+\s+System\.String\[\].* ENDIF:NETCORE_OR_DOTNETDUMP # Issue: https://github.com/dotnet/diagnostics/issues/2947 -!IFDEF:MAJOR_RUNTIME_VERSION_GE_7 !IFDEF:DOTNETDUMP !IFDEF:ARM @@ -220,7 +219,6 @@ VERIFY:(.*\s+\s+\s+\(MethodDesc\s+\s+(\+\s*0x\s+ ENDIF:ARM ENDIF:DOTNETDUMP -ENDIF:MAJOR_RUNTIME_VERSION_GE_7 # Verify that IP2MD works (uses IP from ClrStack) SOSCOMMAND:ClrStack diff --git a/src/SOS/SOS.UnitTests/Scripts/StackTests.script b/src/SOS/SOS.UnitTests/Scripts/StackTests.script index e7bb519a48..d140295527 100644 --- a/src/SOS/SOS.UnitTests/Scripts/StackTests.script +++ b/src/SOS/SOS.UnitTests/Scripts/StackTests.script @@ -151,7 +151,6 @@ VERIFY:.*\s+\s+\s+System\.InvalidOperationException\s+ VERIFY:.*\s+\s+\s+System\.String.* # Issue: https://github.com/dotnet/diagnostics/issues/2947 -!IFDEF:MAJOR_RUNTIME_VERSION_GE_7 !IFDEF:DOTNETDUMP !IFDEF:ARM @@ -174,4 +173,3 @@ VERIFY:.*\s+\s+\s+\(MethodDesc\s+\s+\+\s*0x\s+Ne ENDIF:ARM ENDIF:DOTNETDUMP -ENDIF:MAJOR_RUNTIME_VERSION_GE_7 diff --git a/src/SOS/SOS.UnitTests/Scripts/WebApp.script b/src/SOS/SOS.UnitTests/Scripts/WebApp.script index f5e7e5eef7..ffa91ff7e9 100644 --- a/src/SOS/SOS.UnitTests/Scripts/WebApp.script +++ b/src/SOS/SOS.UnitTests/Scripts/WebApp.script @@ -34,11 +34,19 @@ EXTCOMMAND:parallelstacks EXTCOMMAND:timerinfo VERIFY:\s*\s*timers\s* +SOSCOMMAND:runtimes + +EXTCOMMAND:runtimes + # Verify that ClrStack with no options works SOSCOMMAND:ClrStack VERIFY:.*OS Thread Id:\s+0x\s+.* VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+ +EXTCOMMAND:ClrStack +VERIFY:.*OS Thread Id:\s+0x\s+.* +VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+ + # Verify that ClrStack for all threads works SOSCOMMAND:ClrStack -all diff --git a/src/SOS/Strike/Strike.vcxproj b/src/SOS/Strike/Strike.vcxproj index b8ec9fe5bc..be63febcfb 100644 --- a/src/SOS/Strike/Strike.vcxproj +++ b/src/SOS/Strike/Strike.vcxproj @@ -265,7 +265,7 @@ true Level3 true - NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;_TARGET_WIN64_=1;SOS_TARGET_AMD64=1;SOS_TARGET_ARM64=1;STRIKE;USE_STL;FX_VER_INTERNALNAME_STR=SOS.dll;CMAKE_INTDIR="Release";sos_EXPORTS;%(PreprocessorDefinitions) + HOST_WINDOWS;NDEBUG;URTBLDENV_FRIENDLY=Retail;_AMD64_;_WIN64;AMD64;BIT64=1;_TARGET_64BIT_=1;_TARGET_AMD64_=1;DBG_TARGET_64BIT=1;DBG_TARGET_AMD64=1;DBG_TARGET_WIN64=1;WIN32;_WIN32;WINVER=0x0602;_WIN32_WINNT=0x0602;WIN32_LEAN_AND_MEAN=1;_CRT_SECURE_NO_WARNINGS;FEATURE_COMINTEROP;FEATURE_HIJACK;_SECURE_SCL=0;_TARGET_WIN64_=1;SOS_TARGET_AMD64=1;SOS_TARGET_ARM64=1;STRIKE;USE_STL;FX_VER_INTERNALNAME_STR=SOS.dll;CMAKE_INTDIR="Release";sos_EXPORTS;%(PreprocessorDefinitions) $(IntDir) diff --git a/src/SOS/Strike/sos.def b/src/SOS/Strike/sos.def index e548eac314..6dec87fd17 100644 --- a/src/SOS/Strike/sos.def +++ b/src/SOS/Strike/sos.def @@ -74,7 +74,9 @@ EXPORTS EHInfo ehinfo=EHInfo Ehinfo=EHInfo + enummemory ext + sos=ext FinalizeQueue finalizequeue=FinalizeQueue fq=FinalizeQueue diff --git a/src/SOS/Strike/sos_unixexports.src b/src/SOS/Strike/sos_unixexports.src index 35bd51fa0c..9ac9f71d9a 100644 --- a/src/SOS/Strike/sos_unixexports.src +++ b/src/SOS/Strike/sos_unixexports.src @@ -4,13 +4,11 @@ AnalyzeOOM bpmd -clrmodules ClrStack dbgout DumpALC DumpArray DumpAssembly -DumpAsync DumpClass DumpDelegate DumpDomain @@ -32,7 +30,7 @@ EEHeap EEVersion EEStack EHInfo -ext +enummemory FinalizeQueue FindAppDomain FindRoots @@ -50,7 +48,6 @@ HistRoot HistStats IP2MD ListNearObj -logging Name2EE ObjSize PrintException @@ -58,9 +55,9 @@ PathTo runtimes StopOnCatch SetClrPath -SetSymbolServer SOSFlush SOSStatus +runtimes SuppressJitOptimization SyncBlk Threads diff --git a/src/SOS/Strike/sosdocsunix.txt b/src/SOS/Strike/sosdocsunix.txt index 6eb004882b..00127b9d5a 100644 --- a/src/SOS/Strike/sosdocsunix.txt +++ b/src/SOS/Strike/sosdocsunix.txt @@ -2227,8 +2227,7 @@ You can use the "dotnet --info" in a command shell to find the path of an instal COMMAND: setsymbolserver. COMMAND: loadsymbols. -COMMAND: sympath. -SetSymbolServer [-ms] [-disable] [-log] [-loadsymbols] [-cache ] [-directory ] [-timeout ] [-pat ] [-sympath ] [] +SetSymbolServer [-ms] [-disable] [-log] [-loadsymbols] [-cache ] [-directory ] [-timeout ] [-pat ] [] -ms - Use the public Microsoft symbol server. -disable - Disable symbol download support. @@ -2236,7 +2235,6 @@ SetSymbolServer [-ms] [-disable] [-log] [-loadsymbols] [-cache ] [- -timeout - Specify the symbol server timeout in minutes -pat - Access token to the authenticated server. -cache - Specific a symbol cache directory. The default is $HOME/.dotnet/symbolcache if not specified. --sympath - Add server, cache and directory paths in the Windows symbol path format. -loadsymbols - Attempts to download the native .NET Core symbols for the runtime - Symbol server URL. @@ -2260,10 +2258,6 @@ To add a directory to search for symbols: This command can be used so the module/symbol file structure does not have to match the machine file structure that the core dump was generated. -The "sympath" option/command alias allows Windows symbol paths to be parsed: - - (lldb) sympath "/home/mikem/localsymbols;srv*/home/mikem/symbolcache*https://msdl.microsoft.com/download/symbols". - To clear the default cache run "rm -r $HOME/.dotnet/symbolcache" in a command shell. If you receive an error like the one below on a core dump, you need to set the .NET Core diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index dd5177e95b..e974e1684c 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -105,6 +105,7 @@ #include "cordebug.h" #include "dacprivate.h" #include "corexcep.h" +#include #define CORHANDLE_MASK 0x1 #define SWITCHED_OUT_FIBER_OSID 0xbaadf00d; @@ -10357,9 +10358,7 @@ DECLARE_API(SOSStatus) IHostServices* hostServices = GetHostServices(); if (hostServices != nullptr) { - std::string command("sosstatus "); - command.append(args); - Status = hostServices->DispatchCommand(command.c_str()); + Status = hostServices->DispatchCommand("sosstatus", args); } else { @@ -15697,6 +15696,108 @@ DECLARE_API(StopOnCatch) return S_OK; } +class EnumMemoryCallback : public ICLRDataEnumMemoryRegionsCallback, ICLRDataEnumMemoryRegionsLoggingCallback +{ +private: + LONG m_ref; + bool m_log; + +public: + EnumMemoryCallback(bool log) : + m_ref(1), + m_log(log) + { + } + + virtual ~EnumMemoryCallback() + { + } + + STDMETHODIMP QueryInterface( + ___in REFIID InterfaceId, + ___out PVOID* Interface) + { + if (InterfaceId == IID_IUnknown || + InterfaceId == IID_ICLRDataEnumMemoryRegionsCallback) + { + *Interface = (ICLRDataEnumMemoryRegionsCallback*)this; + AddRef(); + return S_OK; + } + else if (InterfaceId == IID_ICLRDataEnumMemoryRegionsLoggingCallback) + { + *Interface = (ICLRDataEnumMemoryRegionsLoggingCallback*)this; + AddRef(); + return S_OK; + } + else + { + *Interface = nullptr; + return E_NOINTERFACE; + } + } + + STDMETHODIMP_(ULONG) AddRef() + { + LONG ref = InterlockedIncrement(&m_ref); + return ref; + } + + STDMETHODIMP_(ULONG) Release() + { + LONG ref = InterlockedDecrement(&m_ref); + if (ref == 0) + { + delete this; + } + return ref; + } + + HRESULT STDMETHODCALLTYPE EnumMemoryRegion( + /* [in] */ CLRDATA_ADDRESS address, + /* [in] */ ULONG32 size) + { + if (m_log) + { + ExtOut("%016llx %08x\n", address, size); + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE LogMessage( + /* [in] */ LPCSTR message) + { + ExtOut("%s", message); + return S_OK; + } +}; + +DECLARE_API(enummemory) +{ + INIT_API(); + + ToRelease enumMemoryRegions; + Status = g_clrData->QueryInterface(__uuidof(ICLRDataEnumMemoryRegions), (void**)&enumMemoryRegions); + if (SUCCEEDED(Status)) + { + ToRelease callback = new EnumMemoryCallback(false); + ULONG32 minidumpType = + (MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); + Status = enumMemoryRegions->EnumMemoryRegions(callback, minidumpType, CLRDataEnumMemoryFlags::CLRDATA_ENUM_MEM_DEFAULT); + if (FAILED(Status)) + { + ExtErr("EnumMemoryRegions FAILED %08x\n", Status); + } + } + return Status; +} + #ifndef FEATURE_PAL // This is an undocumented SOS extension command intended to help test SOS @@ -16008,9 +16109,7 @@ DECLARE_API(SetClrPath) IHostServices* hostServices = GetHostServices(); if (hostServices != nullptr) { - std::string command("setclrpath "); - command.append(args); - return hostServices->DispatchCommand(command.c_str()); + return hostServices->DispatchCommand("setclrpath", args); } else { @@ -16054,9 +16153,7 @@ DECLARE_API(runtimes) IHostServices* hostServices = GetHostServices(); if (hostServices != nullptr) { - std::string command("runtimes "); - command.append(args); - Status = hostServices->DispatchCommand(command.c_str()); + Status = hostServices->DispatchCommand("runtimes", args); } else { @@ -16099,31 +16196,22 @@ DECLARE_API(runtimes) return Status; } +#ifdef HOST_WINDOWS + // // Executes managed extension commands // -HRESULT ExecuteCommand(PCSTR command, PCSTR args) +HRESULT ExecuteCommand(PCSTR commandName, PCSTR args) { IHostServices* hostServices = GetHostServices(); if (hostServices != nullptr) { - std::string commandLine(command); - if (args != nullptr && strlen(args) > 0) - { - commandLine.append(" "); - commandLine.append(args); - } - if (!commandLine.empty()) + if (commandName != nullptr && strlen(commandName) > 0) { - return hostServices->DispatchCommand(commandLine.c_str()); + return hostServices->DispatchCommand(commandName, args); } } - else - { - ExtErr("Command not loaded\n"); - return E_FAIL; - } - return S_OK; + return E_NOTIMPL; } // @@ -16162,15 +16250,44 @@ DECLARE_API(logging) return ExecuteCommand("logging", args); } +typedef HRESULT (*PFN_COMMAND)(PDEBUG_CLIENT client, PCSTR args); + // // Executes managed extension commands // DECLARE_API(ext) { INIT_API_EXT(); - return ExecuteCommand("", args); + + if (args == nullptr || strlen(args) <= 0) + { + args = "Help"; + } + std::string arguments(args); + size_t pos = arguments.find(' '); + std::string commandName = arguments.substr(0, pos); + if (pos != std::string::npos) + { + arguments = arguments.substr(pos + 1); + } + else + { + arguments.clear(); + } + Status = ExecuteCommand(commandName.c_str(), arguments.c_str()); + if (Status == E_NOTIMPL) + { + PFN_COMMAND commandFunc = (PFN_COMMAND)GetProcAddress(g_hInstance, commandName.c_str()); + if (commandFunc != nullptr) + { + Status = (*commandFunc)(client, arguments.c_str()); + } + } + return Status; } +#endif // HOST_WINDOWS + void PrintHelp (__in_z LPCSTR pszCmdName) { static LPSTR pText = NULL; diff --git a/src/SOS/inc/hostservices.h b/src/SOS/inc/hostservices.h index 6b7c19eb6f..bf4403845f 100644 --- a/src/SOS/inc/hostservices.h +++ b/src/SOS/inc/hostservices.h @@ -76,18 +76,20 @@ IHostServices : public IUnknown /// /// Dispatches the command line to managed extension /// - /// full command line + /// command name + /// command arguments /// error code virtual HRESULT STDMETHODCALLTYPE DispatchCommand( - PCSTR commandLine) = 0; + PCSTR commandName, + PCSTR arguments) = 0; /// /// Displays the help for a managed extension command /// - /// + /// /// error code virtual HRESULT STDMETHODCALLTYPE DisplayHelp( - PCSTR command) = 0; + PCSTR commandName) = 0; /// /// Uninitialize the extension infrastructure diff --git a/src/SOS/lldbplugin/services.cpp b/src/SOS/lldbplugin/services.cpp index c278558289..fde35e73f8 100644 --- a/src/SOS/lldbplugin/services.cpp +++ b/src/SOS/lldbplugin/services.cpp @@ -2113,19 +2113,17 @@ class ExtensionCommand : public lldb::SBCommandPluginInterface result.SetStatus(lldb::eReturnStatusFailed); return false; } - std::string commandLine; - commandLine.append(m_commandName); - commandLine.append(" "); + std::string commandArguments; if (arguments != nullptr) { - for (const char* arg = *arguments; arg; arg = *(++arguments)) + for (const char* arg = *arguments; arg != nullptr; arg = *(++arguments)) { - commandLine.append(arg); - commandLine.append(" "); + commandArguments.append(arg); + commandArguments.append(" "); } } g_services->FlushCheck(); - HRESULT hr = hostservices->DispatchCommand(commandLine.c_str()); + HRESULT hr = hostservices->DispatchCommand(m_commandName, commandArguments.c_str()); if (hr != S_OK) { result.SetStatus(lldb::eReturnStatusFailed); @@ -2784,6 +2782,66 @@ LLDBServices::AddCommand( return command; } +void +LLDBServices::AddManagedCommand( + const char* name, + const char* help) +{ + HRESULT hr = AddCommand(name, help, nullptr, 0); + if (FAILED(hr)) + { + Output(DEBUG_OUTPUT_ERROR, "AddManagedCommand FAILED %08x\n", hr); + } +} + +bool +LLDBServices::ExecuteCommand( + const char* commandName, + char** arguments, + lldb::SBCommandReturnObject &result) +{ + // Build all the possible arguments into a string + std::string commandArguments; + for (const char* arg = *arguments; arg != nullptr; arg = *(++arguments)) + { + commandArguments.append(arg); + commandArguments.append(" "); + } + // Load and initialize the managed extensions and commands before we check the m_commands list. + IHostServices* hostservices = GetHostServices(); + + // If the command is a native SOS or managed extension command execute it through the lldb command added. + if (m_commands.find(commandName) != m_commands.end()) + { + std::string commandLine; + commandLine.append(commandName); + if (!commandArguments.empty()) + { + commandLine.append(" "); + commandLine.append(commandArguments); + } + lldb::ReturnStatus status = m_interpreter.HandleCommand(commandLine.c_str(), result); + result.SetStatus(status); + return true; + } + + // Fallback to dispatch it as a managed command for those commands that couldn't be added + // directly to the lldb interpreter because of existing commands or aliases. + if (hostservices != nullptr) + { + g_services->FlushCheck(); + HRESULT hr = hostservices->DispatchCommand(commandName, commandArguments.c_str()); + if (hr != E_NOTIMPL) + { + result.SetStatus(hr == S_OK ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusFailed); + return true; + } + } + + // Command not found; attempt dispatch to native SOS module + return false; +} + HRESULT LLDBServices::InternalOutputVaList( ULONG mask, diff --git a/src/SOS/lldbplugin/services.h b/src/SOS/lldbplugin/services.h index 558f30d856..d741ed51eb 100644 --- a/src/SOS/lldbplugin/services.h +++ b/src/SOS/lldbplugin/services.h @@ -414,5 +414,9 @@ class LLDBServices : public ILLDBServices, public ILLDBServices2, public IDebugg lldb::SBCommand AddCommand(const char *name, lldb::SBCommandPluginInterface *impl, const char *help); + void AddManagedCommand(const char* name, const char* help); + + bool ExecuteCommand( const char* commandName, char** arguments, lldb::SBCommandReturnObject &result); + HRESULT InternalOutputVaList(ULONG mask, PCSTR format, va_list args); }; diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 2ed9a26cf1..d9bee0214f 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -38,21 +38,27 @@ class sosCommand : public lldb::SBCommandPluginInterface { result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - LoadSos(); - - if (g_sosHandle != nullptr) + const char* sosCommand = m_command; + if (sosCommand == nullptr) { - const char* sosCommand = m_command; - if (sosCommand == nullptr) + if (arguments == nullptr || *arguments == nullptr) { - if (arguments == nullptr || *arguments == nullptr) { - sosCommand = "Help"; - } - else + sosCommand = "Help"; + } + else + { + sosCommand = *arguments++; + if (g_services->ExecuteCommand(sosCommand, arguments, result)) { - sosCommand = *arguments++; + return result.Succeeded(); } } + } + + LoadSos(); + + if (g_sosHandle != nullptr) + { CommandFunc commandFunc = (CommandFunc)dlsym(g_sosHandle, sosCommand); if (commandFunc) { @@ -149,16 +155,16 @@ bool sosCommandInitialize(lldb::SBDebugger debugger) { g_services->AddCommand("sos", new sosCommand(nullptr), "Various .NET Core debugging commands. See 'soshelp' for more details. sos "); - g_services->AddCommand("ext", new sosCommand("ext"), "Execute extension command. See 'soshelp' for more details. ext "); + g_services->AddCommand("ext", new sosCommand(nullptr), "Various .NET Core debugging commands. See 'soshelp' for more details. ext "); g_services->AddCommand("bpmd", new sosCommand("bpmd"), "Creates a breakpoint at the specified managed method in the specified module."); - g_services->AddCommand("clrmodules", new sosCommand("clrmodules"), "Lists the managed modules in the process."); + g_services->AddManagedCommand("clrmodules", "Lists the managed modules in the process."); g_services->AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only."); g_services->AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running."); g_services->AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method."); g_services->AddCommand("dbgout", new sosCommand("dbgout"), "Enable/disable (-off) internal SOS logging."); g_services->AddCommand("dumpalc", new sosCommand("DumpALC"), "Displays details about a collectible AssemblyLoadContext to which the specified object is loaded."); g_services->AddCommand("dumparray", new sosCommand("DumpArray"), "Displays details about a managed array."); - g_services->AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays information about async \"stacks\" on the garbage-collected heap."); + g_services->AddManagedCommand("dumpasync", "Displays information about async \"stacks\" on the garbage-collected heap."); g_services->AddCommand("dumpassembly", new sosCommand("DumpAssembly"), "Displays details about an assembly."); g_services->AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address."); g_services->AddCommand("dumpdelegate", new sosCommand("DumpDelegate"), "Displays information about a delegate."); @@ -198,20 +204,20 @@ sosCommandInitialize(lldb::SBDebugger debugger) g_services->AddCommand("histstats", new sosCommand("HistStats"), "Displays stress log stats."); g_services->AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled."); g_services->AddCommand("listnearobj", new sosCommand("ListNearObj"), "displays the object preceeding and succeeding the address passed."); - g_services->AddCommand("loadsymbols", new sosCommand("SetSymbolServer", "-loadsymbols"), "Load the .NET Core native module symbols."); - g_services->AddCommand("logging", new sosCommand("logging"), "Enable/disable internal SOS logging."); + g_services->AddManagedCommand("loadsymbols", "Load the .NET Core native module symbols."); + g_services->AddManagedCommand("logging", "Enable/disable internal SOS logging."); g_services->AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module."); g_services->AddCommand("objsize", new sosCommand("ObjSize"), "Displays the size of the specified object."); - g_services->AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); g_services->AddCommand("pathto", new sosCommand("PathTo"), "Displays the GC path from to ."); + g_services->AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); + g_services->AddCommand("printexception", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address."); g_services->AddCommand("runtimes", new sosCommand("runtimes"), "List the runtimes in the target or change the default runtime."); g_services->AddCommand("stoponcatch", new sosCommand("StopOnCatch"), "Debuggee will break the next time a managed exception is caught during execution"); g_services->AddCommand("setclrpath", new sosCommand("SetClrPath"), "Set the path to load the runtime DAC/DBI files."); - g_services->AddCommand("setsymbolserver", new sosCommand("SetSymbolServer"), "Enables the symbol server support "); - g_services->AddCommand("sympath", new sosCommand("SetSymbolServer", "-sympath"), "Add server, cache and directory paths in the Windows symbol path format."); + g_services->AddManagedCommand("setsymbolserver", "Enables the symbol server support "); g_services->AddCommand("soshelp", new sosCommand("Help"), "Displays all available commands when no parameter is specified, or displays detailed help information about the specified command. soshelp "); - g_services->AddCommand("sosflush", new sosCommand("SOSFlush"), "Flushes the DAC caches."); g_services->AddCommand("sosstatus", new sosCommand("SOSStatus"), "Displays the global SOS status."); + g_services->AddCommand("sosflush", new sosCommand("SOSFlush"), "Flushes the DAC caches."); g_services->AddCommand("syncblk", new sosCommand("SyncBlk"), "Displays the SyncBlock holder info."); g_services->AddCommand("threadpool", new sosCommand("ThreadPool"), "Displays info about the runtime thread pool."); g_services->AddCommand("threadstate", new sosCommand("ThreadState"), "Pretty prints the meaning of a threads state."); diff --git a/src/Tools/dotnet-dump/Analyzer.cs b/src/Tools/dotnet-dump/Analyzer.cs index 7532b870df..069e3af3bf 100644 --- a/src/Tools/dotnet-dump/Analyzer.cs +++ b/src/Tools/dotnet-dump/Analyzer.cs @@ -58,6 +58,7 @@ public Analyzer() _commandService.AddCommands(new Assembly[] { typeof(SOSHost).Assembly }); _commandService.AddCommands(typeof(HelpCommand), (services) => new HelpCommand(_commandService, services)); _commandService.AddCommands(typeof(ExitCommand), (services) => new ExitCommand(_consoleProvider.Stop)); + _commandService.AddCommands(typeof(SOSCommand), (services) => new SOSCommand(_commandService, services)); } public Task Analyze(FileInfo dump_path, string[] command) diff --git a/src/Tools/dotnet-dump/Commands/ReadMemoryCommand.cs b/src/Tools/dotnet-dump/Commands/ReadMemoryCommand.cs index a6f7a25c90..6cf6ec614b 100644 --- a/src/Tools/dotnet-dump/Commands/ReadMemoryCommand.cs +++ b/src/Tools/dotnet-dump/Commands/ReadMemoryCommand.cs @@ -6,7 +6,7 @@ using System; using System.Text; -namespace Microsoft.Diagnostics.ExtensionCommands +namespace Microsoft.Diagnostics.Tools.Dump { [Command(Name = "readmemory", Aliases = new string[] { "d" }, Help = "Dump memory contents.")] [Command(Name = "db", DefaultOptions = "--ascii:true --unicode:false --ascii-string:false --unicode-string:false -c:128 -l:1 -w:16", Help = "Dump memory as bytes.")] diff --git a/src/Tools/dotnet-dump/Commands/SOSCommand.cs b/src/Tools/dotnet-dump/Commands/SOSCommand.cs new file mode 100644 index 0000000000..4d3a2f4a8f --- /dev/null +++ b/src/Tools/dotnet-dump/Commands/SOSCommand.cs @@ -0,0 +1,60 @@ +// 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.DebugServices.Implementation; +using SOS.Hosting; +using System; +using System.Linq; + +namespace Microsoft.Diagnostics.Tools.Dump +{ + [Command(Name = "sos", Aliases = new string[] { "ext" }, Help = "Run SOS command", Flags = CommandFlags.Global | CommandFlags.Manual)] + public class SOSCommand : CommandBase + { + private readonly CommandService _commandService; + private readonly IServiceProvider _services; + private SOSHost _sosHost; + + [Argument(Name = "arguments", Help = "SOS command and arguments.")] + public string[] Arguments { get; set; } + + public SOSCommand(CommandService commandService, IServiceProvider services) + { + _commandService = commandService; + _services = services; + } + + public override void Invoke() + { + string commandLine; + string commandName; + if (Arguments != null && Arguments.Length > 0) + { + commandLine = string.Concat(Arguments.Select((arg) => arg + " ")).Trim(); + commandName = Arguments[0]; + } + else + { + commandLine = commandName = "help"; + } + if (_commandService.IsCommand(commandName)) + { + _commandService.Execute(commandLine, _services); + } + else + { + if (_sosHost is null) + { + _sosHost = _services.GetService(); + if (_sosHost is null) + { + throw new DiagnosticsException($"'{commandName}' command not found"); + } + } + _sosHost.ExecuteCommand(commandLine); + } + } + } +} diff --git a/src/shared/inc/clrdata.idl b/src/shared/inc/clrdata.idl index 0ce58c6fa7..4252dc6409 100644 --- a/src/shared/inc/clrdata.idl +++ b/src/shared/inc/clrdata.idl @@ -25,6 +25,7 @@ import "unknwn.idl"; interface ICLRDataEnumMemoryRegions; interface ICLRDataEnumMemoryRegionsCallback; interface ICLRDataEnumMemoryRegionsCallback2; +interface ICLRDataEnumMemoryRegionsCallback3; interface ICLRDataTarget; interface ICLRDataTarget2; interface ICLRMetadataLocator; @@ -287,6 +288,20 @@ interface ICLRDataEnumMemoryRegionsCallback2 : ICLRDataEnumMemoryRegionsCallback [in, size_is(bufferSize)] BYTE* buffer); } +/* + * Optional callback interface for logging EnumMemoryRegions operations and errors. + */ +[ + object, + local, + uuid(F315248D-8B79-49DB-B184-37426559F703) +] +interface ICLRDataEnumMemoryRegionsLoggingCallback : IUnknown +{ + HRESULT LogMessage( + [in] LPCSTR message); +} + /* * Flags for controlling which memory regions are enumerated. */ diff --git a/src/shared/inc/dumpcommon.h b/src/shared/inc/dumpcommon.h new file mode 100644 index 0000000000..83a0f447c4 --- /dev/null +++ b/src/shared/inc/dumpcommon.h @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef DEBUGGER_DUMPCOMMON_H +#define DEBUGGER_DUMPCOMMON_H + +#ifdef HOST_UNIX +typedef enum _MINIDUMP_TYPE { + MiniDumpNormal = 0x00000000, + MiniDumpWithDataSegs = 0x00000001, + MiniDumpWithFullMemory = 0x00000002, + MiniDumpWithHandleData = 0x00000004, + MiniDumpFilterMemory = 0x00000008, + MiniDumpScanMemory = 0x00000010, + MiniDumpWithUnloadedModules = 0x00000020, + MiniDumpWithIndirectlyReferencedMemory = 0x00000040, + MiniDumpFilterModulePaths = 0x00000080, + MiniDumpWithProcessThreadData = 0x00000100, + MiniDumpWithPrivateReadWriteMemory = 0x00000200, + MiniDumpWithoutOptionalData = 0x00000400, + MiniDumpWithFullMemoryInfo = 0x00000800, + MiniDumpWithThreadInfo = 0x00001000, + MiniDumpWithCodeSegs = 0x00002000, + MiniDumpWithoutAuxiliaryState = 0x00004000, + MiniDumpWithFullAuxiliaryState = 0x00008000, + MiniDumpWithPrivateWriteCopyMemory = 0x00010000, + MiniDumpIgnoreInaccessibleMemory = 0x00020000, + MiniDumpWithTokenInformation = 0x00040000, + MiniDumpWithModuleHeaders = 0x00080000, + MiniDumpFilterTriage = 0x00100000, + MiniDumpWithAvxXStateContext = 0x00200000, + MiniDumpValidTypeFlags = 0x003fffff, +} MINIDUMP_TYPE; +#endif // HOST_UNIX + +#if defined(DACCESS_COMPILE) || defined(RIGHT_SIDE_COMPILE) + +// When debugging against minidumps, we frequently need to ignore errors +// due to the dump not having memory content. +// You should be VERY careful using these macros. Because our code does not +// distinguish target types, when you allow memory to be missing because a dump +// target may not have that memory content by-design you are also implicitly +// allowing that same data to be missing from a live debugging target. +// Also, be aware that these macros exist in code under vm\. You must be careful to +// only allow them to change execution for DAC and DBI. +// Be careful state is such that execution can continue if the target is missing +// memory. +// In general, there are two solutions to this problem: +// a) add the memory to all minidumps +// b) stop forcing the memory to always be present +// All decisions between a & b focus on cost. For a, cost is adding the memory & a complete +// path to locate it to the dump, both in terms of dump generation time and most +// especially in terms of dump size (we cannot make MiniDumpNormal many MB for trivial +// apps). +// For b, cost is that we lose some of our validation when we have to turn off asserts +// and other checks for targets that should always have the missing memory present +// because we have no concept of allowing it to be missing only from a dump. + +// This seemingly awkward try block starting tag is so that when the macro is used over +// multiple source lines we don't create a useless try/catch block. This is important +// when using the macros in vm\ code. +#define EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY EX_TRY +#define EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY \ + EX_CATCH \ + { \ + if ((GET_EXCEPTION()->GetHR() != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) && \ + (GET_EXCEPTION()->GetHR() != CORDBG_E_READVIRTUAL_FAILURE) ) \ + { \ + EX_RETHROW; \ + } \ + } \ + EX_END_CATCH(SwallowAllExceptions) + +#define EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER EX_TRY +#define EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER \ + EX_CATCH \ + { \ + if ((GET_EXCEPTION()->GetHR() != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) && \ + (GET_EXCEPTION()->GetHR() != CORDBG_E_READVIRTUAL_FAILURE) ) \ + { \ + EX_RETHROW; \ + } \ + else \ + +#define EX_TRY_ALLOW_DATATARGET_MISSING_OR_INCONSISTENT_MEMORY EX_TRY +#define EX_END_CATCH_ALLOW_DATATARGET_MISSING_OR_INCONSISTENT_MEMORY \ + EX_CATCH \ + { \ + if ((GET_EXCEPTION()->GetHR() != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) && \ + (GET_EXCEPTION()->GetHR() != CORDBG_E_READVIRTUAL_FAILURE) && \ + (GET_EXCEPTION()->GetHR() != CORDBG_E_TARGET_INCONSISTENT)) \ + { \ + EX_RETHROW; \ + } \ + } \ + EX_END_CATCH(SwallowAllExceptions) + + +#define EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER \ + } \ + EX_END_CATCH(SwallowAllExceptions) + +// Only use this version for wrapping single source lines, or you'll make debugging +// painful. +#define ALLOW_DATATARGET_MISSING_MEMORY(sourceCode) \ + EX_TRY \ + { \ + sourceCode \ + } \ + EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY + +#define ALLOW_DATATARGET_MISSING_OR_INCONSISTENT_MEMORY(sourceCode) \ + EX_TRY \ + { \ + sourceCode \ + } \ + EX_END_CATCH_ALLOW_DATATARGET_MISSING_OR_INCONSISTENT_MEMORY + +#else +#define EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY +#define EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY +#define EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER \ + #error This macro is only intended for use in DAC code! +#define EX_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER \ + #error This macro is only intended for use in DAC code! +#define EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY_WITH_HANDLER \ + #error This macro is only intended for use in DAC code! + + +#define ALLOW_DATATARGET_MISSING_MEMORY(sourceCode) \ + sourceCode + +#endif // defined(DACCESS_COMPILE) || defined(RIGHT_SIDE_COMPILE) + + +#endif //DEBUGGER_DUMPCOMMON_H diff --git a/src/shared/pal/prebuilt/idl/clrdata_i.cpp b/src/shared/pal/prebuilt/idl/clrdata_i.cpp index 7d6b61a14f..872841a0d9 100644 --- a/src/shared/pal/prebuilt/idl/clrdata_i.cpp +++ b/src/shared/pal/prebuilt/idl/clrdata_i.cpp @@ -1,16 +1,13 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. + /* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ /* link this file in with the server and any clients */ - /* File created by MIDL compiler version 8.01.0622 */ -/* at Mon Jan 18 19:14:07 2038 - */ -/* Compiler settings for C:/ssd/runtime/src/coreclr/inc/clrdata.idl: - Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0622 + /* File created by MIDL compiler version 8.01.0626 */ +/* Compiler settings for clrdata.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0626 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: @@ -89,6 +86,9 @@ MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegionsCallback,0xBCDD6908,0xBA2D,0x MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegionsCallback2,0x3721A26F,0x8B91,0x4D98,0xA3,0x88,0xDB,0x17,0xB3,0x56,0xFA,0xDB); +MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegionsLoggingCallback,0xF315248D,0x8B79,0x49DB,0xB1,0x84,0x37,0x42,0x65,0x59,0xF7,0x03); + + MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegions,0x471c35b4,0x7c2f,0x4ef0,0xa9,0x45,0x00,0xf8,0xc3,0x80,0x56,0xf1); #undef MIDL_DEFINE_GUID diff --git a/src/shared/pal/prebuilt/inc/clrdata.h b/src/shared/pal/prebuilt/inc/clrdata.h index 29f72974c5..3999908b26 100644 --- a/src/shared/pal/prebuilt/inc/clrdata.h +++ b/src/shared/pal/prebuilt/inc/clrdata.h @@ -1,14 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. + /* this ALWAYS GENERATED file contains the definitions for the interfaces */ - /* File created by MIDL compiler version 8.01.0622 */ -/* at Mon Jan 18 19:14:07 2038 - */ -/* Compiler settings for C:/ssd/runtime/src/coreclr/inc/clrdata.idl: - Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0622 + /* File created by MIDL compiler version 8.01.0626 */ +/* Compiler settings for clrdata.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0626 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: @@ -44,6 +41,14 @@ #pragma once #endif +#ifndef DECLSPEC_XFGVIRT +#if _CONTROL_FLOW_GUARD_XFG +#define DECLSPEC_XFGVIRT(base, func) __declspec(xfg_virtual(base, func)) +#else +#define DECLSPEC_XFGVIRT(base, func) +#endif +#endif + /* Forward Declarations */ #ifndef __ICLRDataTarget_FWD_DEFINED__ @@ -95,6 +100,13 @@ typedef interface ICLRDataEnumMemoryRegionsCallback2 ICLRDataEnumMemoryRegionsCa #endif /* __ICLRDataEnumMemoryRegionsCallback2_FWD_DEFINED__ */ +#ifndef __ICLRDataEnumMemoryRegionsLoggingCallback_FWD_DEFINED__ +#define __ICLRDataEnumMemoryRegionsLoggingCallback_FWD_DEFINED__ +typedef interface ICLRDataEnumMemoryRegionsLoggingCallback ICLRDataEnumMemoryRegionsLoggingCallback; + +#endif /* __ICLRDataEnumMemoryRegionsLoggingCallback_FWD_DEFINED__ */ + + #ifndef __ICLRDataEnumMemoryRegions_FWD_DEFINED__ #define __ICLRDataEnumMemoryRegions_FWD_DEFINED__ typedef interface ICLRDataEnumMemoryRegions ICLRDataEnumMemoryRegions; @@ -119,6 +131,7 @@ extern "C"{ + typedef ULONG64 CLRDATA_ADDRESS; STDAPI CLRDataCreateInstance(REFIID iid, ICLRDataTarget* target, void** iface); @@ -205,31 +218,38 @@ EXTERN_C const IID IID_ICLRDataTarget; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataTarget * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataTarget * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataTarget * This); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetMachineType) HRESULT ( STDMETHODCALLTYPE *GetMachineType )( ICLRDataTarget * This, /* [out] */ ULONG32 *machineType); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetPointerSize) HRESULT ( STDMETHODCALLTYPE *GetPointerSize )( ICLRDataTarget * This, /* [out] */ ULONG32 *pointerSize); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetImageBase) HRESULT ( STDMETHODCALLTYPE *GetImageBase )( ICLRDataTarget * This, /* [string][in] */ LPCWSTR imagePath, /* [out] */ CLRDATA_ADDRESS *baseAddress); + DECLSPEC_XFGVIRT(ICLRDataTarget, ReadVirtual) HRESULT ( STDMETHODCALLTYPE *ReadVirtual )( ICLRDataTarget * This, /* [in] */ CLRDATA_ADDRESS address, @@ -237,6 +257,7 @@ EXTERN_C const IID IID_ICLRDataTarget; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesRead); + DECLSPEC_XFGVIRT(ICLRDataTarget, WriteVirtual) HRESULT ( STDMETHODCALLTYPE *WriteVirtual )( ICLRDataTarget * This, /* [in] */ CLRDATA_ADDRESS address, @@ -244,22 +265,26 @@ EXTERN_C const IID IID_ICLRDataTarget; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesWritten); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetTLSValue) HRESULT ( STDMETHODCALLTYPE *GetTLSValue )( ICLRDataTarget * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [out] */ CLRDATA_ADDRESS *value); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetTLSValue) HRESULT ( STDMETHODCALLTYPE *SetTLSValue )( ICLRDataTarget * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [in] */ CLRDATA_ADDRESS value); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetCurrentThreadID) HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )( ICLRDataTarget * This, /* [out] */ ULONG32 *threadID); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetThreadContext) HRESULT ( STDMETHODCALLTYPE *GetThreadContext )( ICLRDataTarget * This, /* [in] */ ULONG32 threadID, @@ -267,12 +292,14 @@ EXTERN_C const IID IID_ICLRDataTarget; /* [in] */ ULONG32 contextSize, /* [size_is][out] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetThreadContext) HRESULT ( STDMETHODCALLTYPE *SetThreadContext )( ICLRDataTarget * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 contextSize, /* [size_is][in] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, Request) HRESULT ( STDMETHODCALLTYPE *Request )( ICLRDataTarget * This, /* [in] */ ULONG32 reqCode, @@ -384,31 +411,38 @@ EXTERN_C const IID IID_ICLRDataTarget2; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataTarget2 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataTarget2 * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataTarget2 * This); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetMachineType) HRESULT ( STDMETHODCALLTYPE *GetMachineType )( ICLRDataTarget2 * This, /* [out] */ ULONG32 *machineType); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetPointerSize) HRESULT ( STDMETHODCALLTYPE *GetPointerSize )( ICLRDataTarget2 * This, /* [out] */ ULONG32 *pointerSize); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetImageBase) HRESULT ( STDMETHODCALLTYPE *GetImageBase )( ICLRDataTarget2 * This, /* [string][in] */ LPCWSTR imagePath, /* [out] */ CLRDATA_ADDRESS *baseAddress); + DECLSPEC_XFGVIRT(ICLRDataTarget, ReadVirtual) HRESULT ( STDMETHODCALLTYPE *ReadVirtual )( ICLRDataTarget2 * This, /* [in] */ CLRDATA_ADDRESS address, @@ -416,6 +450,7 @@ EXTERN_C const IID IID_ICLRDataTarget2; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesRead); + DECLSPEC_XFGVIRT(ICLRDataTarget, WriteVirtual) HRESULT ( STDMETHODCALLTYPE *WriteVirtual )( ICLRDataTarget2 * This, /* [in] */ CLRDATA_ADDRESS address, @@ -423,22 +458,26 @@ EXTERN_C const IID IID_ICLRDataTarget2; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesWritten); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetTLSValue) HRESULT ( STDMETHODCALLTYPE *GetTLSValue )( ICLRDataTarget2 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [out] */ CLRDATA_ADDRESS *value); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetTLSValue) HRESULT ( STDMETHODCALLTYPE *SetTLSValue )( ICLRDataTarget2 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [in] */ CLRDATA_ADDRESS value); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetCurrentThreadID) HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )( ICLRDataTarget2 * This, /* [out] */ ULONG32 *threadID); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetThreadContext) HRESULT ( STDMETHODCALLTYPE *GetThreadContext )( ICLRDataTarget2 * This, /* [in] */ ULONG32 threadID, @@ -446,12 +485,14 @@ EXTERN_C const IID IID_ICLRDataTarget2; /* [in] */ ULONG32 contextSize, /* [size_is][out] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetThreadContext) HRESULT ( STDMETHODCALLTYPE *SetThreadContext )( ICLRDataTarget2 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 contextSize, /* [size_is][in] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, Request) HRESULT ( STDMETHODCALLTYPE *Request )( ICLRDataTarget2 * This, /* [in] */ ULONG32 reqCode, @@ -460,6 +501,7 @@ EXTERN_C const IID IID_ICLRDataTarget2; /* [in] */ ULONG32 outBufferSize, /* [size_is][out] */ BYTE *outBuffer); + DECLSPEC_XFGVIRT(ICLRDataTarget2, AllocVirtual) HRESULT ( STDMETHODCALLTYPE *AllocVirtual )( ICLRDataTarget2 * This, /* [in] */ CLRDATA_ADDRESS addr, @@ -468,6 +510,7 @@ EXTERN_C const IID IID_ICLRDataTarget2; /* [in] */ ULONG32 protectFlags, /* [out] */ CLRDATA_ADDRESS *virt); + DECLSPEC_XFGVIRT(ICLRDataTarget2, FreeVirtual) HRESULT ( STDMETHODCALLTYPE *FreeVirtual )( ICLRDataTarget2 * This, /* [in] */ CLRDATA_ADDRESS addr, @@ -585,31 +628,38 @@ EXTERN_C const IID IID_ICLRDataTarget3; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataTarget3 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataTarget3 * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataTarget3 * This); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetMachineType) HRESULT ( STDMETHODCALLTYPE *GetMachineType )( ICLRDataTarget3 * This, /* [out] */ ULONG32 *machineType); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetPointerSize) HRESULT ( STDMETHODCALLTYPE *GetPointerSize )( ICLRDataTarget3 * This, /* [out] */ ULONG32 *pointerSize); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetImageBase) HRESULT ( STDMETHODCALLTYPE *GetImageBase )( ICLRDataTarget3 * This, /* [string][in] */ LPCWSTR imagePath, /* [out] */ CLRDATA_ADDRESS *baseAddress); + DECLSPEC_XFGVIRT(ICLRDataTarget, ReadVirtual) HRESULT ( STDMETHODCALLTYPE *ReadVirtual )( ICLRDataTarget3 * This, /* [in] */ CLRDATA_ADDRESS address, @@ -617,6 +667,7 @@ EXTERN_C const IID IID_ICLRDataTarget3; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesRead); + DECLSPEC_XFGVIRT(ICLRDataTarget, WriteVirtual) HRESULT ( STDMETHODCALLTYPE *WriteVirtual )( ICLRDataTarget3 * This, /* [in] */ CLRDATA_ADDRESS address, @@ -624,22 +675,26 @@ EXTERN_C const IID IID_ICLRDataTarget3; /* [in] */ ULONG32 bytesRequested, /* [out] */ ULONG32 *bytesWritten); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetTLSValue) HRESULT ( STDMETHODCALLTYPE *GetTLSValue )( ICLRDataTarget3 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [out] */ CLRDATA_ADDRESS *value); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetTLSValue) HRESULT ( STDMETHODCALLTYPE *SetTLSValue )( ICLRDataTarget3 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 index, /* [in] */ CLRDATA_ADDRESS value); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetCurrentThreadID) HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )( ICLRDataTarget3 * This, /* [out] */ ULONG32 *threadID); + DECLSPEC_XFGVIRT(ICLRDataTarget, GetThreadContext) HRESULT ( STDMETHODCALLTYPE *GetThreadContext )( ICLRDataTarget3 * This, /* [in] */ ULONG32 threadID, @@ -647,12 +702,14 @@ EXTERN_C const IID IID_ICLRDataTarget3; /* [in] */ ULONG32 contextSize, /* [size_is][out] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, SetThreadContext) HRESULT ( STDMETHODCALLTYPE *SetThreadContext )( ICLRDataTarget3 * This, /* [in] */ ULONG32 threadID, /* [in] */ ULONG32 contextSize, /* [size_is][in] */ BYTE *context); + DECLSPEC_XFGVIRT(ICLRDataTarget, Request) HRESULT ( STDMETHODCALLTYPE *Request )( ICLRDataTarget3 * This, /* [in] */ ULONG32 reqCode, @@ -661,6 +718,7 @@ EXTERN_C const IID IID_ICLRDataTarget3; /* [in] */ ULONG32 outBufferSize, /* [size_is][out] */ BYTE *outBuffer); + DECLSPEC_XFGVIRT(ICLRDataTarget2, AllocVirtual) HRESULT ( STDMETHODCALLTYPE *AllocVirtual )( ICLRDataTarget3 * This, /* [in] */ CLRDATA_ADDRESS addr, @@ -669,24 +727,28 @@ EXTERN_C const IID IID_ICLRDataTarget3; /* [in] */ ULONG32 protectFlags, /* [out] */ CLRDATA_ADDRESS *virt); + DECLSPEC_XFGVIRT(ICLRDataTarget2, FreeVirtual) HRESULT ( STDMETHODCALLTYPE *FreeVirtual )( ICLRDataTarget3 * This, /* [in] */ CLRDATA_ADDRESS addr, /* [in] */ ULONG32 size, /* [in] */ ULONG32 typeFlags); + DECLSPEC_XFGVIRT(ICLRDataTarget3, GetExceptionRecord) HRESULT ( STDMETHODCALLTYPE *GetExceptionRecord )( ICLRDataTarget3 * This, /* [in] */ ULONG32 bufferSize, /* [out] */ ULONG32 *bufferUsed, /* [size_is][out] */ BYTE *buffer); + DECLSPEC_XFGVIRT(ICLRDataTarget3, GetExceptionContextRecord) HRESULT ( STDMETHODCALLTYPE *GetExceptionContextRecord )( ICLRDataTarget3 * This, /* [in] */ ULONG32 bufferSize, /* [out] */ ULONG32 *bufferUsed, /* [size_is][out] */ BYTE *buffer); + DECLSPEC_XFGVIRT(ICLRDataTarget3, GetExceptionThreadID) HRESULT ( STDMETHODCALLTYPE *GetExceptionThreadID )( ICLRDataTarget3 * This, /* [out] */ ULONG32 *threadID); @@ -802,18 +864,22 @@ EXTERN_C const IID IID_ICLRRuntimeLocator; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRRuntimeLocator * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRRuntimeLocator * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRRuntimeLocator * This); + DECLSPEC_XFGVIRT(ICLRRuntimeLocator, GetRuntimeBase) HRESULT ( STDMETHODCALLTYPE *GetRuntimeBase )( ICLRRuntimeLocator * This, /* [out] */ CLRDATA_ADDRESS *baseAddress); @@ -890,18 +956,22 @@ EXTERN_C const IID IID_ICLRMetadataLocator; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRMetadataLocator * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRMetadataLocator * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRMetadataLocator * This); + DECLSPEC_XFGVIRT(ICLRMetadataLocator, GetMetadata) HRESULT ( STDMETHODCALLTYPE *GetMetadata )( ICLRMetadataLocator * This, /* [in] */ LPCWSTR imagePath, @@ -979,18 +1049,22 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsCallback; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataEnumMemoryRegionsCallback * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataEnumMemoryRegionsCallback * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataEnumMemoryRegionsCallback * This); + DECLSPEC_XFGVIRT(ICLRDataEnumMemoryRegionsCallback, EnumMemoryRegion) HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegion )( ICLRDataEnumMemoryRegionsCallback * This, /* [in] */ CLRDATA_ADDRESS address, @@ -1062,23 +1136,28 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsCallback2; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataEnumMemoryRegionsCallback2 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataEnumMemoryRegionsCallback2 * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataEnumMemoryRegionsCallback2 * This); + DECLSPEC_XFGVIRT(ICLRDataEnumMemoryRegionsCallback, EnumMemoryRegion) HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegion )( ICLRDataEnumMemoryRegionsCallback2 * This, /* [in] */ CLRDATA_ADDRESS address, /* [in] */ ULONG32 size); + DECLSPEC_XFGVIRT(ICLRDataEnumMemoryRegionsCallback2, UpdateMemoryRegion) HRESULT ( STDMETHODCALLTYPE *UpdateMemoryRegion )( ICLRDataEnumMemoryRegionsCallback2 * This, /* [in] */ CLRDATA_ADDRESS address, @@ -1126,7 +1205,91 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsCallback2; #endif /* __ICLRDataEnumMemoryRegionsCallback2_INTERFACE_DEFINED__ */ -/* interface __MIDL_itf_clrdata_0000_0007 */ +#ifndef __ICLRDataEnumMemoryRegionsLoggingCallback_INTERFACE_DEFINED__ +#define __ICLRDataEnumMemoryRegionsLoggingCallback_INTERFACE_DEFINED__ + +/* interface ICLRDataEnumMemoryRegionsLoggingCallback */ +/* [uuid][local][object] */ + + +EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsLoggingCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("F315248D-8B79-49DB-B184-37426559F703") + ICLRDataEnumMemoryRegionsLoggingCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE LogMessage( + /* [in] */ LPCSTR message) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRDataEnumMemoryRegionsLoggingCallbackVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRDataEnumMemoryRegionsLoggingCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRDataEnumMemoryRegionsLoggingCallback * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRDataEnumMemoryRegionsLoggingCallback * This); + + DECLSPEC_XFGVIRT(ICLRDataEnumMemoryRegionsLoggingCallback, LogMessage) + HRESULT ( STDMETHODCALLTYPE *LogMessage )( + ICLRDataEnumMemoryRegionsLoggingCallback * This, + /* [in] */ LPCSTR message); + + END_INTERFACE + } ICLRDataEnumMemoryRegionsLoggingCallbackVtbl; + + interface ICLRDataEnumMemoryRegionsLoggingCallback + { + CONST_VTBL struct ICLRDataEnumMemoryRegionsLoggingCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICLRDataEnumMemoryRegionsLoggingCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRDataEnumMemoryRegionsLoggingCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRDataEnumMemoryRegionsLoggingCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRDataEnumMemoryRegionsLoggingCallback_LogMessage(This,message) \ + ( (This)->lpVtbl -> LogMessage(This,message) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRDataEnumMemoryRegionsLoggingCallback_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_clrdata_0000_0008 */ /* [local] */ typedef @@ -1140,8 +1303,8 @@ enum CLRDataEnumMemoryFlags -extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0007_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0007_v0_0_s_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0008_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0008_v0_0_s_ifspec; #ifndef __ICLRDataEnumMemoryRegions_INTERFACE_DEFINED__ #define __ICLRDataEnumMemoryRegions_INTERFACE_DEFINED__ @@ -1172,18 +1335,22 @@ EXTERN_C const IID IID_ICLRDataEnumMemoryRegions; { BEGIN_INTERFACE + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICLRDataEnumMemoryRegions * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); + DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ICLRDataEnumMemoryRegions * This); + DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ICLRDataEnumMemoryRegions * This); + DECLSPEC_XFGVIRT(ICLRDataEnumMemoryRegions, EnumMemoryRegions) HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegions )( ICLRDataEnumMemoryRegions * This, /* [in] */ ICLRDataEnumMemoryRegionsCallback *callback,