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

Add support for LogPoints in OpenDebugAD7 #1013

Merged
merged 8 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
WardenGnaw marked this conversation as resolved.
Show resolved Hide resolved
}

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this have a meaningful message? I don't remember you setting the message when you were throwing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only time this exception is thrown is when we cant find a matching '}' for interpolation.

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