Skip to content

Commit

Permalink
Support HandleReadMemoryRequestAsync (#1028)
Browse files Browse the repository at this point in the history
* Support HandleReadMemoryRequestAsync and MemoryRef

This allows OpenDebugAD7 to support the ReadMemoryRequest for DAP.

This adds MemoryReferences in EvaluateRequest.
  • Loading branch information
WardenGnaw authored Sep 2, 2020
1 parent 4c21dbd commit e1b8dda
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 8 deletions.
12 changes: 11 additions & 1 deletion src/MIDebugEngine/AD7.Impl/AD7Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,20 @@ public interface IDebugProgramDAP
/// [PreserveSig]
int GetPointerSize([Out] out int pResult);
}

/// <summary>
/// IDebugMemoryBytesDAP for Debug Adapter Protocol
/// </summary>
[ComImport()]
[ComVisible(true)]
[Guid("CF4FADE1-3252-4680-9E70-8B44CA92DD3F")]
[InterfaceType(1)]
public interface IDebugMemoryBytesDAP
{
/// <summary>
/// This method will create an IDebugMemoryContext from a given address.
/// </summary>
[PreserveSig]
int CreateMemoryContext([In] ulong address, [Out, MarshalAs(UnmanagedType.Interface)] out IDebugMemoryContext2 ppResult);
}
}
79 changes: 74 additions & 5 deletions src/OpenDebugAD7/AD7DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ protected override void HandleInitializeRequestAsync(IRequestResponder<Initializ
SupportsConditionalBreakpoints = m_engineConfiguration.ConditionalBP,
ExceptionBreakpointFilters = m_engineConfiguration.ExceptionSettings.ExceptionBreakpointFilters.Select(item => 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);
Expand Down Expand Up @@ -1371,7 +1372,8 @@ protected override void HandleVariablesRequestAsync(IRequestResponder<VariablesA
Dictionary<string, Variable> variablesDictionary = new Dictionary<string, Variable>();
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}";
Expand All @@ -1388,8 +1390,9 @@ protected override void HandleVariablesRequestAsync(IRequestResponder<VariablesA
}
else
{
string memoryReference = AD7Utils.GetMemoryReferenceFromIDebugProperty(childProperties[0].pProperty);
// Shortcut when no duplicate can exist
response.Variables.Add(m_variableManager.CreateVariable(ref childProperties[0], variableEvaluationData.propertyInfoFlags));
response.Variables.Add(m_variableManager.CreateVariable(ref childProperties[0], variableEvaluationData.propertyInfoFlags, memoryReference));
}
}
}
Expand Down Expand Up @@ -2016,7 +2019,9 @@ protected override void HandleEvaluateRequestAsync(IRequestResponder<EvaluateArg
return;
}

Variable variable = m_variableManager.CreateVariable(ref propertyInfo[0], propertyInfoFlags);
string memoryReference = AD7Utils.GetMemoryReferenceFromIDebugProperty(property);

Variable variable = m_variableManager.CreateVariable(ref propertyInfo[0], propertyInfoFlags, memoryReference);

if (context != EvaluateArguments.ContextValue.Hover)
{
Expand All @@ -2030,9 +2035,73 @@ protected override void HandleEvaluateRequestAsync(IRequestResponder<EvaluateArg
{
Result = variable.Value,
Type = variable.Type,
VariablesReference = variable.VariablesReference
VariablesReference = variable.VariablesReference,
MemoryReference = memoryReference
});
}


protected override void HandleReadMemoryRequestAsync(IRequestResponder<ReadMemoryArguments, ReadMemoryResponse> 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
Expand Down
9 changes: 9 additions & 0 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 @@ -282,4 +282,7 @@
<data name="Error_InterpolateVariableMissingProperties" xml:space="preserve">
<value>Failed to get property information.</value>
</data>
<data name="Error_Scenario_ReadMemory" xml:space="preserve">
<value>Unable to read memory. {0}</value>
</data>
</root>
17 changes: 17 additions & 0 deletions src/OpenDebugAD7/AD7Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
7 changes: 5 additions & 2 deletions src/OpenDebugAD7/VariableManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -72,6 +74,7 @@ internal Variable CreateVariable(ref DEBUG_PROPERTY_INFO propertyInfo, enum_DEBU
Type = type,
VariablesReference = handle,
EvaluateName = propertyInfo.bstrFullName,
MemoryReference = memoryReference
};
}

Expand Down

0 comments on commit e1b8dda

Please sign in to comment.