[gnome-builder/wip/chergert/bug1: 5/42] debugger: add IdeDebugManager
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/bug1: 5/42] debugger: add IdeDebugManager
- Date: Wed, 30 Aug 2017 06:30:07 +0000 (UTC)
commit b6f11ed8b3f24057346bb4605f9dee4b520ae8d1
Author: Christian Hergert <chergert redhat com>
Date: Thu Aug 24 21:30:56 2017 -0700
debugger: add IdeDebugManager
The debug manager is a helper for us to bind the IdeDebugger plugin
class to the run handler system.
libide/debugger/ide-debug-manager.c | 389 +++++++++++++++++++++++++++++++++++
libide/debugger/ide-debug-manager.h | 35 +++
libide/debugger/ide-debugger.c | 50 +++++-
libide/debugger/ide-debugger.h | 35 +++-
libide/ide-context.c | 22 ++
libide/ide.h | 1 +
libide/meson.build | 2 +
7 files changed, 522 insertions(+), 12 deletions(-)
---
diff --git a/libide/debugger/ide-debug-manager.c b/libide/debugger/ide-debug-manager.c
new file mode 100644
index 0000000..ee7f6a9
--- /dev/null
+++ b/libide/debugger/ide-debug-manager.c
@@ -0,0 +1,389 @@
+/* ide-debug-manager.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 "ide-debug-manager"
+
+#include <dazzle.h>
+#include <glib/gi18n.h>
+
+#include "ide-debug.h"
+
+#include "debugger/ide-debug-manager.h"
+#include "debugger/ide-debugger.h"
+#include "plugins/ide-extension-util.h"
+#include "runner/ide-runner.h"
+
+struct _IdeDebugManager
+{
+ IdeObject parent_instance;
+
+ IdeDebugger *debugger;
+ DzlBindingGroup *debugger_bindings;
+ DzlSignalGroup *debugger_signals;
+ IdeRunner *runner;
+
+ guint active : 1;
+};
+
+typedef struct
+{
+ IdeDebugger *debugger;
+ IdeRunner *runner;
+ gint priority;
+} DebuggerLookup;
+
+enum {
+ PROP_0,
+ PROP_ACTIVE,
+ PROP_DEBUGGER,
+ N_PROPS
+};
+
+enum {
+ BREAKPOINT_ADDED,
+ BREAKPOINT_REMOVED,
+ BREAKPOINT_REACHED,
+ N_SIGNALS
+};
+
+static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
+
+G_DEFINE_TYPE (IdeDebugManager, ide_debug_manager, IDE_TYPE_OBJECT)
+
+static void
+ide_debug_manager_set_active (IdeDebugManager *self,
+ gboolean active)
+{
+ g_assert (IDE_IS_DEBUG_MANAGER (self));
+
+ active = !!active;
+
+ if (active != self->active)
+ {
+ self->active = active;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ACTIVE]);
+ }
+}
+
+static void
+ide_debug_manager_debugger_stopped (IdeDebugManager *self,
+ IdeDebuggerStopReason stop_reason,
+ IdeDebuggerBreakpoint *breakpoint,
+ IdeDebugger *debugger)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEBUG_MANAGER (self));
+ g_assert (IDE_IS_DEBUGGER_STOP_REASON (stop_reason));
+ g_assert (!breakpoint || IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
+ g_assert (IDE_IS_DEBUGGER (debugger));
+
+ switch (stop_reason)
+ {
+ case IDE_DEBUGGER_STOP_EXITED:
+ case IDE_DEBUGGER_STOP_EXITED_NORMALLY:
+ case IDE_DEBUGGER_STOP_EXITED_SIGNALED:
+ /* Cleanup any lingering debugger process */
+ if (self->runner != NULL)
+ ide_runner_force_quit (self->runner);
+ break;
+
+ case IDE_DEBUGGER_STOP_BREAKPOINT_HIT:
+ case IDE_DEBUGGER_STOP_FUNCTION_FINISHED:
+ case IDE_DEBUGGER_STOP_LOCATION_REACHED:
+ case IDE_DEBUGGER_STOP_SIGNAL_RECEIVED:
+ case IDE_DEBUGGER_STOP_CATCH:
+ case IDE_DEBUGGER_STOP_UNKNOWN:
+ if (breakpoint != NULL)
+ {
+ IDE_TRACE_MSG ("Emitting breakpoint-reached");
+ g_signal_emit (self, signals [BREAKPOINT_REACHED], 0, breakpoint);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ IDE_EXIT;
+}
+
+static void
+ide_debug_manager_finalize (GObject *object)
+{
+ IdeDebugManager *self = (IdeDebugManager *)object;
+
+ g_clear_object (&self->debugger);
+ g_clear_object (&self->debugger_bindings);
+ g_clear_object (&self->debugger_signals);
+ g_clear_object (&self->runner);
+
+ G_OBJECT_CLASS (ide_debug_manager_parent_class)->finalize (object);
+}
+
+static void
+ide_debug_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDebugManager *self = IDE_DEBUG_MANAGER (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, self->active);
+ break;
+
+ case PROP_DEBUGGER:
+ g_value_set_object (value, self->debugger);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_debug_manager_class_init (IdeDebugManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_debug_manager_finalize;
+ object_class->get_property = ide_debug_manager_get_property;
+
+ /**
+ * IdeDebugManager:active:
+ *
+ * If the debugger is active.
+ *
+ * This can be used to determine if the controls should be made visible
+ * in the workbench.
+ */
+ properties [PROP_ACTIVE] =
+ g_param_spec_boolean ("active",
+ "Active",
+ "If the debugger is running",
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_DEBUGGER] =
+ g_param_spec_object ("debugger",
+ "Debugger",
+ "The current debugger being used",
+ IDE_TYPE_DEBUGGER,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ signals [BREAKPOINT_ADDED] =
+ g_signal_new ("breakpoint-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
+
+ signals [BREAKPOINT_REMOVED] =
+ g_signal_new ("breakpoint-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
+
+ signals [BREAKPOINT_REACHED] =
+ g_signal_new ("breakpoint-reached",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
+}
+
+static void
+ide_debug_manager_init (IdeDebugManager *self)
+{
+ self->debugger_signals = dzl_signal_group_new (IDE_TYPE_DEBUGGER);
+
+ dzl_signal_group_connect_object (self->debugger_signals,
+ "stopped",
+ G_CALLBACK (ide_debug_manager_debugger_stopped),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+debugger_lookup (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ DebuggerLookup *lookup = user_data;
+ IdeDebugger *debugger = (IdeDebugger *)exten;
+ gint priority = G_MAXINT;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_DEBUGGER (debugger));
+ g_assert (lookup != NULL);
+
+ if (ide_debugger_supports_runner (debugger, lookup->runner, &priority))
+ {
+ if (lookup->debugger == NULL || priority < lookup->priority)
+ {
+ g_set_object (&lookup->debugger, debugger);
+ lookup->priority = priority;
+ }
+ }
+}
+
+/**
+ * ide_debug_manager_find_debugger:
+ * @self: a #IdeDebugManager
+ * @runner: An #IdeRunner
+ *
+ * Locates a debugger for the given runner, or %NULL if no debugger
+ * supports the runner.
+ *
+ * Returns: (transfer full) (nullable): An #IdeDebugger or %NULL
+ */
+IdeDebugger *
+ide_debug_manager_find_debugger (IdeDebugManager *self,
+ IdeRunner *runner)
+{
+ g_autoptr(PeasExtensionSet) set = NULL;
+ IdeContext *context;
+ DebuggerLookup lookup;
+
+ g_return_val_if_fail (IDE_IS_DEBUG_MANAGER (self), NULL);
+ g_return_val_if_fail (IDE_IS_RUNNER (runner), NULL);
+
+ context = ide_object_get_context (IDE_OBJECT (runner));
+
+ lookup.debugger = NULL;
+ lookup.runner = runner;
+ lookup.priority = G_MAXINT;
+
+ set = ide_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_DEBUGGER,
+ "context", context,
+ NULL);
+
+ peas_extension_set_foreach (set, debugger_lookup, &lookup);
+
+ return lookup.debugger;
+}
+
+static void
+ide_debug_manager_runner_exited (IdeDebugManager *self,
+ IdeRunner *runner)
+{
+ g_assert (IDE_IS_DEBUG_MANAGER (self));
+ g_assert (IDE_IS_RUNNER (runner));
+
+ g_clear_object (&self->runner);
+ g_clear_object (&self->debugger);
+
+ ide_debug_manager_set_active (self, FALSE);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUGGER]);
+}
+
+/**
+ * ide_debug_manager_start:
+ * @self: an #IdeDebugManager
+ * @runner: an #IdeRunner
+ * @error: A location for an @error
+ *
+ * Attempts to start a runner using a discovered debugger backend.
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ */
+gboolean
+ide_debug_manager_start (IdeDebugManager *self,
+ IdeRunner *runner,
+ GError **error)
+{
+ g_autoptr(IdeDebugger) debugger = NULL;
+ gboolean ret = FALSE;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_DEBUG_MANAGER (self), FALSE);
+ g_return_val_if_fail (IDE_IS_RUNNER (runner), FALSE);
+
+ debugger = ide_debug_manager_find_debugger (self, runner);
+
+ if (debugger == NULL)
+ {
+ ide_runner_set_failed (runner, TRUE);
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("A suitable debugger could not be found."));
+ IDE_GOTO (failure);
+ }
+
+ ide_debugger_prepare (debugger, runner);
+
+ g_signal_connect_object (runner,
+ "exited",
+ G_CALLBACK (ide_debug_manager_runner_exited),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->runner = g_object_ref (runner);
+ self->debugger = g_steal_pointer (&debugger);
+
+ dzl_binding_group_set_source (self->debugger_bindings, self->debugger);
+ dzl_signal_group_set_target (self->debugger_signals, self->debugger);
+
+ ide_debug_manager_set_active (self, TRUE);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUGGER]);
+
+ ret = TRUE;
+
+failure:
+ IDE_RETURN (ret);
+}
+
+void
+ide_debug_manager_stop (IdeDebugManager *self)
+{
+ g_return_if_fail (IDE_IS_DEBUG_MANAGER (self));
+
+ dzl_binding_group_set_source (self->debugger_bindings, NULL);
+ dzl_signal_group_set_target (self->debugger_signals, NULL);
+
+ if (self->runner != NULL)
+ {
+ ide_runner_force_quit (self->runner);
+ g_clear_object (&self->runner);
+ }
+
+ g_clear_object (&self->debugger);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUGGER]);
+}
+
+gboolean
+ide_debug_manager_get_active (IdeDebugManager *self)
+{
+ g_return_val_if_fail (IDE_IS_DEBUG_MANAGER (self), FALSE);
+
+ return self->active;
+}
diff --git a/libide/debugger/ide-debug-manager.h b/libide/debugger/ide-debug-manager.h
new file mode 100644
index 0000000..e0bdbf7
--- /dev/null
+++ b/libide/debugger/ide-debug-manager.h
@@ -0,0 +1,35 @@
+/* ide-debug-manager.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/>.
+ */
+
+#pragma once
+
+#include "ide-object.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_DEBUG_MANAGER (ide_debug_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeDebugManager, ide_debug_manager, IDE, DEBUG_MANAGER, IdeObject)
+
+gboolean ide_debug_manager_get_active (IdeDebugManager *self);
+gboolean ide_debug_manager_start (IdeDebugManager *self,
+ IdeRunner *runner,
+ GError **error);
+void ide_debug_manager_stop (IdeDebugManager *self);
+
+G_END_DECLS
diff --git a/libide/debugger/ide-debugger.c b/libide/debugger/ide-debugger.c
index 7ebf0f5..05b3eb3 100644
--- a/libide/debugger/ide-debugger.c
+++ b/libide/debugger/ide-debugger.c
@@ -50,7 +50,7 @@ typedef struct
guint is_running : 1;
} IdeDebuggerPrivate;
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (IdeDebugger, ide_debugger, G_TYPE_OBJECT,
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (IdeDebugger, ide_debugger, IDE_TYPE_OBJECT,
G_ADD_PRIVATE (IdeDebugger)
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
_ide_debugger_class_init_actions))
@@ -1946,3 +1946,51 @@ ide_debugger_disassemble_finish (IdeDebugger *self,
return IDE_DEBUGGER_GET_CLASS (self)->disassemble_finish (self, result, error);
}
+
+/**
+ * ide_debugger_supports_runner:
+ * @self: an #IdeDebugger
+ * @runner: an #IdeRunner
+ * @priority: (out): A location for a priority
+ *
+ * Checks if the debugger supports a given runner. The debugger may need
+ * to check if the binary type matches it's expectation.
+ *
+ * Returns: %TRUE if the #IdeDebugger supports the runner.
+ */
+gboolean
+ide_debugger_supports_runner (IdeDebugger *self,
+ IdeRunner *runner,
+ gint *priority)
+{
+ gint dummy = 0;
+
+ g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
+ g_return_val_if_fail (IDE_IS_RUNNER (runner), FALSE);
+
+ if (priority == NULL)
+ priority = &dummy;
+ else
+ *priority = 0;
+
+ return IDE_DEBUGGER_GET_CLASS (self)->supports_runner (self, runner, priority);
+}
+
+/**
+ * ide_debugger_prepare:
+ * @self: an #IdeDebugger
+ * @runner: an #IdeRunner
+ *
+ * Prepares the runner to launch a debugger and target process.
+ *
+ * Since: 3.26
+ */
+void
+ide_debugger_prepare (IdeDebugger *self,
+ IdeRunner *runner)
+{
+ g_return_if_fail (IDE_IS_DEBUGGER (self));
+ g_return_if_fail (IDE_IS_RUNNER (runner));
+
+ IDE_DEBUGGER_GET_CLASS (self)->prepare (self, runner);
+}
diff --git a/libide/debugger/ide-debugger.h b/libide/debugger/ide-debugger.h
index c24fa1e..335fc6d 100644
--- a/libide/debugger/ide-debugger.h
+++ b/libide/debugger/ide-debugger.h
@@ -20,25 +20,28 @@
#include <gio/gio.h>
-#include "ide-debugger-breakpoint.h"
-#include "ide-debugger-frame.h"
-#include "ide-debugger-instruction.h"
-#include "ide-debugger-library.h"
-#include "ide-debugger-register.h"
-#include "ide-debugger-thread-group.h"
-#include "ide-debugger-thread.h"
-#include "ide-debugger-types.h"
-#include "ide-debugger-variable.h"
+#include "ide-object.h"
+
+#include "debugger/ide-debugger-breakpoint.h"
+#include "debugger/ide-debugger-frame.h"
+#include "debugger/ide-debugger-instruction.h"
+#include "debugger/ide-debugger-library.h"
+#include "debugger/ide-debugger-register.h"
+#include "debugger/ide-debugger-thread-group.h"
+#include "debugger/ide-debugger-thread.h"
+#include "debugger/ide-debugger-types.h"
+#include "debugger/ide-debugger-variable.h"
+#include "runner/ide-runner.h"
G_BEGIN_DECLS
#define IDE_TYPE_DEBUGGER (ide_debugger_get_type())
-G_DECLARE_DERIVABLE_TYPE (IdeDebugger, ide_debugger, IDE, DEBUGGER, GObject)
+G_DECLARE_DERIVABLE_TYPE (IdeDebugger, ide_debugger, IDE, DEBUGGER, IdeObject)
struct _IdeDebuggerClass
{
- GObjectClass parent_class;
+ IdeObjectClass parent_class;
/* Signals */
@@ -76,6 +79,11 @@ struct _IdeDebuggerClass
/* Virtual Functions */
+ gboolean (*supports_runner) (IdeDebugger *self,
+ IdeRunner *runner,
+ gint *priority);
+ void (*prepare) (IdeDebugger *self,
+ IdeRunner *runner);
gboolean (*get_can_move) (IdeDebugger *self,
IdeDebuggerMovement movement);
void (*move_async) (IdeDebugger *self,
@@ -210,6 +218,11 @@ struct _IdeDebuggerClass
gpointer _reserved32;
};
+gboolean ide_debugger_supports_runner (IdeDebugger *self,
+ IdeRunner *runner,
+ gint *priority);
+void ide_debugger_prepare (IdeDebugger *self,
+ IdeRunner *runner);
GListModel *ide_debugger_get_breakpoints (IdeDebugger *self);
const gchar *ide_debugger_get_display_name (IdeDebugger *self);
void ide_debugger_set_display_name (IdeDebugger *self,
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 0f1166e..fa62cbe 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -36,6 +36,7 @@
#include "buildsystem/ide-build-system-discovery.h"
#include "buildsystem/ide-configuration-manager.h"
#include "diagnostics/ide-diagnostics-manager.h"
+#include "debugger/ide-debug-manager.h"
#include "devices/ide-device-manager.h"
#include "doap/ide-doap.h"
#include "history/ide-back-forward-list-private.h"
@@ -69,6 +70,7 @@ struct _IdeContext
IdeBuildSystem *build_system;
gchar *build_system_hint;
IdeConfigurationManager *configuration_manager;
+ IdeDebugManager *debug_manager;
IdeDiagnosticsManager *diagnostics_manager;
IdeDeviceManager *device_manager;
IdeDoap *doap;
@@ -848,6 +850,10 @@ ide_context_init (IdeContext *self)
"context", self,
NULL);
+ self->debug_manager = g_object_new (IDE_TYPE_DEBUG_MANAGER,
+ "context", self,
+ NULL);
+
self->diagnostics_manager = g_object_new (IDE_TYPE_DIAGNOSTICS_MANAGER,
"context", self,
NULL);
@@ -2480,3 +2486,19 @@ ide_context_get_diagnostics_manager (IdeContext *self)
return self->diagnostics_manager;
}
+
+/**
+ * ide_context_get_debug_manager:
+ * @self: An #IdeContext
+ *
+ * Gets the debug manager for the context.
+ *
+ * Returns: (transfer none): An #IdeDebugManager
+ */
+IdeDebugManager *
+ide_context_get_debug_manager (IdeContext *self)
+{
+ g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
+
+ return self->debug_manager;
+}
diff --git a/libide/ide.h b/libide/ide.h
index 9fddea0..aa13aab 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -62,6 +62,7 @@ G_BEGIN_DECLS
#include "buildsystem/ide-configuration-provider.h"
#include "buildsystem/ide-environment-variable.h"
#include "buildsystem/ide-environment.h"
+#include "debugger/ide-debug-manager.h"
#include "debugger/ide-debugger-breakpoint.h"
#include "debugger/ide-debugger-frame.h"
#include "debugger/ide-debugger-instruction.h"
diff --git a/libide/meson.build b/libide/meson.build
index dd2fce9..b03c7e8 100644
--- a/libide/meson.build
+++ b/libide/meson.build
@@ -85,6 +85,7 @@ libide_public_headers = [
'buildsystem/ide-configuration-provider.h',
'buildsystem/ide-environment-variable.h',
'buildsystem/ide-environment.h',
+ 'debugger/ide-debug-manager.h',
'debugger/ide-debugger-breakpoint.h',
'debugger/ide-debugger-frame.h',
'debugger/ide-debugger-instruction.h',
@@ -297,6 +298,7 @@ libide_public_sources = [
'buildsystem/ide-configuration-provider.c',
'buildsystem/ide-environment-variable.c',
'buildsystem/ide-environment.c',
+ 'debugger/ide-debug-manager.c',
'debugger/ide-debugger-breakpoint.c',
'debugger/ide-debugger-frame.c',
'debugger/ide-debugger-instruction.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]