From: Mike McLaughlin Date: Sat, 23 Dec 2023 07:53:38 +0000 (-0800) Subject: Add CLRMA support to SOS. (#4437) X-Git-Tag: accepted/tizen/unified/20241231.014852~40^2~255 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=684a636d7d3879146b75e546c58dec477740792b;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Add CLRMA support to SOS. (#4437) Add the CLRMA exports on SOS.dll. Implement the CLRMA interfaces on top of ICrashInfoServices. Update ICrashInfoService to be more generic and not JSON crash info specific. Renamed IManagedException to IException. Add IStackFrame.GetMethodName replacing Offset/MethodName. Cleanup/change name of SOSHost.INativeClient Change TraceError used in extensions lib not to depend on SOS globals being initialized --- diff --git a/diagnostics.sln b/diagnostics.sln index 23ae2ff91..08398b86b 100644 --- a/diagnostics.sln +++ b/diagnostics.sln @@ -219,6 +219,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Debug EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "inc", "inc", "{BE45F03E-D700-404F-A890-8ED7D8969958}" ProjectSection(SolutionItems) = preProject + src\SOS\inc\clrma.h = src\SOS\inc\clrma.h + src\SOS\inc\clrma.idl = src\SOS\inc\clrma.idl src\SOS\inc\debuggerservices.h = src\SOS\inc\debuggerservices.h src\SOS\inc\host.h = src\SOS\inc\host.h src\SOS\inc\hostservices.h = src\SOS\inc\hostservices.h diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs index 2f7282e0a..cee810569 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Linq; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; @@ -22,7 +24,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation /// public const uint FAST_FAIL_EXCEPTION_DOTNET_AOT = 0x48; - public sealed class CrashInfoJson + private sealed class CrashInfoJson { [JsonPropertyName("version")] public string Version { get; set; } @@ -48,10 +50,10 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public string Message { get; set; } [JsonPropertyName("exception")] - public CrashInfoException Exception { get; set; } + public ExceptionJson Exception { get; set; } } - public sealed class CrashInfoException : IManagedException + private sealed class ExceptionJson { [JsonPropertyName("address")] [JsonConverter(typeof(HexUInt64Converter))] @@ -68,17 +70,13 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public string Type { get; set; } [JsonPropertyName("stack")] - public CrashInfoStackFrame[] Stack { get; set; } - - IEnumerable IManagedException.Stack => Stack; + public StackFrameJson[] Stack { get; set; } [JsonPropertyName("inner")] - public CrashInfoException[] InnerExceptions { get; set; } - - IEnumerable IManagedException.InnerExceptions => InnerExceptions; + public ExceptionJson[] InnerExceptions { get; set; } } - public sealed class CrashInfoStackFrame : IStackFrame + private sealed class StackFrameJson { [JsonPropertyName("ip")] [JsonConverter(typeof(HexUInt64Converter))] @@ -100,7 +98,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public string MethodName { get; set; } } - public sealed class HexUInt64Converter : JsonConverter + private sealed class HexUInt64Converter : JsonConverter { public override ulong Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { @@ -117,7 +115,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public override void Write(Utf8JsonWriter writer, ulong value, JsonSerializerOptions options) => throw new NotImplementedException(); } - public sealed class HexUInt32Converter : JsonConverter + private sealed class HexUInt32Converter : JsonConverter { public override uint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { @@ -134,7 +132,90 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public override void Write(Utf8JsonWriter writer, uint value, JsonSerializerOptions options) => throw new NotImplementedException(); } - public static ICrashInfoService Create(uint hresult, ReadOnlySpan triageBuffer) + private sealed class CrashInfoException : IException + { + private readonly ExceptionJson _exception; + private readonly IModuleService _moduleService; + private IStack _stack; + private IEnumerable _inner; + + public CrashInfoException(ExceptionJson exception, IModuleService moduleService) + { + Debug.Assert(exception != null); + Debug.Assert(moduleService != null); + _exception = exception; + _moduleService = moduleService; + } + + public ulong Address => _exception.Address; + + public uint HResult => _exception.HResult; + + public string Message => _exception.Message; + + public string Type => _exception.Type; + + public IStack Stack => _stack ??= new CrashInfoStack(_exception.Stack, _moduleService); + + public IEnumerable InnerExceptions => _inner ??= _exception.InnerExceptions != null ? _exception.InnerExceptions.Select((inner) => new CrashInfoException(inner, _moduleService)) : Array.Empty(); + } + + private sealed class CrashInfoStack : IStack + { + private readonly IStackFrame[] _stackFrames; + + public CrashInfoStack(StackFrameJson[] stackFrames, IModuleService moduleService) + { + _stackFrames = stackFrames != null ? stackFrames.Select((frame) => new CrashInfoStackFrame(frame, moduleService)).ToArray() : Array.Empty(); + } + + public int FrameCount => _stackFrames.Length; + + public IStackFrame GetStackFrame(int index) => _stackFrames[index]; + } + + private sealed class CrashInfoStackFrame : IStackFrame + { + private readonly StackFrameJson _stackFrame; + private readonly IModuleService _moduleService; + + public CrashInfoStackFrame(StackFrameJson stackFrame, IModuleService moduleService) + { + Debug.Assert(stackFrame != null); + Debug.Assert(moduleService != null); + _stackFrame = stackFrame; + _moduleService = moduleService; + } + + public ulong InstructionPointer => _stackFrame.InstructionPointer; + + public ulong StackPointer => _stackFrame.StackPointer; + + public ulong ModuleBase => _stackFrame.ModuleBase; + + public void GetMethodName(out string moduleName, out string methodName, out ulong displacement) + { + moduleName = null; + methodName = _stackFrame.MethodName; + displacement = _stackFrame.Offset; + + if (ModuleBase != 0) + { + IModule module = _moduleService.GetModuleFromBaseAddress(_stackFrame.ModuleBase); + if (module != null) + { + moduleName = Path.GetFileNameWithoutExtension(module.FileName); + if (string.IsNullOrEmpty(methodName)) + { + IModuleSymbols moduleSymbols = module.Services.GetService(); + moduleSymbols?.TryGetSymbolName(_stackFrame.InstructionPointer, out methodName, out displacement); + } + } + } + } + } + + public static ICrashInfoService Create(uint hresult, ReadOnlySpan triageBuffer, IModuleService moduleService) { CrashInfoService crashInfoService = null; try @@ -145,7 +226,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation { if (Version.TryParse(crashInfo.Version, out Version protocolVersion) && protocolVersion.Major >= 1) { - crashInfoService = new(crashInfo.Thread, hresult, crashInfo); + crashInfoService = new(crashInfo.Thread, hresult, crashInfo, moduleService); } else { @@ -157,14 +238,16 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation Trace.TraceError($"CrashInfoService: JsonSerializer.Deserialize failed"); } } - catch (Exception ex) when (ex is JsonException or NotSupportedException or DecoderFallbackException or ArgumentException) + catch (Exception ex) when (ex is System.Text.Json.JsonException or NotSupportedException or DecoderFallbackException or ArgumentException) { Trace.TraceError($"CrashInfoService: {ex}"); } return crashInfoService; } - private CrashInfoService(uint threadId, uint hresult, CrashInfoJson crashInfo) + private readonly IException _exception; + + private CrashInfoService(uint threadId, uint hresult, CrashInfoJson crashInfo, IModuleService moduleService) { ThreadId = threadId; HResult = hresult; @@ -173,7 +256,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation RuntimeVersion = crashInfo.RuntimeVersion; RuntimeType = (RuntimeType)crashInfo.RuntimeType; Message = crashInfo.Message; - Exception = crashInfo.Exception; + _exception = crashInfo.Exception != null ? new CrashInfoException(crashInfo.Exception, moduleService) : null; } #region ICrashInfoService @@ -192,7 +275,60 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation public string Message { get; } - public IManagedException Exception { get; } + public IException GetException(ulong address) + { + // Only supports getting the "current" exception or the crash exception. + if (address != 0) + { + if (address != _exception.Address) + { + throw new ArgumentOutOfRangeException(nameof(address)); + } + } + return _exception; + } + + public IException GetThreadException(uint threadId) + { + // Only supports getting the "current" exception or the crash thread's exception + if (threadId != 0) + { + if (threadId != ThreadId) + { + throw new ArgumentOutOfRangeException(nameof(threadId)); + } + } + return _exception; + } + + public IEnumerable GetNestedExceptions(uint threadId) + { + // Only supports getting the "current" exception or the crash thread's exception + if (threadId != 0) + { + if (threadId != ThreadId) + { + throw new ArgumentOutOfRangeException(nameof(threadId)); + } + } + + List exceptions = new() { + _exception + }; + + AddExceptions(_exception.InnerExceptions); + + void AddExceptions(IEnumerable inner) + { + foreach (IException exception in inner) + { + exceptions.Add(exception); + AddExceptions(exception.InnerExceptions); + } + } + + return exceptions; + } #endregion } diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs index e7fad8aea..075636ec9 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs @@ -65,7 +65,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation { if (InitializeValue(Module.Flags.InitializeVersion)) { - if (!_moduleInfo.Version.Equals(Utilities.EmptyVersion)) + if (_moduleInfo.Version != null && !_moduleInfo.Version.Equals(Utilities.EmptyVersion)) { _version = _moduleInfo.Version; } diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/SpecialDiagInfo.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/SpecialDiagInfo.cs index 32d7989a9..74a5093b9 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/SpecialDiagInfo.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/SpecialDiagInfo.cs @@ -102,7 +102,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation Span buffer = new byte[triageBufferSize]; if (services.GetService().ReadMemory(triageBufferAddress, buffer, out int bytesRead) && bytesRead == triageBufferSize) { - return CrashInfoService.Create(hresult, buffer); + return CrashInfoService.Create(hresult, buffer, services.GetService()); } else { diff --git a/src/Microsoft.Diagnostics.DebugServices/ICrashInfoService.cs b/src/Microsoft.Diagnostics.DebugServices/ICrashInfoService.cs index 1d04cab52..143532cdc 100644 --- a/src/Microsoft.Diagnostics.DebugServices/ICrashInfoService.cs +++ b/src/Microsoft.Diagnostics.DebugServices/ICrashInfoService.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DebugServices { @@ -57,8 +58,27 @@ namespace Microsoft.Diagnostics.DebugServices string Message { get; } /// - /// The exception that caused the crash or null + /// The exception at the address /// - IManagedException Exception { get; } + /// address of exception object or 0 for current exception + /// exception or null if none + /// invalid exception address + IException GetException(ulong address); + + /// + /// Returns the thread's current exception. + /// + /// OS thread id + /// exception or null if none + /// invalid thread id + IException GetThreadException(uint threadId); + + /// + /// Returns all the thread's nested exception. + /// + /// OS thread id + /// array of nested exceptions + /// invalid thread id + IEnumerable GetNestedExceptions(uint threadId); } } diff --git a/src/Microsoft.Diagnostics.DebugServices/IException.cs b/src/Microsoft.Diagnostics.DebugServices/IException.cs new file mode 100644 index 000000000..13c3493d4 --- /dev/null +++ b/src/Microsoft.Diagnostics.DebugServices/IException.cs @@ -0,0 +1,43 @@ +// 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.Generic; + +namespace Microsoft.Diagnostics.DebugServices +{ + /// + /// Describes a managed exception + /// + public interface IException + { + /// + /// Exception object address + /// + ulong Address { get; } + + /// + /// The exception type name + /// + string Type { get; } + + /// + /// The exception message + /// + string Message { get; } + + /// + /// Exception.HResult + /// + uint HResult { get; } + + /// + /// Stack trace of exception or null + /// + IStack Stack { get; } + + /// + /// The inner exception or exceptions in the AggregateException case + /// + IEnumerable InnerExceptions { get; } + } +} diff --git a/src/Microsoft.Diagnostics.DebugServices/IManagedException.cs b/src/Microsoft.Diagnostics.DebugServices/IManagedException.cs deleted file mode 100644 index f73b172e5..000000000 --- a/src/Microsoft.Diagnostics.DebugServices/IManagedException.cs +++ /dev/null @@ -1,43 +0,0 @@ -// 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.Generic; - -namespace Microsoft.Diagnostics.DebugServices -{ - /// - /// Describes a managed exception - /// - public interface IManagedException - { - /// - /// Exception object address - /// - ulong Address { get; } - - /// - /// The exception type name - /// - string Type { get; } - - /// - /// The exception message - /// - string Message { get; } - - /// - /// Exception.HResult - /// - uint HResult { get; } - - /// - /// Stack trace of exception - /// - IEnumerable Stack { get; } - - /// - /// The inner exception or exceptions in the AggregateException case - /// - IEnumerable InnerExceptions { get; } - } -} diff --git a/src/Microsoft.Diagnostics.DebugServices/IStack.cs b/src/Microsoft.Diagnostics.DebugServices/IStack.cs new file mode 100644 index 000000000..b8d0a77e3 --- /dev/null +++ b/src/Microsoft.Diagnostics.DebugServices/IStack.cs @@ -0,0 +1,27 @@ +// 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.Generic; + +namespace Microsoft.Diagnostics.DebugServices +{ + /// + /// Native or managed stack + /// + public interface IStack + { + /// + /// Number of total stack frames + /// + int FrameCount { get; } + + /// + /// Get an individual stack frame + /// + /// stack frame index + /// frame + /// invalid index + IStackFrame GetStackFrame(int index); + } +} diff --git a/src/Microsoft.Diagnostics.DebugServices/IStackFrame.cs b/src/Microsoft.Diagnostics.DebugServices/IStackFrame.cs index 42f33eb7f..2fd8a6e7d 100644 --- a/src/Microsoft.Diagnostics.DebugServices/IStackFrame.cs +++ b/src/Microsoft.Diagnostics.DebugServices/IStackFrame.cs @@ -21,16 +21,14 @@ namespace Microsoft.Diagnostics.DebugServices /// /// The module base of the IP /// - public ulong ModuleBase { get; } + ulong ModuleBase { get; } /// - /// Offset from beginning of method + /// Returns the module, method name and displacement /// - uint Offset { get; } - - /// - /// The exception type name - /// - string MethodName { get; } + /// the module name of the method or null + /// the method name or null + /// the offset from the beginning of the function + void GetMethodName(out string moduleName, out string methodName, out ulong displacement); } } diff --git a/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj b/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj index e550154f2..1c547c5c6 100644 --- a/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj +++ b/src/Microsoft.Diagnostics.DebugServices/Microsoft.Diagnostics.DebugServices.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 true diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/CrashInfoCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/CrashInfoCommand.cs index 67c69b3ae..41ad047e6 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/CrashInfoCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/CrashInfoCommand.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -15,17 +16,12 @@ namespace Microsoft.Diagnostics.ExtensionCommands [ServiceImport(Optional = true)] public ICrashInfoService CrashInfo { get; set; } - [ServiceImport] - public IModuleService ModuleService { get; set; } - public override void Invoke() { if (CrashInfo == null) { throw new DiagnosticsException("No crash info to display"); } - WriteLine(); - WriteLine($"CrashReason: {CrashInfo.CrashReason}"); WriteLine($"ThreadId: {CrashInfo.ThreadId:X4}"); WriteLine($"HResult: {CrashInfo.HResult:X4}"); @@ -34,47 +30,64 @@ namespace Microsoft.Diagnostics.ExtensionCommands WriteLine($"RuntimeVersion: {CrashInfo.RuntimeVersion}"); WriteLine($"Message: {CrashInfo.Message}"); - if (CrashInfo.Exception != null) + WriteLine(); + WriteLine("** Current Exception **"); + WriteLine(); + IException exception = CrashInfo.GetException(0); + if (exception != null) + { + WriteLine("-----------------------------------------------"); + PrintException(exception, string.Empty); + } + + WriteLine(); + WriteLine($"** Thread {CrashInfo.ThreadId} Exception **"); + WriteLine(); + exception = CrashInfo.GetThreadException(CrashInfo.ThreadId); + if (exception != null) + { + WriteLine("-----------------------------------------------"); + PrintException(exception, string.Empty); + } + + WriteLine(); + WriteLine("** Nested Exceptions **"); + WriteLine(); + IEnumerable exceptions = CrashInfo.GetNestedExceptions(CrashInfo.ThreadId); + foreach (IException ex in exceptions) { WriteLine("-----------------------------------------------"); - PrintException(CrashInfo.Exception, string.Empty); + PrintException(ex, string.Empty); } } - private void PrintException(IManagedException exception, string indent) + private void PrintException(IException exception, string indent) { WriteLine($"{indent}Exception object: {exception.Address:X16}"); WriteLine($"{indent}Exception type: {exception.Type}"); WriteLine($"{indent}HResult: {exception.HResult:X8}"); WriteLine($"{indent}Message: {exception.Message}"); - if (exception.Stack != null && exception.Stack.Any()) + IStack stack = exception.Stack; + if (stack.FrameCount > 0) { WriteLine($"{indent}StackTrace:"); WriteLine($"{indent} IP Function"); - foreach (IStackFrame frame in exception.Stack) + for (int index = 0; index < stack.FrameCount; index++) { - string moduleName = ""; - if (frame.ModuleBase != 0) - { - IModule module = ModuleService.GetModuleFromBaseAddress(frame.ModuleBase); - if (module != null) - { - moduleName = Path.GetFileName(module.FileName); - } - } - string methodName = frame.MethodName ?? ""; - WriteLine($"{indent} {frame.InstructionPointer:X16} {moduleName}!{methodName} + 0x{frame.Offset:X}"); + IStackFrame frame = stack.GetStackFrame(index); + frame.GetMethodName(out string moduleName, out string methodName, out ulong displacement); + WriteLine($"{indent} {frame.InstructionPointer:X16} {moduleName ?? ""}!{methodName ?? ""} + 0x{displacement:X}"); } } - if (exception.InnerExceptions != null) + if (exception.InnerExceptions.Any()) { - WriteLine("InnerExceptions:"); - foreach (IManagedException inner in exception.InnerExceptions) + WriteLine($"{indent}InnerExceptions:"); + foreach (IException inner in exception.InnerExceptions) { - WriteLine("-----------------------------------------------"); - PrintException(inner, " "); + WriteLine($"{indent}-----------------------------------------------"); + PrintException(inner, $"{indent} "); } } } diff --git a/src/SOS/SOS.Extensions/Clrma/ExceptionWrapper.cs b/src/SOS/SOS.Extensions/Clrma/ExceptionWrapper.cs new file mode 100644 index 000000000..7380306a6 --- /dev/null +++ b/src/SOS/SOS.Extensions/Clrma/ExceptionWrapper.cs @@ -0,0 +1,211 @@ +// 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.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace SOS.Extensions.Clrma +{ + public sealed class ExceptionWrapper : COMCallableIUnknown + { + public static readonly Guid IID_ICLRMAClrException = new("7C165652-D539-472e-A6CF-F657FFF31751"); + + public IException Exception { get; } + + public IntPtr ICLRMACClrException { get; } + + private ExceptionWrapper[] _innerExceptions; + + public ExceptionWrapper(IException exception) + { + Debug.Assert(exception != null); + Exception = exception; + + VTableBuilder builder = AddInterface(IID_ICLRMAClrException, validate: false); + builder.AddMethod(new DebuggerCommandDelegate(DebuggerCommand)); + builder.AddMethod(new AddressDelegate(GetAddress)); + builder.AddMethod(new HResultDelegate(GetHResult)); + builder.AddMethod(new TypeDelegate(GetType)); + builder.AddMethod(new MessageDelegate(GetMessage)); + builder.AddMethod(new FrameCountDelegate(FrameCount)); + builder.AddMethod(new FrameDelegate(Frame)); + builder.AddMethod(new InnerExceptionCountDelegate(InnerExceptionCount)); + builder.AddMethod(new InnerExceptionDelegate(InnerException)); + ICLRMACClrException = builder.Complete(); + + AddRef(); + } + + protected override void Destroy() + { + Trace.TraceInformation("ExceptionWrapper.Destroy"); + } + + private int DebuggerCommand( + IntPtr self, + out string command) + { + command = null; + return HResult.S_FALSE; + } + + private int GetAddress( + IntPtr self, + out ulong address) + { + address = Exception.Address; + return HResult.S_OK; + } + + private int GetHResult( + IntPtr self, + out uint hresult) + { + hresult = Exception.HResult; + return HResult.S_OK; + } + + private int GetType( + IntPtr self, + out string type) + { + type = Exception.Type; + return HResult.S_OK; + } + + private int GetMessage( + IntPtr self, + out string message) + { + message = Exception.Message; + return HResult.S_OK; + } + + private int FrameCount( + IntPtr self, + out int count) + { + count = Exception.Stack.FrameCount; + return count > 0 ? HResult.S_OK : HResult.S_FALSE; + } + + private int Frame( + IntPtr self, + int nFrame, + out ulong ip, + out ulong sp, + out string moduleName, + out string functionName, + out ulong displacement) + { + ip = 0; + sp = 0; + moduleName = null; + functionName = null; + displacement = 0; + IStackFrame frame; + try + { + frame = Exception.Stack.GetStackFrame(nFrame); + } + catch (ArgumentOutOfRangeException) + { + return ManagedAnalysisWrapper.E_BOUNDS; + } + ip = frame.InstructionPointer; + sp = frame.StackPointer; + frame.GetMethodName(out moduleName, out functionName, out displacement); + moduleName ??= $"module_{frame.ModuleBase:X16}"; + functionName ??= $"function_{frame.InstructionPointer:X16}"; + return HResult.S_OK; + } + + private int InnerExceptionCount( + IntPtr self, + out ushort count) + { + count = (ushort)InnerExceptions.Length; + return count > 0 ? HResult.S_OK : HResult.S_FALSE; + } + + private int InnerException( + IntPtr self, + ushort index, + out IntPtr clrmaClrException) + { + clrmaClrException = IntPtr.Zero; + if (index >= InnerExceptions.Length) + { + return ManagedAnalysisWrapper.E_BOUNDS; + } + ExceptionWrapper exception = InnerExceptions[index]; + exception.AddRef(); + clrmaClrException = exception.ICLRMACClrException; + return HResult.S_OK; + } + + private ExceptionWrapper[] InnerExceptions + { + get { return _innerExceptions ??= Exception.InnerExceptions.Select((exception) => new ExceptionWrapper(exception)).ToArray(); } + } + + #region ICLRMAClrException delegates + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int DebuggerCommandDelegate( + [In] IntPtr self, + [Out, MarshalAs(UnmanagedType.BStr)] out string command); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int AddressDelegate( + [In] IntPtr self, + [Out] out ulong address); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int HResultDelegate( + [In] IntPtr self, + [Out] out uint hresult); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int TypeDelegate( + [In] IntPtr self, + [Out, MarshalAs(UnmanagedType.BStr)] out string type); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int MessageDelegate( + [In] IntPtr self, + [Out, MarshalAs(UnmanagedType.BStr)] out string message); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int FrameCountDelegate( + [In] IntPtr self, + [Out] out int count); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int FrameDelegate( + [In] IntPtr self, + [In] int nFrame, + [Out] out ulong ip, + [Out] out ulong sp, + [Out, MarshalAs(UnmanagedType.BStr)] out string moduleName, + [Out, MarshalAs(UnmanagedType.BStr)] out string functionName, + [Out] out ulong displacement); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int InnerExceptionCountDelegate( + [In] IntPtr self, + [Out] out ushort count); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int InnerExceptionDelegate( + [In] IntPtr self, + [In] ushort index, + [Out] out IntPtr clrmaClrException); + + #endregion + } +} diff --git a/src/SOS/SOS.Extensions/Clrma/ManagedAnalysisWrapper.cs b/src/SOS/SOS.Extensions/Clrma/ManagedAnalysisWrapper.cs new file mode 100644 index 000000000..9e4fb309a --- /dev/null +++ b/src/SOS/SOS.Extensions/Clrma/ManagedAnalysisWrapper.cs @@ -0,0 +1,245 @@ +// 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.Diagnostics; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime.Utilities; +using SOS.Hosting; +using SOS.Hosting.DbgEng.Interop; + +namespace SOS.Extensions.Clrma +{ + public sealed class ManagedAnalysisWrapper : COMCallableIUnknown + { + public static readonly Guid IID_ICLRManagedAnalysis = new("8CA73A16-C017-4c8f-AD51-B758727478CA"); + + public const int E_BOUNDS = unchecked((int)0x8000000B); + public const uint DEBUG_ANY_ID = uint.MaxValue; + + private readonly IServiceProvider _serviceProvider; + private readonly ServiceWrapper _serviceWrapper; + private ICrashInfoService _crashInfoService; + private IDebugClient _debugClient; + private ThreadWrapper _thread; + private ExceptionWrapper _exception; + + public ManagedAnalysisWrapper(ITarget target, IServiceProvider serviceProvider, ServiceWrapper serviceWrapper) + { + _serviceProvider = serviceProvider; + _serviceWrapper = serviceWrapper; + + target.OnFlushEvent.Register(Flush); + + VTableBuilder builder = AddInterface(IID_ICLRManagedAnalysis, validate: false); + builder.AddMethod(new GetProviderNameDelegate(GetProviderName)); + builder.AddMethod(new AssociateClientDelegate(AssociateClient)); + builder.AddMethod(new GetThreadDelegate(GetThread)); + builder.AddMethod(new GetExceptionDelegate(GetException)); + builder.AddMethod(new ObjectInspectionDelegate(ObjectInspection)); + builder.Complete(); + // Since this wrapper is only created through a ServiceWrapper factory, no AddRef() is needed. + } + + protected override void Destroy() + { + Trace.TraceInformation("ManagedAnalysisWrapper.Destroy"); + _serviceWrapper.RemoveServiceWrapper(ManagedAnalysisWrapper.IID_ICLRManagedAnalysis); + Flush(); + } + + private void Flush() + { + _crashInfoService = null; + FlushDebugClient(); + FlushThread(); + FlushException(); + } + + private void FlushDebugClient() + { + if (_debugClient != null) + { + int count = Marshal.ReleaseComObject(_debugClient); + Debug.Assert(count >= 0); + _debugClient = null; + } + } + + private void FlushThread() + { + _thread?.ReleaseWithCheck(); + _thread = null; + } + + private void FlushException() + { + _exception?.ReleaseWithCheck(); + _exception = null; + } + + private int GetProviderName( + IntPtr self, + out string provider) + { + provider = "SOSCLRMA"; + return HResult.S_OK; + } + + private int AssociateClient( + IntPtr self, + IntPtr punk) + { + // If the crash info service doesn't exist, then tell Watson/CLRMA to go on to the next provider + if (CrashInfoService is null) + { + return HResult.E_NOINTERFACE; + } + FlushDebugClient(); + _debugClient = Marshal.GetObjectForIUnknown(punk) as IDebugClient; + if (_debugClient == null) + { + return HResult.E_NOINTERFACE; + } + // We don't currently need the IDebugClient instance passed this this function. + return HResult.S_OK; + } + + private int GetThread( + IntPtr self, + uint osThreadId, + out IntPtr clrmaClrThread) + { + clrmaClrThread = IntPtr.Zero; + if (CrashInfoService is null) + { + return HResult.E_FAIL; + } + // osThreadId == 0 is current thread and -1 is "last event thread". The only thread + // information we have currently is the crashing thread id so always return it. + if (osThreadId == 0) + { + HResult hr = ((IDebugSystemObjects)_debugClient).GetCurrentThreadSystemId(out osThreadId); + if (!hr.IsOK) + { + return hr; + } + } + else if (osThreadId == uint.MaxValue) + { + HResult hr = ((IDebugControl)_debugClient).GetLastEventInformation( + out DEBUG_EVENT _, + out uint _, + out uint threadIndex, + IntPtr.Zero, + 0, + out uint _, + null, + 0, + out uint _); + + if (!hr.IsOK) + { + return hr; + } + if (threadIndex == DEBUG_ANY_ID) + { + return HResult.E_INVALIDARG; + } + uint[] ids = new uint[1]; + uint[] sysIds = new uint[1]; + hr = ((IDebugSystemObjects)_debugClient).GetThreadIdsByIndex(threadIndex, 1, ids, sysIds); + if (!hr.IsOK) + { + return hr; + } + osThreadId = sysIds[0]; + } + if (_thread is null || _thread.ThreadId != osThreadId) + { + IThread thread = ThreadService?.GetThreadFromId(osThreadId); + if (thread is null) + { + return HResult.E_INVALIDARG; + } + FlushThread(); + _thread = new ThreadWrapper(CrashInfoService, thread); + } + _thread.AddRef(); + clrmaClrThread = _thread.ICLRMACClrThread; + return HResult.S_OK; + } + + private int GetException( + IntPtr self, + ulong address, + out IntPtr clrmaClrException) + { + clrmaClrException = IntPtr.Zero; + if (_exception is null || _exception.Exception.Address != address) + { + IException exception = null; + try + { + exception = CrashInfoService?.GetException(address); + } + catch (ArgumentOutOfRangeException) + { + } + if (exception is null) + { + return HResult.E_INVALIDARG; + } + FlushException(); + _exception = new ExceptionWrapper(exception); + } + _exception.AddRef(); + clrmaClrException = _exception.ICLRMACClrException; + return HResult.S_OK; + } + + private int ObjectInspection( + IntPtr self, + out IntPtr clrmaObjectInspection) + { + clrmaObjectInspection = IntPtr.Zero; + return HResult.E_NOTIMPL; + } + + private ICrashInfoService CrashInfoService => _crashInfoService ??= _serviceProvider.GetService(); + + private IThreadService ThreadService => _serviceProvider.GetService(); + + #region ICLRManagedAnalysis delegates + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int GetProviderNameDelegate( + [In] IntPtr self, + [Out, MarshalAs(UnmanagedType.BStr)] out string provider); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int AssociateClientDelegate( + [In] IntPtr self, + [In] IntPtr punk); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int GetThreadDelegate( + [In] IntPtr self, + [In] uint osThreadId, + [Out] out IntPtr clrmaClrThread); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int GetExceptionDelegate( + [In] IntPtr self, + [In] ulong address, + [Out] out IntPtr clrmaClrException); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int ObjectInspectionDelegate( + [In] IntPtr self, + [Out] out IntPtr objectInspection); + + #endregion + } +} diff --git a/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs b/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs new file mode 100644 index 000000000..5c797ea20 --- /dev/null +++ b/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs @@ -0,0 +1,208 @@ +// 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.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.Runtime.Utilities; +using SOS.Hosting; + +namespace SOS.Extensions.Clrma +{ + public sealed class ThreadWrapper : COMCallableIUnknown + { + public static readonly Guid IID_ICLRMAClrThread = new("9849CFC9-0868-406e-9059-6B04E9ADBBB8"); + + public uint ThreadId => _thread.ThreadId; + + public IntPtr ICLRMACClrThread { get; } + + private readonly ICrashInfoService _crashInfoService; + private readonly IThread _thread; + private ExceptionWrapper _currentException; + private ExceptionWrapper[] _nestedExceptions; + + public ThreadWrapper(ICrashInfoService crashInfoService, IThread thread) + { + Debug.Assert(crashInfoService != null); + _crashInfoService = crashInfoService; + _thread = thread; + + VTableBuilder builder = AddInterface(IID_ICLRMAClrThread, validate: false); + builder.AddMethod(new DebuggerCommandDelegate(DebuggerCommand)); + builder.AddMethod(new OSThreadIdDelegate(OSThreadId)); + builder.AddMethod(new FrameCountDelegate(FrameCount)); + builder.AddMethod(new FrameDelegate(Frame)); + builder.AddMethod(new CurrentExceptionDelegate(CurrentException)); + builder.AddMethod(new NestedExceptionCountDelegate(NestedExceptionCount)); + builder.AddMethod(new NestedExceptionDelegate(NestedException)); + ICLRMACClrThread = builder.Complete(); + + AddRef(); + } + + protected override void Destroy() + { + Trace.TraceInformation("ThreadWrapper.Destroy"); + _currentException?.ReleaseWithCheck(); + _currentException = null; + } + + private int DebuggerCommand( + IntPtr self, + out string command) + { + command = null; + return HResult.S_FALSE; + } + + private int OSThreadId( + IntPtr self, + out uint osThreadId) + { + osThreadId = ThreadId; + return osThreadId > 0 ? HResult.S_OK : HResult.S_FALSE; + } + + private int FrameCount( + IntPtr self, + out int count) + { + count = 0; + return HResult.E_NOTIMPL; + } + + private int Frame( + IntPtr self, + int nFrame, + out ulong ip, + out ulong sp, + out string moduleName, + out string functionName, + out ulong displacement) + { + ip = 0; + sp = 0; + moduleName = null; + functionName = null; + displacement = 0; + return HResult.E_NOTIMPL; + } + + private int CurrentException( + IntPtr self, + out IntPtr clrmaClrException) + { + clrmaClrException = IntPtr.Zero; + if (_currentException is null) + { + IException exception = null; + try + { + exception = _crashInfoService.GetThreadException(ThreadId); + } + catch (ArgumentOutOfRangeException) + { + } + if (exception is null) + { + return HResult.S_FALSE; + } + _currentException ??= new ExceptionWrapper(exception); + } + _currentException.AddRef(); + clrmaClrException = _currentException.ICLRMACClrException; + return HResult.S_OK; + } + + private int NestedExceptionCount( + IntPtr self, + out ushort count) + { + count = (ushort)NestedExceptions.Length; + return count > 0 ? HResult.S_OK : HResult.S_FALSE; + } + + private int NestedException( + IntPtr self, + ushort index, + out IntPtr clrmaClrException) + { + clrmaClrException = IntPtr.Zero; + if (index >= NestedExceptions.Length) + { + return ManagedAnalysisWrapper.E_BOUNDS; + } + ExceptionWrapper exception = NestedExceptions[index]; + exception.AddRef(); + clrmaClrException = exception.ICLRMACClrException; + return HResult.S_OK; + } + + private ExceptionWrapper[] NestedExceptions + { + get + { + if (_nestedExceptions is null) + { + try + { + _nestedExceptions = _crashInfoService.GetNestedExceptions(ThreadId).Select((exception) => new ExceptionWrapper(exception)).ToArray(); + } + catch (ArgumentOutOfRangeException) + { + _nestedExceptions = Array.Empty(); + } + } + return _nestedExceptions; + } + } + + #region ICLRMAClrThread delegates + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int DebuggerCommandDelegate( + [In] IntPtr self, + [Out, MarshalAs(UnmanagedType.BStr)] out string command); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int OSThreadIdDelegate( + [In] IntPtr self, + [Out] out uint osThreadId); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int FrameCountDelegate( + [In] IntPtr self, + [Out] out int count); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int FrameDelegate( + [In] IntPtr self, + [In] int nFrame, + [Out] out ulong ip, + [Out] out ulong sp, + [Out, MarshalAs(UnmanagedType.BStr)] out string moduleName, + [Out, MarshalAs(UnmanagedType.BStr)] out string functionName, + [Out] out ulong displacement); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int CurrentExceptionDelegate( + [In] IntPtr self, + [Out] out IntPtr clrmaClrException); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int NestedExceptionCountDelegate( + [In] IntPtr self, + [Out] out ushort count); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int NestedExceptionDelegate( + [In] IntPtr self, + [In] ushort index, + [Out] out IntPtr clrmaClrException); + + #endregion + } +} diff --git a/src/SOS/SOS.Extensions/DebuggerServices.cs b/src/SOS/SOS.Extensions/DebuggerServices.cs index b5702a7a8..9f4fe231f 100644 --- a/src/SOS/SOS.Extensions/DebuggerServices.cs +++ b/src/SOS/SOS.Extensions/DebuggerServices.cs @@ -16,7 +16,7 @@ using SOS.Hosting.DbgEng.Interop; namespace SOS.Extensions { - internal sealed unsafe class DebuggerServices : CallableCOMWrapper, SOSHost.INativeClient + internal sealed unsafe class DebuggerServices : CallableCOMWrapper, SOSHost.INativeDebugger { internal enum OperatingSystem { @@ -41,7 +41,6 @@ namespace SOS.Extensions : base(new RefCountedFreeLibrary(IntPtr.Zero), IID_IDebuggerServices, punk) { _hostType = hostType; - Client = punk; // This uses COM marshalling code, so we also check that the OSPlatform is Windows. if (hostType == HostType.DbgEng && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -54,9 +53,20 @@ namespace SOS.Extensions } } - #region INativeClient + #region SOSHost.INativeDebugger - public IntPtr Client { get; } + public IntPtr GetNativeClient() + { + if (_hostType == HostType.DbgEng) + { + return QueryInterface(typeof(IDebugClient).GUID); + } + else if (_hostType == HostType.Lldb) + { + return QueryInterface(LLDBServices.IID_ILLDBServices); + } + throw new InvalidOperationException($"DebuggerServices.GetNativeClient: invalid host type {_hostType}"); + } #endregion diff --git a/src/SOS/SOS.Extensions/HostServices.cs b/src/SOS/SOS.Extensions/HostServices.cs index 9ee85d194..c5c042ce5 100644 --- a/src/SOS/SOS.Extensions/HostServices.cs +++ b/src/SOS/SOS.Extensions/HostServices.cs @@ -223,7 +223,7 @@ namespace SOS.Extensions _serviceContainer.AddService(_serviceManager); _serviceContainer.AddService(this); _serviceContainer.AddService(this); - _serviceContainer.AddService(DebuggerServices); + _serviceContainer.AddService(DebuggerServices); _serviceContainer.AddService(_commandService); _serviceContainer.AddService(_symbolService); _serviceContainer.AddService(fileLoggingConsoleService); diff --git a/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs b/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs index 6e29077ef..fd4a8648c 100644 --- a/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using Microsoft.Diagnostics.DebugServices; using Microsoft.Diagnostics.DebugServices.Implementation; using Microsoft.Diagnostics.Runtime.Utilities; +using SOS.Extensions.Clrma; using SOS.Hosting; using SOS.Hosting.DbgEng.Interop; using Architecture = System.Runtime.InteropServices.Architecture; @@ -106,6 +107,9 @@ namespace SOS.Extensions } Finished(); + + TargetWrapper targetWrapper = Services.GetService(); + targetWrapper?.ServiceWrapper.AddServiceWrapper(ManagedAnalysisWrapper.IID_ICLRManagedAnalysis, () => new ManagedAnalysisWrapper(this, Services, targetWrapper.ServiceWrapper)); } private unsafe ICrashInfoService CreateCrashInfoService(IServiceProvider services, DebuggerServices debuggerServices) @@ -129,7 +133,7 @@ namespace SOS.Extensions Span buffer = new byte[triageBufferSize]; if (services.GetService().ReadMemory(triageBufferAddress, buffer, out int bytesRead) && bytesRead == triageBufferSize) { - return CrashInfoService.Create(hresult, buffer); + return CrashInfoService.Create(hresult, buffer, services.GetService()); } else { diff --git a/src/SOS/SOS.Hosting/LLDBServices.cs b/src/SOS/SOS.Hosting/LLDBServices.cs index 5ac39d92a..1e6b12709 100644 --- a/src/SOS/SOS.Hosting/LLDBServices.cs +++ b/src/SOS/SOS.Hosting/LLDBServices.cs @@ -13,10 +13,10 @@ using SOS.Hosting.DbgEng.Interop; namespace SOS.Hosting { - internal sealed unsafe class LLDBServices : COMCallableIUnknown + public sealed unsafe class LLDBServices : COMCallableIUnknown { - private static readonly Guid IID_ILLDBServices = new("2E6C569A-9E14-4DA4-9DFC-CDB73A532566"); - private static readonly Guid IID_ILLDBServices2 = new("012F32F0-33BA-4E8E-BC01-037D382D8A5E"); + public static readonly Guid IID_ILLDBServices = new("2E6C569A-9E14-4DA4-9DFC-CDB73A532566"); + public static readonly Guid IID_ILLDBServices2 = new("012F32F0-33BA-4E8E-BC01-037D382D8A5E"); public IntPtr ILLDBServices { get; } diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs index 3891c0063..5d23b98c3 100644 --- a/src/SOS/SOS.Hosting/SOSHost.cs +++ b/src/SOS/SOS.Hosting/SOSHost.cs @@ -24,12 +24,12 @@ namespace SOS.Hosting /// /// Provides the native debugger's debug client instance /// - public interface INativeClient + public interface INativeDebugger { - /// - /// Native debugger client interface - /// - IntPtr Client { get; } + /// + /// Get the native SOS client for commands (IDebugClient under dbgeng, ILLDBServices under lldb) + /// + public IntPtr GetNativeClient(); } // This is what dbgeng/IDebuggerServices returns for non-PE modules that don't have a timestamp @@ -58,21 +58,20 @@ namespace SOS.Hosting private readonly IntPtr _client; private readonly ulong _ignoreAddressBitsMask; - private readonly bool _releaseClient; /// /// Create an instance of the hosting class. Has the lifetime of the target. /// - public SOSHost(ITarget target, IMemoryService memoryService, [ServiceImport(Optional = true)] INativeClient client) + public SOSHost(ITarget target, IMemoryService memoryService, [ServiceImport(Optional = true)] INativeDebugger nativeDebugger) { Target = target; MemoryService = memoryService; _ignoreAddressBitsMask = memoryService.SignExtensionMask(); // If running under a native debugger, use the client instance supplied by the debugger for commands - if (client != null) + if (nativeDebugger != null) { - _client = client.Client; + _client = nativeDebugger.GetNativeClient(); } else { @@ -86,17 +85,14 @@ namespace SOS.Hosting LLDBServices lldbServices = new(this); _client = lldbServices.ILLDBServices; } - _releaseClient = true; } + Debug.Assert(_client != IntPtr.Zero); } void IDisposable.Dispose() { Trace.TraceInformation($"SOSHost.Dispose"); - if (_releaseClient) - { - ComWrapper.ReleaseWithCheck(_client); - } + ComWrapper.ReleaseWithCheck(_client); } /// diff --git a/src/SOS/SOS.Hosting/SOSLibrary.cs b/src/SOS/SOS.Hosting/SOSLibrary.cs index 42e1f3e42..c8d4fc70a 100644 --- a/src/SOS/SOS.Hosting/SOSLibrary.cs +++ b/src/SOS/SOS.Hosting/SOSLibrary.cs @@ -17,7 +17,7 @@ namespace SOS.Hosting public sealed class SOSLibrary : IDisposable { /// - /// Provides the SOS module handle + /// Provides the SOS module path and handle /// public interface ISOSModule { diff --git a/src/SOS/SOS.Hosting/ServiceWrapper.cs b/src/SOS/SOS.Hosting/ServiceWrapper.cs index 125fda099..78300591e 100644 --- a/src/SOS/SOS.Hosting/ServiceWrapper.cs +++ b/src/SOS/SOS.Hosting/ServiceWrapper.cs @@ -25,6 +25,7 @@ namespace SOS.Hosting wrapper.ReleaseWithCheck(); } _wrappers.Clear(); + _factories.Clear(); } /// @@ -48,12 +49,11 @@ namespace SOS.Hosting } /// - /// Remove the service instance + /// Remove the service instance (doesn't release it) but not the factory. /// /// guid public void RemoveServiceWrapper(in Guid serviceId) { - _factories.Remove(serviceId); _wrappers.Remove(serviceId); } diff --git a/src/SOS/SOS.Hosting/TargetWrapper.cs b/src/SOS/SOS.Hosting/TargetWrapper.cs index daf13d851..8960df57c 100644 --- a/src/SOS/SOS.Hosting/TargetWrapper.cs +++ b/src/SOS/SOS.Hosting/TargetWrapper.cs @@ -30,11 +30,12 @@ namespace SOS.Hosting private readonly ITarget _target; private readonly IContextService _contextService; - public TargetWrapper(ITarget target, IContextService contextService, ISymbolService symbolService, IMemoryService memoryService) + public TargetWrapper( + ITarget target, + IContextService contextService, + ISymbolService symbolService, + IMemoryService memoryService) { - Debug.Assert(target != null); - Debug.Assert(contextService != null); - Debug.Assert(symbolService != null); _target = target; _contextService = contextService; @@ -62,7 +63,6 @@ namespace SOS.Hosting protected override void Destroy() { Trace.TraceInformation("TargetWrapper.Destroy"); - ServiceWrapper.RemoveServiceWrapper(SymbolServiceWrapper.IID_ISymbolService); ServiceWrapper.Dispose(); } diff --git a/src/SOS/Strike/CMakeLists.txt b/src/SOS/Strike/CMakeLists.txt index 8b095e69a..19551ab0a 100644 --- a/src/SOS/Strike/CMakeLists.txt +++ b/src/SOS/Strike/CMakeLists.txt @@ -82,6 +82,7 @@ if (CLR_CMAKE_HOST_WIN32) add_definitions(-DUSE_STL) set(SOS_SOURCES + clrma.cpp disasm.cpp dllsext.cpp eeheap.cpp diff --git a/src/SOS/Strike/Strike.vcxproj b/src/SOS/Strike/Strike.vcxproj index 29dde66bf..609d90ec0 100644 --- a/src/SOS/Strike/Strike.vcxproj +++ b/src/SOS/Strike/Strike.vcxproj @@ -385,6 +385,7 @@ + diff --git a/src/SOS/Strike/Strike.vcxproj.filters b/src/SOS/Strike/Strike.vcxproj.filters index e7b14e9ea..53a91f82d 100644 --- a/src/SOS/Strike/Strike.vcxproj.filters +++ b/src/SOS/Strike/Strike.vcxproj.filters @@ -33,6 +33,7 @@ platform + diff --git a/src/SOS/Strike/clrma.cpp b/src/SOS/Strike/clrma.cpp new file mode 100644 index 000000000..7ffc2fe2a --- /dev/null +++ b/src/SOS/Strike/clrma.cpp @@ -0,0 +1,59 @@ +#include +#include +#include // IDL +#include "exts.h" + +HRESULT CLRMACreateInstance(ICLRManagedAnalysis** ppCLRMA); +HRESULT CLRMAReleaseInstance(); + +ICLRManagedAnalysis* g_managedAnalysis = nullptr; + +// +// Exports +// + +HRESULT CLRMACreateInstance(ICLRManagedAnalysis** ppCLRMA) +{ + HRESULT hr = E_UNEXPECTED; + + if (ppCLRMA == nullptr) + { + return E_INVALIDARG; + } + *ppCLRMA = nullptr; + + if (g_managedAnalysis == nullptr) + { + Extensions* extensions = Extensions::GetInstance(); + if (extensions == nullptr || extensions->GetDebuggerServices() == nullptr) + { + return E_FAIL; + } + ITarget* target = extensions->GetTarget(); + if (target == nullptr) + { + return E_FAIL; + } + hr = target->GetService(__uuidof(ICLRManagedAnalysis), (void**)&g_managedAnalysis); + if (FAILED(hr)) + { + return hr; + } + } + else + { + g_managedAnalysis->AddRef(); + } + *ppCLRMA = g_managedAnalysis; + return S_OK; +} + +HRESULT CLRMAReleaseInstance() +{ + if (g_managedAnalysis != nullptr) + { + g_managedAnalysis->Release(); + g_managedAnalysis = nullptr; + } + return S_OK; +} diff --git a/src/SOS/Strike/sos.def b/src/SOS/Strike/sos.def index f298a3f9f..7f594e187 100644 --- a/src/SOS/Strike/sos.def +++ b/src/SOS/Strike/sos.def @@ -253,6 +253,9 @@ EXPORTS TraceToCode tracetocode=TraceToCode + CLRMACreateInstance + CLRMAReleaseInstance + SOSInitializeByHost SOSUninitializeByHost InitializeHostServices diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index ec384ea23..9fa4c8d86 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -4416,20 +4416,6 @@ void ExtErr(PCSTR Format, ...) va_end(Args); } -/// -/// Internal trace output for extensions library -/// -void TraceError(PCSTR format, ...) -{ - if (Output::g_bDbgOutput) - { - va_list args; - va_start(args, format); - OutputVaList(DEBUG_OUTPUT_ERROR, format, args); - va_end(args); - } -} - void ExtDbgOut(PCSTR Format, ...) { if (Output::g_bDbgOutput) diff --git a/src/SOS/extensions/extensions.cpp b/src/SOS/extensions/extensions.cpp index 186608893..a3f48bfcd 100644 --- a/src/SOS/extensions/extensions.cpp +++ b/src/SOS/extensions/extensions.cpp @@ -234,3 +234,45 @@ bool GetAbsolutePath(const char* path, std::string& absolutePath) } return false; } + +/// +/// Internal output helper function +/// +void InternalOutputVaList( + ULONG mask, + PCSTR format, + va_list args) +{ + char str[1024]; + va_list argsCopy; + va_copy(argsCopy, args); + + // Try and format our string into a fixed buffer first and see if it fits + size_t length = vsnprintf(str, sizeof(str), format, args); + if (length < sizeof(str)) + { + Extensions::GetInstance()->GetDebuggerServices()->OutputString(mask, str); + } + else + { + // Our stack buffer wasn't big enough to contain the entire formatted string + char *str_ptr = (char*)::malloc(length + 1); + if (str_ptr != nullptr) + { + vsnprintf(str_ptr, length + 1, format, argsCopy); + Extensions::GetInstance()->GetDebuggerServices()->OutputString(mask, str_ptr); + ::free(str_ptr); + } + } +} + +/// +/// Internal trace output for extensions library +/// +void TraceError(PCSTR format, ...) +{ + va_list args; + va_start(args, format); + InternalOutputVaList(DEBUG_OUTPUT_ERROR, format, args); + va_end(args); +} diff --git a/src/SOS/extensions/hostcoreclr.cpp b/src/SOS/extensions/hostcoreclr.cpp index 025d6a3f9..0ec62b486 100644 --- a/src/SOS/extensions/hostcoreclr.cpp +++ b/src/SOS/extensions/hostcoreclr.cpp @@ -640,7 +640,7 @@ static HRESULT InitializeNetCoreHost() char* exePath = minipal_getexepath(); if (!exePath) { - TraceError("Could not get full path to current executable"); + TraceError("Could not get full path to current executable\n"); return E_FAIL; } diff --git a/src/SOS/inc/clrma.h b/src/SOS/inc/clrma.h new file mode 100644 index 000000000..34f6944b0 --- /dev/null +++ b/src/SOS/inc/clrma.h @@ -0,0 +1,735 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.01.0628 */ +/* at Mon Jan 18 19:14:07 2038 + */ +/* Compiler settings for C:\ssd\reliability.banganalyze\src\CLRMA\Interface\idl\CLRMA.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0628 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCNDR_H_VERSION__ */ + + +#ifndef __CLRMA_h__ +#define __CLRMA_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#ifndef DECLSPEC_XFGVIRT +#if defined(_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 __ICLRManagedAnalysis_FWD_DEFINED__ +#define __ICLRManagedAnalysis_FWD_DEFINED__ +typedef interface ICLRManagedAnalysis ICLRManagedAnalysis; + +#endif /* __ICLRManagedAnalysis_FWD_DEFINED__ */ + + +#ifndef __ICLRMAClrThread_FWD_DEFINED__ +#define __ICLRMAClrThread_FWD_DEFINED__ +typedef interface ICLRMAClrThread ICLRMAClrThread; + +#endif /* __ICLRMAClrThread_FWD_DEFINED__ */ + + +#ifndef __ICLRMAClrException_FWD_DEFINED__ +#define __ICLRMAClrException_FWD_DEFINED__ +typedef interface ICLRMAClrException ICLRMAClrException; + +#endif /* __ICLRMAClrException_FWD_DEFINED__ */ + + +#ifndef __ICLRMAObjectInspection_FWD_DEFINED__ +#define __ICLRMAObjectInspection_FWD_DEFINED__ +typedef interface ICLRMAObjectInspection ICLRMAObjectInspection; + +#endif /* __ICLRMAObjectInspection_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + + +#ifndef __CLRMA_LIBRARY_DEFINED__ +#define __CLRMA_LIBRARY_DEFINED__ + +/* library CLRMA */ +/* [helpstring][version][uuid] */ + + + + + + +EXTERN_C const IID LIBID_CLRMA; + +#ifndef __ICLRManagedAnalysis_INTERFACE_DEFINED__ +#define __ICLRManagedAnalysis_INTERFACE_DEFINED__ + +/* interface ICLRManagedAnalysis */ +/* [object][helpstring][uuid] */ + + +EXTERN_C const IID IID_ICLRManagedAnalysis; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8CA73A16-C017-4c8f-AD51-B758727478CA") + ICLRManagedAnalysis : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProviderName( + /* [retval][out] */ BSTR *bstrProvider) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE AssociateClient( + /* [in] */ IUnknown *pUnknown) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetThread( + /* [in] */ ULONG osThreadID, + /* [retval][out] */ ICLRMAClrThread **ppClrThread) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetException( + /* [in] */ ULONG64 addr, + /* [retval][out] */ ICLRMAClrException **ppClrException) = 0; + + virtual /* [propget][helpstring] */ HRESULT STDMETHODCALLTYPE get_ObjectInspection( + /* [retval][out] */ ICLRMAObjectInspection **ppObjectInspection) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRManagedAnalysisVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRManagedAnalysis * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRManagedAnalysis * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRManagedAnalysis * This); + + DECLSPEC_XFGVIRT(ICLRManagedAnalysis, get_ProviderName) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_ProviderName )( + ICLRManagedAnalysis * This, + /* [retval][out] */ BSTR *bstrProvider); + + DECLSPEC_XFGVIRT(ICLRManagedAnalysis, AssociateClient) + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *AssociateClient )( + ICLRManagedAnalysis * This, + /* [in] */ IUnknown *pUnknown); + + DECLSPEC_XFGVIRT(ICLRManagedAnalysis, GetThread) + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetThread )( + ICLRManagedAnalysis * This, + /* [in] */ ULONG osThreadID, + /* [retval][out] */ ICLRMAClrThread **ppClrThread); + + DECLSPEC_XFGVIRT(ICLRManagedAnalysis, GetException) + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetException )( + ICLRManagedAnalysis * This, + /* [in] */ ULONG64 addr, + /* [retval][out] */ ICLRMAClrException **ppClrException); + + DECLSPEC_XFGVIRT(ICLRManagedAnalysis, get_ObjectInspection) + /* [propget][helpstring] */ HRESULT ( STDMETHODCALLTYPE *get_ObjectInspection )( + ICLRManagedAnalysis * This, + /* [retval][out] */ ICLRMAObjectInspection **ppObjectInspection); + + END_INTERFACE + } ICLRManagedAnalysisVtbl; + + interface ICLRManagedAnalysis + { + CONST_VTBL struct ICLRManagedAnalysisVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICLRManagedAnalysis_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRManagedAnalysis_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRManagedAnalysis_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRManagedAnalysis_get_ProviderName(This,bstrProvider) \ + ( (This)->lpVtbl -> get_ProviderName(This,bstrProvider) ) + +#define ICLRManagedAnalysis_AssociateClient(This,pUnknown) \ + ( (This)->lpVtbl -> AssociateClient(This,pUnknown) ) + +#define ICLRManagedAnalysis_GetThread(This,osThreadID,ppClrThread) \ + ( (This)->lpVtbl -> GetThread(This,osThreadID,ppClrThread) ) + +#define ICLRManagedAnalysis_GetException(This,addr,ppClrException) \ + ( (This)->lpVtbl -> GetException(This,addr,ppClrException) ) + +#define ICLRManagedAnalysis_get_ObjectInspection(This,ppObjectInspection) \ + ( (This)->lpVtbl -> get_ObjectInspection(This,ppObjectInspection) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRManagedAnalysis_INTERFACE_DEFINED__ */ + + +#ifndef __ICLRMAClrThread_INTERFACE_DEFINED__ +#define __ICLRMAClrThread_INTERFACE_DEFINED__ + +/* interface ICLRMAClrThread */ +/* [object][helpstring][uuid] */ + + +EXTERN_C const IID IID_ICLRMAClrThread; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9849CFC9-0868-406e-9059-6B04E9ADBBB8") + ICLRMAClrThread : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DebuggerCommand( + /* [retval][out] */ BSTR *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_OSThreadId( + /* [retval][out] */ ULONG *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_FrameCount( + /* [retval][out] */ UINT *pCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE Frame( + /* [in] */ UINT nFrame, + /* [out] */ ULONG64 *pAddrIP, + /* [out] */ ULONG64 *pAddrSP, + /* [out] */ BSTR *bstrModule, + /* [out] */ BSTR *bstrFunction, + /* [out] */ ULONG64 *pDisplacement) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CurrentException( + /* [retval][out] */ ICLRMAClrException **ppClrException) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_NestedExceptionCount( + /* [retval][out] */ USHORT *pCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE NestedException( + /* [in] */ USHORT nIndex, + /* [retval][out] */ ICLRMAClrException **ppClrException) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRMAClrThreadVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRMAClrThread * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRMAClrThread * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRMAClrThread * This); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, get_DebuggerCommand) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DebuggerCommand )( + ICLRMAClrThread * This, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, get_OSThreadId) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_OSThreadId )( + ICLRMAClrThread * This, + /* [retval][out] */ ULONG *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, get_FrameCount) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_FrameCount )( + ICLRMAClrThread * This, + /* [retval][out] */ UINT *pCount); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, Frame) + HRESULT ( STDMETHODCALLTYPE *Frame )( + ICLRMAClrThread * This, + /* [in] */ UINT nFrame, + /* [out] */ ULONG64 *pAddrIP, + /* [out] */ ULONG64 *pAddrSP, + /* [out] */ BSTR *bstrModule, + /* [out] */ BSTR *bstrFunction, + /* [out] */ ULONG64 *pDisplacement); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, get_CurrentException) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_CurrentException )( + ICLRMAClrThread * This, + /* [retval][out] */ ICLRMAClrException **ppClrException); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, get_NestedExceptionCount) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_NestedExceptionCount )( + ICLRMAClrThread * This, + /* [retval][out] */ USHORT *pCount); + + DECLSPEC_XFGVIRT(ICLRMAClrThread, NestedException) + HRESULT ( STDMETHODCALLTYPE *NestedException )( + ICLRMAClrThread * This, + /* [in] */ USHORT nIndex, + /* [retval][out] */ ICLRMAClrException **ppClrException); + + END_INTERFACE + } ICLRMAClrThreadVtbl; + + interface ICLRMAClrThread + { + CONST_VTBL struct ICLRMAClrThreadVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICLRMAClrThread_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRMAClrThread_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRMAClrThread_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRMAClrThread_get_DebuggerCommand(This,pValue) \ + ( (This)->lpVtbl -> get_DebuggerCommand(This,pValue) ) + +#define ICLRMAClrThread_get_OSThreadId(This,pValue) \ + ( (This)->lpVtbl -> get_OSThreadId(This,pValue) ) + +#define ICLRMAClrThread_get_FrameCount(This,pCount) \ + ( (This)->lpVtbl -> get_FrameCount(This,pCount) ) + +#define ICLRMAClrThread_Frame(This,nFrame,pAddrIP,pAddrSP,bstrModule,bstrFunction,pDisplacement) \ + ( (This)->lpVtbl -> Frame(This,nFrame,pAddrIP,pAddrSP,bstrModule,bstrFunction,pDisplacement) ) + +#define ICLRMAClrThread_get_CurrentException(This,ppClrException) \ + ( (This)->lpVtbl -> get_CurrentException(This,ppClrException) ) + +#define ICLRMAClrThread_get_NestedExceptionCount(This,pCount) \ + ( (This)->lpVtbl -> get_NestedExceptionCount(This,pCount) ) + +#define ICLRMAClrThread_NestedException(This,nIndex,ppClrException) \ + ( (This)->lpVtbl -> NestedException(This,nIndex,ppClrException) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRMAClrThread_INTERFACE_DEFINED__ */ + + +#ifndef __ICLRMAClrException_INTERFACE_DEFINED__ +#define __ICLRMAClrException_INTERFACE_DEFINED__ + +/* interface ICLRMAClrException */ +/* [object][helpstring][uuid] */ + + +EXTERN_C const IID IID_ICLRMAClrException; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7C165652-D539-472e-A6CF-F657FFF31751") + ICLRMAClrException : public IUnknown + { + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_DebuggerCommand( + /* [retval][out] */ BSTR *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Address( + /* [retval][out] */ ULONG64 *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HResult( + /* [retval][out] */ HRESULT *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Type( + /* [retval][out] */ BSTR *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Message( + /* [retval][out] */ BSTR *pValue) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_FrameCount( + /* [retval][out] */ UINT *pCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE Frame( + /* [in] */ UINT nFrame, + /* [out] */ ULONG64 *pAddrIP, + /* [out] */ ULONG64 *pAddrSP, + /* [out] */ BSTR *pModule, + /* [out] */ BSTR *pFunction, + /* [out] */ ULONG64 *pDisplacement) = 0; + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_InnerExceptionCount( + /* [retval][out] */ USHORT *pCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE InnerException( + /* [in] */ USHORT nIndex, + /* [retval][out] */ ICLRMAClrException **ppClrException) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRMAClrExceptionVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRMAClrException * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRMAClrException * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRMAClrException * This); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_DebuggerCommand) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_DebuggerCommand )( + ICLRMAClrException * This, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_Address) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Address )( + ICLRMAClrException * This, + /* [retval][out] */ ULONG64 *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_HResult) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_HResult )( + ICLRMAClrException * This, + /* [retval][out] */ HRESULT *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_Type) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Type )( + ICLRMAClrException * This, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_Message) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_Message )( + ICLRMAClrException * This, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_FrameCount) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_FrameCount )( + ICLRMAClrException * This, + /* [retval][out] */ UINT *pCount); + + DECLSPEC_XFGVIRT(ICLRMAClrException, Frame) + HRESULT ( STDMETHODCALLTYPE *Frame )( + ICLRMAClrException * This, + /* [in] */ UINT nFrame, + /* [out] */ ULONG64 *pAddrIP, + /* [out] */ ULONG64 *pAddrSP, + /* [out] */ BSTR *pModule, + /* [out] */ BSTR *pFunction, + /* [out] */ ULONG64 *pDisplacement); + + DECLSPEC_XFGVIRT(ICLRMAClrException, get_InnerExceptionCount) + /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_InnerExceptionCount )( + ICLRMAClrException * This, + /* [retval][out] */ USHORT *pCount); + + DECLSPEC_XFGVIRT(ICLRMAClrException, InnerException) + HRESULT ( STDMETHODCALLTYPE *InnerException )( + ICLRMAClrException * This, + /* [in] */ USHORT nIndex, + /* [retval][out] */ ICLRMAClrException **ppClrException); + + END_INTERFACE + } ICLRMAClrExceptionVtbl; + + interface ICLRMAClrException + { + CONST_VTBL struct ICLRMAClrExceptionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICLRMAClrException_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRMAClrException_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRMAClrException_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRMAClrException_get_DebuggerCommand(This,pValue) \ + ( (This)->lpVtbl -> get_DebuggerCommand(This,pValue) ) + +#define ICLRMAClrException_get_Address(This,pValue) \ + ( (This)->lpVtbl -> get_Address(This,pValue) ) + +#define ICLRMAClrException_get_HResult(This,pValue) \ + ( (This)->lpVtbl -> get_HResult(This,pValue) ) + +#define ICLRMAClrException_get_Type(This,pValue) \ + ( (This)->lpVtbl -> get_Type(This,pValue) ) + +#define ICLRMAClrException_get_Message(This,pValue) \ + ( (This)->lpVtbl -> get_Message(This,pValue) ) + +#define ICLRMAClrException_get_FrameCount(This,pCount) \ + ( (This)->lpVtbl -> get_FrameCount(This,pCount) ) + +#define ICLRMAClrException_Frame(This,nFrame,pAddrIP,pAddrSP,pModule,pFunction,pDisplacement) \ + ( (This)->lpVtbl -> Frame(This,nFrame,pAddrIP,pAddrSP,pModule,pFunction,pDisplacement) ) + +#define ICLRMAClrException_get_InnerExceptionCount(This,pCount) \ + ( (This)->lpVtbl -> get_InnerExceptionCount(This,pCount) ) + +#define ICLRMAClrException_InnerException(This,nIndex,ppClrException) \ + ( (This)->lpVtbl -> InnerException(This,nIndex,ppClrException) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRMAClrException_INTERFACE_DEFINED__ */ + + +#ifndef __ICLRMAObjectInspection_INTERFACE_DEFINED__ +#define __ICLRMAObjectInspection_INTERFACE_DEFINED__ + +/* interface ICLRMAObjectInspection */ +/* [object][helpstring][uuid] */ + + +EXTERN_C const IID IID_ICLRMAObjectInspection; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("836259DB-7452-4b2b-95C4-4BC52CB9ABC7") + ICLRMAObjectInspection : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetType( + /* [in] */ ULONG64 addr, + /* [retval][out] */ BSTR *pValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAddressFromCcwAddress( + /* [in] */ ULONG64 addr, + /* [retval][out] */ ULONG64 *pAddress) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetField_SystemString( + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ BSTR *pValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetField_SystemUInt32( + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ ULONG *pValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetField_SystemInt32( + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ LONG *pValue) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ICLRMAObjectInspectionVtbl + { + BEGIN_INTERFACE + + DECLSPEC_XFGVIRT(IUnknown, QueryInterface) + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICLRMAObjectInspection * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + DECLSPEC_XFGVIRT(IUnknown, AddRef) + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICLRMAObjectInspection * This); + + DECLSPEC_XFGVIRT(IUnknown, Release) + ULONG ( STDMETHODCALLTYPE *Release )( + ICLRMAObjectInspection * This); + + DECLSPEC_XFGVIRT(ICLRMAObjectInspection, GetType) + HRESULT ( STDMETHODCALLTYPE *GetType )( + ICLRMAObjectInspection * This, + /* [in] */ ULONG64 addr, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAObjectInspection, GetAddressFromCcwAddress) + HRESULT ( STDMETHODCALLTYPE *GetAddressFromCcwAddress )( + ICLRMAObjectInspection * This, + /* [in] */ ULONG64 addr, + /* [retval][out] */ ULONG64 *pAddress); + + DECLSPEC_XFGVIRT(ICLRMAObjectInspection, GetField_SystemString) + HRESULT ( STDMETHODCALLTYPE *GetField_SystemString )( + ICLRMAObjectInspection * This, + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ BSTR *pValue); + + DECLSPEC_XFGVIRT(ICLRMAObjectInspection, GetField_SystemUInt32) + HRESULT ( STDMETHODCALLTYPE *GetField_SystemUInt32 )( + ICLRMAObjectInspection * This, + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ ULONG *pValue); + + DECLSPEC_XFGVIRT(ICLRMAObjectInspection, GetField_SystemInt32) + HRESULT ( STDMETHODCALLTYPE *GetField_SystemInt32 )( + ICLRMAObjectInspection * This, + /* [in] */ ULONG64 addr, + /* [in] */ BSTR bstrField, + /* [retval][out] */ LONG *pValue); + + END_INTERFACE + } ICLRMAObjectInspectionVtbl; + + interface ICLRMAObjectInspection + { + CONST_VTBL struct ICLRMAObjectInspectionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICLRMAObjectInspection_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICLRMAObjectInspection_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICLRMAObjectInspection_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICLRMAObjectInspection_GetType(This,addr,pValue) \ + ( (This)->lpVtbl -> GetType(This,addr,pValue) ) + +#define ICLRMAObjectInspection_GetAddressFromCcwAddress(This,addr,pAddress) \ + ( (This)->lpVtbl -> GetAddressFromCcwAddress(This,addr,pAddress) ) + +#define ICLRMAObjectInspection_GetField_SystemString(This,addr,bstrField,pValue) \ + ( (This)->lpVtbl -> GetField_SystemString(This,addr,bstrField,pValue) ) + +#define ICLRMAObjectInspection_GetField_SystemUInt32(This,addr,bstrField,pValue) \ + ( (This)->lpVtbl -> GetField_SystemUInt32(This,addr,bstrField,pValue) ) + +#define ICLRMAObjectInspection_GetField_SystemInt32(This,addr,bstrField,pValue) \ + ( (This)->lpVtbl -> GetField_SystemInt32(This,addr,bstrField,pValue) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICLRMAObjectInspection_INTERFACE_DEFINED__ */ + +#endif /* __CLRMA_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/src/SOS/inc/clrma.idl b/src/SOS/inc/clrma.idl new file mode 100644 index 000000000..bd880068c --- /dev/null +++ b/src/SOS/inc/clrma.idl @@ -0,0 +1,103 @@ +// +// CLRMA.idl +// + +import "unknwn.idl"; + +[ + uuid(511BCC9D-5B25-4d15-8F00-4DDFB0C142D5), + version(3.0), + helpstring("CLR Managed Analysis") +] +library CLRMA +{ + // + // Forward declarations + // + + interface ICLRManagedAnalysis; + interface ICLRMAClrThread; + interface ICLRMAClrException; + interface ICLRMAObjectInspection; + + // + // Interface declarations + // + + // ICLRManagedAnalysis + [ + uuid(8CA73A16-C017-4c8f-AD51-B758727478CA), + helpstring("ICLRManagedAnalysis interface") + ] + interface ICLRManagedAnalysis : IUnknown + { + [propget] HRESULT ProviderName([out, retval] BSTR* bstrProvider); + + [helpstring("Associate a debug engine (usually an IDebugClient) with the CLRMA Provider.")] + HRESULT AssociateClient([in] IUnknown* pUnknown); + + [helpstring("-1 : Last Event Thread, 0 : Current Thread, NN : OS Thread ID (TID)")] + HRESULT GetThread([in] ULONG osThreadID, [out, retval] ICLRMAClrThread** ppClrThread); + + [helpstring(" 0 : Current Thread's Current Exception\nNN : Exception Object Address")] + HRESULT GetException([in] ULONG64 addr, [out, retval] ICLRMAClrException** ppClrException); + + [helpstring("Interface to Inspect Objects")] + [propget] HRESULT ObjectInspection([out, retval] ICLRMAObjectInspection** ppObjectInspection); + }; + + // ICLRMAClrThread + [ + uuid(9849CFC9-0868-406e-9059-6B04E9ADBBB8), + helpstring("ICLRMAClrThread interface") + ] + interface ICLRMAClrThread : IUnknown + { + [propget] HRESULT DebuggerCommand([out, retval] BSTR* pValue); + [propget] HRESULT OSThreadId([out, retval] ULONG* pValue); + + [propget] HRESULT FrameCount([out, retval] UINT* pCount); + HRESULT Frame([in] UINT nFrame, [out] ULONG64* pAddrIP, [out] ULONG64* pAddrSP, [out] BSTR* bstrModule, [out] BSTR* bstrFunction, [out] ULONG64* pDisplacement); + + [propget] HRESULT CurrentException([out, retval] ICLRMAClrException** ppClrException); + + [propget] HRESULT NestedExceptionCount([out, retval] USHORT* pCount); + HRESULT NestedException([in] USHORT nIndex, [out, retval] ICLRMAClrException** ppClrException); + }; + + // ICLRMAClrException + [ + uuid(7C165652-D539-472e-A6CF-F657FFF31751), + helpstring("ICLRMAClrException interface") + ] + interface ICLRMAClrException : IUnknown + { + [propget] HRESULT DebuggerCommand([out, retval] BSTR* pValue); + [propget] HRESULT Address([out, retval] ULONG64* pValue); + [propget] HRESULT HResult([out, retval] HRESULT* pValue); + [propget] HRESULT Type([out, retval] BSTR* pValue); + [propget] HRESULT Message([out, retval] BSTR* pValue); + + [propget] HRESULT FrameCount([out, retval] UINT* pCount); + HRESULT Frame([in] UINT nFrame, [out] ULONG64* pAddrIP, [out] ULONG64* pAddrSP, [out] BSTR* pModule, [out] BSTR* pFunction, [out] ULONG64* pDisplacement) ; + + [propget] HRESULT InnerExceptionCount([out, retval] USHORT* pCount); + HRESULT InnerException([in] USHORT nIndex, [out, retval] ICLRMAClrException** ppClrException); + }; + + // ICLRMAObjectInspection + [ + uuid(836259DB-7452-4b2b-95C4-4BC52CB9ABC7), + helpstring("ICLRMAObjectInspection interface") + ] + interface ICLRMAObjectInspection : IUnknown + { + HRESULT GetType([in] ULONG64 addr, [out, retval] BSTR* pValue); + HRESULT GetAddressFromCcwAddress([in] ULONG64 addr, [out, retval] ULONG64* pAddress); + + HRESULT GetField_SystemString([in] ULONG64 addr, [in] BSTR bstrField, [out, retval] BSTR* pValue); + HRESULT GetField_SystemUInt32([in] ULONG64 addr, [in] BSTR bstrField, [out, retval] ULONG* pValue); + HRESULT GetField_SystemInt32([in] ULONG64 addr, [in] BSTR bstrField, [out, retval] LONG* pValue); + }; + +}; // CLRMA Library diff --git a/src/SOS/lldbplugin/services.cpp b/src/SOS/lldbplugin/services.cpp index 1ecc09571..f340a069a 100644 --- a/src/SOS/lldbplugin/services.cpp +++ b/src/SOS/lldbplugin/services.cpp @@ -973,7 +973,7 @@ LLDBServices::GetNameByOffset( goto exit; } - address = module.ResolveFileAddress(offset); + address = target.ResolveLoadAddress(offset); if (!address.IsValid()) { hr = E_INVALIDARG; @@ -1445,16 +1445,7 @@ LLDBServices::GetModuleSize( /* const */ lldb::SBModule& module) { ULONG64 size = 0; -#if defined(__APPLE__) - mach_header_64 header; - ULONG read; - HRESULT hr = ReadVirtual(baseAddress, &header, sizeof(mach_header_64), &read) == S_OK; - if (SUCCEEDED(hr)) - { - // Since MachO segments are not contiguous the image size is just the headers/commands - size = sizeof(mach_header_64) + header.sizeofcmds; - } -#else + // Find the first section with an valid base address int numSections = module.GetNumSections(); for (int si = 0; si < numSections; si++) @@ -1462,10 +1453,15 @@ LLDBServices::GetModuleSize( lldb::SBSection section = module.GetSectionAtIndex(si); if (section.IsValid()) { +#if defined(__APPLE__) + if (strcmp(section.GetName(), "__LINKEDIT") == 0) + { + continue; + } + #endif size += section.GetByteSize(); } } -#endif // For core dumps lldb doesn't return the section sizes when it // doesn't have access to the actual module file, but SOS (like // the SymbolReader code) still needs a non-zero module size. diff --git a/src/SOS/lldbplugin/sosplugin.cpp b/src/SOS/lldbplugin/sosplugin.cpp index 2c39d5034..f4ef26e1c 100644 --- a/src/SOS/lldbplugin/sosplugin.cpp +++ b/src/SOS/lldbplugin/sosplugin.cpp @@ -19,14 +19,3 @@ bool lldb::PluginInitialize(lldb::SBDebugger debugger) sethostruntimeCommandInitialize(debugger); return true; } - -/// -/// Internal trace output for extensions library -/// -void TraceError(PCSTR format, ...) -{ - va_list args; - va_start(args, format); - g_services->InternalOutputVaList(DEBUG_OUTPUT_ERROR, format, args); - va_end(args); -}