* Trying to avoid pausing on breakpoint while invoking methods.
* Adding test case for it as discussed with @radical offline.
* Creating new tests and fixing its behavior.
* Addressing @radical comments offline.
* same behavior for stepping, disable global_stepping while evaluating expression.
* Renaming function as suggested by @radical
gboolean terminated;
/* Whenever to disable breakpoints (used during invokes) */
- gboolean disable_breakpoints;
+ gboolean disable_breakpoint_and_stepping;
/*
* Number of times this thread has been resumed using resume_thread ().
/* Callbacks used by debugger-engine */
static MonoContext* tls_get_restore_state (void *the_tls);
static gboolean try_process_suspend (void *tls, MonoContext *ctx, gboolean from_breakpoint);
-static gboolean begin_breakpoint_processing (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
static void begin_single_step_processing (MonoContext *ctx, gboolean from_signal);
static gboolean ensure_jit (DbgEngineStackFrame* the_frame);
static int ensure_runtime_is_suspended (void);
memset (&cbs, 0, sizeof (cbs));
cbs.tls_get_restore_state = tls_get_restore_state;
cbs.try_process_suspend = try_process_suspend;
- cbs.begin_breakpoint_processing = begin_breakpoint_processing;
+ cbs.begin_breakpoint_processing = mono_begin_breakpoint_processing;
cbs.begin_single_step_processing = begin_single_step_processing;
cbs.ss_discard_frame_context = mono_ss_discard_frame_context;
cbs.ss_calculate_framecount = mono_ss_calculate_framecount;
GET_TLS_DATA_FROM_THREAD (thread);
return tls;
}
+
+bool
+mono_wasm_is_breakpoint_and_stepping_disabled (void)
+{
+ return mono_wasm_get_tls ()->disable_breakpoint_and_stepping;
+}
#endif
#ifdef HOST_WASI
GET_DEBUGGER_TLS();
g_assert (tls);
// We are already processing a breakpoint event
- if (tls->disable_breakpoints)
+ if (tls->disable_breakpoint_and_stepping)
return;
mono_stopwatch_stop (&tls->step_time);
break;
MonoObject *ex;
ERROR_DECL (error);
MonoObject *obj;
- gboolean old_disable_breakpoints = FALSE;
+ gboolean old_disable_breakpoint_and_stepping = FALSE;
DebuggerTlsData *tls;
/*
tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
if (tls) {
- old_disable_breakpoints = tls->disable_breakpoints;
- tls->disable_breakpoints = TRUE;
+ old_disable_breakpoint_and_stepping = tls->disable_breakpoint_and_stepping;
+ tls->disable_breakpoint_and_stepping = TRUE;
}
method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type));
if (!method) {
if (tls)
- tls->disable_breakpoints = old_disable_breakpoints;
+ tls->disable_breakpoint_and_stepping = old_disable_breakpoint_and_stepping;
return 0;
}
obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error);
mono_error_assert_ok (error);
if (tls)
- tls->disable_breakpoints = old_disable_breakpoints;
+ tls->disable_breakpoint_and_stepping = old_disable_breakpoint_and_stepping;
return get_objid (obj);
}
-static gboolean
-begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
+bool
+mono_begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
{
DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
#else
NOT_IMPLEMENTED;
#endif
- if (tls->disable_breakpoints)
+ if (tls->disable_breakpoint_and_stepping)
return FALSE;
return TRUE;
}
if (tls != NULL) {
if (tls->abort_requested)
return;
- if (tls->disable_breakpoints)
+ if (tls->disable_breakpoint_and_stepping)
return;
}
if (i < nargs)
return err;
- if (invoke->flags & INVOKE_FLAG_DISABLE_BREAKPOINTS)
- tls->disable_breakpoints = TRUE;
+ if (invoke->flags & INVOKE_FLAG_DISABLE_BREAKPOINTS_AND_STEPPING)
+ tls->disable_breakpoint_and_stepping = TRUE;
else
- tls->disable_breakpoints = FALSE;
+ tls->disable_breakpoint_and_stepping = FALSE;
/*
* Add an LMF frame to link the stack frames on the invoke method with our caller.
}
}
- tls->disable_breakpoints = FALSE;
+ tls->disable_breakpoint_and_stepping = FALSE;
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
if (invoke->has_ctx)
void
mono_wasm_save_thread_context (void);
+bool
+mono_wasm_is_breakpoint_and_stepping_disabled (void);
#endif
void
bool
mono_debugger_agent_receive_and_process_command (void);
+
+bool
+mono_begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
#endif
#define INVOKE_FLAG_SINGLE_THREADED MDBGPROT_INVOKE_FLAG_SINGLE_THREADED
#define INVOKE_FLAG_VIRTUAL MDBGPROT_INVOKE_FLAG_VIRTUAL
-#define INVOKE_FLAG_DISABLE_BREAKPOINTS MDBGPROT_INVOKE_FLAG_DISABLE_BREAKPOINTS
+#define INVOKE_FLAG_DISABLE_BREAKPOINTS_AND_STEPPING MDBGPROT_INVOKE_FLAG_DISABLE_BREAKPOINTS_AND_STEPPING
#define INVOKE_FLAG_RETURN_OUT_THIS MDBGPROT_INVOKE_FLAG_RETURN_OUT_THIS
#define INVOKE_FLAG_RETURN_OUT_ARGS MDBGPROT_INVOKE_FLAG_RETURN_OUT_ARGS
} MdbgProtStackFrameFlags;
typedef enum {
- MDBGPROT_INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
+ MDBGPROT_INVOKE_FLAG_DISABLE_BREAKPOINTS_AND_STEPPING = 1,
MDBGPROT_INVOKE_FLAG_SINGLE_THREADED = 2,
MDBGPROT_INVOKE_FLAG_RETURN_OUT_THIS = 4,
MDBGPROT_INVOKE_FLAG_RETURN_OUT_ARGS = 8,
typedef struct {
MonoContext *(*tls_get_restore_state) (void *tls);
gboolean (*try_process_suspend) (void *tls, MonoContext *ctx, gboolean from_breakpoint);
- gboolean (*begin_breakpoint_processing) (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
+ bool (*begin_breakpoint_processing) (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
void (*begin_single_step_processing) (MonoContext *ctx, gboolean from_signal);
void (*ss_discard_frame_context) (void *tls);
return FALSE;
}
-static gboolean
+static bool
begin_breakpoint_processing (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
{
- return TRUE;
+ return mono_begin_breakpoint_processing(tls, ctx, ji, from_signal);
}
static void
static void
mono_wasm_single_step_hit (void)
{
+ if (mono_wasm_is_breakpoint_and_stepping_disabled ())
+ return;
mono_de_process_single_step (mono_wasm_get_tls (), FALSE);
}
InvokeData invoke_data;
memset (&invoke_data, 0, sizeof (InvokeData));
invoke_data.endp = data + size;
+ invoke_data.flags = INVOKE_FLAG_DISABLE_BREAKPOINTS_AND_STEPPING;
error = mono_do_invoke_method (tls, &buf, &invoke_data, data, &data);
}
else if (command_set == MDBGPROT_CMD_SET_VM && (command == MDBGPROT_CMD_GET_ASSEMBLY_BYTES))
fn_table->mono_wasm_single_step_hit = mono_wasm_single_step_hit;
}
-#endif
\ No newline at end of file
+#endif
{
return await insp.WaitFor(what);
}
+ public async Task WaitForConsoleMessage(string message)
+ {
+ object llock = new();
+ var tcs = new TaskCompletionSource();
+ insp.On("Runtime.consoleAPICalled", async (args, c) =>
+ {
+ (string line, string type) = insp.FormatConsoleAPICalled(args);
+ if (string.IsNullOrEmpty(line))
+ return await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
+ lock (llock)
+ {
+ try
+ {
+ if (line == message)
+ {
+ tcs.SetResult();
+ }
+ }
+ catch (Exception ex)
+ {
+ tcs.SetException(ex);
+ }
+ }
+
+ return tcs.Task.IsCompleted
+ ? await Task.FromResult(ProtocolEventHandlerReturn.RemoveHandler)
+ : await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
+ });
+
+ await tcs.Task;
+ }
public async Task WaitForScriptParsedEventsAsync(params string[] paths)
{
object llock = new();
props = await GetObjectOnFrame(frame, "this");
CheckNumber(props, "a", 11);
});
+
+ [ConditionalTheory(nameof(RunningOnChrome))]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task EvaluateMethodWithBPWhilePausedInADifferentMethodAndNotHit(bool setBreakpointBeforePause)
+ {
+ await cli.SendCommand("DotnetDebugger.setEvaluationOptions", JObject.FromObject(new { options = new { noFuncEval = false } }), token);
+ var waitForScript = WaitForConsoleMessage("console.warning: MONO_WASM: Adding an id (0) that already exists in commands_received");
+ if (setBreakpointBeforePause)
+ await SetBreakpointInMethod("debugger-test.dll", "TestEvaluateDontPauseOnBreakpoint", "MyMethod2", 1);
+ await CheckInspectLocalsAtBreakpointSite(
+ "TestEvaluateDontPauseOnBreakpoint", "run", 3, "TestEvaluateDontPauseOnBreakpoint.run",
+ "window.setTimeout(function() { invoke_static_method ('[debugger-test] TestEvaluateDontPauseOnBreakpoint:run'); })",
+ wait_for_event_fn: async (pause_location) =>
+ {
+ if (!setBreakpointBeforePause)
+ await SetBreakpointInMethod("debugger-test.dll", "TestEvaluateDontPauseOnBreakpoint", "MyMethod2", 1);
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ await EvaluateOnCallFrameAndCheck(id,
+ ("myVar.MyMethod2()", TString("Object 11")),
+ ("myVar.MyMethod3()", TString("Object 11")),
+ ("myVar.MyCount", TString("Object 11")),
+ ("myVar.MyMethod()", TString("Object 10")),
+ ("myVar", TObject("TestEvaluateDontPauseOnBreakpoint", description: "Object 11")));
+ var props = await GetObjectOnFrame(pause_location["callFrames"][0], "myVar");
+ await CheckString(props, "MyCount", "Object 11");
+ });
+ await SendCommandAndCheck(null, "Debugger.resume", null, 0, 0, "TestEvaluateDontPauseOnBreakpoint.MyMethod2");
+ await SendCommandAndCheck(null, "Debugger.resume", null, 0, 0, "TestEvaluateDontPauseOnBreakpoint.MyMethod");
+ Assert.False(waitForScript.IsCompleted);
+ }
}
}
}
}
- private (string line, string type) FormatConsoleAPICalled(JObject args)
+ internal (string line, string type) FormatConsoleAPICalled(JObject args)
{
string? type = args?["type"]?.Value<string>();
List<string> consoleArgs = new();
}
}
}
+[System.Diagnostics.DebuggerDisplay("{MyMethod2(),nq}")]
+public class TestEvaluateDontPauseOnBreakpoint
+{
+ public int count;
+ public static void run()
+ {
+ var myVar = new TestEvaluateDontPauseOnBreakpoint();
+ myVar.count = 10;
+ myVar.MyMethod2();
+ myVar.MyMethod();
+ }
+ public string MyMethod() {
+ System.Diagnostics.Debugger.Break();
+ return string.Format("Object {0}", count);
+ }
+ public string MyMethod2() {
+ return string.Format("Object {0}", count + 1);
+ }
+ public string MyMethod3() {
+ return MyMethod2();
+ }
+ public string MyCount
+ {
+ get
+ {
+ return MyMethod2();
+ }
+ }
+}