diff --git a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs index e204d153e..f3f404244 100755 --- a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs @@ -35,7 +35,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, IDisposable + sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, 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; @@ -1138,6 +1138,16 @@ public int WriteAt(IDebugMemoryContext2 pStartContext, uint dwCount, byte[] rgbM #endregion + #region IDebugMemoryBytesDAP + + int IDebugMemoryBytesDAP.CreateMemoryContext(ulong address, out IDebugMemoryContext2 ppResult) + { + ppResult = new AD7MemoryAddress(this, address, null); + return Constants.S_OK; + } + + #endregion + #region IDebugEngine110 public int SetMainThreadSettingsCallback110(IDebugSettingsCallback110 pCallback) { diff --git a/src/Microsoft.VisualStudio.Debugger.Interop.DAP/Microsoft.VisualStudio.Debugger.Interop.DAP.cs b/src/Microsoft.VisualStudio.Debugger.Interop.DAP/Microsoft.VisualStudio.Debugger.Interop.DAP.cs index ab3e588c7..b433c33aa 100644 --- a/src/Microsoft.VisualStudio.Debugger.Interop.DAP/Microsoft.VisualStudio.Debugger.Interop.DAP.cs +++ b/src/Microsoft.VisualStudio.Debugger.Interop.DAP/Microsoft.VisualStudio.Debugger.Interop.DAP.cs @@ -52,4 +52,20 @@ public interface IDebugProgramDAP /// [PreserveSig] int GetPointerSize([Out] out int pResult); } + + /// + /// IDebugMemoryBytesDAP for Debug Adapter Protocol + /// + [ComImport()] + [ComVisible(true)] + [Guid("CF4FADE1-3252-4680-9E70-8B44CA92DD3F")] + [InterfaceType(1)] + public interface IDebugMemoryBytesDAP + { + /// + /// This method will create an IDebugMemoryContext from a given address. + /// + [PreserveSig] + int CreateMemoryContext([In] ulong address, [Out, MarshalAs(UnmanagedType.Interface)] out IDebugMemoryContext2 ppResult); + } } diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index c369b04bf..315a70396 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -619,7 +619,8 @@ protected override void HandleInitializeRequestAsync(IRequestResponder new ExceptionBreakpointsFilter() { Default = item.@default, Filter = item.filter, Label = item.label }).ToList(), SupportsClipboardContext = m_engineConfiguration.ClipboardContext, - SupportsLogPoints = true + SupportsLogPoints = true, + SupportsReadMemoryRequest = true }; responder.SetResponse(initializeResponse); @@ -1371,7 +1372,8 @@ protected override void HandleVariablesRequestAsync(IRequestResponder variablesDictionary = new Dictionary(); for (uint c = 0; c < count; c++) { - var variable = m_variableManager.CreateVariable(ref childProperties[c], variableEvaluationData.propertyInfoFlags); + string memoryReference = AD7Utils.GetMemoryReferenceFromIDebugProperty(childProperties[c].pProperty); + var variable = m_variableManager.CreateVariable(ref childProperties[c], variableEvaluationData.propertyInfoFlags, memoryReference); int uniqueCounter = 2; string variableName = variable.Name; string variableNameFormat = "{0} #{1}"; @@ -1388,8 +1390,9 @@ protected override void HandleVariablesRequestAsync(IRequestResponder responder) + { + int hr; + ReadMemoryArguments rma = responder.Arguments; + ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_ReadMemory); + try + { + if (string.IsNullOrEmpty(rma.MemoryReference)) + { + throw new ArgumentException("ReadMemoryArguments.MemoryReference is null or empty."); + } + ulong address; + if (rma.MemoryReference.StartsWith("0x", StringComparison.Ordinal)) + { + address = Convert.ToUInt64(rma.MemoryReference.Substring(2), 16); + } + else + { + address = Convert.ToUInt64(rma.MemoryReference, 10); + } + + if (rma.Offset.HasValue && rma.Offset.Value != 0) + { + if (rma.Offset < 0) + { + address += (ulong)rma.Offset.Value; + } + else + { + address -= (ulong)-rma.Offset.Value; + } + } + + hr = ((IDebugMemoryBytesDAP)m_engine).CreateMemoryContext(address, out IDebugMemoryContext2 memoryContext); + eb.CheckHR(hr); + + byte[] data = new byte[rma.Count]; + uint unreadableBytes = 0; + uint bytesRead = 0; + + if (rma.Count != 0) + { + hr = m_program.GetMemoryBytes(out IDebugMemoryBytes2 debugMemoryBytes); + eb.CheckHR(hr); + + hr = debugMemoryBytes.ReadAt(memoryContext, (uint)rma.Count, data, out bytesRead, ref unreadableBytes); + eb.CheckHR(hr); + } + + responder.SetResponse(new ReadMemoryResponse() + { + Address = string.Format(CultureInfo.InvariantCulture, "0x{0:X}", address), + Data = Convert.ToBase64String(data, 0, (int)bytesRead), + UnreadableBytes = (int?)unreadableBytes + }); + } + catch (Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } } #endregion diff --git a/src/OpenDebugAD7/AD7Resources.Designer.cs b/src/OpenDebugAD7/AD7Resources.Designer.cs index 10f875757..c8a973fef 100644 --- a/src/OpenDebugAD7/AD7Resources.Designer.cs +++ b/src/OpenDebugAD7/AD7Resources.Designer.cs @@ -271,6 +271,15 @@ internal static string Error_Scenario_Launch { } } + /// + /// Looks up a localized string similar to Unable to read memory. {0}. + /// + internal static string Error_Scenario_ReadMemory { + get { + return ResourceManager.GetString("Error_Scenario_ReadMemory", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unable to step in. {0}. /// diff --git a/src/OpenDebugAD7/AD7Resources.resx b/src/OpenDebugAD7/AD7Resources.resx index 264016e09..b100bbd55 100644 --- a/src/OpenDebugAD7/AD7Resources.resx +++ b/src/OpenDebugAD7/AD7Resources.resx @@ -282,4 +282,7 @@ Failed to get property information. + + Unable to read memory. {0} + \ No newline at end of file diff --git a/src/OpenDebugAD7/AD7Utils.cs b/src/OpenDebugAD7/AD7Utils.cs index 63931eb21..6933256d1 100644 --- a/src/OpenDebugAD7/AD7Utils.cs +++ b/src/OpenDebugAD7/AD7Utils.cs @@ -17,5 +17,22 @@ public static bool IsAnnotatedFrame(ref FRAMEINFO frameInfo) enum_FRAMEINFO_FLAGS_VALUES flags = unchecked((enum_FRAMEINFO_FLAGS_VALUES)frameInfo.m_dwFlags); return flags.HasFlag(enum_FRAMEINFO_FLAGS_VALUES.FIFV_ANNOTATEDFRAME); } + + public static string GetMemoryReferenceFromIDebugProperty(IDebugProperty2 property) + { + if (property != null && property.GetMemoryContext(out IDebugMemoryContext2 memoryContext) == HRConstants.S_OK) + { + CONTEXT_INFO[] contextInfo = new CONTEXT_INFO[1]; + if (memoryContext.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK) + { + if (contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS)) + { + return contextInfo[0].bstrAddress; + } + } + } + + return null; + } } } diff --git a/src/OpenDebugAD7/VariableManager.cs b/src/OpenDebugAD7/VariableManager.cs index 7641d4e6b..553ef9e06 100644 --- a/src/OpenDebugAD7/VariableManager.cs +++ b/src/OpenDebugAD7/VariableManager.cs @@ -49,10 +49,12 @@ internal Variable CreateVariable(IDebugProperty2 property, enum_DEBUGPROP_INFO_F DEBUG_PROPERTY_INFO[] propertyInfo = new DEBUG_PROPERTY_INFO[1]; property.GetPropertyInfo(propertyInfoFlags, Constants.EvaluationRadix, Constants.EvaluationTimeout, null, 0, propertyInfo); - return CreateVariable(ref propertyInfo[0], propertyInfoFlags); + string memoryReference = AD7Utils.GetMemoryReferenceFromIDebugProperty(property); + + return CreateVariable(ref propertyInfo[0], propertyInfoFlags, memoryReference); } - internal Variable CreateVariable(ref DEBUG_PROPERTY_INFO propertyInfo, enum_DEBUGPROP_INFO_FLAGS propertyInfoFlags) + internal Variable CreateVariable(ref DEBUG_PROPERTY_INFO propertyInfo, enum_DEBUGPROP_INFO_FLAGS propertyInfoFlags, string memoryReference) { string name = propertyInfo.bstrName; string val = propertyInfo.bstrValue; @@ -72,6 +74,7 @@ internal Variable CreateVariable(ref DEBUG_PROPERTY_INFO propertyInfo, enum_DEBU Type = type, VariablesReference = handle, EvaluateName = propertyInfo.bstrFullName, + MemoryReference = memoryReference }; }