Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support GoToTargets Request #1102

Merged
merged 12 commits into from
Jan 29, 2021
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;
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
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
87 changes: 86 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();
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
}

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,84 @@ protected override void HandlePauseRequestAsync(IRequestResponder<PauseArguments
responder.SetResponse(new PauseResponse());
}

protected override void HandleGotoRequestAsync(IRequestResponder<GotoArguments> responder)
{
responder.SetError(new ProtocolException("Not implemented exception."));
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
}

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

var source = responder.Arguments.Source;
// TODO: handle this for disassembly debugging
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
if (source.Path == null)
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
{
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)
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
{
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