Skip to content

Commit

Permalink
Merge pull request #1016 from microsoft/master
Browse files Browse the repository at this point in the history
Add support for LogPoints in OpenDebugAD7 (#1013)
  • Loading branch information
WardenGnaw authored Jun 30, 2020
2 parents e39a919 + 185e133 commit 49b72ec
Show file tree
Hide file tree
Showing 8 changed files with 794 additions and 21 deletions.
131 changes: 112 additions & 19 deletions src/OpenDebugAD7/AD7DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEven
private bool m_isAttach;
private bool m_isCoreDump;
private bool m_isStopped = false;
private bool m_isStepping = false;

private readonly TaskCompletionSource<object> m_configurationDoneTCS = new TaskCompletionSource<object>();

Expand Down Expand Up @@ -237,6 +238,31 @@ private ProtocolException VerifyProcessId(string processId, string telemetryEven
return null;
}

private IList<Tracepoint> GetTracepoints(IDebugBreakpointEvent2 debugEvent)
{
IList<Tracepoint> tracepoints = new List<Tracepoint>();

if (debugEvent != null)
{
debugEvent.EnumBreakpoints(out IEnumDebugBoundBreakpoints2 pBoundBreakpoints);
IDebugBoundBreakpoint2[] boundBp = new IDebugBoundBreakpoint2[1];

uint numReturned = 0;
while (pBoundBreakpoints.Next(1, boundBp, ref numReturned) == HRConstants.S_OK && numReturned == 1)
{
if (boundBp[0].GetPendingBreakpoint(out IDebugPendingBreakpoint2 ppPendingBreakpoint) == HRConstants.S_OK &&
ppPendingBreakpoint.GetBreakpointRequest(out IDebugBreakpointRequest2 ppBPRequest) == HRConstants.S_OK &&
ppBPRequest is AD7BreakPointRequest ad7BreakpointRequest &&
ad7BreakpointRequest.HasTracepoint)
{
tracepoints.Add(ad7BreakpointRequest.Tracepoint);
}
}
}

return tracepoints;
}

#endregion

#region AD7EventHandlers helper methods
Expand All @@ -245,6 +271,7 @@ public void BeforeContinue()
{
if (!m_isCoreDump)
{
m_isStepping = false;
m_isStopped = false;
m_variableManager.Reset();
m_frameHandles.Reset();
Expand Down Expand Up @@ -499,7 +526,6 @@ private void StepInternal(int threadId, enum_STEPKIND stepKind, enum_STEPUNIT st
// If we are already running ignore additional step requests
if (m_isStopped)
{

IDebugThread2 thread = null;
lock (m_threads)
{
Expand All @@ -511,6 +537,7 @@ private void StepInternal(int threadId, enum_STEPKIND stepKind, enum_STEPUNIT st

BeforeContinue();
ErrorBuilder builder = new ErrorBuilder(() => errorMessage);
m_isStepping = true;
try
{
builder.CheckHR(m_program.Step(thread, stepKind, stepUnit));
Expand Down Expand Up @@ -590,7 +617,8 @@ protected override void HandleInitializeRequestAsync(IRequestResponder<Initializ
SupportsFunctionBreakpoints = m_engineConfiguration.FunctionBP,
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
SupportsClipboardContext = m_engineConfiguration.ClipboardContext,
SupportsLogPoints = true
};

responder.SetResponse(initializeResponse);
Expand Down Expand Up @@ -1607,6 +1635,14 @@ protected override void HandleSetBreakpointsRequestAsync(IRequestResponder<SetBr
toRemove.Delete();
dict.Remove(bp.Line);
}
// Check to see if tracepoint changed
else if (!StringComparer.Ordinal.Equals(ad7BPRequest.LogMessage, bp.LogMessage))
{
ad7BPRequest.ClearTracepoint();
var toRemove = dict[bp.Line];
toRemove.Delete();
dict.Remove(bp.Line);
}
else
{
if (ad7BPRequest.BindResult != null)
Expand Down Expand Up @@ -1637,16 +1673,37 @@ protected override void HandleSetBreakpointsRequestAsync(IRequestResponder<SetBr

try
{
eb.CheckHR(m_engine.CreatePendingBreakpoint(pBPRequest, out pendingBp));
eb.CheckHR(pendingBp.Bind());
bool verified = true;
if (!string.IsNullOrEmpty(bp.LogMessage))
{
// Make sure tracepoint is valid.
verified = pBPRequest.SetLogMessage(bp.LogMessage);
}

dict[bp.Line] = pendingBp;
resBreakpoints.Add(new Breakpoint()
if (verified)
{
Id = (int)pBPRequest.Id,
Verified = true,
Line = bp.Line
});
eb.CheckHR(m_engine.CreatePendingBreakpoint(pBPRequest, out pendingBp));
eb.CheckHR(pendingBp.Bind());

dict[bp.Line] = pendingBp;

resBreakpoints.Add(new Breakpoint()
{
Id = (int)pBPRequest.Id,
Verified = verified,
Line = bp.Line
});
}
else
{
resBreakpoints.Add(new Breakpoint()
{
Id = (int)pBPRequest.Id,
Verified = verified,
Line = bp.Line,
Message = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_UnableToParseLogMessage)
});
}
}
catch (Exception e)
{
Expand Down Expand Up @@ -1893,12 +1950,10 @@ protected override void HandleEvaluateRequestAsync(IRequestResponder<EvaluateArg
hr = frame.GetExpressionContext(out expressionContext);
eb.CheckHR(hr);

const uint InputRadix = 10;
DAPEvalFlags dapEvalFlags = DAPEvalFlags.NONE;
IDebugExpression2 expressionObject;
string error;
uint errorIndex;
hr = expressionContext.ParseText(expression, enum_PARSEFLAGS.PARSE_EXPRESSION, InputRadix, out expressionObject, out error, out errorIndex);
hr = expressionContext.ParseText(expression, enum_PARSEFLAGS.PARSE_EXPRESSION, Constants.ParseRadix, out expressionObject, out error, out errorIndex);
if (!string.IsNullOrEmpty(error))
{
// TODO: Is this how errors should be returned?
Expand All @@ -1919,14 +1974,14 @@ protected override void HandleEvaluateRequestAsync(IRequestResponder<EvaluateArg
flags |= enum_EVALFLAGS.EVAL_NOSIDEEFFECTS;
}

if (context == EvaluateArguments.ContextValue.Clipboard)
{
dapEvalFlags |= DAPEvalFlags.CLIPBOARD_CONTEXT;
}

IDebugProperty2 property;
if (expressionObject is IDebugExpressionDAP expressionDapObject)
{
DAPEvalFlags dapEvalFlags = DAPEvalFlags.NONE;
if (context == EvaluateArguments.ContextValue.Clipboard)
{
dapEvalFlags |= DAPEvalFlags.CLIPBOARD_CONTEXT;
}
hr = expressionDapObject.EvaluateSync(flags, dapEvalFlags, Constants.EvaluationTimeout, null, out property);
}
else
Expand Down Expand Up @@ -2094,7 +2149,45 @@ public void HandleIDebugEntryPointEvent2(IDebugEngine2 pEngine, IDebugProcess2 p

public void HandleIDebugBreakpointEvent2(IDebugEngine2 pEngine, IDebugProcess2 pProcess, IDebugProgram2 pProgram, IDebugThread2 pThread, IDebugEvent2 pEvent)
{
FireStoppedEvent(pThread, StoppedEvent.ReasonValue.Breakpoint);
IList<Tracepoint> tracepoints = GetTracepoints(pEvent as IDebugBreakpointEvent2);
if (tracepoints.Any())
{
ThreadPool.QueueUserWorkItem((o) =>
{
foreach (var tp in tracepoints)
{
int hr = tp.GetLogMessage(pThread, Constants.ParseRadix, m_processName, out string logMessage);
if (hr != HRConstants.S_OK)
{
DebuggerTelemetry.ReportError(DebuggerTelemetry.TelemetryTracepointEventName, logMessage);
m_logger.WriteLine(LoggingCategory.DebuggerError, logMessage);
}
else
{
m_logger.WriteLine(LoggingCategory.DebuggerStatus, logMessage);
}
}

// Need to check to see if the previous continuation of the debuggee was a step.
// If so, we need to send a stopping event to the UI to signal the step completed successfully.
if (!m_isStepping)
{
ThreadPool.QueueUserWorkItem((obj) =>
{
BeforeContinue();
m_program.Continue(pThread);
});
}
else
{
FireStoppedEvent(pThread, StoppedEvent.ReasonValue.Breakpoint);
}
});
}
else
{
FireStoppedEvent(pThread, StoppedEvent.ReasonValue.Breakpoint);
}
}

public void HandleIDebugBreakEvent2(IDebugEngine2 pEngine, IDebugProcess2 pProcess, IDebugProgram2 pProgram, IDebugThread2 pThread, IDebugEvent2 pEvent)
Expand Down
35 changes: 35 additions & 0 deletions src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,40 @@ public int GetChecksum(ref Guid guidAlgorithm, CHECKSUM_DATA[] checksumData)
return HRConstants.E_FAIL;
}
}

#region Tracepoints

private string m_logMessage;
private Tracepoint m_Tracepoint;

public void ClearTracepoint()
{
m_logMessage = null;
m_Tracepoint = null;
}

public bool SetLogMessage(string logMessage)
{
try
{
m_Tracepoint = Tracepoint.CreateTracepoint(logMessage);
DebuggerTelemetry.ReportEvent(DebuggerTelemetry.TelemetryTracepointEventName);
}
catch (InvalidTracepointException e)
{
DebuggerTelemetry.ReportError(DebuggerTelemetry.TelemetryTracepointEventName, e.Message);
return false;
}
m_logMessage = logMessage;
return true;
}

public string LogMessage => m_logMessage;

public bool HasTracepoint => !string.IsNullOrEmpty(m_logMessage) && m_Tracepoint != null;

public Tracepoint Tracepoint => m_Tracepoint;

#endregion
}
}
72 changes: 72 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.

24 changes: 24 additions & 0 deletions src/OpenDebugAD7/AD7Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@
<data name="Error_UnableToSetBreakpoint" xml:space="preserve">
<value>Error setting breakpoint. {0}</value>
</data>
<data name="Error_UnableToParseLogMessage" xml:space="preserve">
<value>Unable to parse 'logMessage'.</value>
</data>
<data name="Msg_E_CRASHDUMP_UNSUPPORTED" xml:space="preserve">
<value>This operation is not supported when debugging dump files.</value>
</data>
Expand Down Expand Up @@ -258,4 +261,25 @@
<value>Exception occurred: '{0}'</value>
<comment>{0} is the exception string</comment>
</data>
<data name="Error_InterpolateMissingFrames" xml:space="preserve">
<value>Unable to interpolate logMessage because frames could not be retrieved.</value>
</data>
<data name="Error_InterpolateMissingThread" xml:space="preserve">
<value>Unable to interpolate logMessage because current thread is missing.</value>
</data>
<data name="Error_InterpolateMissingTopFrame" xml:space="preserve">
<value>Unable to interpolate logMessage because there is no top frame.</value>
</data>
<data name="Error_InterpolateVariableEvaluateFailed" xml:space="preserve">
<value>Failed to evaluate expression.</value>
</data>
<data name="Error_InterpolateVariableMissingContext" xml:space="preserve">
<value>Unable to get context from frame.</value>
</data>
<data name="Error_InterpolateVariableMissingExpressionObject" xml:space="preserve">
<value>No expression object found.</value>
</data>
<data name="Error_InterpolateVariableMissingProperties" xml:space="preserve">
<value>Failed to get property information.</value>
</data>
</root>
4 changes: 3 additions & 1 deletion src/OpenDebugAD7/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ internal static class Constants
{
// POST_PREVIEW_TODO: no-func-eval support, radix, timeout
public const uint EvaluationRadix = 10;
public const uint ParseRadix = 10;
public const uint EvaluationTimeout = 5000;
public const int DisconnectTimeout = 2000;
public const int DefaultTracepointCallstackDepth = 10;
}
}
}
1 change: 1 addition & 0 deletions src/OpenDebugAD7/OpenDebugAD7.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
<Compile Include="Telemetry\TelemetryHelper.cs" />
<Compile Include="TextPositionTuple.cs" />
<Compile Include="ThreadFrameEnumInfo.cs" />
<Compile Include="Tracepoint.cs" />
<Compile Include="VariableManager.cs" />
<Compile Include="AD7DebugSession.cs" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 49b72ec

Please sign in to comment.