[gnome-builder/wip/chergert/debugger] gdb: port plugin to C
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger] gdb: port plugin to C
- Date: Sun, 26 Mar 2017 02:44:21 +0000 (UTC)
commit 270e9e98bbc8ef766970e302b515a23818fe9ea1
Author: Christian Hergert <chergert redhat com>
Date: Sat Mar 25 19:43:48 2017 -0700
gdb: port plugin to C
Python was fine for some prototyping, but the G-I issues are slowing down
my ability to iterate quickly. So I guess we'll just do this plugin in C.
I was hoping to use this one as an example, but I guess we'll just do a
mock debugger to show people how to do it.
configure.ac | 2 +
plugins/Makefile.am | 1 +
plugins/gdb/Makefile.am | 29 ++++
plugins/gdb/configure.ac | 12 ++
plugins/gdb/gbp-gdb-debugger.c | 357 ++++++++++++++++++++++++++++++++++++++++
plugins/gdb/gbp-gdb-debugger.h | 32 ++++
plugins/gdb/gbp-gdb-plugin.c | 27 +++
plugins/gdb/gdb.plugin | 3 +-
plugins/gdb/gdb_plugin.py | 141 ----------------
plugins/gdb/meson.build | 23 +++
plugins/meson.build | 1 +
11 files changed, 485 insertions(+), 143 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 2e331c7..bb67b53 100644
--- a/configure.ac
+++ b/configure.ac
@@ -308,6 +308,7 @@ m4_include([plugins/file-search/configure.ac])
m4_include([plugins/flatpak/configure.ac])
m4_include([plugins/fpaste/configure.ac])
m4_include([plugins/gcc/configure.ac])
+m4_include([plugins/gdb/configure.ac])
m4_include([plugins/gettext/configure.ac])
m4_include([plugins/git/configure.ac])
m4_include([plugins/gnome-code-assistance/configure.ac])
@@ -594,6 +595,7 @@ echo " Editorconfig ......................... : ${enable_editorconfig}"
echo " Flatpak .............................. : ${enable_flatpak_plugin}"
echo " Fpaste.org ........................... : ${enable_fpaste_plugin}"
echo " GCC .................................. : ${enable_gcc_plugin}"
+echo " GDB .................................. : ${enable_gdb_plugin}"
echo " Gettext .............................. : ${enable_gettext_plugin}"
echo " Git Version Control .................. : ${enable_git_plugin}"
echo " Global File Search ................... : ${enable_file_search_plugin}"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index c6347b7..b5cffb3 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -17,6 +17,7 @@ SUBDIRS = \
flatpak \
fpaste \
gcc \
+ gdb \
gettext \
git \
gnome-code-assistance \
diff --git a/plugins/gdb/Makefile.am b/plugins/gdb/Makefile.am
new file mode 100644
index 0000000..4489429
--- /dev/null
+++ b/plugins/gdb/Makefile.am
@@ -0,0 +1,29 @@
+if ENABLE_GDB_PLUGIN
+
+EXTRA_DIST = $(plugin_DATA)
+
+plugindir = $(libdir)/gnome-builder/plugins
+plugin_LTLIBRARIES = libgdb-plugin.la
+dist_plugin_DATA = gdb.plugin
+
+libgdb_plugin_la_SOURCES = \
+ gbp-gdb-debugger.c \
+ gbp-gdb-debugger.h \
+ gbp-gdb-plugin.c \
+ $(NULL)
+
+libgdb_plugin_la_CFLAGS = \
+ $(PLUGIN_CFLAGS) \
+ -I$(top_srcdir)/contrib/mi2 \
+ $(NULL)
+
+libgdb_plugin_la_LDFLAGS = \
+ $(PLUGIN_LDFLAGS) \
+ $(top_builddir)/contrib/mi2/libmi2-glib.la \
+ $(NULL)
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/gdb/configure.ac b/plugins/gdb/configure.ac
new file mode 100644
index 0000000..415a4e5
--- /dev/null
+++ b/plugins/gdb/configure.ac
@@ -0,0 +1,12 @@
+# --enable-gdb-plugin=yes/no
+AC_ARG_ENABLE([gdb-plugin],
+ [AS_HELP_STRING([--enable-gdb-plugin=@<:@yes/no@:>@],
+ [Build with support for searching files in global search.])],
+ [enable_gdb_plugin=$enableval],
+ [enable_gdb_plugin=yes])
+
+# for if ENABLE_GDB_PLUGIN in Makefile.am
+AM_CONDITIONAL(ENABLE_GDB_PLUGIN, test x$enable_gdb_plugin != xno)
+
+# Ensure our makefile is generated by autoconf
+AC_CONFIG_FILES([plugins/gdb/Makefile])
diff --git a/plugins/gdb/gbp-gdb-debugger.c b/plugins/gdb/gbp-gdb-debugger.c
new file mode 100644
index 0000000..001992b
--- /dev/null
+++ b/plugins/gdb/gbp-gdb-debugger.c
@@ -0,0 +1,357 @@
+/* gbp-gdb-debugger.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-gdb-plugin"
+
+#include <glib/gi18n.h>
+#include <egg-signal-group.h>
+#include <mi2-glib.h>
+
+#include "gbp-gdb-debugger.h"
+
+struct _GbpGdbDebugger
+{
+ IdeObject parent;
+ Mi2Client *client;
+ EggSignalGroup *client_signals;
+ IdeRunner *runner;
+ EggSignalGroup *runner_signals;
+ gint mapped_fd;
+};
+
+enum {
+ PROP_0,
+ PROP_CAN_STEP_IN,
+ PROP_CAN_STEP_OVER,
+ PROP_CAN_CONTINUE,
+ N_PROPS
+};
+
+/* Globals */
+static GParamSpec *properties [N_PROPS];
+
+/* Forward Declarations */
+static void debugger_iface_init (IdeDebuggerInterface *iface);
+static void gbp_gdb_debugger_finalize (GObject *object);
+static gchar *gbp_gdb_debugger_get_name (IdeDebugger *debugger);
+static void gbp_gdb_debugger_prepare (IdeDebugger *debugger,
+ IdeRunner *runner);
+static gboolean gbp_gdb_debugger_supports_runner (IdeDebugger *debugger,
+ IdeRunner *runner,
+ gint *priority);
+static void gbp_gdb_debugger_on_runner_spawned (GbpGdbDebugger *self,
+ const gchar *identifier,
+ IdeRunner *runner);
+static void gbp_gdb_debugger_on_runner_exited (GbpGdbDebugger *self,
+ IdeRunner *runner);
+static void gbp_gdb_debugger_on_client_breakpoint_inserted (GbpGdbDebugger *self,
+ Mi2Breakpoint *breakpoint,
+ Mi2Client *client);
+static void gbp_gdb_debugger_on_client_breakpoint_removed (GbpGdbDebugger *self,
+ gint breakpoint_id,
+ Mi2Client *client);
+static void gbp_gdb_debugger_on_client_event (GbpGdbDebugger *self,
+ Mi2EventMessage *message,
+ Mi2Client *client);
+static void gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
+ Mi2StopReason reason,
+ Mi2EventMessage *message,
+ Mi2Client *client);
+static void gbp_gdb_debugger_on_client_log (GbpGdbDebugger *self,
+ const gchar *message,
+ Mi2Client *client);
+
+/* Type initialization */
+G_DEFINE_TYPE_WITH_CODE (GbpGdbDebugger, gbp_gdb_debugger, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_DEBUGGER, debugger_iface_init))
+
+static gchar *
+gbp_gdb_debugger_get_name (IdeDebugger *debugger)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (debugger));
+
+ return g_strdup (_("GNU Debugger"));
+}
+
+static gboolean
+gbp_gdb_debugger_supports_runner (IdeDebugger *debugger,
+ IdeRunner *runner,
+ gint *priority)
+{
+ IdeRuntime *runtime;
+
+ g_assert (IDE_IS_DEBUGGER (debugger));
+ g_assert (IDE_IS_RUNNER (runner));
+ 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;
+ }
+
+ return FALSE;
+}
+
+static void
+gbp_gdb_debugger_prepare (IdeDebugger *debugger,
+ IdeRunner *runner)
+{
+ static gchar *prepend_argv[] = { "gdb", "--interpreter", "mi2", "--args" };
+ GbpGdbDebugger *self = (GbpGdbDebugger *)debugger;
+ int tty_fd;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (IDE_IS_RUNNER (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]);
+
+ /* Connect to all our important signals */
+ egg_signal_group_set_target (self->runner_signals, runner);
+
+ /*
+ * We steal and remap the PTY fd into the process so that gdb does not get
+ * the controlling terminal, but instead allow us to ask gdb to setup the
+ * inferrior with that same PTY.
+ */
+ if (-1 != (tty_fd = ide_runner_steal_tty (runner)))
+ self->mapped_fd = ide_runner_take_fd (runner, tty_fd, -1);
+
+ /* 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);
+
+ IDE_EXIT;
+}
+
+static void
+debugger_iface_init (IdeDebuggerInterface *iface)
+{
+ iface->get_name = gbp_gdb_debugger_get_name;
+ iface->prepare = gbp_gdb_debugger_prepare;
+ iface->supports_runner = gbp_gdb_debugger_supports_runner;
+}
+
+static void
+gbp_gdb_debugger_on_runner_spawned (GbpGdbDebugger *self,
+ const gchar *identifier,
+ IdeRunner *runner)
+{
+ g_autoptr(GIOStream) io_stream = NULL;
+ g_autofree gchar *inferior_command = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (self->client == NULL);
+ 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));
+
+ /* Setup our mi2 client to RPC to gdb */
+ self->client = mi2_client_new (io_stream);
+
+ /* Connect to all our signals up front necessary to control gdb */
+ egg_signal_group_set_target (self->client_signals, self->client);
+
+ /* Now ask the mi2 client to start procesing data */
+ mi2_client_listen_async (self->client, NULL, NULL, NULL);
+
+ /* Ask gdb to use our mapped in FD for the TTY when spawning the child */
+ inferior_command = g_strdup_printf ("-gdb-set inferrior-tty /proc/self/fd/%d", self->mapped_fd);
+ mi2_client_exec_async (self->client, inferior_command, NULL, NULL, NULL);
+
+ /* Now ask gdb to start running the program */
+ mi2_client_run_async (self->client, NULL, NULL, NULL);
+
+ IDE_EXIT;
+}
+
+static void
+gbp_gdb_debugger_on_runner_exited (GbpGdbDebugger *self,
+ IdeRunner *runner)
+{
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (IDE_IS_RUNNER (runner));
+
+ IDE_EXIT;
+}
+
+static void
+gbp_gdb_debugger_on_client_breakpoint_inserted (GbpGdbDebugger *self,
+ Mi2Breakpoint *breakpoint,
+ Mi2Client *client)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (MI2_IS_BREAKPOINT (breakpoint));
+ g_assert (MI2_IS_CLIENT (client));
+
+}
+
+static void
+gbp_gdb_debugger_on_client_breakpoint_removed (GbpGdbDebugger *self,
+ gint breakpoint_id,
+ Mi2Client *client)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (breakpoint_id > 0);
+ g_assert (MI2_IS_CLIENT (client));
+
+}
+
+static void
+gbp_gdb_debugger_on_client_event (GbpGdbDebugger *self,
+ Mi2EventMessage *message,
+ Mi2Client *client)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (MI2_IS_EVENT_MESSAGE (message));
+ g_assert (MI2_IS_CLIENT (client));
+
+}
+
+static void
+gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
+ Mi2StopReason reason,
+ Mi2EventMessage *message,
+ Mi2Client *client)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (MI2_IS_EVENT_MESSAGE (message));
+ g_assert (MI2_IS_CLIENT (client));
+
+}
+
+static void
+gbp_gdb_debugger_on_client_log (GbpGdbDebugger *self,
+ const gchar *message,
+ Mi2Client *client)
+{
+ g_assert (GBP_IS_GDB_DEBUGGER (self));
+ g_assert (message != NULL);
+ g_assert (MI2_IS_CLIENT (client));
+
+}
+
+static void
+gbp_gdb_debugger_finalize (GObject *object)
+{
+ GbpGdbDebugger *self = (GbpGdbDebugger *)object;
+
+ g_clear_object (&self->client_signals);
+ g_clear_object (&self->client);
+ g_clear_object (&self->runner_signals);
+ g_clear_object (&self->runner);
+
+ G_OBJECT_CLASS (gbp_gdb_debugger_parent_class)->finalize (object);
+}
+
+static void
+gbp_gdb_debugger_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_CAN_STEP_IN:
+ case PROP_CAN_STEP_OVER:
+ case PROP_CAN_CONTINUE:
+ g_value_set_boolean (value, FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_gdb_debugger_class_init (GbpGdbDebuggerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gbp_gdb_debugger_finalize;
+ object_class->get_property = gbp_gdb_debugger_get_property;
+
+#define REGISTER_BOOLEAN(NAME, name) \
+ properties [NAME] = g_param_spec_boolean (name, NULL, NULL, FALSE, \
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)
+
+ REGISTER_BOOLEAN (PROP_CAN_STEP_IN, "can-step-in");
+ REGISTER_BOOLEAN (PROP_CAN_STEP_OVER, "can-step-over");
+ REGISTER_BOOLEAN (PROP_CAN_CONTINUE, "can-continue");
+
+#undef REGISTER_BOOLEAN
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_gdb_debugger_init (GbpGdbDebugger *self)
+{
+ self->runner_signals = egg_signal_group_new (IDE_TYPE_RUNNER);
+
+ egg_signal_group_connect_object (self->runner_signals,
+ "spawned",
+ G_CALLBACK (gbp_gdb_debugger_on_runner_spawned),
+ self,
+ G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->runner_signals,
+ "exited",
+ G_CALLBACK (gbp_gdb_debugger_on_runner_exited),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->client_signals = egg_signal_group_new (MI2_TYPE_CLIENT);
+
+ egg_signal_group_connect_object (self->runner_signals,
+ "breakpoint-inserted",
+ G_CALLBACK (gbp_gdb_debugger_on_client_breakpoint_inserted),
+ self,
+ G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->runner_signals,
+ "breakpoint-removed",
+ G_CALLBACK (gbp_gdb_debugger_on_client_breakpoint_removed),
+ self,
+ G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->runner_signals,
+ "event",
+ G_CALLBACK (gbp_gdb_debugger_on_client_event),
+ self,
+ G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->runner_signals,
+ "stopped",
+ G_CALLBACK (gbp_gdb_debugger_on_client_stopped),
+ self,
+ G_CONNECT_SWAPPED);
+ egg_signal_group_connect_object (self->runner_signals,
+ "log",
+ G_CALLBACK (gbp_gdb_debugger_on_client_log),
+ self,
+ G_CONNECT_SWAPPED);
+}
diff --git a/plugins/gdb/gbp-gdb-debugger.h b/plugins/gdb/gbp-gdb-debugger.h
new file mode 100644
index 0000000..3be86d7
--- /dev/null
+++ b/plugins/gdb/gbp-gdb-debugger.h
@@ -0,0 +1,32 @@
+/* gbp-gdb-debugger.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GBP_GDB_DEBUGGER_H
+#define GBP_GDB_DEBUGGER_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GDB_DEBUGGER (gbp_gdb_debugger_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGdbDebugger, gbp_gdb_debugger, GBP, GDB_DEBUGGER, IdeObject)
+
+G_END_DECLS
+
+#endif /* GBP_GDB_DEBUGGER_H */
diff --git a/plugins/gdb/gbp-gdb-plugin.c b/plugins/gdb/gbp-gdb-plugin.c
new file mode 100644
index 0000000..8a721e4
--- /dev/null
+++ b/plugins/gdb/gbp-gdb-plugin.c
@@ -0,0 +1,27 @@
+/* gbp-gdb-plugin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ide.h>
+
+#include "gbp-gdb-debugger.h"
+
+void
+peas_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module, IDE_TYPE_DEBUGGER, GBP_TYPE_GDB_DEBUGGER);
+}
diff --git a/plugins/gdb/gdb.plugin b/plugins/gdb/gdb.plugin
index 50aa598..96aea9d 100644
--- a/plugins/gdb/gdb.plugin
+++ b/plugins/gdb/gdb.plugin
@@ -1,6 +1,5 @@
[Plugin]
-Module=gdb_plugin
-Loader=python3
+Module=gdb-plugin
Name=Gdb
Description=Provides integration with the GNU Debugger
Authors=Christian Hergert <chergert redhat com>
diff --git a/plugins/gdb/meson.build b/plugins/gdb/meson.build
new file mode 100644
index 0000000..b494068
--- /dev/null
+++ b/plugins/gdb/meson.build
@@ -0,0 +1,23 @@
+if get_option('with_gdb')
+
+gdb_sources = [
+ 'gbp-gdb-debugger.c',
+ 'gbp-gdb-debugger.h',
+ 'gbp-gdb-plugin.c',
+]
+
+gdb_deps = plugin_deps + [
+ libmi2_glib_dep,
+]
+
+shared_module('gdb-plugin', gdb_sources,
+ dependencies: gdb_deps,
+ link_args: plugin_link_args,
+ link_depends: plugin_link_deps,
+ install: true,
+ install_dir: plugindir,
+)
+
+install_data('gdb.plugin', install_dir: plugindir)
+
+endif
diff --git a/plugins/meson.build b/plugins/meson.build
index c7ddc37..8892925 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -28,6 +28,7 @@ subdir('file-search')
subdir('flatpak')
subdir('fpaste')
subdir('gcc')
+subdir('gdb')
subdir('gettext')
subdir('git')
subdir('gnome-code-assistance')
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]