Skip to content

Commit

Permalink
Merge pull request EvilBeaver#1434 from akpaevj/feature/exception-bre…
Browse files Browse the repository at this point in the history
…akpoints

Feature/exception breakpoints
  • Loading branch information
EvilBeaver authored Aug 5, 2024
2 parents ae93a2e + ba75813 commit ad7fe24
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 22 deletions.
8 changes: 7 additions & 1 deletion src/OneScript.DebugProtocol/IDebuggerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ public interface IDebuggerService
/// Все точки останова уже установлены, все настройки сделаны
/// </summary>
void Execute(int threadId);


/// <summary>
/// Добавление фильтров точек останова для исплючений
/// </summary>
/// <param name="filters"></param>
void SetMachineExceptionBreakpoints((string Id, string Condition)[] filters);

/// <summary>
/// Установка точек остановки
/// </summary>
Expand Down
35 changes: 31 additions & 4 deletions src/OneScript.DebugServices/DefaultBreakpointManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@ This Source Code Form is subject to the terms of the
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Linq;
using OneScript.Commons;
using ScriptEngine.Machine;

namespace OneScript.DebugServices
{
public class DefaultBreakpointManager : IBreakpointManager
{
private readonly Dictionary<string, string> _exceptionBreakpointsFilters = new Dictionary<string, string>();
private readonly List<BreakpointDescriptor> _breakpoints = new List<BreakpointDescriptor>();
private int _idsGenerator;

public void SetExceptionBreakpoints((string Id, string Condition)[] filters)
{
_exceptionBreakpointsFilters?.Clear();
filters?.ForEach(c =>_exceptionBreakpointsFilters.Add(c.Id, c.Condition));
}

public void SetBreakpoints(string module, (int Line, string Condition)[] breakpoints)
{
var cleaned = _breakpoints.Where(x => x.Module != module)
Expand All @@ -27,17 +36,35 @@ public void SetBreakpoints(string module, (int Line, string Condition)[] breakpo
_breakpoints.AddRange(cleaned);
}

public bool Find(string module, int line)
{
return _breakpoints.Find(x => x.Module.Equals(module) && x.LineNumber == line) != null;
}
public bool FindBreakpoint(string module, int line)
=> _breakpoints.Find(x => x.Module.Equals(module) && x.LineNumber == line) != null;

public string GetCondition(string module, int line)
=> _breakpoints.Find(x => x.Module.Equals(module) && x.LineNumber == line).Condition;

public void Clear()
{
_breakpoints.Clear();
_exceptionBreakpointsFilters.Clear();
}

public bool StopOnAnyException(string message)
=> NeedStopOnException("all", message);

public bool StopOnUncaughtException(string message)
=> NeedStopOnException("uncaught", message);

private bool NeedStopOnException(string filterId, string message)
{
if (_exceptionBreakpointsFilters?.TryGetValue(filterId, out var condition) == true)
{
if (string.IsNullOrEmpty(condition))
return true;
else
return message.Contains(condition);
}

return false;
}
}
}
9 changes: 9 additions & 0 deletions src/OneScript.DebugServices/DefaultDebugService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public void Execute(int threadId)
}
}

public void SetMachineExceptionBreakpoints((string Id, string Condition)[] filters)
{
_breakpointManager.SetExceptionBreakpoints(filters);

// Уведомить все потоки о новых фильтрах
foreach (var machine in _threadManager.GetAllTokens().Select(x => x.Machine))
machine.SetDebugMode(_breakpointManager);
}

public Breakpoint[] SetMachineBreakpoints(Breakpoint[] breaksToSet)
{
var confirmedBreakpoints = new List<Breakpoint>();
Expand Down
8 changes: 7 additions & 1 deletion src/ScriptEngine/Machine/IDebugController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ public interface IDebugController : IDisposable

public interface IBreakpointManager
{
void SetExceptionBreakpoints((string Id, string Condition)[] filters);

void SetBreakpoints(string module, (int Line, string Condition)[] breakpoints);

bool StopOnAnyException(string message);

bool StopOnUncaughtException(string message);

bool Find(string module, int line);
bool FindBreakpoint(string module, int line);

string GetCondition(string module, int line);

Expand Down
19 changes: 18 additions & 1 deletion src/ScriptEngine/Machine/MachineInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,14 @@ private void ExecuteCode()
{
SetScriptExceptionSource(exc);

if (ShouldRethrowException(exc))
var shouldRethrow = ShouldRethrowException(exc);

if (MachineStopped != null && _stopManager != null)
if (_stopManager.Breakpoints.StopOnAnyException(exc.MessageWithoutCodeFragment) ||
shouldRethrow && _stopManager.Breakpoints.StopOnUncaughtException(exc.MessageWithoutCodeFragment))
EmitStopOnException();

if (shouldRethrow)
throw;
}
}
Expand Down Expand Up @@ -1297,6 +1304,16 @@ private void LineNum(int arg)
NextInstruction();
}

