From e97b2b62b169fb703f4f1f49029d125c206b597a Mon Sep 17 00:00:00 2001 From: Andreas Hollandt Date: Sat, 5 Sep 2020 13:45:51 +0200 Subject: [PATCH 1/5] implement reverse execution send CapabilitiesEvent after target launch to correctly signal StepBack support introduce IDebugReversibleEngineProgram160 to properly handle execution direction like VS --- .../CommandFactories/MICommandFactory.cs | 29 ++++-- src/MICore/CommandFactories/gdb.cs | 14 +-- src/MICore/CommandFactories/lldb.cs | 10 ++- src/MIDebugEngine/AD7.Impl/AD7Engine.cs | 24 +++-- .../Engine.Impl/DebuggedProcess.cs | 41 ++++++--- src/MIDebugEngine/Natvis.Impl/Natvis.cs | 4 + src/OpenDebugAD7/AD7DebugSession.cs | 89 ++++++++++++++++--- 7 files changed, 161 insertions(+), 50 deletions(-) diff --git a/src/MICore/CommandFactories/MICommandFactory.cs b/src/MICore/CommandFactories/MICommandFactory.cs index c8b69dcd8..57e2be4d3 100644 --- a/src/MICore/CommandFactories/MICommandFactory.cs +++ b/src/MICore/CommandFactories/MICommandFactory.cs @@ -5,11 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; -using System.IO; using System.Text; -using System.Collections.ObjectModel; using System.Linq; -using System.Globalization; using Microsoft.VisualStudio.Debugger.Interop; namespace MICore @@ -212,33 +209,43 @@ public async Task StackListVariables(PrintValue printValues, int #region Program Execution - public async Task ExecStep(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecStep(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-step"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecNext(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecNext(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-next"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecFinish(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecFinish(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-finish"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecStepInstruction(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecStepInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-step-instruction"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecNextInstruction(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecNextInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-next-instruction"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } @@ -254,9 +261,11 @@ public virtual async Task ExecRun() /// /// Continues running the target process /// - public async Task ExecContinue() + public async Task ExecContinue(bool forward = true) { string command = "-exec-continue"; + if (!forward) + command += " --reverse"; await _debugger.CmdAsync(command, ResultClass.running); } @@ -686,6 +695,8 @@ public virtual bool CanDetach() return true; } + abstract public Task GetTargetFeatures(); + abstract public Task> StartAddressesForLine(string file, uint line); /// diff --git a/src/MICore/CommandFactories/gdb.cs b/src/MICore/CommandFactories/gdb.cs index 92c28938b..08f8d0d1d 100644 --- a/src/MICore/CommandFactories/gdb.cs +++ b/src/MICore/CommandFactories/gdb.cs @@ -1,19 +1,15 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; using System.IO; -using System.Text; -using System.Collections.ObjectModel; -using System.Linq; using System.Globalization; namespace MICore { - internal class GdbMICommandFactory : MICommandFactory + internal sealed class GdbMICommandFactory : MICommandFactory { private int _currentThreadId = 0; private uint _currentFrameLevel = 0; @@ -183,6 +179,12 @@ public override async Task> StartAddressesForLine(string file, uint return addresses; } + public override async Task GetTargetFeatures() + { + Results results = await _debugger.CmdAsync("-list-target-features", ResultClass.done); + return results.Find("features").AsStrings; + } + public override async Task EnableTargetAsyncOption() { // Linux attach TODO: GDB will fail this command when attaching. This is worked around diff --git a/src/MICore/CommandFactories/lldb.cs b/src/MICore/CommandFactories/lldb.cs index 738a47f5a..54446f96b 100644 --- a/src/MICore/CommandFactories/lldb.cs +++ b/src/MICore/CommandFactories/lldb.cs @@ -3,18 +3,15 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; using System.IO; using System.Text; -using System.Collections.ObjectModel; -using System.Linq; using System.Globalization; using Microsoft.VisualStudio.Debugger.Interop; namespace MICore { - internal class LlldbMICommandFactory : MICommandFactory + internal sealed class LlldbMICommandFactory : MICommandFactory { public override string Name { @@ -119,6 +116,11 @@ public override Task EnableTargetAsyncOption() return Task.FromResult((object)null); } + public override Task GetTargetFeatures() + { + return Task.FromResult(new string[0]); + } + public override string GetTargetArchitectureCommand() { return "platform status"; diff --git a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs index 0535572a6..cb0ca2487 100755 --- a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Runtime.ExceptionServices; using Microsoft.VisualStudio.Debugger.Interop; using Microsoft.VisualStudio.Debugger.Interop.UnixPortSupplier; using System.Diagnostics; @@ -35,7 +33,7 @@ namespace Microsoft.MIDebugEngine [System.Runtime.InteropServices.ComVisible(true)] [System.Runtime.InteropServices.Guid("0fc2f352-2fc1-4f80-8736-51cd1ab28f16")] - sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDebugMemoryBytesDAP, IDisposable + sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugReversibleEngineProgram160, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDebugMemoryBytesDAP, IDisposable { // used to send events to the debugger. Some examples of these events are thread create, exception thrown, module load. private EngineCallback _engineCallback; @@ -171,6 +169,7 @@ internal bool ProgramCreateEventSent get; private set; } + public ExecuteDirection ExecutionDirection { get; private set; } public string GetAddressDescription(ulong ip) { @@ -778,11 +777,11 @@ public int Continue(IDebugThread2 pThread) { if (_pollThread.IsPollThread()) { - _debuggedProcess.Continue(thread?.GetDebuggedThread()); + _debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection); } else { - _pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread())); + _pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection)); } } catch (InvalidCoreDumpOperationException) @@ -973,7 +972,7 @@ public int Step(IDebugThread2 pThread, enum_STEPKIND kind, enum_STEPUNIT unit) return Constants.E_FAIL; } - _debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit)); + _debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit, ExecutionDirection)); } catch (InvalidCoreDumpOperationException) { @@ -1061,6 +1060,19 @@ public int WatchForThreadStep(IDebugProgram2 pOriginatingProgram, uint dwTid, in #endregion + #region IDebugEngineProgram2 Members + int IDebugReversibleEngineProgram160.CanReverse() + { + return DebuggedProcess.TargetFeatures.Contains("reverse") ? Constants.S_OK : Constants.S_FALSE; + } + + int IDebugReversibleEngineProgram160.SetExecuteDirection(ExecuteDirection ExecuteDirection) + { + ExecutionDirection = ExecuteDirection; + return Constants.S_OK; + } + #endregion + #region IDebugMemoryBytes2 Members public int GetSize(out ulong pqwSize) diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index 011ff4f28..b01d3cea3 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using MICore; @@ -19,7 +19,7 @@ namespace Microsoft.MIDebugEngine { - internal class DebuggedProcess : MICore.Debugger + internal sealed class DebuggedProcess : MICore.Debugger { public AD_PROCESS_ID Id { get; private set; } public AD7Engine Engine { get; private set; } @@ -32,6 +32,7 @@ internal class DebuggedProcess : MICore.Debugger public Disassembly Disassembly { get; private set; } public ExceptionManager ExceptionManager { get; private set; } public CygwinFilePathMapper CygwinFilePathMapper { get; private set; } + public string[] TargetFeatures { get; private set; } private List _moduleList; private ISampleEngineCallback _callback; @@ -600,6 +601,8 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) } } } + // now the exe is loaded and we can check target features + TargetFeatures = await MICommandFactory.GetTargetFeatures(); success = true; } @@ -1381,7 +1384,13 @@ private async Task HandleBreakModeEvent(ResultEventArgs results, BreakRequest br { if (breakRequest == BreakRequest.None) { + // FIXME: we also end up here when gdb prints + // "No more reverse-execution history." + // but does not set a stopped event reason Debug.Fail("Unknown stopping reason"); + // FIXME: this will show up as "Exception occurred" in vscode which + // confusingly suggests that an exception has occurred in the debuggee. + // But OnError() only prints something in the console rather than in the editor _callback.OnException(thread, "Unknown", "Unknown stopping event", 0); } } @@ -1669,10 +1678,16 @@ protected override void ScheduleResultProcessing(Action func) _worker.PostOperation(() => { func(); }); } - public async Task Execute(DebuggedThread thread) + public async Task Execute(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward) { await ExceptionManager.EnsureSettingsUpdated(); + if (executionDirection == ExecuteDirection.ExecuteDirection_Reverse) + { + await MICommandFactory.ExecContinue(false); + return; + } + // Should clear stepping state if (_worker.IsPollThread()) { @@ -1684,30 +1699,32 @@ public async Task Execute(DebuggedThread thread) } } - public Task Continue(DebuggedThread thread) + public Task Continue(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward) { // Called after Stopping event - return Execute(thread); + return Execute(thread, executionDirection); } - public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit) + public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit, ExecuteDirection direction = ExecuteDirection.ExecuteDirection_Forward) { this.VerifyNotDebuggingCoreDump(); await ExceptionManager.EnsureSettingsUpdated(); + // STEP_BACKWARDS is deprecated, use direction + bool isForwardStep = direction == ExecuteDirection.ExecuteDirection_Forward; if ((unit == enum_STEPUNIT.STEP_LINE) || (unit == enum_STEPUNIT.STEP_STATEMENT)) { switch (kind) { case enum_STEPKIND.STEP_INTO: - await MICommandFactory.ExecStep(threadId); + await MICommandFactory.ExecStep(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OVER: - await MICommandFactory.ExecNext(threadId); + await MICommandFactory.ExecNext(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OUT: - await MICommandFactory.ExecFinish(threadId); + await MICommandFactory.ExecFinish(threadId, isForwardStep); break; default: throw new NotImplementedException(); @@ -1718,13 +1735,13 @@ public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit) switch (kind) { case enum_STEPKIND.STEP_INTO: - await MICommandFactory.ExecStepInstruction(threadId); + await MICommandFactory.ExecStepInstruction(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OVER: - await MICommandFactory.ExecNextInstruction(threadId); + await MICommandFactory.ExecNextInstruction(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OUT: - await MICommandFactory.ExecFinish(threadId); + await MICommandFactory.ExecFinish(threadId, isForwardStep); break; default: throw new NotImplementedException(); diff --git a/src/MIDebugEngine/Natvis.Impl/Natvis.cs b/src/MIDebugEngine/Natvis.Impl/Natvis.cs index 273623beb..4d2c40b77 100755 --- a/src/MIDebugEngine/Natvis.Impl/Natvis.cs +++ b/src/MIDebugEngine/Natvis.Impl/Natvis.cs @@ -964,6 +964,10 @@ private VisualizerInfo FindType(IVariableInformation variable) { return ((VisualizerWrapper)variable).Visualizer; } + + if (string.IsNullOrEmpty(variable.TypeName)) + return null; + if (_vizCache.ContainsKey(variable.TypeName)) { return _vizCache[variable.TypeName]; diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index fed2c86a0..232a73dff 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -29,6 +29,18 @@ namespace OpenDebugAD7 { + // not in the DAP dll yet + internal sealed class CapabilitiesEvent : DebugEvent + { + internal CapabilitiesEvent() + : base("capabilities") + { + } + + [JsonProperty("capabilities")] + internal InitializeResponse Capabilities; + } + internal sealed class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2 { // This is a general purpose lock. Don't hold it across long operations. @@ -796,7 +808,7 @@ private void SetCategoryGuidExceptions(Guid categoryId, enum_EXCEPTION_STATE sta } } - private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranularity granularity, string errorMessage) + private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranularity granularity, ExecuteDirection stepDirection, string errorMessage) { // If we are already running ignore additional step requests if (!m_isStopped) @@ -830,6 +842,7 @@ private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranular } try { + ((IDebugReversibleEngineProgram160)m_engine).SetExecuteDirection(stepDirection); builder.CheckHR(m_program.Step(thread, stepKind, stepUnit)); } catch (AD7Exception) @@ -1148,6 +1161,14 @@ protected override void HandleLaunchRequestAsync(IRequestResponder responder) + private void ContinueInternal(int threadId, ExecuteDirection direction) { - int threadId = responder.Arguments.ThreadId; - // Sometimes we can get a threadId of 0. Make sure we don't look it up in this case, otherwise we will crash. IDebugThread2 thread = null; lock (m_threads) @@ -1475,13 +1502,9 @@ protected override void HandleContinueRequestAsync(IRequestResponder responder) + { + try + { + ContinueInternal(responder.Arguments.ThreadId, ExecuteDirection.ExecuteDirection_Forward); + responder.SetResponse(new ContinueResponse()); + } + catch (AD7Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } + } + + protected override void HandleReverseContinueRequestAsync(IRequestResponder responder) + { + try + { + ContinueInternal(responder.Arguments.ThreadId, ExecuteDirection.ExecuteDirection_Reverse); + responder.SetResponse(new ContinueResponse()); + } + catch (AD7Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } + } + protected override void HandleStepInRequestAsync(IRequestResponder responder) { try { var granularity = responder.Arguments.Granularity.GetValueOrDefault(); - StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_INTO, granularity, AD7Resources.Error_Scenario_Step_In); + StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_INTO, granularity, ExecuteDirection.ExecuteDirection_Forward, AD7Resources.Error_Scenario_Step_In); responder.SetResponse(new StepInResponse()); } catch (AD7Exception e) @@ -1511,7 +1560,7 @@ protected override void HandleNextRequestAsync(IRequestResponder try { var granularity = responder.Arguments.Granularity.GetValueOrDefault(); - StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_OVER, granularity, AD7Resources.Error_Scenario_Step_Next); + StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_OVER, granularity, ExecuteDirection.ExecuteDirection_Forward, AD7Resources.Error_Scenario_Step_Next); responder.SetResponse(new NextResponse()); } catch (AD7Exception e) @@ -1525,7 +1574,7 @@ protected override void HandleStepOutRequestAsync(IRequestResponder responder) + { + try + { + var granularity = responder.Arguments.Granularity.GetValueOrDefault(); + StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_OVER, granularity, ExecuteDirection.ExecuteDirection_Reverse, AD7Resources.Error_Scenario_Step_Next); + responder.SetResponse(new StepBackResponse()); + } + catch (AD7Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } + } + protected override void HandlePauseRequestAsync(IRequestResponder responder) { // TODO: wait for break event From a79ab2f0c082d9f3dfabea7dc2b370e1106ec8e6 Mon Sep 17 00:00:00 2001 From: Andreas Hollandt Date: Thu, 17 Sep 2020 17:23:21 +0200 Subject: [PATCH 2/5] handle record-started/stopped events and send updated Capabilities whenever the process is stopped --- .../CommandFactories/MICommandFactory.cs | 1 + src/MICore/Debugger.cs | 12 ++++++ .../Engine.Impl/DebuggedProcess.cs | 23 +++++++++- src/OpenDebugAD7/AD7DebugSession.cs | 42 +++++++++++-------- .../OpenDebug/CustomProtocolObjects.cs | 4 +- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/MICore/CommandFactories/MICommandFactory.cs b/src/MICore/CommandFactories/MICommandFactory.cs index 57e2be4d3..3298c01db 100644 --- a/src/MICore/CommandFactories/MICommandFactory.cs +++ b/src/MICore/CommandFactories/MICommandFactory.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Threading.Tasks; using System.Text; using System.Linq; diff --git a/src/MICore/Debugger.cs b/src/MICore/Debugger.cs index de2796da2..a48ac0d80 100755 --- a/src/MICore/Debugger.cs +++ b/src/MICore/Debugger.cs @@ -44,6 +44,8 @@ public class Debugger : ITransportCallback public event EventHandler ThreadCreatedEvent; public event EventHandler ThreadExitedEvent; public event EventHandler ThreadGroupExitedEvent; + public event EventHandler RecordStartedEvent; + public event EventHandler RecordStoppedEvent; public event EventHandler TelemetryEvent; private int _exiting; public ProcessState ProcessState { get; private set; } @@ -1446,6 +1448,16 @@ private void OnNotificationOutput(string cmd) results = _miResults.ParseResultList(cmd.Substring("thread-exited,".Length)); ThreadExitedEvent(this, new ResultEventArgs(results, 0)); } + else if (cmd.StartsWith("record-started,", StringComparison.Ordinal)) + { + results = _miResults.ParseResultList(cmd.Substring("record-started,".Length)); + RecordStartedEvent(this, new ResultEventArgs(results, 0)); + } + else if (cmd.StartsWith("record-stopped,", StringComparison.Ordinal)) + { + results = _miResults.ParseResultList(cmd.Substring("record-stopped,".Length)); + RecordStoppedEvent(this, new ResultEventArgs(results, 0)); + } else if (cmd.StartsWith("telemetry,", StringComparison.Ordinal)) { results = _miResults.ParseResultList(cmd.Substring("telemetry,".Length)); diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index b01d3cea3..9933c74ac 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -434,6 +434,21 @@ public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngin ThreadCache.ThreadGroupExitedEvent(result.Results.FindString("id")); }; + RecordStartedEvent += async delegate (object o, EventArgs args) + { + var result = args as ResultEventArgs; + string threadGroup = result.Results.FindString("thread-group"); // e.g. "i1" + string method = result.Results.FindString("method"); // e.g. "full" + await UpdateTargetFeatures(); + }; + + RecordStoppedEvent += async delegate (object o, EventArgs args) + { + var result = args as ResultEventArgs; + string threadGroup = result.Results.FindString("thread-group"); // e.g. "i1" + await UpdateTargetFeatures(); + }; + TelemetryEvent += (object o, ResultEventArgs args) => { string eventName; @@ -541,6 +556,12 @@ private async Task EnsureModulesLoaded() } } + private async Task UpdateTargetFeatures() + { + TargetFeatures = await MICommandFactory.GetTargetFeatures(); + // TODO: notify OpenDebugAD7 to run AD7DebugSession.UpdateCapabilities + } + public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) { bool success = false; @@ -602,7 +623,7 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) } } // now the exe is loaded and we can check target features - TargetFeatures = await MICommandFactory.GetTargetFeatures(); + await UpdateTargetFeatures(); success = true; } diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 232a73dff..8ce56dfb0 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -527,7 +527,7 @@ public void BeforeContinue() m_gotoCodeContexts.Clear(); } - public void Stopped(IDebugThread2 thread) + private void Stopped(IDebugThread2 thread) { Debug.Assert(m_variableManager.IsEmpty(), "Why do we have variable handles?"); Debug.Assert(m_frameHandles.IsEmpty, "Why do we have frame handles?"); @@ -537,6 +537,7 @@ public void Stopped(IDebugThread2 thread) internal void FireStoppedEvent(IDebugThread2 thread, StoppedEvent.ReasonValue reason, string text = null) { Stopped(thread); + UpdateCapabilities(); // Switch to another thread as engines may not expect to be called back on their event thread ThreadPool.QueueUserWorkItem((o) => @@ -1033,6 +1034,27 @@ protected override void HandleInitializeRequestAsync(IRequestResponder responder) { const string telemetryEventName = DebuggerTelemetry.TelemetryLaunchEventName; @@ -1161,13 +1183,7 @@ protected override void HandleLaunchRequestAsync(IRequestResponder Date: Sat, 17 Jul 2021 14:31:16 +0200 Subject: [PATCH 3/5] remove custom CapabilitiesEvent --- src/OpenDebugAD7/AD7DebugSession.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 8ce56dfb0..8a6b06c8b 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -29,18 +29,6 @@ namespace OpenDebugAD7 { - // not in the DAP dll yet - internal sealed class CapabilitiesEvent : DebugEvent - { - internal CapabilitiesEvent() - : base("capabilities") - { - } - - [JsonProperty("capabilities")] - internal InitializeResponse Capabilities; - } - internal sealed class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2 { // This is a general purpose lock. Don't hold it across long operations. @@ -1044,7 +1032,7 @@ private void UpdateCapabilities() m_canReverse = canReverse; Protocol.SendEvent(new CapabilitiesEvent() { - Capabilities = new InitializeResponse() + Capabilities = new Capabilities() { SupportsStepBack = canReverse, ExceptionBreakpointFilters = null, // FIXME: this is just to prevent unwanted response entries From b498508fbb942d6e5231a739ee1500d248154aa4 Mon Sep 17 00:00:00 2001 From: Andreas Hollandt Date: Thu, 16 Jun 2022 13:54:52 +0200 Subject: [PATCH 4/5] fix IDebugReversibleEngineProgram160 handling --- src/OpenDebugAD7/AD7DebugSession.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 8a6b06c8b..21e669aa1 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -831,7 +831,8 @@ private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranular } try { - ((IDebugReversibleEngineProgram160)m_engine).SetExecuteDirection(stepDirection); + if (m_program is IDebugReversibleEngineProgram160 rprog) + rprog.SetExecuteDirection(stepDirection); builder.CheckHR(m_program.Step(thread, stepKind, stepUnit)); } catch (AD7Exception) @@ -1025,7 +1026,10 @@ protected override void HandleInitializeRequestAsync(IRequestResponder Date: Fri, 17 Jun 2022 14:28:31 +0200 Subject: [PATCH 5/5] address review comments --- src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs | 3 ++- src/OpenDebugAD7/AD7DebugSession.cs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index 9933c74ac..6da4c90c8 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -559,7 +559,8 @@ private async Task EnsureModulesLoaded() private async Task UpdateTargetFeatures() { TargetFeatures = await MICommandFactory.GetTargetFeatures(); - // TODO: notify OpenDebugAD7 to run AD7DebugSession.UpdateCapabilities + // NOTE: Currently OpenDebugAD7 polls if we can reverse execute on every stop. + // It would be better to notify it instead from here so it can update the Capabilities } public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 21e669aa1..ce5e858a7 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -1026,10 +1026,11 @@ protected override void HandleInitializeRequestAsync(IRequestResponder