diff --git a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs index 7865a3887..a99f43dd4 100755 --- a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs @@ -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)); diff --git a/src/MIDebugEngine/AD7.Impl/AD7Events.cs b/src/MIDebugEngine/AD7.Impl/AD7Events.cs index 2b031bfd4..022d24908 100644 --- a/src/MIDebugEngine/AD7.Impl/AD7Events.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7Events.cs @@ -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) diff --git a/src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs b/src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs index f478379ad..318e50e2e 100644 --- a/src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs @@ -2,11 +2,8 @@ // 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 { @@ -14,7 +11,7 @@ namespace Microsoft.MIDebugEngine // 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; @@ -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; } @@ -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); @@ -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; } @@ -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. diff --git a/src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs b/src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs index 82ec4c1e5..9033f3740 100644 --- a/src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs @@ -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; } @@ -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); } } diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 9921e0019..b5eb9d671 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -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; @@ -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(); @@ -44,6 +45,10 @@ internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEven private readonly DebugEventLogger m_logger; private readonly Dictionary> m_breakpoints; + + private readonly ConcurrentDictionary m_gotoCodeContexts = new ConcurrentDictionary(); + private int m_nextContextId = 1; + private Dictionary m_functionBreakpoints; private readonly HandleCollection m_frameHandles; @@ -350,6 +355,7 @@ public void BeforeContinue() m_isStopped = false; m_variableManager.Reset(); m_frameHandles.Reset(); + m_gotoCodeContexts.Clear(); } public void Stopped(IDebugThread2 thread) @@ -793,6 +799,7 @@ protected override void HandleInitializeRequestAsync(IRequestResponder responder) + { + responder.SetError(new ProtocolException(AD7Resources.Error_NotImplementedSetNextStatement)); + } + + protected override void HandleGotoTargetsRequestAsync(IRequestResponder 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(); + + 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 responder) { int threadReference = responder.Arguments.ThreadId; diff --git a/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs b/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs index 1528236a1..96d36f1d7 100644 --- a/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs +++ b/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs @@ -8,7 +8,7 @@ namespace OpenDebugAD7.AD7Impl { - internal class AD7BreakPointRequest : IDebugBreakpointRequest2, IDebugBreakpointChecksumRequest2 + internal sealed class AD7BreakPointRequest : IDebugBreakpointRequest2, IDebugBreakpointChecksumRequest2 { private static uint s_nextBreakpointId = 0; diff --git a/src/OpenDebugAD7/AD7Impl/AD7DocumentPosition.cs b/src/OpenDebugAD7/AD7Impl/AD7DocumentPosition.cs index be69bd49a..002ffa8d7 100644 --- a/src/OpenDebugAD7/AD7Impl/AD7DocumentPosition.cs +++ b/src/OpenDebugAD7/AD7Impl/AD7DocumentPosition.cs @@ -8,7 +8,7 @@ namespace OpenDebugAD7.AD7Impl { - internal class AD7DocumentPosition : IDebugDocumentPosition2, IDebugDocumentPosition110 + internal sealed class AD7DocumentPosition : IDebugDocumentPosition2, IDebugDocumentPosition110 { public string Path { diff --git a/src/OpenDebugAD7/AD7Resources.Designer.cs b/src/OpenDebugAD7/AD7Resources.Designer.cs index ccfa43728..b029c99c5 100644 --- a/src/OpenDebugAD7/AD7Resources.Designer.cs +++ b/src/OpenDebugAD7/AD7Resources.Designer.cs @@ -226,6 +226,15 @@ internal static string Error_MissingOutParam { } } + /// + /// Looks up a localized string similar to Set next statement is not supported by the current debugger.. + /// + internal static string Error_NotImplementedSetNextStatement { + get { + return ResourceManager.GetString("Error_NotImplementedSetNextStatement", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0}: property '{1}' is invalid.. /// @@ -433,16 +442,6 @@ internal static string Locals_Scope_Name { } } - /// - /// Looks up a localized string similar to Registers. - /// - internal static string Registers_Scope_Name - { - get { - return ResourceManager.GetString("Registers_Scope_Name", resourceCulture); - } - } - /// /// Looks up a localized string similar to Debugger failed to signal process termination.. /// @@ -534,6 +533,15 @@ internal static string ProcessExitMessage { } } + /// + /// Looks up a localized string similar to Registers. + /// + internal static string Registers_Scope_Name { + get { + return ResourceManager.GetString("Registers_Scope_Name", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not detect launch url.. /// diff --git a/src/OpenDebugAD7/AD7Resources.resx b/src/OpenDebugAD7/AD7Resources.resx index 33a8db067..bc916064d 100644 --- a/src/OpenDebugAD7/AD7Resources.resx +++ b/src/OpenDebugAD7/AD7Resources.resx @@ -298,4 +298,7 @@ Unable to retrieve stack trace. {0} + + Set next statement is not supported by the current debugger. + \ No newline at end of file