private void EmitStopOnException()
{
if (MachineStopped != null && _stopManager != null)
{
CreateFullCallstack();
var args = new MachineStoppedEventArgs(MachineStopReason.Exception, Environment.CurrentManagedThreadId, "");
MachineStopped?.Invoke(this, args);
}
}

private void EmitStopEventIfNecessary()
{
if (MachineStopped != null && _stopManager != null && _stopManager.ShouldStopAtThisLine(_module.Source.Location, _currentFrame))
Expand Down
4 changes: 1 addition & 3 deletions src/ScriptEngine/Machine/MachineStopManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ internal enum DebugState
SteppingOut
}



internal class MachineStopManager
{
private struct StopPoint
Expand Down Expand Up @@ -119,7 +117,7 @@ public bool ShouldStopAtThisLine(string module, ExecutionFrame currentFrame)

private bool HitBreakpointOnLine(string module, ExecutionFrame currentFrame)
{
return _breakpoints.Find(module, currentFrame.LineNumber);
return _breakpoints.FindBreakpoint(module, currentFrame.LineNumber);
}

private bool FrameIsInStopList(ExecutionFrame currentFrame)
Expand Down
30 changes: 25 additions & 5 deletions src/VSCode.DebugAdapter/DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@ public class Breakpoint
public bool verified { get; }
public int line { get; }

public Breakpoint(bool verified, int line) {
public Breakpoint(bool verified)
{
this.verified = verified;
line = 0;
}

public Breakpoint(bool verified, int line) {
this.verified = verified;
this.line = line;
}
Expand Down Expand Up @@ -180,6 +186,7 @@ public class Capabilities : ResponseBody {
public bool supportsFunctionBreakpoints;
public bool supportsConditionalBreakpoints;
public bool supportsEvaluateForHovers;
public bool supportsExceptionFilterOptions;
public dynamic[] exceptionBreakpointFilters;
public bool supportTerminateDebuggee;
}
Expand Down Expand Up @@ -262,15 +269,28 @@ public class SetBreakpointsResponseBody : ResponseBody

public SetBreakpointsResponseBody(List<Breakpoint> bpts = null) {
if (bpts == null)
breakpoints = new Breakpoint[0];
else
breakpoints = Array.Empty<Breakpoint>();
else
breakpoints = bpts.ToArray<Breakpoint>();
}
}

// ---- The Session --------------------------------------------------------
public class SetExceptionBreakpointsResponseBody : ResponseBody
{
public Breakpoint[] breakpoints { get; }

public SetExceptionBreakpointsResponseBody(List<Breakpoint> bpts = null)
{
if (bpts == null)
breakpoints = Array.Empty<Breakpoint>();
else
breakpoints = bpts.ToArray<Breakpoint>();
}
}

// ---- The Session --------------------------------------------------------

public abstract class DebugSession : ProtocolServer
public abstract class DebugSession : ProtocolServer
{
private bool _clientLinesStartAt1 = true;
private bool _clientPathsAreUri = true;
Expand Down
5 changes: 5 additions & 0 deletions src/VSCode.DebugAdapter/DebugeeProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public void Kill()
_process.WaitForExit(1500);
}

public void SetExceptionsBreakpoints((string Id, string Condition)[] filters)
{
_debugger.SetMachineExceptionBreakpoints(filters);
}

public Breakpoint[] SetBreakpoints(IEnumerable<Breakpoint> breakpoints)
{
var confirmedBreaks = _debugger.SetMachineBreakpoints(breakpoints.ToArray());
Expand Down
60 changes: 53 additions & 7 deletions src/VSCode.DebugAdapter/OscriptDebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ This Source Code Form is subject to the terms of the
using System.IO;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OneScript.DebugProtocol;
using Serilog;
using VSCodeDebug;
using static System.Net.WebRequestMethods;


namespace VSCode.DebugAdapter
Expand Down Expand Up @@ -43,7 +45,26 @@ public override void Initialize(Response response, dynamic args)
supportsConditionalBreakpoints = true,
supportsFunctionBreakpoints = false,
supportsConfigurationDoneRequest = true,
exceptionBreakpointFilters = new dynamic[0],
supportsExceptionFilterOptions = true,
exceptionBreakpointFilters = new dynamic[]
{
new
{
filter = "uncaught",
label = "Необработанные исключения",
description = "Остановка при возникновении необработанного исключения",
supportsCondition = true,
conditionDescription = "Искомая подстрока текста исключения"
},
new
{
filter = "all",
label = "Все исключения",
description = "Остановка при возникновении любого исключения",
supportsCondition = true,
conditionDescription = "Искомая подстрока текста исключения"
}
},
supportsEvaluateForHovers = true,
supportTerminateDebuggee = true
});
Expand Down Expand Up @@ -113,7 +134,7 @@ public override void Launch(Response response, dynamic args)
public override void Attach(Response response, dynamic arguments)
{
LogCommandReceived();
_process.DebugPort = getInt(arguments, "debugPort", 2801);
_process.DebugPort = GetFromContainer(arguments, "debugPort", 2801);
_process.ProcessExited += (s, e) =>
{
Log.Information("Debuggee has exited");
Expand Down Expand Up @@ -148,6 +169,31 @@ public override void Disconnect(Response response, dynamic arguments)
SendResponse(response);
}

public override void SetExceptionBreakpoints(Response response, dynamic arguments)
{
LogCommandReceived(arguments);
Log.Debug("Exception breakpoints: {Data}", JsonConvert.SerializeObject(arguments));

var acceptedFilters = new List<VSCodeDebug.Breakpoint>();
var filters = new List<(string Id, string Condition)>();

foreach(var filter in arguments.filters)
{
filters.Add((filter, ""));
acceptedFilters.Add(new VSCodeDebug.Breakpoint(true));
}

foreach (var filterOption in arguments.filterOptions)
{
filters.Add((filterOption.filterId, filterOption.condition ?? ""));
acceptedFilters.Add(new VSCodeDebug.Breakpoint(true));
}

_process.SetExceptionsBreakpoints(filters.ToArray());

SendResponse(response, new SetExceptionBreakpointsResponseBody(acceptedFilters));
}

public override void SetBreakpoints(Response response, dynamic arguments)
{
LogCommandReceived();
Expand Down Expand Up @@ -322,7 +368,7 @@ public override void StackTrace(Response response, dynamic arguments)
public override void Scopes(Response response, dynamic arguments)
{
LogCommandReceived();
int frameId = getInt(arguments, "frameId");
int frameId = GetFromContainer(arguments, "frameId", 0);
var frame = _framesHandles.Get(frameId, null);
if (frame == null)
{
Expand All @@ -338,7 +384,7 @@ public override void Scopes(Response response, dynamic arguments)
public override void Variables(Response response, dynamic arguments)
{
LogCommandReceived();
int varsHandle = getInt(arguments, "variablesReference");
int varsHandle = GetFromContainer(arguments, "variablesReference", 0);
var variables = _variableHandles.Get(varsHandle, null);
if (variables == null)
{
Expand Down Expand Up @@ -386,7 +432,7 @@ public override void Evaluate(Response response, dynamic arguments)
{
LogCommandReceived();
// expression, frameId, context
int frameId = getInt(arguments, "frameId");
int frameId = GetFromContainer(arguments, "frameId", 0);
var frame = _framesHandles.Get(frameId, null);
if (frame == null)
{
Expand Down Expand Up @@ -438,11 +484,11 @@ private void SendOutput(string category, string data)
}
}

private static int getInt(dynamic container, string propertyName, int dflt = 0)
private static T GetFromContainer<T>(dynamic container, string propertyName, T dflt = default)
{
try
{
return (int)container[propertyName];
return (T)container[propertyName];
}
catch (Exception)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ public void Execute(int threadId)
WriteCommand(threadId);
}

public void SetMachineExceptionBreakpoints((string Id, string Condition)[] filters)
{
WriteCommand(filters);
}

public Breakpoint[] SetMachineBreakpoints(Breakpoint[] breaksToSet)
{
WriteCommand(breaksToSet);
Expand Down

0 comments on commit ad7fe24

Please sign in to comment.