[gnome-builder/wip/chergert/debugger: 79/89] debugger: start on breakpoint-reached signal
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger: 79/89] debugger: start on breakpoint-reached signal
- Date: Tue, 9 May 2017 01:12:15 +0000 (UTC)
commit 38726664cd45fdc8341350e0abd57cb291ec3cd1
Author: Christian Hergert <chergert redhat com>
Date: Tue Apr 4 14:14:02 2017 -0700
debugger: start on breakpoint-reached signal
We want to jump to the breakpoint location when the debugger stops at
a location.
We still need more plumbing here, and support for non-source breakpoints
such as logical address (where we might need to disassemble).
libide/Makefile.am | 2 +
libide/debugger/ide-breakpoint.c | 270 ++++++++++++++++++++++++
libide/debugger/ide-breakpoint.h | 62 ++++++
libide/debugger/ide-debug-manager.c | 2 +
libide/debugger/ide-debugger-workbench-addin.c | 115 ++++++++++-
libide/ide-types.h | 1 +
plugins/gdb/gbp-gdb-debugger.c | 25 +++
7 files changed, 472 insertions(+), 5 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 79743c8..ed98d9e 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -49,6 +49,7 @@ libide_1_0_la_public_headers = \
buildsystem/ide-configuration-provider.h \
buildsystem/ide-environment-variable.h \
buildsystem/ide-environment.h \
+ debugger/ide-breakpoint.h \
debugger/ide-debugger.h \
debugger/ide-debug-manager.h \
debugger/ide-debugger-breakpoints.h \
@@ -238,6 +239,7 @@ libide_1_0_la_public_sources = \
buildsystem/ide-configuration-provider.c \
buildsystem/ide-environment-variable.c \
buildsystem/ide-environment.c \
+ debugger/ide-breakpoint.c \
debugger/ide-debugger.c \
debugger/ide-debug-manager.c \
debugger/ide-debugger-breakpoints.c \
diff --git a/libide/debugger/ide-breakpoint.c b/libide/debugger/ide-breakpoint.c
new file mode 100644
index 0000000..adaaa54
--- /dev/null
+++ b/libide/debugger/ide-breakpoint.c
@@ -0,0 +1,270 @@
+/* ide-breakpoint.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-breakpoint"
+
+#include "debugger/ide-breakpoint.h"
+
+typedef struct
+{
+ gchar *id;
+ GFile *file;
+ guint line;
+ guint enabled : 1;
+} IdeBreakpointPrivate;
+
+enum {
+ PROP_0,
+ PROP_ENABLED,
+ PROP_FILE,
+ PROP_ID,
+ PROP_LINE,
+ N_PROPS
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdeBreakpoint, ide_breakpoint, G_TYPE_OBJECT)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_breakpoint_finalize (GObject *object)
+{
+ IdeBreakpoint *self = (IdeBreakpoint *)object;
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_clear_object (&priv->file);
+ g_clear_pointer (&priv->id, g_free);
+
+ G_OBJECT_CLASS (ide_breakpoint_parent_class)->finalize (object);
+}
+
+static void
+ide_breakpoint_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeBreakpoint *self = IDE_BREAKPOINT (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ g_value_set_boolean (value, ide_breakpoint_get_enabled (self));
+ break;
+
+ case PROP_FILE:
+ g_value_set_object (value, ide_breakpoint_get_file (self));
+ break;
+
+ case PROP_ID:
+ g_value_set_string (value, ide_breakpoint_get_id (self));
+ break;
+
+ case PROP_LINE:
+ g_value_set_uint (value, ide_breakpoint_get_line (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_breakpoint_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeBreakpoint *self = IDE_BREAKPOINT (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ ide_breakpoint_set_enabled (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_FILE:
+ ide_breakpoint_set_file (self, g_value_get_object (value));
+ break;
+
+ case PROP_ID:
+ ide_breakpoint_set_id (self, g_value_get_string (value));
+ break;
+
+ case PROP_LINE:
+ ide_breakpoint_set_line (self, g_value_get_uint (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_breakpoint_class_init (IdeBreakpointClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_breakpoint_finalize;
+ object_class->get_property = ide_breakpoint_get_property;
+ object_class->set_property = ide_breakpoint_set_property;
+
+ properties [PROP_ID] =
+ g_param_spec_string ("id",
+ "Id",
+ "Identifier for the breakpoint",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_FILE] =
+ g_param_spec_object ("file",
+ "File",
+ "The file for the breakpoint",
+ G_TYPE_FILE,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_LINE] =
+ g_param_spec_uint ("line",
+ "Line",
+ "The line number of the breakpoint",
+ 0,
+ G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_ENABLED] =
+ g_param_spec_boolean ("enabled",
+ "Enabled",
+ "If the breakpoint is enabled",
+ FALSE,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_breakpoint_init (IdeBreakpoint *self)
+{
+}
+
+const gchar *
+ide_breakpoint_get_id (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), NULL);
+
+ return priv->id;
+}
+
+void
+ide_breakpoint_set_id (IdeBreakpoint *self,
+ const gchar *id)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ if (g_strcmp0 (priv->id, id) != 0)
+ {
+ g_free (priv->id);
+ priv->id = g_strdup (id);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
+ }
+}
+
+/**
+ * ide_breakpoint_get_file:
+ *
+ * Gets the file containing the breakpoint, or %NULL.
+ *
+ * Returns: (transfer none) (nullable): A #GFile or %NULL.
+ */
+GFile *
+ide_breakpoint_get_file (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), NULL);
+
+ return priv->file;
+}
+
+void
+ide_breakpoint_set_file (IdeBreakpoint *self,
+ GFile *file)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ if (g_set_object (&priv->file, file))
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_FILE]);
+}
+
+guint
+ide_breakpoint_get_line (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), 0);
+
+ return priv->line;
+}
+
+void
+ide_breakpoint_set_line (IdeBreakpoint *self,
+ guint line)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ if (priv->line != line)
+ {
+ priv->line = line;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LINE]);
+ }
+}
+
+gboolean
+ide_breakpoint_get_enabled (IdeBreakpoint *self)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_BREAKPOINT (self), FALSE);
+
+ return priv->enabled;
+}
+
+void
+ide_breakpoint_set_enabled (IdeBreakpoint *self,
+ gboolean enabled)
+{
+ IdeBreakpointPrivate *priv = ide_breakpoint_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_BREAKPOINT (self));
+
+ enabled = !!enabled;
+
+ if (priv->enabled != enabled)
+ {
+ priv->enabled = enabled;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENABLED]);
+ }
+}
diff --git a/libide/debugger/ide-breakpoint.h b/libide/debugger/ide-breakpoint.h
new file mode 100644
index 0000000..72cd7c2
--- /dev/null
+++ b/libide/debugger/ide-breakpoint.h
@@ -0,0 +1,62 @@
+/* ide-breakpoint.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 IDE_BREAKPOINT_H
+#define IDE_BREAKPOINT_H
+
+#include <gio/gio.h>
+
+#include "ide-types.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_BREAKPOINT (ide_breakpoint_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (IdeBreakpoint, ide_breakpoint, IDE, BREAKPOINT, GObject)
+
+struct _IdeBreakpointClass
+{
+ GObjectClass parent_class;
+
+ gpointer _reserved1;
+ gpointer _reserved2;
+ gpointer _reserved3;
+ gpointer _reserved4;
+ gpointer _reserved5;
+ gpointer _reserved6;
+ gpointer _reserved7;
+ gpointer _reserved8;
+};
+
+IdeBreakpoint *ide_breakpoint_new (void);
+const gchar *ide_breakpoint_get_id (IdeBreakpoint *self);
+void ide_breakpoint_set_id (IdeBreakpoint *self,
+ const gchar *id);
+GFile *ide_breakpoint_get_file (IdeBreakpoint *self);
+void ide_breakpoint_set_file (IdeBreakpoint *self,
+ GFile *file);
+guint ide_breakpoint_get_line (IdeBreakpoint *self);
+void ide_breakpoint_set_line (IdeBreakpoint *self,
+ guint line);
+gboolean ide_breakpoint_get_enabled (IdeBreakpoint *self);
+void ide_breakpoint_set_enabled (IdeBreakpoint *self,
+ gboolean enabled);
+
+G_END_DECLS
+
+#endif /* IDE_BREAKPOINT_H */
diff --git a/libide/debugger/ide-debug-manager.c b/libide/debugger/ide-debug-manager.c
index 027f060..5257a45 100644
--- a/libide/debugger/ide-debug-manager.c
+++ b/libide/debugger/ide-debug-manager.c
@@ -24,6 +24,7 @@
#include "ide-debug.h"
+#include "debugger/ide-breakpoint.h"
#include "debugger/ide-debug-manager.h"
#include "debugger/ide-debugger.h"
#include "plugins/ide-extension-util.h"
@@ -59,6 +60,7 @@ enum {
enum {
BREAKPOINT_ADDED,
BREAKPOINT_REMOVED,
+ BREAKPOINT_REACHED,
N_SIGNALS
};
diff --git a/libide/debugger/ide-debugger-workbench-addin.c b/libide/debugger/ide-debugger-workbench-addin.c
index 93d46aa..d5c0607 100644
--- a/libide/debugger/ide-debugger-workbench-addin.c
+++ b/libide/debugger/ide-debugger-workbench-addin.c
@@ -20,6 +20,10 @@
#include <glib/gi18n.h>
+#include <egg-signal-group.h>
+#include <gtksourceview/gtksource.h>
+
+#include "debugger/ide-breakpoint.h"
#include "debugger/ide-debug-manager.h"
#include "debugger/ide-debugger-controls.h"
#include "debugger/ide-debugger-perspective.h"
@@ -33,6 +37,7 @@ struct _IdeDebuggerWorkbenchAddin
IdeDebuggerControls *controls;
IdeWorkbenchMessage *message;
IdeDebuggerPerspective *perspective;
+ EggSignalGroup *debug_manager_signals;
};
static void
@@ -107,6 +112,36 @@ controls_notify_child_revealed (IdeDebuggerWorkbenchAddin *self,
}
static void
+debug_manager_breakpoint_reached (IdeDebuggerWorkbenchAddin *self,
+ IdeBreakpoint *breakpoint,
+ IdeDebugger *debugger)
+{
+ g_autoptr(IdeUri) uri = NULL;
+ GFile *file;
+ guint line;
+
+ g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+ g_assert (IDE_IS_BREAKPOINT (breakpoint));
+ g_assert (IDE_IS_DEBUGGER (debugger));
+
+ if (NULL == (file = ide_breakpoint_get_file (breakpoint)) ||
+ NULL == (uri = ide_uri_new_from_file (file)))
+ return;
+
+ if (0 != (line = ide_breakpoint_get_line (breakpoint)))
+ {
+ g_autofree gchar *fragment = g_strdup_printf ("L%u", line);
+ ide_uri_set_fragment (uri, fragment);
+ }
+
+ ide_workbench_addin_open_async (IDE_WORKBENCH_ADDIN (self),
+ uri,
+ NULL,
+ IDE_WORKBENCH_OPEN_FLAGS_NONE,
+ NULL, NULL, NULL);
+}
+
+static void
ide_debugger_workbench_addin_load (IdeWorkbenchAddin *addin,
IdeWorkbench *workbench)
{
@@ -131,17 +166,26 @@ ide_debugger_workbench_addin_load (IdeWorkbenchAddin *addin,
headerbar = ide_workbench_get_headerbar (workbench);
+ self->debug_manager_signals = egg_signal_group_new (IDE_TYPE_DEBUG_MANAGER);
+
+ egg_signal_group_connect_object (self->debug_manager_signals,
+ "notify::active",
+ G_CALLBACK (debug_manager_notify_active),
+ self,
+ G_CONNECT_SWAPPED);
+
+ egg_signal_group_connect_object (self->debug_manager_signals,
+ "breakpoint-reached",
+ G_CALLBACK (debug_manager_breakpoint_reached),
+ self,
+ G_CONNECT_SWAPPED);
+
self->controls = g_object_new (IDE_TYPE_DEBUGGER_CONTROLS,
"transition-duration", 500,
"transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT,
"reveal-child", FALSE,
"visible", FALSE,
NULL);
- g_signal_connect_object (debug_manager,
- "notify::active",
- G_CALLBACK (debug_manager_notify_active),
- self,
- G_CONNECT_SWAPPED);
g_signal_connect_object (self->controls,
"notify::child-revealed",
G_CALLBACK (controls_notify_child_revealed),
@@ -191,6 +235,8 @@ ide_debugger_workbench_addin_unload (IdeWorkbenchAddin *addin,
context = ide_workbench_get_context (workbench);
run_manager = ide_context_get_run_manager (context);
+ g_clear_object (&self->debug_manager_signals);
+
/* Remove the handler to initiate the debugger */
ide_run_manager_remove_handler (run_manager, "debugger");
@@ -208,10 +254,69 @@ ide_debugger_workbench_addin_unload (IdeWorkbenchAddin *addin,
}
static void
+ide_debugger_workbench_addin_open_async (IdeWorkbenchAddin *addin,
+ IdeUri *uri,
+ const gchar *content_type,
+ IdeWorkbenchOpenFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdeDebuggerWorkbenchAddin *self = (IdeDebuggerWorkbenchAddin *)addin;
+ g_autoptr(GtkSourceFileLoader) loader = NULL;
+ g_autoptr(GtkSourceBuffer) buffer = NULL;
+ g_autoptr(GtkSourceFile) sfile = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GFile) file = NULL;
+ GtkSourceView *view;
+
+ g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (self));
+ g_assert (uri != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, ide_debugger_workbench_addin_open_async);
+
+ file = ide_uri_to_file (uri);
+
+ buffer = gtk_source_buffer_new (NULL);
+ view = g_object_new (GTK_SOURCE_TYPE_VIEW,
+ "buffer", buffer,
+ "visible", TRUE,
+ NULL);
+
+ sfile = gtk_source_file_new ();
+ gtk_source_file_set_location (sfile, file);
+
+ loader = gtk_source_file_loader_new (buffer, sfile);
+ gtk_source_file_loader_load_async (loader,
+ G_PRIORITY_LOW,
+ cancellable,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gboolean
+ide_debugger_workbench_addin_open_finish (IdeWorkbenchAddin *addin,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_DEBUGGER_WORKBENCH_ADDIN (addin));
+ g_assert (G_IS_TASK (result));
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
{
iface->load = ide_debugger_workbench_addin_load;
iface->unload = ide_debugger_workbench_addin_unload;
+ iface->open_async = ide_debugger_workbench_addin_open_async;
+ iface->open_finish = ide_debugger_workbench_addin_open_finish;
}
G_DEFINE_TYPE_WITH_CODE (IdeDebuggerWorkbenchAddin, ide_debugger_workbench_addin, G_TYPE_OBJECT,
diff --git a/libide/ide-types.h b/libide/ide-types.h
index 8643171..206d78d 100644
--- a/libide/ide-types.h
+++ b/libide/ide-types.h
@@ -51,6 +51,7 @@ typedef struct _IdeConfigurationManager IdeConfigurationManager;
typedef struct _IdeContext IdeContext;
typedef struct _IdeDebugger IdeDebugger;
+typedef struct _IdeBreakpoint IdeBreakpoint;
typedef struct _IdeDebugManager IdeDebugManager;
typedef struct _IdeDevice IdeDevice;
diff --git a/plugins/gdb/gbp-gdb-debugger.c b/plugins/gdb/gbp-gdb-debugger.c
index a9cb01c..f183674 100644
--- a/plugins/gdb/gbp-gdb-debugger.c
+++ b/plugins/gdb/gbp-gdb-debugger.c
@@ -328,6 +328,8 @@ gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
Mi2Client *client)
{
IdeDebuggerStopReason translated;
+ g_autoptr(IdeSourceLocation) location = NULL;
+ GVariant *fra;
IDE_ENTRY;
@@ -357,6 +359,29 @@ gbp_gdb_debugger_on_client_stopped (GbpGdbDebugger *self,
break;
}
+ if (NULL != (fra = mi2_message_get_param (MI2_MESSAGE (message), "frame")) &&
+ g_variant_is_of_type (fra, G_VARIANT_TYPE ("a{sv}")))
+ {
+ GVariantDict dict;
+ const gchar *filename = NULL;
+ const gchar *line = NULL;
+
+ g_variant_dict_init (&dict, fra);
+ g_variant_dict_lookup (&dict, "fullname", "&s", &filename);
+ g_variant_dict_lookup (&dict, "line", "&s", &line);
+
+ if (filename != NULL && line != NULL)
+ {
+ IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
+ g_autoptr(GFile) gfile = g_file_new_for_path (filename);
+ g_autoptr(IdeFile) ifile = ide_file_new (context, gfile);
+
+ location = ide_source_location_new (ifile,
+ g_ascii_strtoll (line, NULL, 10),
+ 0, 0);
+ }
+ }
+
gbp_gdb_debugger_notify_properties (self);
ide_debugger_emit_stopped (IDE_DEBUGGER (self), translated, NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]