Skip to content

Commit

Permalink
Support GoToTargets Request (#1102)
Browse files Browse the repository at this point in the history
Support DAP GoToTargets

Co-authored-by: Andreas Hollandt <trass3r@gmail.com>
  • Loading branch information
WardenGnaw and Trass3r authored Jan 29, 2021
1 parent a8678a0 commit fbbc993
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/MIDebugEngine/AD7.Impl/AD7Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ public int EnumCodeContexts(IDebugDocumentPosition2 docPosition, out IEnumDebugC
{
var codeCxt = new AD7MemoryAddress(this, a, null);
TEXT_POSITION pos;
pos.dwLine = line;
pos.dwLine = line - 1;
pos.dwColumn = 0;
MITextPosition textPosition = new MITextPosition(documentName, pos, pos);
codeCxt.SetDocumentContext(new AD7DocumentContext(textPosition, codeCxt));
Expand Down
2 changes: 1 addition & 1 deletion src/MIDebugEngine/AD7.Impl/AD7Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ public AD7ExceptionEvent(string name, string description, uint code, Guid? excep
{
_name = name;
_code = code;
_description = description ?? name;
_description = string.IsNullOrEmpty(description) ? name : description;
_category = exceptionCategory ?? EngineConstants.EngineId;

switch (state)
Expand Down
34 changes: 18 additions & 16 deletions src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Debugger.Interop;
using MICore;
using Microsoft.MIDebugEngine.Natvis;

namespace Microsoft.MIDebugEngine
{
// And implementation of IDebugCodeContext2 and IDebugMemoryContext2.
// IDebugMemoryContext2 represents a position in the address space of the machine running the program being debugged.
// IDebugCodeContext2 represents the starting position of a code instruction.
// For most run-time architectures today, a code context can be thought of as an address in a program's execution stream.
internal class AD7MemoryAddress : IDebugCodeContext2
internal sealed class AD7MemoryAddress : IDebugCodeContext2
{
private readonly AD7Engine _engine;
private readonly ulong _address;
Expand Down Expand Up @@ -42,6 +39,9 @@ public void SetDocumentContext(IDebugDocumentContext2 docContext)
// Adds a specified value to the current context's address to create a new context.
public int Add(ulong dwCount, out IDebugMemoryContext2 newAddress)
{
// NB: this is not correct for IDebugCodeContext2 according to the docs
// https://docs.microsoft.com/en-us/visualstudio/extensibility/debugger/reference/idebugcodecontext2#remarks
// But it's not used in practice (instead: IDebugDisassemblyStream2.Seek)
newAddress = new AD7MemoryAddress(_engine, (uint)dwCount + _address, null);
return Constants.S_OK;
}
Expand Down Expand Up @@ -160,19 +160,22 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
{
pinfo[0].dwFields = 0;

if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0)
if ((dwFields & (enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS | enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE)) != 0)
{
pinfo[0].bstrAddress = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch);
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS;
string addr = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch);
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0)
{
pinfo[0].bstrAddress = addr;
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS;
}
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0)
{
pinfo[0].bstrAddressAbsolute = addr;
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE;
}
}

// Fields not supported by the sample
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0) { }
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0)
{
pinfo[0].bstrAddressAbsolute = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch);
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE;
}
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0)
{
DebuggedModule module = _engine.DebuggedProcess.ResolveAddress(_address);
Expand All @@ -195,7 +198,6 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION;
}
}
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) { }

return Constants.S_OK;
}
Expand All @@ -210,10 +212,10 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
}

// Gets the user-displayable name for this context
// This is not supported by the sample engine.
public int GetName(out string pbstrName)
{
throw new NotImplementedException();
pbstrName = _functionName ?? Engine.GetAddressDescription(_address);
return Constants.S_OK;
}

