diff --git a/src/Microsoft.Diagnostics.Runtime/DacInterface/DacDataTarget.cs b/src/Microsoft.Diagnostics.Runtime/DacInterface/DacDataTarget.cs index b54028756..f82f4022d 100644 --- a/src/Microsoft.Diagnostics.Runtime/DacInterface/DacDataTarget.cs +++ b/src/Microsoft.Diagnostics.Runtime/DacInterface/DacDataTarget.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Diagnostics.Runtime/DataReaders/DbgEng/DbgEngDataReader.cs b/src/Microsoft.Diagnostics.Runtime/DataReaders/DbgEng/DbgEngDataReader.cs new file mode 100644 index 000000000..e8bb3f538 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DataReaders/DbgEng/DbgEngDataReader.cs @@ -0,0 +1,284 @@ +// 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; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Diagnostics.Runtime.DataReaders.Implementation; +using Microsoft.Diagnostics.Runtime.DbgEng; +using Microsoft.Diagnostics.Runtime.Implementation; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime +{ + internal sealed class DbgEngDataReader : CommonMemoryReader, IDataReader, IDisposable, IThreadReader + { + private static int s_totalInstanceCount; + + private DebugClient _client = null!; + private DebugControl _control = null!; + private DebugDataSpaces _spaces = null!; + private DebugAdvanced _advanced = null!; + private DebugSymbols _symbols = null!; + private DebugSystemObjects _systemObjects = null!; + + private bool _disposed; + + private List? _modules; + private int? _pointerSize; + private Architecture? _architecture; + private static readonly RefCountedFreeLibrary _library = new(IntPtr.Zero); + + public string DisplayName { get; } + public OSPlatform TargetPlatform => OSPlatform.Windows; + + ~DbgEngDataReader() + { + Dispose(false); + } + + public DbgEngDataReader(string displayName, Stream stream, bool leaveOpen) + : this((stream as FileStream)?.Name ?? throw new NotSupportedException($"{nameof(DbgEngDataReader)} can only be used with real files. Try to use {nameof(FileStream)}.")) + { + DisplayName = displayName; + if (!leaveOpen) + stream?.Dispose(); + } + + public DbgEngDataReader(IntPtr pDebugClient) + { + if (pDebugClient == IntPtr.Zero) + throw new ArgumentNullException(nameof(pDebugClient)); + + DisplayName = $"DbgEng, IDebugClient={pDebugClient.ToInt64():x}"; + CreateClient(pDebugClient); + _systemObjects.Init(); + } + + public DbgEngDataReader(string dumpFile) + { + if (!File.Exists(dumpFile)) + throw new FileNotFoundException(dumpFile); + + DisplayName = dumpFile; + + IntPtr pClient = CreateIDebugClient(); + CreateClient(pClient); + HResult hr = _client.OpenDumpFile(dumpFile); + if (hr != 0) + { + const int STATUS_MAPPED_FILE_SIZE_ZERO = unchecked((int)0xC000011E); + + if (hr == HResult.E_INVALIDARG || hr == (STATUS_MAPPED_FILE_SIZE_ZERO | 0x10000000)) + throw new InvalidDataException($"'{dumpFile}' is not a crash dump."); + + throw new ClrDiagnosticsException($"Could not load crash dump, HRESULT: {hr}", hr).AddData("DumpFile", dumpFile); + } + + // This actually "attaches" to the crash dump. + HResult result = _control.WaitForEvent(0xffffffff); + _systemObjects.Init(); + DebugOnly.Assert(result); + } + + public DbgEngDataReader(int processId, bool invasive, uint msecTimeout) + { + DisplayName = $"{processId:x}"; + + IntPtr client = CreateIDebugClient(); + CreateClient(client); + + DebugAttach attach = invasive ? DebugAttach.Default : DebugAttach.NonInvasive; + _control.AddEngineOptions(DebugControl.INITIAL_BREAK); + + HResult hr = _client.AttachProcess((uint)processId, attach); + + if (hr) + hr = _control.WaitForEvent(msecTimeout); + + if (hr == HResult.S_FALSE) + { + throw new TimeoutException("Break in did not occur within the allotted timeout."); + } + + if (hr != 0) + { + if ((uint)hr.Value == 0xd00000bb) + throw new InvalidOperationException("Mismatched architecture between this process and the target process."); + + if (!WindowsFunctions.IsProcessRunning(processId)) + throw new ArgumentException($"Process {processId} is not running."); + + throw new ArgumentException($"Could not attach to process {processId}, HRESULT: 0x{hr:x}"); + } + } + + public bool IsThreadSafe => true; // Enforced by Debug* wrappers. + + public int ProcessId => (int)_systemObjects.GetProcessId(); + + public Architecture Architecture => _architecture ??= _control.GetEffectiveProcessorType() switch + { + IMAGE_FILE_MACHINE.I386 => Architecture.X86, + IMAGE_FILE_MACHINE.AMD64 => Architecture.X64, + IMAGE_FILE_MACHINE.ARM or + IMAGE_FILE_MACHINE.THUMB or + IMAGE_FILE_MACHINE.THUMB2 => Architecture.Arm, + IMAGE_FILE_MACHINE.ARM64 => Architecture.Arm64, + IMAGE_FILE_MACHINE.RISCV64 => (Architecture)9 /* Architecture.RiscV64 */, + _ => (Architecture)(-1) + }; + + [DefaultDllImportSearchPaths(DllImportSearchPath.LegacyBehavior)] + [DllImport("dbgeng.dll")] + public static extern int DebugCreate(in Guid InterfaceId, out IntPtr Interface); + + public override int PointerSize => _pointerSize ??= _control.IsPointer64Bit() ? sizeof(long) : sizeof(int); + + public void FlushCachedData() + { + _modules = null; + } + + public bool GetThreadContext(uint threadID, uint contextFlags, Span context) + { + uint id = _systemObjects.GetThreadIdBySystemId(threadID); + _systemObjects.SetCurrentThread(id); + return _advanced.GetThreadContext(context); + } + + private ulong[] GetImageBases() + { + int count = _symbols.GetNumberModules(); + + List bases = new(count); + for (int i = 0; i < count; ++i) + { + ulong image = _symbols.GetModuleByIndex(i); + if (image != 0) + bases.Add(image); + } + + return bases.ToArray(); + } + + public IEnumerable EnumerateModules() + { + if (_modules != null) + return _modules; + + ulong[] bases = GetImageBases(); + if (bases.Length == 0) + return Enumerable.Empty(); + + List modules = new(); + if (_symbols.GetModuleParameters(bases, out DEBUG_MODULE_PARAMETERS[] mods)) + { + for (int i = 0; i < bases.Length; ++i) + { + string? fn = _symbols.GetModuleNameStringWide(DebugModuleName.Image, i, bases[i]) ?? ""; + + ModuleInfo info = new PEModuleInfo(this, bases[i], fn, true, mods[i].Size, mods[i].TimeDateStamp, GetVersionInfo(bases[i])); + modules.Add(info); + } + } + + _modules = modules; + return modules; + } + + private static IntPtr CreateIDebugClient() + { + Guid guid = new("27fe5639-8407-4f47-8364-ee118fb08ac8"); + int hr = DebugCreate(guid, out IntPtr ptr); + DebugOnly.Assert(hr == 0); + + return ptr; + } + + private void CreateClient(IntPtr ptr) + { + _systemObjects = new DebugSystemObjects(_library, ptr); + _client = new DebugClient(_library, ptr, _systemObjects); + _control = new DebugControl(_library, ptr, _systemObjects); + _spaces = new DebugDataSpaces(_library, ptr, _systemObjects); + _advanced = new DebugAdvanced(_library, ptr, _systemObjects); + _symbols = new DebugSymbols(_library, ptr, _systemObjects); + + _client.SuppressRelease(); + _control.SuppressRelease(); + _spaces.SuppressRelease(); + _advanced.SuppressRelease(); + _symbols.SuppressRelease(); + _systemObjects.SuppressRelease(); + + Interlocked.Increment(ref s_totalInstanceCount); + } + + public override int Read(ulong address, Span buffer) + { + DebugOnly.Assert(!buffer.IsEmpty); + return _spaces.ReadVirtual(address, buffer); + } + + public Version? GetVersionInfo(ulong baseAddress) + { + if (!FindModuleIndex(baseAddress, out int index)) + return null; + + return _symbols.GetModuleVersionInformation(index, baseAddress); + } + + private bool FindModuleIndex(ulong baseAddr, out int index) + { + /* GetModuleByOffset returns the first module (from startIndex) which + * includes baseAddr. + * However when loading 64-bit dumps of 32-bit processes it seems that + * the module sizes are sometimes wrong, which may cause a wrong module + * to be found because it overlaps the beginning of the queried module, + * so search until we find a module that actually has the correct + * baseAddr */ + int nextIndex = 0; + while (true) + { + if (!_symbols.GetModuleByOffset(baseAddr, nextIndex, out index, out ulong claimedBaseAddr)) + { + index = 0; + return false; + } + + if (claimedBaseAddr == baseAddr) + return true; + + nextIndex = index + 1; + } + } + + public IEnumerable EnumerateOSThreadIds() => _systemObjects.GetThreadIds(); + public ulong GetThreadTeb(uint osThreadId) => _systemObjects.GetThreadTeb(osThreadId); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (_disposed) + return; + + _disposed = true; + + int count = Interlocked.Decrement(ref s_totalInstanceCount); + if (count == 0 && disposing) + { + _client.EndSession(DebugEnd.ActiveDetach); + _client.DetachProcesses(); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DataTarget.cs b/src/Microsoft.Diagnostics.Runtime/DataTarget.cs index 41d6b800c..7fbe321d3 100644 --- a/src/Microsoft.Diagnostics.Runtime/DataTarget.cs +++ b/src/Microsoft.Diagnostics.Runtime/DataTarget.cs @@ -437,6 +437,21 @@ public static DataTarget CreateSnapshotAndAttach(int processId, TokenCredential? throw GetPlatformException(); } + /// + /// Creates a DataTarget from an IDebugClient interface. This allows callers to interop with the DbgEng debugger + /// (cdb.exe, windbg.exe, dbgeng.dll). + /// + /// An IDebugClient interface. + /// A instance. + public static DataTarget CreateFromDbgEng(IntPtr pDebugClient) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + throw GetPlatformException(); + + CustomDataTarget customTarget = new(new DbgEngDataReader(pDebugClient), null); + return new DataTarget(customTarget); + } + private static PlatformNotSupportedException GetPlatformException([CallerMemberName] string? method = null) => new($"{method} is not supported on {RuntimeInformation.OSDescription}."); } diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_CLASS_QUALIFIER.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_CLASS_QUALIFIER.cs new file mode 100644 index 000000000..fc242040e --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_CLASS_QUALIFIER.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ +#pragma warning disable CA1069 // Enums values should not be duplicated + internal enum DEBUG_CLASS_QUALIFIER : uint + { + KERNEL_CONNECTION = 0, + KERNEL_LOCAL = 1, + KERNEL_EXDI_DRIVER = 2, + KERNEL_IDNA = 3, + KERNEL_SMALL_DUMP = 1024, + KERNEL_DUMP = 1025, + KERNEL_FULL_DUMP = 1026, + USER_WINDOWS_PROCESS = 0, + USER_WINDOWS_PROCESS_SERVER = 1, + USER_WINDOWS_IDNA = 2, + USER_WINDOWS_SMALL_DUMP = 1024, + USER_WINDOWS_DUMP = 1026 + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_FORMAT.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_FORMAT.cs new file mode 100644 index 000000000..e4336a6d6 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_FORMAT.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [Flags] + internal enum DEBUG_FORMAT : uint + { + DEFAULT = 0x00000000, + CAB_SECONDARY_ALL_IMAGES = 0x10000000, + WRITE_CAB = 0x20000000, + CAB_SECONDARY_FILES = 0x40000000, + NO_OVERWRITE = 0x80000000, + + USER_SMALL_FULL_MEMORY = 0x00000001, + USER_SMALL_HANDLE_DATA = 0x00000002, + USER_SMALL_UNLOADED_MODULES = 0x00000004, + USER_SMALL_INDIRECT_MEMORY = 0x00000008, + USER_SMALL_DATA_SEGMENTS = 0x00000010, + USER_SMALL_FILTER_MEMORY = 0x00000020, + USER_SMALL_FILTER_PATHS = 0x00000040, + USER_SMALL_PROCESS_THREAD_DATA = 0x00000080, + USER_SMALL_PRIVATE_READ_WRITE_MEMORY = 0x00000100, + USER_SMALL_NO_OPTIONAL_DATA = 0x00000200, + USER_SMALL_FULL_MEMORY_INFO = 0x00000400, + USER_SMALL_THREAD_INFO = 0x00000800, + USER_SMALL_CODE_SEGMENTS = 0x00001000, + USER_SMALL_NO_AUXILIARY_STATE = 0x00002000, + USER_SMALL_FULL_AUXILIARY_STATE = 0x00004000, + USER_SMALL_IGNORE_INACCESSIBLE_MEM = 0x08000000 + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_MODULE_PARAMETERS.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_MODULE_PARAMETERS.cs new file mode 100644 index 000000000..22b00aebe --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DEBUG_MODULE_PARAMETERS.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct DEBUG_MODULE_PARAMETERS + { + public ulong Base; + public int Size; + public int TimeDateStamp; + public uint Checksum; + public uint Flags; + public uint SymbolType; + public uint ImageNameSize; + public uint ModuleNameSize; + public uint LoadedImageNameSize; + public uint SymbolFileNameSize; + public uint MappedImageNameSize; + public fixed ulong Reserved[2]; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAdvanced.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAdvanced.cs new file mode 100644 index 000000000..7d6b9a666 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAdvanced.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugAdvanced : CallableCOMWrapper + { + internal static readonly Guid IID_IDebugAdvanced = new("f2df5f53-071f-47bd-9de6-5734c3fed689"); + + public DebugAdvanced(RefCountedFreeLibrary library, IntPtr pUnk, DebugSystemObjects sys) + : base(library, IID_IDebugAdvanced, pUnk) + { + _sys = sys; + SuppressRelease(); + } + + private ref readonly IDebugAdvancedVTable VTable => ref Unsafe.AsRef(_vtable); + + public HResult GetThreadContext(Span context) + { + using IDisposable holder = _sys.Enter(); + fixed (byte* ptr = context) + return VTable.GetThreadContext(Self, ptr, context.Length); + } + + private readonly DebugSystemObjects _sys; + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugAdvancedVTable + { + public readonly delegate* unmanaged[Stdcall] GetThreadContext; + public readonly IntPtr SetThreadContext; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAttach.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAttach.cs new file mode 100644 index 000000000..aaea13b3d --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugAttach.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [Flags] + internal enum DebugAttach : uint + { + Default = 0, + NonInvasive = 1, + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugClient.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugClient.cs new file mode 100644 index 000000000..6e2c55359 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugClient.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugClient : CallableCOMWrapper + { + internal static readonly Guid IID_IDebugClient = new("27fe5639-8407-4f47-8364-ee118fb08ac8"); + + private readonly DebugSystemObjects _sys; + + public DebugClient(RefCountedFreeLibrary library, IntPtr pUnk, DebugSystemObjects system) + : base(library, IID_IDebugClient, pUnk) + { + _sys = system; + SuppressRelease(); + } + + private ref readonly IDebugClientVTable VTable => ref Unsafe.AsRef(_vtable); + + public void EndSession(DebugEnd mode) + { + using IDisposable holder = _sys.Enter(); + int hr = VTable.EndSession(Self, mode); + DebugOnly.Assert(hr == 0); + } + + public void DetachProcesses() + { + using IDisposable holder = _sys.Enter(); + int hr = VTable.DetachProcesses(Self); + DebugOnly.Assert(hr == 0); + } + + public HResult AttachProcess(uint pid, DebugAttach flags) + { + HResult hr = VTable.AttachProcess(Self, 0, pid, flags); + + _sys.Init(); + return hr; + } + + public HResult OpenDumpFile(string dumpFile) + { + return VTable.OpenDumpFile(Self, dumpFile); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugClientVTable + { + public readonly IntPtr AttachKernel; + public readonly IntPtr GetKernelConnectionOptions; + public readonly IntPtr SetKernelConnectionOptions; + public readonly IntPtr StartProcessServer; + public readonly IntPtr ConnectProcessServer; + public readonly IntPtr DisconnectProcessServer; + public readonly IntPtr GetRunningProcessSystemIds; + public readonly IntPtr GetRunningProcessSystemIdByExecutableName; + public readonly IntPtr GetRunningProcessDescription; + public readonly delegate* unmanaged[Stdcall] AttachProcess; + public readonly IntPtr CreateProcess; + public readonly IntPtr CreateProcessAndAttach; + public readonly IntPtr GetProcessOptions; + public readonly IntPtr AddProcessOptions; + public readonly IntPtr RemoveProcessOptions; + public readonly IntPtr SetProcessOptions; + public readonly delegate* unmanaged[Stdcall] OpenDumpFile; + public readonly IntPtr WriteDumpFile; + public readonly IntPtr ConnectSession; + public readonly IntPtr StartServer; + public readonly IntPtr OutputServer; + public readonly IntPtr TerminateProcesses; + public readonly delegate* unmanaged[Stdcall] DetachProcesses; + public readonly delegate* unmanaged[Stdcall] EndSession; + public readonly IntPtr GetExitCode; + public readonly IntPtr DispatchCallbacks; + public readonly IntPtr ExitDispatch; + public readonly IntPtr CreateClient; + public readonly IntPtr GetInputCallbacks; + public readonly IntPtr SetInputCallbacks; + public readonly IntPtr GetOutputCallbacks; + public readonly IntPtr SetOutputCallbacks; + public readonly IntPtr GetOutputMask; + public readonly IntPtr SetOutputMask; + public readonly IntPtr GetOtherOutputMask; + public readonly IntPtr SetOtherOutputMask; + public readonly IntPtr GetOutputWidth; + public readonly IntPtr SetOutputWidth; + public readonly IntPtr GetOutputLinePrefix; + public readonly IntPtr SetOutputLinePrefix; + public readonly IntPtr GetIdentity; + public readonly IntPtr OutputIdentity; + public readonly IntPtr GetEventCallbacks; + public readonly IntPtr SetEventCallbacks; + public readonly IntPtr FlushCallbacks; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugControl.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugControl.cs new file mode 100644 index 000000000..86855ab8e --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugControl.cs @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugControl : CallableCOMWrapper + { + public const int INITIAL_BREAK = 0x20; + + internal static readonly Guid IID_IDebugControl2 = new("d4366723-44df-4bed-8c7e-4c05424f4588"); + + private readonly DebugSystemObjects _sys; + + public DebugControl(RefCountedFreeLibrary library, IntPtr pUnk, DebugSystemObjects sys) + : base(library, IID_IDebugControl2, pUnk) + { + _sys = sys; + SuppressRelease(); + } + + private ref readonly IDebugControlVTable VTable => ref Unsafe.AsRef(_vtable); + + public IMAGE_FILE_MACHINE GetEffectiveProcessorType() + { + using IDisposable holder = _sys.Enter(); + int hr = VTable.GetEffectiveProcessorType(Self, out IMAGE_FILE_MACHINE result); + if (hr == 0) + return result; + + return IMAGE_FILE_MACHINE.UNKNOWN; + } + + public bool IsPointer64Bit() + { + using IDisposable holder = _sys.Enter(); + int hr = VTable.IsPointer64Bit(Self); + return hr == 0; + } + + public HResult WaitForEvent(uint timeout) + { + using IDisposable holder = _sys.Enter(); + return VTable.WaitForEvent(Self, 0, timeout); + } + + public HResult AddEngineOptions(int options) + { + using IDisposable holder = _sys.Enter(); + return VTable.AddEngineOptions(Self, options); + } + + public DEBUG_FORMAT GetDumpFormat() + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetDumpFormatFlags(Self, out DEBUG_FORMAT result); + if (hr) + return result; + + return DEBUG_FORMAT.DEFAULT; + } + + public DEBUG_CLASS_QUALIFIER GetDebuggeeClassQualifier() + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetDebuggeeType(Self, out _, out DEBUG_CLASS_QUALIFIER result); + DebugOnly.Assert(hr.IsOK); + return result; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugControlVTable + { + public readonly IntPtr GetInterrupt; + public readonly IntPtr SetInterrupt; + public readonly IntPtr GetInterruptTimeout; + public readonly IntPtr SetInterruptTimeout; + public readonly IntPtr GetLogFile; + public readonly IntPtr OpenLogFile; + public readonly IntPtr CloseLogFile; + public readonly IntPtr GetLogMask; + public readonly IntPtr SetLogMask; + public readonly IntPtr Input; + public readonly IntPtr ReturnInput; + public readonly IntPtr Output; + public readonly IntPtr OutputVaList; + public readonly IntPtr ControlledOutput; + public readonly IntPtr ControlledOutputVaList; + public readonly IntPtr OutputPrompt; + public readonly IntPtr OutputPromptVaList; + public readonly IntPtr GetPromptText; + public readonly IntPtr OutputCurrentState; + public readonly IntPtr OutputVersionInformation; + public readonly IntPtr GetNotifyEventHandle; + public readonly IntPtr SetNotifyEventHandle; + public readonly IntPtr Assemble; + public readonly IntPtr Disassemble; + public readonly IntPtr GetDisassembleEffectiveOffset; + public readonly IntPtr OutputDisassembly; + public readonly IntPtr OutputDisassemblyLines; + public readonly IntPtr GetNearInstruction; + public readonly IntPtr GetStackTrace; + public readonly IntPtr GetReturnOffset; + public readonly IntPtr OutputStackTrace; + public readonly delegate* unmanaged[Stdcall] GetDebuggeeType; + public readonly IntPtr GetActualProcessorType; + public readonly IntPtr GetExecutingProcessorType; + public readonly IntPtr GetNumberPossibleExecutingProcessorTypes; + public readonly IntPtr GetPossibleExecutingProcessorTypes; + public readonly IntPtr GetNumberProcessors; + public readonly IntPtr GetSystemVersion; + public readonly IntPtr GetPageSize; + public readonly delegate* unmanaged[Stdcall] IsPointer64Bit; + public readonly IntPtr ReadBugCheckData; + public readonly IntPtr GetNumberSupportedProcessorTypes; + public readonly IntPtr GetSupportedProcessorTypes; + public readonly IntPtr GetProcessorTypeNames; + public readonly delegate* unmanaged[Stdcall] GetEffectiveProcessorType; + public readonly IntPtr SetEffectiveProcessorType; + public readonly IntPtr GetExecutionStatus; + public readonly IntPtr SetExecutionStatus; + public readonly IntPtr GetCodeLevel; + public readonly IntPtr SetCodeLevel; + public readonly IntPtr GetEngineOptions; + public readonly delegate* unmanaged[Stdcall] AddEngineOptions; + public readonly IntPtr RemoveEngineOptions; + public readonly IntPtr SetEngineOptions; + public readonly IntPtr GetSystemErrorControl; + public readonly IntPtr SetSystemErrorControl; + public readonly IntPtr GetTextMacro; + public readonly IntPtr SetTextMacro; + public readonly IntPtr GetRadix; + public readonly IntPtr SetRadix; + public readonly IntPtr Evaluate; + public readonly IntPtr CoerceValue; + public readonly IntPtr CoerceValues; + public readonly IntPtr Execute; + public readonly IntPtr ExecuteCommandFile; + public readonly IntPtr GetNumberBreakpoints; + public readonly IntPtr GetBreakpointByIndex; + public readonly IntPtr GetBreakpointById; + public readonly IntPtr GetBreakpointParameters; + public readonly IntPtr AddBreakpoint; + public readonly IntPtr RemoveBreakpoint; + public readonly IntPtr AddExtension; + public readonly IntPtr RemoveExtension; + public readonly IntPtr GetExtensionByPath; + public readonly IntPtr CallExtension; + public readonly IntPtr GetExtensionFunction; + public readonly IntPtr GetWindbgExtensionApis32; + public readonly IntPtr GetWindbgExtensionApis64; + public readonly IntPtr GetNumberEventFilters; + public readonly IntPtr GetEventFilterText; + public readonly IntPtr GetEventFilterCommand; + public readonly IntPtr SetEventFilterCommand; + public readonly IntPtr GetSpecificFilterParameters; + public readonly IntPtr SetSpecificFilterParameters; + public readonly IntPtr GetSpecificEventFilterArgument; + public readonly IntPtr SetSpecificEventFilterArgument; + public readonly IntPtr GetExceptionFilterParameters; + public readonly IntPtr SetExceptionFilterParameters; + public readonly IntPtr GetExceptionFilterSecondCommand; + public readonly IntPtr SetExceptionFilterSecondCommand; + public readonly delegate* unmanaged[Stdcall] WaitForEvent; + public readonly IntPtr GetLastEventInformation; + + public readonly IntPtr GetCurrentTimeDate; + public readonly IntPtr GetCurrentSystemUpTime; + public readonly delegate* unmanaged[Stdcall] GetDumpFormatFlags; + public readonly IntPtr GetNumberTextReplacements; + public readonly IntPtr GetTextReplacement; + public readonly IntPtr SetTextReplacement; + public readonly IntPtr RemoveTextReplacements; + public readonly IntPtr OutputTextReplacements; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugDataSpaces.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugDataSpaces.cs new file mode 100644 index 000000000..37fe966a7 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugDataSpaces.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugDataSpaces : CallableCOMWrapper + { + internal static readonly Guid IID_IDebugDataSpaces2 = new("7a5e852f-96e9-468f-ac1b-0b3addc4a049"); + + public DebugDataSpaces(RefCountedFreeLibrary library, IntPtr pUnk, DebugSystemObjects sys) + : base(library, IID_IDebugDataSpaces2, pUnk) + { + _sys = sys; + SuppressRelease(); + } + + private ref readonly IDebugDataSpacesVTable VTable => ref Unsafe.AsRef(_vtable); + + public int ReadVirtual(ulong address, Span buffer) + { + using IDisposable holder = _sys.Enter(); + fixed (byte* ptr = buffer) + { + HResult hr = VTable.ReadVirtual(Self, address, ptr, buffer.Length, out int read); + return read; + } + } + + public HResult QueryVirtual(ulong address, out MEMORY_BASIC_INFORMATION64 info) + { + using IDisposable holder = _sys.Enter(); + return VTable.QueryVirtual(Self, address, out info); + } + private readonly DebugSystemObjects _sys; + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugDataSpacesVTable + { + public readonly delegate* unmanaged[Stdcall] ReadVirtual; + public readonly IntPtr WriteVirtual; + public readonly IntPtr SearchVirtual; + public readonly IntPtr ReadVirtualUncached; + public readonly IntPtr WriteVirtualUncached; + public readonly IntPtr ReadPointersVirtual; + public readonly IntPtr WritePointersVirtual; + public readonly IntPtr ReadPhysical; + public readonly IntPtr WritePhysical; + public readonly IntPtr ReadControl; + public readonly IntPtr WriteControl; + public readonly IntPtr ReadIo; + public readonly IntPtr WriteIo; + public readonly IntPtr ReadMsr; + public readonly IntPtr WriteMsr; + public readonly IntPtr ReadBusData; + public readonly IntPtr WriteBusData; + public readonly IntPtr CheckLowMemory; + public readonly IntPtr ReadDebuggerData; + public readonly IntPtr ReadProcessorSystemData; + public readonly IntPtr VirtualToPhysical; + public readonly IntPtr GetVirtualTranslationPhysicalOffsets; + public readonly IntPtr ReadHandleData; + public readonly IntPtr FillVirtual; + public readonly IntPtr FillPhysical; + public readonly delegate* unmanaged[Stdcall] QueryVirtual; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugEnd.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugEnd.cs new file mode 100644 index 000000000..52870f1ce --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugEnd.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal enum DebugEnd + { + Passive, + ActiveTerminate, + ActiveDetach, + EndReentrant, + EndDisconnect + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugModuleName.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugModuleName.cs new file mode 100644 index 000000000..e83191448 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugModuleName.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal enum DebugModuleName : uint + { + Image, + Module, + LoadedImage, + SymbolFile, + MappedImage, + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSymbols.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSymbols.cs new file mode 100644 index 000000000..3b8ebfe03 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSymbols.cs @@ -0,0 +1,234 @@ +// 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.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugSymbols : CallableCOMWrapper + { + internal static readonly Guid IID_IDebugSymbols3 = new("f02fbecc-50ac-4f36-9ad9-c975e8f32ff8"); + + public DebugSymbols(RefCountedFreeLibrary library, IntPtr pUnk, DebugSystemObjects sys) + : base(library, IID_IDebugSymbols3, pUnk) + { + _sys = sys; + SuppressRelease(); + } + + private ref readonly IDebugSymbols3VTable VTable => ref Unsafe.AsRef(_vtable); + + public string? GetModuleNameStringWide(DebugModuleName which, int index, ulong imageBase) + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetModuleNameStringWide(Self, which, index, imageBase, null, 0, out int needed); + if (!hr) + return null; + + string nameResult = new('\0', needed - 1); + fixed (char* nameResultPtr = nameResult) + { + hr = VTable.GetModuleNameStringWide(Self, which, index, imageBase, nameResultPtr, needed, out _); + if (hr) + return nameResult; + } + + return null; + } + + public int GetNumberModules() + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetNumberModules(Self, out int count, out _); + return hr ? count : 0; + } + + public ulong GetModuleByIndex(int i) + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetModuleByIndex(Self, i, out ulong imageBase); + return hr ? imageBase : 0; + } + + public HResult GetModuleParameters(ulong[] bases, out DEBUG_MODULE_PARAMETERS[] parameters) + { + parameters = new DEBUG_MODULE_PARAMETERS[bases.Length]; + + fixed (ulong* pBases = bases) + fixed (DEBUG_MODULE_PARAMETERS* pParams = parameters) + { + using IDisposable holder = _sys.Enter(); + HResult hr = VTable.GetModuleParameters(Self, bases.Length, pBases, 0, pParams); + return hr; + } + } + + public Version GetModuleVersionInformation(int index, ulong imgBase) + { + byte* item = stackalloc byte[3] { (byte)'\\', (byte)'\\', 0 }; + + using IDisposable holder = _sys.Enter(); + + byte[] buffer = ArrayPool.Shared.Rent(256); + try + { + HResult hr; + fixed (byte* pBuffer = buffer) + hr = VTable.GetModuleVersionInformation(Self, index, imgBase, item, pBuffer, buffer.Length, out _); + + if (!hr) + return new Version(); + + int minor = Unsafe.As(ref buffer[8]); + int major = Unsafe.As(ref buffer[10]); + int patch = Unsafe.As(ref buffer[12]); + int revision = Unsafe.As(ref buffer[14]); + + return new Version(major, minor, revision, patch); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + public HResult GetModuleByOffset(ulong address, int index, out int outIndex, out ulong imgBase) + { + using IDisposable holder = _sys.Enter(); + return VTable.GetModuleByOffset(Self, address, index, out outIndex, out imgBase); + } + private readonly DebugSystemObjects _sys; + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugSymbols3VTable + { + public readonly IntPtr GetSymbolOptions; + public readonly IntPtr AddSymbolOptions; + public readonly IntPtr RemoveSymbolOptions; + public readonly IntPtr SetSymbolOptions; + public readonly IntPtr GetNameByOffset; + public readonly IntPtr GetOffsetByName; + public readonly IntPtr GetNearNameByOffset; + public readonly IntPtr GetLineByOffset; + public readonly IntPtr GetOffsetByLine; + public readonly delegate* unmanaged[Stdcall] GetNumberModules; + public readonly delegate* unmanaged[Stdcall] GetModuleByIndex; + public readonly IntPtr GetModuleByModuleName; + public readonly delegate* unmanaged[Stdcall] GetModuleByOffset; + public readonly IntPtr GetModuleNames; + public readonly delegate* unmanaged[Stdcall] GetModuleParameters; + public readonly IntPtr GetSymbolModule; + public readonly IntPtr GetTypeName; + public readonly IntPtr GetTypeId; + public readonly IntPtr GetTypeSize; + public readonly IntPtr GetFieldOffset; + public readonly IntPtr GetSymbolTypeId; + public readonly IntPtr GetOffsetTypeId; + public readonly IntPtr ReadTypedDataVirtual; + public readonly IntPtr WriteTypedDataVirtual; + public readonly IntPtr OutputTypedDataVirtual; + public readonly IntPtr ReadTypedDataPhysical; + public readonly IntPtr WriteTypedDataPhysical; + public readonly IntPtr OutputTypedDataPhysical; + public readonly IntPtr GetScope; + public readonly IntPtr SetScope; + public readonly IntPtr ResetScope; + public readonly IntPtr GetScopeSymbolGroup; + public readonly IntPtr CreateSymbolGroup; + public readonly IntPtr StartSymbolMatch; + public readonly IntPtr GetNextSymbolMatch; + public readonly IntPtr EndSymbolMatch; + public readonly IntPtr Reload; + public readonly IntPtr GetSymbolPath; + public readonly IntPtr SetSymbolPath; + public readonly IntPtr AppendSymbolPath; + public readonly IntPtr GetImagePath; + public readonly IntPtr SetImagePath; + public readonly IntPtr AppendImagePath; + public readonly IntPtr GetSourcePath; + public readonly IntPtr GetSourcePathElement; + public readonly IntPtr SetSourcePath; + public readonly IntPtr AppendSourcePath; + public readonly IntPtr FindSourceFile; + public readonly IntPtr GetSourceFileLineOffsets; + public readonly delegate* unmanaged[Stdcall] GetModuleVersionInformation; + public readonly IntPtr GetModuleNameString; + public readonly IntPtr GetConstantName; + public readonly IntPtr GetFieldName; + public readonly IntPtr GetTypeOptions; + public readonly IntPtr AddTypeOptions; + public readonly IntPtr RemoveTypeOptions; + public readonly IntPtr SetTypeOptions; + public readonly IntPtr GetNameByOffsetWide; + public readonly IntPtr GetOffsetByNameWide; + public readonly IntPtr GetNearNameByOffsetWide; + public readonly IntPtr GetLineByOffsetWide; + public readonly IntPtr GetOffsetByLineWide; + public readonly IntPtr GetModuleByModuleNameWide; + public readonly IntPtr GetSymbolModuleWide; + public readonly IntPtr GetTypeNameWide; + public readonly IntPtr GetTypeIdWide; + public readonly IntPtr GetFieldOffsetWide; + public readonly IntPtr GetSymbolTypeIdWide; + public readonly IntPtr GetScopeSymbolGroup2; + public readonly IntPtr CreateSymbolGroup2; + public readonly IntPtr StartSymbolMatchWide; + public readonly IntPtr GetNextSymbolMatchWide; + public readonly IntPtr ReloadWide; + public readonly IntPtr GetSymbolPathWide; + public readonly IntPtr SetSymbolPathWide; + public readonly IntPtr AppendSymbolPathWide; + public readonly IntPtr GetImagePathWide; + public readonly IntPtr SetImagePathWide; + public readonly IntPtr AppendImagePathWide; + public readonly IntPtr GetSourcePathWide; + public readonly IntPtr GetSourcePathElementWide; + public readonly IntPtr SetSourcePathWide; + public readonly IntPtr AppendSourcePathWide; + public readonly IntPtr FindSourceFileWide; + public readonly IntPtr GetSourceFileLineOffsetsWide; + public readonly IntPtr GetModuleVersionInformationWide; + public readonly delegate* unmanaged[Stdcall] GetModuleNameStringWide; + public readonly IntPtr GetConstantNameWide; + public readonly IntPtr GetFieldNameWide; + public readonly IntPtr IsManagedModule; + public readonly IntPtr GetModuleByModuleName2; + public readonly IntPtr GetModuleByModuleName2Wide; + public readonly IntPtr GetModuleByOffset2; + public readonly IntPtr AddSyntheticModule; + public readonly IntPtr AddSyntheticModuleWide; + public readonly IntPtr RemoveSyntheticModule; + public readonly IntPtr GetCurrentScopeFrameIndex; + public readonly IntPtr SetScopeFrameByIndex; + public readonly IntPtr SetScopeFromJitDebugInfo; + public readonly IntPtr SetScopeFromStoredEvent; + public readonly IntPtr OutputSymbolByOffset; + public readonly IntPtr GetFunctionEntryByOffset; + public readonly IntPtr GetFieldTypeAndOffset; + public readonly IntPtr GetFieldTypeAndOffsetWide; + public readonly IntPtr AddSyntheticSymbol; + public readonly IntPtr AddSyntheticSymbolWide; + public readonly IntPtr RemoveSyntheticSymbol; + public readonly IntPtr GetSymbolEntriesByOffset; + public readonly IntPtr GetSymbolEntriesByName; + public readonly IntPtr GetSymbolEntriesByNameWide; + public readonly IntPtr GetSymbolEntryByToken; + public readonly IntPtr GetSymbolEntryInformation; + public readonly IntPtr GetSymbolEntryString; + public readonly IntPtr GetSymbolEntryStringWide; + public readonly IntPtr GetSymbolEntryOffsetRegions; + public readonly IntPtr GetSymbolEntryBySymbolEntry; + public readonly IntPtr GetSourceEntriesByOffset; + public readonly IntPtr GetSourceEntriesByLine; + public readonly IntPtr GetSourceEntriesByLineWide; + public readonly IntPtr GetSourceEntryString; + public readonly IntPtr GetSourceEntryStringWide; + public readonly IntPtr GetSourceEntryOffsetRegions; + public readonly IntPtr GetSourceEntryBySourceEntry; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSystemObjects.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSystemObjects.cs new file mode 100644 index 000000000..5e505a048 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/DebugSystemObjects.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Diagnostics.Runtime.Utilities; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + internal sealed unsafe class DebugSystemObjects : CallableCOMWrapper + { + internal static readonly Guid IID_DebugSystemObjects3 = new("e9676e2f-e286-4ea3-b0f9-dfe5d9fc330e"); + + public DebugSystemObjects(RefCountedFreeLibrary library, IntPtr pUnk) + : base(library, IID_DebugSystemObjects3, pUnk) + { + SuppressRelease(); + } + + private ref readonly IDebugSystemObjects3VTable VTable => ref Unsafe.AsRef(_vtable); + +#pragma warning disable CA1822 + public IDisposable Enter() => new SystemHolder(); +#pragma warning restore CA1822 + + public uint GetProcessId() + { + using IDisposable holder = Enter(); + HResult hr = VTable.GetCurrentProcessSystemId(Self, out uint id); + return hr ? id : 0; + } + + private HResult SetCurrentSystemId(int id) + { + HResult hr = VTable.SetCurrentSystemId(Self, id); + DebugOnly.Assert(hr); + return hr; + } + + public HResult SetCurrentThread(uint id) + { + using IDisposable holder = Enter(); + HResult hr = VTable.SetCurrentThreadId(Self, id); + DebugOnly.Assert(hr); + return hr; + } + + public uint GetCurrentThread() + { + using IDisposable holder = Enter(); + HResult hr = VTable.GetCurrentThreadId(Self, out uint id); + + return hr ? id : 0; + } + + public int GetNumberThreads() + { + using IDisposable holder = Enter(); + HResult hr = VTable.GetNumberThreads(Self, out int count); + DebugOnly.Assert(hr); + return count; + } + + public ulong GetThreadTeb(uint osThreadId) + { + using IDisposable holder = Enter(); + + ulong teb = 0; + uint currId = GetCurrentThread(); + + uint debuggerThreadId = GetThreadIdBySystemId(osThreadId); + HResult hr = SetCurrentThread(debuggerThreadId); + if (hr) + { + hr = VTable.GetCurrentThreadTeb(Self, out teb); + if (!hr) + teb = 0; + } + + SetCurrentThread(currId); + return teb; + } + + internal void Init() + { + HResult hr = VTable.GetCurrentSystemId(Self, out int id); + DebugOnly.Assert(hr); + _systemId = id; + } + + public uint[] GetThreadIds() + { + using IDisposable holder = Enter(); + + int count = GetNumberThreads(); + if (count == 0) + return Array.Empty(); + + uint[] result = new uint[count]; + fixed (uint* pResult = result) + { + HResult hr = VTable.GetThreadIdsByIndex(Self, 0, count, null, pResult); + if (hr) + return result; + + return Array.Empty(); + } + } + + public uint GetThreadIdBySystemId(uint sysId) + { + using IDisposable holder = Enter(); + HResult hr = VTable.GetThreadIdBySystemId(Self, sysId, out uint result); + DebugOnly.Assert(hr); + return result; + } + + private int _systemId = -1; + + private sealed class SystemHolder : IDisposable + { + private static readonly object _sync = new(); + + public SystemHolder() + { + Monitor.Enter(_sync); + } + + public void Dispose() + { + Monitor.Exit(_sync); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal readonly unsafe struct IDebugSystemObjects3VTable + { + public readonly IntPtr GetEventThread; + public readonly IntPtr GetEventProcess; + public readonly delegate* unmanaged[Stdcall] GetCurrentThreadId; + public readonly delegate* unmanaged[Stdcall] SetCurrentThreadId; + public readonly IntPtr GetCurrentProcessId; + public readonly IntPtr SetCurrentProcessId; + public readonly delegate* unmanaged[Stdcall] GetNumberThreads; + public readonly IntPtr GetTotalNumberThreads; + public readonly delegate* unmanaged[Stdcall] GetThreadIdsByIndex; + public readonly IntPtr GetThreadIdByProcessor; + public readonly IntPtr GetCurrentThreadDataOffset; + public readonly IntPtr GetThreadIdByDataOffset; + public readonly delegate* unmanaged[Stdcall] GetCurrentThreadTeb; + public readonly IntPtr GetThreadIdByTeb; + public readonly IntPtr GetCurrentThreadSystemId; + public readonly delegate* unmanaged[Stdcall] GetThreadIdBySystemId; + public readonly IntPtr GetCurrentThreadHandle; + public readonly IntPtr GetThreadIdByHandle; + public readonly IntPtr GetNumberProcesses; + public readonly IntPtr GetProcessIdsByIndex; + public readonly IntPtr GetCurrentProcessDataOffset; + public readonly IntPtr GetProcessIdByDataOffset; + public readonly IntPtr GetCurrentProcessPeb; + public readonly IntPtr GetProcessIdByPeb; + public readonly delegate* unmanaged[Stdcall] GetCurrentProcessSystemId; + public readonly IntPtr GetProcessIdBySystemId; + public readonly IntPtr GetCurrentProcessHandle; + public readonly IntPtr GetProcessIdByHandle; + public readonly IntPtr GetCurrentProcessExecutableName; + public readonly IntPtr GetCurrentProcessUpTime; + public readonly IntPtr GetImplicitThreadDataOffset; + public readonly IntPtr SetImplicitThreadDataOffset; + public readonly IntPtr GetImplicitProcessDataOffset; + public readonly IntPtr SetImplicitProcessDataOffset; + public readonly IntPtr GetEventSystem; + public readonly delegate* unmanaged[Stdcall] GetCurrentSystemId; + public readonly delegate* unmanaged[Stdcall] SetCurrentSystemId; + public readonly IntPtr GetNumberSystems; + public readonly IntPtr GetSystemIdsByIndex; + public readonly IntPtr GetTotalNumberThreadsAndProcesses; + public readonly IntPtr GetCurrentSystemServer; + public readonly IntPtr GetSystemByServer; + public readonly IntPtr GetCurrentSystemServerName; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/MEM.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/MEM.cs new file mode 100644 index 000000000..095984dab --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/MEM.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [Flags] + internal enum MEM : uint + { + COMMIT = 0x1000, + RESERVE = 0x2000, + DECOMMIT = 0x4000, + RELEASE = 0x8000, + FREE = 0x10000, + PRIVATE = 0x20000, + MAPPED = 0x40000, + RESET = 0x80000, + TOP_DOWN = 0x100000, + WRITE_WATCH = 0x200000, + PHYSICAL = 0x400000, + ROTATE = 0x800000, + LARGE_PAGES = 0x20000000, + FOURMB_PAGES = 0x80000000, + + IMAGE = 0x1000000 + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/MEMORY_BASIC_INFORMATION64.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/MEMORY_BASIC_INFORMATION64.cs new file mode 100644 index 000000000..6c8d7bb79 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/MEMORY_BASIC_INFORMATION64.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [StructLayout(LayoutKind.Sequential)] + internal struct MEMORY_BASIC_INFORMATION64 + { + public ulong BaseAddress; + public ulong AllocationBase; + public PAGE AllocationProtect; + public uint __alignment1; + public ulong RegionSize; + public MEM State; + public PAGE Protect; + public MEM Type; + public uint __alignment2; + } +} \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Runtime/DbgEng/PAGE.cs b/src/Microsoft.Diagnostics.Runtime/DbgEng/PAGE.cs new file mode 100644 index 000000000..790431463 --- /dev/null +++ b/src/Microsoft.Diagnostics.Runtime/DbgEng/PAGE.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.Runtime.DbgEng +{ + [Flags] + internal enum PAGE : uint + { + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + GUARD = 0x100, + NOCACHE = 0x200, + WRITECOMBINE = 0x400 + } +} \ No newline at end of file