[gnome-builder] plugins/gdb: port to GTK 4
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] plugins/gdb: port to GTK 4
- Date: Tue, 12 Jul 2022 06:39:16 +0000 (UTC)
commit 1e3c6ec9d0bdd5d8e622bac3d196e345ffdd64d2
Author: Christian Hergert <chergert redhat com>
Date: Mon Jul 11 22:45:17 2022 -0700
plugins/gdb: port to GTK 4
- Use IdeRunContext and new IdeDebugger interface API
- Use IdeUnixFDMap to get FDs to pass along
- Improve signal dispatch and quit signal support
- Update .plugin
src/plugins/gdb/gbp-gdb-debugger.c | 225 ++++++++++++++++++++-----------------
src/plugins/gdb/gdb.plugin | 7 +-
2 files changed, 124 insertions(+), 108 deletions(-)
---
diff --git a/src/plugins/gdb/gbp-gdb-debugger.c b/src/plugins/gdb/gbp-gdb-debugger.c
index 52c6629b7..256344892 100644
--- a/src/plugins/gdb/gbp-gdb-debugger.c
+++ b/src/plugins/gdb/gbp-gdb-debugger.c
@@ -20,7 +20,6 @@
#define G_LOG_DOMAIN "gbp-gdb-debugger"
-#include <dazzle.h>
#include <libide-io.h>
#include <libide-terminal.h>
#include <string.h>
@@ -38,16 +37,10 @@ struct _GbpGdbDebugger
GCancellable *read_cancellable;
GHashTable *register_names;
GFile *builddir;
+ IdeRuntime *current_runtime;
- DzlSignalGroup *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;
@@ -117,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 = dzl_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.
*/
@@ -139,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);
}
@@ -665,6 +651,14 @@ gbp_gdb_debugger_handle_stopped (GbpGdbDebugger *self,
ide_debugger_emit_thread_selected (IDE_DEBUGGER (self), thread);
ide_debugger_emit_stopped (IDE_DEBUGGER (self), stop_reason, breakpoint);
+
+ /* Currently, we expect to have gdb exit with the program. We might change that
+ * at some point, but it's currently the expectation.
+ */
+ if (stop_reason == IDE_DEBUGGER_STOP_EXITED_SIGNALED ||
+ stop_reason == IDE_DEBUGGER_STOP_EXITED_NORMALLY ||
+ stop_reason == IDE_DEBUGGER_STOP_EXITED)
+ gbp_gdb_debugger_exec_async (self, "-gdb-exit", NULL, NULL, NULL);
}
static void
@@ -2322,112 +2316,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);
+ *priority = G_MAXINT;
- if (ide_runtime_contains_program_in_path (runtime, "gdb", NULL))
- {
- *priority = G_MAXINT;
- return TRUE;
- }
-
- g_debug ("Failed to locate gdb in runtime");
-
- 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 */
- dzl_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.
+ */
+ 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 ((pty = ide_runner_get_pty (runner)))
+ 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));
-
- /* 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));
+ g_assert (IDE_IS_PIPELINE (pipeline));
+ g_assert (IDE_IS_RUN_CONTEXT (run_context));
- /* 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;
}
@@ -2506,6 +2534,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;
@@ -2568,8 +2598,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;
@@ -2609,17 +2639,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 = dzl_signal_group_new (IDE_TYPE_RUNNER);
-
- dzl_signal_group_connect_object (self->runner_signals,
- "spawned",
- G_CALLBACK (gbp_gdb_debugger_on_runner_spawned),
- self,
- G_CONNECT_SWAPPED);
}
GbpGdbDebugger *
@@ -2801,8 +2822,6 @@ gbp_gdb_debugger_write_cb (GObject *object,
* This asynchronous function will complete when we have received a response
* from the debugger with the result, or the connection has closed. Whichever
* is first.
- *
- * Since: 3.32
*/
void
gbp_gdb_debugger_exec_async (GbpGdbDebugger *self,
@@ -2903,8 +2922,6 @@ gbp_gdb_debugger_exec_async (GbpGdbDebugger *self,
*
* Returns: a gdbwire_mi_output which should be freed with
* gdbwire_mi_output_free() when no longer in use.
- *
- * Since: 3.32
*/
struct gdbwire_mi_output *
gbp_gdb_debugger_exec_finish (GbpGdbDebugger *self,
diff --git a/src/plugins/gdb/gdb.plugin b/src/plugins/gdb/gdb.plugin
index 90600c78f..cd7a9f696 100644
--- a/src/plugins/gdb/gdb.plugin
+++ b/src/plugins/gdb/gdb.plugin
@@ -2,10 +2,9 @@
Authors=Christian Hergert <chergert redhat com>
Builtin=true
Copyright=Copyright © 2017-2018 Christian Hergert
-Depends=editor;terminal;buildui;debuggerui;
-Description=Provides integration with the GNU Debugger
+Description=Provides debugger integration with gdb
Embedded=_gbp_gdb_register_types
-Hidden=true
Module=gdb
-Name=Gdb
+Name=GNU Debugger
+X-Category=debuggers
X-Debugger-Languages=c,chdr,cpp,cpphdr,fortran,rust,vala,asm
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]