// Subtracts a specified value from the current context's address to create a new context.
Expand Down
8 changes: 2 additions & 6 deletions src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.MIDebugEngine
{
// Represents a logical stack frame on the thread stack.
// Also implements the IDebugExpressionContext interface, which allows expression evaluation and watch windows.
internal class AD7StackFrame : IDebugStackFrame2, IDebugExpressionContext2
internal sealed class AD7StackFrame : IDebugStackFrame2, IDebugExpressionContext2
{
public AD7Engine Engine { get; private set; }
public AD7Thread Thread { get; private set; }
Expand Down Expand Up @@ -53,11 +53,7 @@ public AD7StackFrame(AD7Engine engine, AD7Thread thread, ThreadContext threadCon
if (_textPosition != null)
{
_documentCxt = new AD7DocumentContext(_textPosition, _codeCxt);

if (_codeCxt != null)
{
_codeCxt.SetDocumentContext(_documentCxt);
}
_codeCxt?.SetDocumentContext(_documentCxt);
}
}

Expand Down
89 changes: 88 additions & 1 deletion src/OpenDebugAD7/AD7DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
Expand All @@ -27,7 +28,7 @@

namespace OpenDebugAD7
{
internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2
internal sealed class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2
{
// This is a general purpose lock. Don't hold it across long operations.
private readonly object m_lock = new object();
Expand All @@ -44,6 +45,10 @@ internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEven

private readonly DebugEventLogger m_logger;
private readonly Dictionary<string, Dictionary<int, IDebugPendingBreakpoint2>> m_breakpoints;

private readonly ConcurrentDictionary<int, IDebugCodeContext2> m_gotoCodeContexts = new ConcurrentDictionary<int, IDebugCodeContext2>();
private int m_nextContextId = 1;

private Dictionary<string, IDebugPendingBreakpoint2> m_functionBreakpoints;
private readonly HandleCollection<IDebugStackFrame2> m_frameHandles;

Expand Down Expand Up @@ -350,6 +355,7 @@ public void BeforeContinue()
m_isStopped = false;
m_variableManager.Reset();
m_frameHandles.Reset();
m_gotoCodeContexts.Clear();
}

public void Stopped(IDebugThread2 thread)
Expand Down Expand Up @@ -793,6 +799,7 @@ protected override void HandleInitializeRequestAsync(IRequestResponder<Initializ
SupportsReadMemoryRequest = m_engine is IDebugMemoryBytesDAP, // TODO: Read from configuration or query engine for capabilities.
SupportsModulesRequest = true,
AdditionalModuleColumns = additionalModuleColumns,
SupportsGotoTargetsRequest = true,
SupportsDisassembleRequest = true,
SupportsValueFormattingOptions = true,
};
Expand Down Expand Up @@ -1317,6 +1324,86 @@ protected override void HandlePauseRequestAsync(IRequestResponder<PauseArguments
responder.SetResponse(new PauseResponse());
}

protected override void HandleGotoRequestAsync(IRequestResponder<GotoArguments> responder)
{
responder.SetError(new ProtocolException(AD7Resources.Error_NotImplementedSetNextStatement));
}

protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTargetsArguments, GotoTargetsResponse> responder)
{
var response = new GotoTargetsResponse();

var source = responder.Arguments.Source;

// Virtual documents don't have paths
if (source.Path == null)
{
responder.SetResponse(response);
return;
}

try
{
string convertedPath = m_pathConverter.ConvertClientPathToDebugger(source.Path);
int line = m_pathConverter.ConvertClientLineToDebugger(responder.Arguments.Line);
var docPos = new AD7DocumentPosition(m_sessionConfig, convertedPath, line);

var targets = new List<GotoTarget>();

IEnumDebugCodeContexts2 codeContextsEnum;
if (m_program.EnumCodeContexts(docPos, out codeContextsEnum) == HRConstants.S_OK)
{
var codeContexts = new IDebugCodeContext2[1];
uint nProps = 0;
while (codeContextsEnum.Next(1, codeContexts, ref nProps) == HRConstants.S_OK)
{
var codeContext = codeContexts[0];

string contextName;
codeContext.GetName(out contextName);

line = responder.Arguments.Line;
IDebugDocumentContext2 documentContext;
if (codeContext.GetDocumentContext(out documentContext) == HRConstants.S_OK)
{
var startPos = new TEXT_POSITION[1];
var endPos = new TEXT_POSITION[1];
if (documentContext.GetStatementRange(startPos, endPos) == HRConstants.S_OK)
line = m_pathConverter.ConvertDebuggerLineToClient((int)startPos[0].dwLine);
}

string instructionPointerReference = null;
CONTEXT_INFO[] contextInfo = new CONTEXT_INFO[1];
if (codeContext.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK &&
contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS))
{
instructionPointerReference = contextInfo[0].bstrAddress;
}

int codeContextId = m_nextContextId++;
m_gotoCodeContexts.TryAdd(codeContextId, codeContext);

targets.Add(new GotoTarget()
{
Id = codeContextId,
Label = contextName,
Line = line,
InstructionPointerReference = instructionPointerReference
});
}
}

response.Targets = targets;
}
catch (AD7Exception e)
{
responder.SetError(new ProtocolException(e.Message));
return;
}

responder.SetResponse(response);
}

protected override void HandleStackTraceRequestAsync(IRequestResponder<StackTraceArguments, StackTraceResponse> responder)
{
int threadReference = responder.Arguments.ThreadId;
Expand Down
2 changes: 1 addition & 1 deletion src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace OpenDebugAD7.AD7Impl
{
internal class AD7BreakPointRequest : IDebugBreakpointRequest2, IDebugBreakpointChecksumRequest2
internal sealed class AD7BreakPointRequest : IDebugBreakpointRequest2, IDebugBreakpointChecksumRequest2
{
private static uint s_nextBreakpointId = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/OpenDebugAD7/AD7Impl/AD7DocumentPosition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace OpenDebugAD7.AD7Impl
{
internal class AD7DocumentPosition : IDebugDocumentPosition2, IDebugDocumentPosition110
internal sealed class AD7DocumentPosition : IDebugDocumentPosition2, IDebugDocumentPosition110
{
public string Path
{
Expand Down
28 changes: 18 additions & 10 deletions src/OpenDebugAD7/AD7Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/OpenDebugAD7/AD7Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -298,4 +298,7 @@
<data name="Error_Scenario_StackTrace" xml:space="preserve">
<value>Unable to retrieve stack trace. {0}</value>
</data>
<data name="Error_NotImplementedSetNextStatement" xml:space="preserve">
<value>Set next statement is not supported by the current debugger.</value>
</data>
</root>

0 comments on commit fbbc993

Please sign in to comment.