[gnome-builder/wip/gtk4-port: 1628/1774] libide/debugger: refactor debugger interface




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]