[gnome-builder/wip/gtk4-port: 1628/1774] libide/debugger: refactor debugger interface
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/gtk4-port: 1628/1774] libide/debugger: refactor debugger interface
- Date: Mon, 11 Jul 2022 22:31:52 +0000 (UTC)
commit 292fc5b79ef153fa05ee437327874f22ab053baf
Author: Christian Hergert <chergert redhat com>
Date: Thu Jun 23 22:44:42 2022 -0700
libide/debugger: refactor debugger interface
This changes the check/prepare API to use the abstractions we have now
since the runner plumbing is to be deleted.
src/libide/debugger/ide-debugger.c | 34 +++---
src/libide/debugger/ide-debugger.h | 28 ++---
src/plugins/gdb/gbp-gdb-debugger.c | 212 ++++++++++++++++++++-----------------
3 files changed, 149 insertions(+), 125 deletions(-)
---
diff --git a/src/libide/debugger/ide-debugger.c b/src/libide/debugger/ide-debugger.c
index e803062b5..7b77891f0 100644
--- a/src/libide/debugger/ide-debugger.c
+++ b/src/libide/debugger/ide-debugger.c
@@ -1845,7 +1845,8 @@ ide_debugger_disassemble_finish (IdeDebugger *self,
/**
* ide_debugger_supports_runner:
* @self: an #IdeDebugger
- * @runner: an #IdeRunner
+ * @pipeline: an #IdePipeline
+ * #run_command: an #IdeRunCommand
* @priority: (out): A location for a priority
*
* Checks if the debugger supports a given runner. The debugger may need
@@ -1854,39 +1855,44 @@ ide_debugger_disassemble_finish (IdeDebugger *self,
* Returns: %TRUE if the #IdeDebugger supports the runner.
*/
gboolean
-ide_debugger_supports_runner (IdeDebugger *self,
- IdeRunner *runner,
- gint *priority)
+ide_debugger_supports_run_command (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunCommand *run_command,
+ int *priority)
{
- gint dummy = 0;
+ int dummy = 0;
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
- g_return_val_if_fail (IDE_IS_RUNNER (runner), FALSE);
+ g_return_val_if_fail (IDE_IS_PIPELINE (pipeline), FALSE);
+ g_return_val_if_fail (IDE_IS_RUN_COMMAND (run_command), FALSE);
if (priority == NULL)
priority = &dummy;
else
*priority = 0;
- return IDE_DEBUGGER_GET_CLASS (self)->supports_runner (self, runner, priority);
+ return IDE_DEBUGGER_GET_CLASS (self)->supports_run_command (self, pipeline, run_command, priority);
}
/**
- * ide_debugger_prepare:
+ * ide_debugger_prepare_for_run:
* @self: an #IdeDebugger
- * @runner: an #IdeRunner
+ * @pipeline: an #IdePipeline
+ * @run_command: an #IdeRunContext
*
* Prepares the runner to launch a debugger and target process.
*/
void
-ide_debugger_prepare (IdeDebugger *self,
- IdeRunner *runner)
+ide_debugger_prepare_for_run (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunContext *run_context)
{
g_return_if_fail (IDE_IS_DEBUGGER (self));
- g_return_if_fail (IDE_IS_RUNNER (runner));
+ g_return_if_fail (IDE_IS_PIPELINE (pipeline));
+ g_return_if_fail (IDE_IS_RUN_CONTEXT (run_context));
+ g_return_if_fail (IDE_DEBUGGER_GET_CLASS (self)->prepare_for_run != NULL);
- if (IDE_DEBUGGER_GET_CLASS (self)->prepare)
- IDE_DEBUGGER_GET_CLASS (self)->prepare (self, runner);
+ IDE_DEBUGGER_GET_CLASS (self)->prepare_for_run (self, pipeline, run_context);
}
/**
diff --git a/src/libide/debugger/ide-debugger.h b/src/libide/debugger/ide-debugger.h
index 014b89fb5..a632086a5 100644
--- a/src/libide/debugger/ide-debugger.h
+++ b/src/libide/debugger/ide-debugger.h
@@ -81,11 +81,13 @@ struct _IdeDebuggerClass
/* Virtual Functions */
- gboolean (*supports_runner) (IdeDebugger *self,
- IdeRunner *runner,
- gint *priority);
- void (*prepare) (IdeDebugger *self,
- IdeRunner *runner);
+ gboolean (*supports_run_command) (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunCommand *run_command,
+ int *priority);
+ void (*prepare_for_run) (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunContext *run_context);
gboolean (*get_can_move) (IdeDebugger *self,
IdeDebuggerMovement movement);
void (*move_async) (IdeDebugger *self,
@@ -145,7 +147,7 @@ struct _IdeDebuggerClass
GAsyncResult *result,
GError **error);
void (*send_signal_async) (IdeDebugger *self,
- gint signum,
+ int signum,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
@@ -199,12 +201,14 @@ struct _IdeDebuggerClass
};
IDE_AVAILABLE_IN_ALL
-gboolean ide_debugger_supports_runner (IdeDebugger *self,
- IdeRunner *runner,
- gint *priority);
+gboolean ide_debugger_supports_run_command (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunCommand *run_command,
+ int *priority);
IDE_AVAILABLE_IN_ALL
-void ide_debugger_prepare (IdeDebugger *self,
- IdeRunner *runner);
+void ide_debugger_prepare_for_run (IdeDebugger *self,
+ IdePipeline *pipeline,
+ IdeRunContext *run_context);
IDE_AVAILABLE_IN_ALL
GListModel *ide_debugger_get_breakpoints (IdeDebugger *self);
IDE_AVAILABLE_IN_ALL
@@ -336,7 +340,7 @@ gboolean ide_debugger_move_finish (IdeDebugger
GError **error);
IDE_AVAILABLE_IN_ALL
void ide_debugger_send_signal_async (IdeDebugger *self,
- gint signum,
+ int signum,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/src/plugins/gdb/gbp-gdb-debugger.c b/src/plugins/gdb/gbp-gdb-debugger.c
index 0d7091df4..dae04347d 100644
--- a/src/plugins/gdb/gbp-gdb-debugger.c
+++ b/src/plugins/gdb/gbp-gdb-debugger.c
@@ -37,16 +37,10 @@ struct _GbpGdbDebugger
GCancellable *read_cancellable;
GHashTable *register_names;
GFile *builddir;
+ IdeRuntime *current_runtime;
- IdeSignalGroup *runner_signals;
GSettings *settings;
- /* This is the number for the fd in the inferior process.
- * It is not opened/owned by this instance (as it is in a
- * different process space). No need to close.
- */
- gint mapped_fd;
-
struct gdbwire_mi_parser *parser;
GQueue writequeue;
@@ -116,19 +110,12 @@ gbp_gdb_debugger_translate_path (GbpGdbDebugger *self,
const gchar *path)
{
g_autoptr(GFile) file = NULL;
- IdeRuntime *runtime = NULL;
- IdeRunner *runner;
g_assert (GBP_IS_GDB_DEBUGGER (self));
if (path == NULL)
return NULL;
- /* Discover the current runtime for path translation */
- runner = ide_signal_group_get_target (self->runner_signals);
- if (runner != NULL)
- runtime = ide_runner_get_runtime (runner);
-
/* Generate a path, trying to resolve relative paths to
* make things easier on the runtime path translation.
*/
@@ -138,10 +125,10 @@ gbp_gdb_debugger_translate_path (GbpGdbDebugger *self,
file = g_file_resolve_relative_path (self->builddir, path);
/* If we still have access to the runtime, translate */
- if (runtime != NULL)
+ if (self->current_runtime != NULL)
{
GFile *freeme = file;
- file = ide_runtime_translate_file (runtime, file);
+ file = ide_runtime_translate_file (self->current_runtime, file);
g_clear_object (&freeme);
}
@@ -2321,112 +2308,146 @@ gbp_gdb_debugger_disassemble_finish (IdeDebugger *debugger,
}
static gboolean
-gbp_gdb_debugger_supports_runner (IdeDebugger *debugger,
- IdeRunner *runner,
- gint *priority)
+gbp_gdb_debugger_supports_run_command (IdeDebugger *debugger,
+ IdePipeline *pipeline,
+ IdeRunCommand *run_command,
+ int *priority)
{
- IdeRuntime *runtime;
-
g_assert (GBP_IS_GDB_DEBUGGER (debugger));
- g_assert (IDE_IS_RUNNER (runner));
+ g_assert (IDE_IS_PIPELINE (pipeline));
+ g_assert (IDE_IS_RUN_COMMAND (run_command));
g_assert (priority != NULL);
- runtime = ide_runner_get_runtime (runner);
-
- if (ide_runtime_contains_program_in_path (runtime, "gdb", NULL))
- {
- *priority = G_MAXINT;
- return TRUE;
- }
-
- g_debug ("Failed to locate gdb in runtime");
+ *priority = G_MAXINT;
- return FALSE;
+ return TRUE;
}
-static void
-gbp_gdb_debugger_prepare (IdeDebugger *debugger,
- IdeRunner *runner)
-{
- static const gchar *prepend_argv[] = { "gdb", "--interpreter=mi2", "--args" };
- const char *shell;
- GbpGdbDebugger *self = (GbpGdbDebugger *)debugger;
- IdeEnvironment *env;
- VtePty *pty;
+static gboolean
+gbp_gdb_debugger_run_context_handler_cb (IdeRunContext *run_context,
+ const char * const *argv,
+ const char * const *env,
+ const char *cwd,
+ IdeUnixFDMap *unix_fd_map,
+ gpointer user_data,
+ GError **error)
+{
+ static const char * const allowed_shells[] = { "/bin/sh", "sh", "/bin/bash", "bash", NULL };
+ GbpGdbDebugger *self = user_data;
+ g_autoptr(GIOStream) io_stream = NULL;
+ int pty_source_fd;
+ int pty_dest_fd;
IDE_ENTRY;
g_assert (GBP_IS_GDB_DEBUGGER (self));
- g_assert (IDE_IS_RUNNER (runner));
-
- env = ide_runner_get_environment (runner);
-
- /* Prepend arguments in reverse to preserve ordering */
- for (guint i = G_N_ELEMENTS (prepend_argv); i > 0; i--)
- ide_runner_prepend_argv (runner, prepend_argv [i-1]);
+ g_assert (IDE_IS_RUN_CONTEXT (run_context));
+ g_assert (argv != NULL);
+ g_assert (env != NULL);
+ g_assert (IDE_IS_UNIX_FD_MAP (unix_fd_map));
/* Override $SHELL unless it's sh or bash as that tends to break things
* like '$SHELL -c "exec $APP"' in gdb.
*/
- shell = ide_get_user_shell ();
- if (!ide_str_equal0 (shell, "/bin/sh") && !ide_str_equal0 (shell, "sh") &&
- !ide_str_equal0 (shell, "/bin/bash") && !ide_str_equal0 (shell, "bash"))
- ide_environment_setenv (env, "SHELL", "sh");
+ if (!g_strv_contains (allowed_shells, ide_get_user_shell ()))
+ ide_run_context_setenv (run_context, "SHELL", "sh");
- /* Connect to all our important signals */
- ide_signal_group_set_target (self->runner_signals, runner);
+ /* Specify GDB with mi2 wire protocol */
+ ide_run_context_append_argv (run_context, "gdb");
+ ide_run_context_append_argv (run_context, "--interpreter=mi2");
- /*
- * If there is a PTY device to display the contents of the inferior, then
- * we will create a new FD for that from the PTY and save it to map into
- * the inferior.
+ /* Steal the PTY for the inferior so we can assign it as another
+ * file-descriptor and map it to the inferior from GDB.
*/
- if ((pty = ide_runner_get_pty (runner)))
+ pty_source_fd = ide_unix_fd_map_steal_stdout (unix_fd_map);
+ g_warn_if_fail (pty_source_fd != -1);
+
+ /* Save the PTY fd around to attach after spawning */
+ pty_dest_fd = ide_unix_fd_map_get_max_dest_fd (unix_fd_map) + 1;
+ ide_unix_fd_map_take (unix_fd_map, ide_steal_fd (&pty_source_fd), pty_dest_fd);
+
+ /* Setup a stream to communicate with GDB over which is just a
+ * regular pipe[2] for stdin/stdout.
+ */
+ if (!(io_stream = ide_unix_fd_map_create_stream (unix_fd_map,
+ STDIN_FILENO, STDOUT_FILENO,
+ error)))
+ IDE_RETURN (FALSE);
+
+ /* Now merge the FD map down a layer */
+ if (!ide_run_context_merge_unix_fd_map (run_context, unix_fd_map, error))
+ IDE_RETURN (FALSE);
+
+ /* Now that we have a PTY, we need to make sure our first command is
+ * to set the PTY of the inferior to the FD of the PTY we attached.
+ */
+ ide_run_context_append_argv (run_context, "-ex");
+ ide_run_context_append_formatted (run_context,
+ "set inferior-tty /proc/self/fd/%d",
+ pty_dest_fd);
+
+ /* Set the CWD for the inferior but leave gdb untouched */
+ if (cwd != NULL)
{
- int master_fd = vte_pty_get_fd (pty);
- int tty_fd = ide_pty_intercept_create_slave (master_fd, TRUE);
+ ide_run_context_append_argv (run_context, "-ex");
+ ide_run_context_append_formatted (run_context, "set cwd %s", cwd);
+ }
- if (tty_fd != -1)
+ /* We don't want GDB to get the environment from this layer, so we specify
+ * a wrapper script to set the environment for the inferior only. That
+ * means that "show environment FOO" will not show anything, but the
+ * inferior will see "FOO".
+ */
+ if (env[0] != NULL)
+ {
+ g_autoptr(GString) str = g_string_new ("set exec-wrapper env");
+
+ for (guint i = 0; env[i]; i++)
{
- self->mapped_fd = ide_runner_take_fd (runner, tty_fd, -1);
- ide_runner_set_disable_pty (runner, TRUE);
+ g_autofree char *quoted = g_shell_quote (env[i]);
+
+ g_string_append_c (str, ' ');
+ g_string_append (str, quoted);
}
+
+ ide_run_context_append_argv (run_context, "-ex");
+ ide_run_context_append_argv (run_context, str->str);
}
- /* We need access to stdin/stdout for communicating with gdb */
- ide_runner_set_flags (runner, G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE |
G_SUBPROCESS_FLAGS_STDERR_SILENCE);
+ /* Now we can setup our command from the upper layer. Everything after
+ * this must be part of the inferior's arguments.
+ */
+ ide_run_context_append_argv (run_context, "--args");
+ ide_run_context_append_args (run_context, argv);
- IDE_EXIT;
+ /* Start communicating with gdb */
+ gbp_gdb_debugger_connect (self, io_stream, NULL);
+ ide_debugger_move_async (IDE_DEBUGGER (self),
+ IDE_DEBUGGER_MOVEMENT_START,
+ NULL, NULL, NULL);
+
+ IDE_RETURN (TRUE);
}
static void
-gbp_gdb_debugger_on_runner_spawned (GbpGdbDebugger *self,
- const gchar *identifier,
- IdeRunner *runner)
+gbp_gdb_debugger_prepare_for_run (IdeDebugger *debugger,
+ IdePipeline *pipeline,
+ IdeRunContext *run_context)
{
- g_autoptr(GIOStream) io_stream = NULL;
- g_autofree gchar *tty_command = NULL;
+ GbpGdbDebugger *self = (GbpGdbDebugger *)debugger;
IDE_ENTRY;
g_assert (GBP_IS_GDB_DEBUGGER (self));
- g_assert (identifier != NULL);
- g_assert (IDE_IS_RUNNER (runner));
+ g_assert (IDE_IS_PIPELINE (pipeline));
+ g_assert (IDE_IS_RUN_CONTEXT (run_context));
- /* Create an IOStream to track pipe communication with gdb */
- io_stream = g_simple_io_stream_new (ide_runner_get_stdout (runner),
- ide_runner_get_stdin (runner));
-
- /* Start communicating with gdb */
- gbp_gdb_debugger_connect (self, io_stream, NULL);
-
- /* Ask gdb to use our mapped in FD for the TTY when spawning the child */
- tty_command = g_strdup_printf ("-gdb-set inferior-tty /proc/self/fd/%d", self->mapped_fd);
- gbp_gdb_debugger_exec_async (self, tty_command, NULL, NULL, NULL);
-
- ide_debugger_move_async (IDE_DEBUGGER (self),
- IDE_DEBUGGER_MOVEMENT_START,
- NULL, NULL, NULL);
+ g_set_object (&self->current_runtime,
+ ide_pipeline_get_runtime (pipeline));
+ ide_run_context_push (run_context,
+ gbp_gdb_debugger_run_context_handler_cb,
+ g_object_ref (self),
+ g_object_unref);
IDE_EXIT;
}
@@ -2505,6 +2526,8 @@ gbp_gdb_debugger_dispose (GObject *object)
g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_clear_object (&self->current_runtime);
+
list = self->cmdqueue.head;
self->cmdqueue.head = NULL;
@@ -2567,8 +2590,8 @@ gbp_gdb_debugger_class_init (GbpGdbDebuggerClass *klass)
ide_object_class->parent_set = gbp_gdb_debugger_parent_set;
- debugger_class->supports_runner = gbp_gdb_debugger_supports_runner;
- debugger_class->prepare = gbp_gdb_debugger_prepare;
+ debugger_class->supports_run_command = gbp_gdb_debugger_supports_run_command;
+ debugger_class->prepare_for_run = gbp_gdb_debugger_prepare_for_run;
debugger_class->disassemble_async = gbp_gdb_debugger_disassemble_async;
debugger_class->disassemble_finish = gbp_gdb_debugger_disassemble_finish;
debugger_class->insert_breakpoint_async = gbp_gdb_debugger_insert_breakpoint_async;
@@ -2608,17 +2631,8 @@ gbp_gdb_debugger_init (GbpGdbDebugger *self)
self->parser = gdbwire_mi_parser_create (callbacks);
self->read_cancellable = g_cancellable_new ();
self->read_buffer = g_malloc (READ_BUFFER_LEN);
- self->mapped_fd = -1;
g_queue_init (&self->cmdqueue);
-
- self->runner_signals = ide_signal_group_new (IDE_TYPE_RUNNER);
-
- ide_signal_group_connect_object (self->runner_signals,
- "spawned",
- G_CALLBACK (gbp_gdb_debugger_on_runner_spawned),
- self,
- G_CONNECT_SWAPPED);
}
GbpGdbDebugger *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]