in src/OpenDebugAD7/AD7DebugSession.cs [2167:2381]
protected override void HandleSetBreakpointsRequestAsync(IRequestResponder<SetBreakpointsArguments, SetBreakpointsResponse> responder)
{
SetBreakpointsResponse response = new SetBreakpointsResponse();
string path = null;
string name = null;
if (responder.Arguments.Source != null)
{
string p = responder.Arguments.Source.Path;
if (p != null && p.Trim().Length > 0)
{
path = p;
}
string nm = responder.Arguments.Source.Name;
if (nm != null && nm.Trim().Length > 0)
{
name = nm;
}
}
var source = new Source()
{
Name = name,
Path = path,
SourceReference = 0
};
List<SourceBreakpoint> breakpoints = responder.Arguments.Breakpoints;
bool sourceModified = responder.Arguments.SourceModified.GetValueOrDefault(false);
// we do not support other sources than 'path'
if (source.Path != null)
{
ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_UnableToSetBreakpoint);
try
{
string convertedPath = m_pathConverter.ConvertClientPathToDebugger(source.Path);
if (Utilities.IsWindows() && convertedPath.Length > 2)
{
// vscode may send drive letters with inconsistent casing which will mess up the key
// in the dictionary. see https://github.com/Microsoft/vscode/issues/6268
// Normalize the drive letter casing. Note that drive letters
// are not localized so invariant is safe here.
string drive = convertedPath.Substring(0, 2);
if (char.IsLower(drive[0]) && drive.EndsWith(":", StringComparison.Ordinal))
{
convertedPath = String.Concat(drive.ToUpperInvariant(), convertedPath.Substring(2));
}
}
HashSet<int> lines = new HashSet<int>(breakpoints.Select((b) => b.Line));
Dictionary<int, IDebugPendingBreakpoint2> dict = null;
if (m_breakpoints.ContainsKey(convertedPath))
{
dict = m_breakpoints[convertedPath];
var keys = new int[dict.Keys.Count];
dict.Keys.CopyTo(keys, 0);
foreach (var l in keys)
{
// Delete all breakpoints that are no longer listed.
// In the case of modified source, delete everything.
if (!lines.Contains(l) || sourceModified)
{
var bp = dict[l];
bp.Delete();
dict.Remove(l);
}
}
}
else
{
dict = new Dictionary<int, IDebugPendingBreakpoint2>();
m_breakpoints[convertedPath] = dict;
}
var resBreakpoints = new List<Breakpoint>();
foreach (var bp in breakpoints)
{
if (dict.ContainsKey(bp.Line))
{
// already created
IDebugBreakpointRequest2 breakpointRequest;
if (dict[bp.Line].GetBreakpointRequest(out breakpointRequest) == 0 &&
breakpointRequest is AD7BreakPointRequest ad7BPRequest)
{
// Check to see if this breakpoint has a condition that has changed.
if (!StringComparer.Ordinal.Equals(ad7BPRequest.Condition, bp.Condition))
{
// Condition has been modified. Delete breakpoint so it will be recreated with the updated condition.
var toRemove = dict[bp.Line];
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)
{
// use the breakpoint created from IDebugBreakpointErrorEvent2 or IDebugBreakpointBoundEvent2
resBreakpoints.Add(ad7BPRequest.BindResult);
}
else
{
resBreakpoints.Add(new Breakpoint()
{
Id = (int)ad7BPRequest.Id,
Verified = true,
Line = bp.Line
});
}
continue;
}
}
}
// Create a new breakpoint
if (!dict.ContainsKey(bp.Line))
{
IDebugPendingBreakpoint2 pendingBp;
AD7BreakPointRequest pBPRequest = new AD7BreakPointRequest(m_sessionConfig, convertedPath, m_pathConverter.ConvertClientLineToDebugger(bp.Line), bp.Condition);
try
{
bool verified = true;
if (!string.IsNullOrEmpty(bp.LogMessage))
{
// Make sure tracepoint is valid.
verified = pBPRequest.SetLogMessage(bp.LogMessage);
}
if (verified)
{
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)
{
e = Utilities.GetInnerMost(e);
if (Utilities.IsCorruptingException(e))
{
Utilities.ReportException(e);
}
resBreakpoints.Add(new Breakpoint()
{
Id = (int)pBPRequest.Id,
Verified = false,
Line = bp.Line,
Message = eb.GetMessageForException(e)
});
}
}
}
response.Breakpoints = resBreakpoints;
}
catch (Exception e)
{
// If setBreakpoints returns an error vscode aborts launch, so we never want to return an error,
// so convert this to failure results
e = Utilities.GetInnerMost(e);
if (Utilities.IsCorruptingException(e))
{
Utilities.ReportException(e);
}
string message = eb.GetMessageForException(e);
List<Breakpoint> resBreakpoints = breakpoints.Select(bp => new Breakpoint()
{
Id = (int)AD7BreakPointRequest.GetNextBreakpointId(),
Verified = false,
Line = bp.Line,
Message = message
}).ToList();
response.Breakpoints = resBreakpoints;
}
}
responder.SetResponse(response);
}