[gnome-builder/wip/chergert/debugger: 20/46] mi2: add api to track breakpoints
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger: 20/46] mi2: add api to track breakpoints
- Date: Sat, 25 Mar 2017 22:40:21 +0000 (UTC)
commit dc403645034160c5109d132ced398a5eea285ebc
Author: Christian Hergert <chergert redhat com>
Date: Thu Mar 23 21:47:30 2017 -0700
mi2: add api to track breakpoints
contrib/mi2/mi2-client.c | 252 ++++++++++++++++++++++++++++++++++++++++++++-
contrib/mi2/mi2-client.h | 54 +++++++---
contrib/mi2/test-client.c | 50 +++++++++-
3 files changed, 333 insertions(+), 23 deletions(-)
---
diff --git a/contrib/mi2/mi2-client.c b/contrib/mi2/mi2-client.c
index 184fe6a..8807109 100644
--- a/contrib/mi2/mi2-client.c
+++ b/contrib/mi2/mi2-client.c
@@ -45,6 +45,8 @@ enum {
};
enum {
+ BREAKPOINT_INSERTED,
+ BREAKPOINT_REMOVED,
EVENT,
LOG,
N_SIGNALS
@@ -162,6 +164,22 @@ mi2_client_class_init (Mi2ClientClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
+ signals [BREAKPOINT_INSERTED] =
+ g_signal_new ("breakpoint-inserted",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (Mi2ClientClass, breakpoint_inserted),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, MI2_TYPE_BREAKPOINT);
+
+ signals [BREAKPOINT_REMOVED] =
+ g_signal_new ("breakpoint-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (Mi2ClientClass, breakpoint_removed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
signals [EVENT] =
g_signal_new ("event",
G_TYPE_FROM_CLASS (klass),
@@ -262,15 +280,37 @@ mi2_client_exec_async (Mi2Client *self,
g_steal_pointer (&task));
}
+/**
+ * mi2_client_exec_finish:
+ * @self: An #Mi2Client
+ * @result: A #GAsyncResult
+ * @reply: (optional) (out) (transfer full): A location for a reply.
+ * @error: a location for a #GError or %NULL
+ *
+ * Completes a request to mi2_client_exec_async(). The reply from the
+ * gdb instance will be provided to @message.
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ */
gboolean
-mi2_client_exec_finish (Mi2Client *self,
- GAsyncResult *result,
- GError **error)
+mi2_client_exec_finish (Mi2Client *self,
+ GAsyncResult *result,
+ Mi2ReplyMessage **reply,
+ GError **error)
{
+ g_autoptr(Mi2ReplyMessage) local_message = NULL;
+ gboolean ret;
+
g_return_val_if_fail (MI2_IS_CLIENT (self), FALSE);
g_return_val_if_fail (G_IS_TASK (result), FALSE);
- return g_task_propagate_boolean (G_TASK (result), error);
+ local_message = g_task_propagate_pointer (G_TASK (result), error);
+ ret = !!local_message;
+
+ if (reply)
+ *reply = g_steal_pointer (&local_message);
+
+ return ret;
}
static void
@@ -307,7 +347,7 @@ mi2_client_dispatch (Mi2Client *self,
if (mi2_reply_message_check_error (MI2_REPLY_MESSAGE (message), &error))
g_task_return_error (task, g_steal_pointer (&error));
else
- g_task_return_boolean (task, TRUE);
+ g_task_return_pointer (task, g_object_ref (message), g_object_unref);
}
}
else
@@ -380,6 +420,208 @@ mi2_client_stop_listening (Mi2Client *self)
}
}
+static void
+mi2_client_insert_breakpoint_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Mi2Client *self = (Mi2Client *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = user_data;
+ g_autoptr(Mi2ReplyMessage) message = NULL;
+ Mi2Breakpoint *breakpoint;
+ GVariant *bkpt;
+
+ g_assert (MI2_IS_CLIENT (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!mi2_client_exec_finish (self, result, &message, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ breakpoint = g_task_get_task_data (task);
+
+ bkpt = mi2_message_get_param (MI2_MESSAGE (message), "bkpt");
+
+ if (bkpt != NULL)
+ {
+ GVariantDict dict;
+ const gchar *number = NULL;
+
+ g_variant_dict_init (&dict, bkpt);
+ g_variant_dict_lookup (&dict, "number", "&s", &number);
+ g_variant_dict_clear (&dict);
+
+ mi2_breakpoint_set_id (breakpoint, g_ascii_strtoll (number, NULL, 10));
+ }
+
+ g_signal_emit (self, signals [BREAKPOINT_INSERTED], 0, breakpoint);
+
+ g_task_return_boolean (task, TRUE);
+}
+
+/**
+ * mi2_client_insert_breakpoint_async:
+ * @self: A #Mi2Client
+ * @breakpoint: An #Mi2Breakpoint
+ * @cancellable: (nullable): A #GCancellable or %NULL
+ * @callback: A callback to execute
+ * @user_data: user data for @callback
+ *
+ * Adds a breakpoint at @function. If @filename is specified, the function
+ * will be resolved within that file.
+ *
+ * Call mi2_client_insert_breakpoint_async() to complete the operation.
+ */
+void
+mi2_client_insert_breakpoint_async (Mi2Client *self,
+ Mi2Breakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(Mi2CommandMessage) command = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GString) str = NULL;
+ const gchar *address;
+ const gchar *filename;
+ const gchar *function;
+ const gchar *linespec;
+ gint line_offset;
+
+ g_return_if_fail (MI2_IS_CLIENT (self));
+ g_return_if_fail (MI2_IS_BREAKPOINT (breakpoint));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, mi2_client_insert_breakpoint_async);
+ g_task_set_task_data (task, g_object_ref (breakpoint), g_object_unref);
+
+ str = g_string_new ("-break-insert");
+
+ line_offset = mi2_breakpoint_get_line_offset (breakpoint);
+ linespec = mi2_breakpoint_get_linespec (breakpoint);
+ function = mi2_breakpoint_get_function (breakpoint);
+ filename = mi2_breakpoint_get_filename (breakpoint);
+ address = mi2_breakpoint_get_address (breakpoint);
+
+ if (linespec)
+ g_string_append_printf (str, " %s", linespec);
+
+ if (filename)
+ g_string_append_printf (str, " --source %s", filename);
+
+ if (function)
+ g_string_append_printf (str, " --function %s", function);
+
+ if (line_offset)
+ g_string_append_printf (str, " --line %d", line_offset);
+
+ if (address)
+ g_string_append_printf (str, " %s", address);
+
+ command = g_object_new (MI2_TYPE_COMMAND_MESSAGE,
+ "command", str,
+ NULL);
+
+ mi2_client_exec_async (self,
+ str->str,
+ cancellable,
+ mi2_client_insert_breakpoint_cb,
+ g_steal_pointer (&task));
+}
+
+gint
+mi2_client_insert_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (MI2_IS_CLIENT (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_int (G_TASK (result), error);
+}
+
+static void
+mi2_client_remove_breakpoint_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Mi2Client *self = (Mi2Client *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = user_data;
+ gint id;
+
+ g_assert (MI2_IS_CLIENT (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!mi2_client_exec_finish (self, result, NULL, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ id = GPOINTER_TO_INT (g_task_get_task_data (task));
+ g_signal_emit (self, signals [BREAKPOINT_REMOVED], 0, id);
+
+ g_task_return_boolean (task, TRUE);
+}
+
+/**
+ * mi2_client_remove_breakpoint_async:
+ * @self: A #Mi2Client
+ * @breakpoint_id: The id of the breakpoint
+ * @cancellable: (nullable): A #GCancellable or %NULL
+ * @callback: A callback to execute
+ * @user_data: user data for @callback
+ *
+ * Removes a breakpoint that was previously added.
+ *
+ * Call mi2_client_remove_breakpoint_finish() to complete the operation.
+ */
+void
+mi2_client_remove_breakpoint_async (Mi2Client *self,
+ gint breakpoint_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(Mi2CommandMessage) command = NULL;
+ g_autofree gchar *str = NULL;
+
+ g_return_if_fail (MI2_IS_CLIENT (self));
+ g_return_if_fail (breakpoint_id > 0);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, mi2_client_remove_breakpoint_async);
+ g_task_set_task_data (task, GINT_TO_POINTER (breakpoint_id), NULL);
+
+ str = g_strdup_printf ("-break-delete %d", breakpoint_id);
+
+ command = g_object_new (MI2_TYPE_COMMAND_MESSAGE,
+ "command", str,
+ NULL);
+
+ mi2_client_exec_async (self,
+ str,
+ cancellable,
+ mi2_client_remove_breakpoint_cb,
+ g_steal_pointer (&task));
+}
+
+gboolean
+mi2_client_remove_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (MI2_IS_CLIENT (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
#if 0
void
mi2_client_async (Mi2Client *self,
diff --git a/contrib/mi2/mi2-client.h b/contrib/mi2/mi2-client.h
index 98d5445..56de564 100644
--- a/contrib/mi2/mi2-client.h
+++ b/contrib/mi2/mi2-client.h
@@ -23,8 +23,10 @@
G_BEGIN_DECLS
+#include "mi2-breakpoint.h"
#include "mi2-message.h"
#include "mi2-event-message.h"
+#include "mi2-reply-message.h"
#define MI2_TYPE_CLIENT (mi2_client_get_type())
@@ -34,10 +36,14 @@ struct _Mi2ClientClass
{
GObjectClass parent_instance;
- void (*log) (Mi2Client *self,
- const gchar *log);
- void (*event) (Mi2Client *self,
- Mi2EventMessage *message);
+ void (*log) (Mi2Client *self,
+ const gchar *log);
+ void (*event) (Mi2Client *self,
+ Mi2EventMessage *message);
+ void (*breakpoint_inserted) (Mi2Client *client,
+ Mi2Breakpoint *breakpoint);
+ void (*breakpoint_removed) (Mi2Client *client,
+ gint breakpoint_id);
gpointer _reserved1;
gpointer _reserved2;
@@ -57,17 +63,35 @@ struct _Mi2ClientClass
gpointer _reserved16;
};
-Mi2Client *mi2_client_new (GIOStream *stream);
-void mi2_client_exec_async (Mi2Client *self,
- const gchar *command,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean mi2_client_exec_finish (Mi2Client *self,
- GAsyncResult *result,
- GError **error);
-void mi2_client_start_listening (Mi2Client *self);
-void mi2_client_stop_listening (Mi2Client *self);
+Mi2Client *mi2_client_new (GIOStream *stream);
+void mi2_client_exec_async (Mi2Client *self,
+ const gchar *command,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_exec_finish (Mi2Client *self,
+ GAsyncResult *result,
+ Mi2ReplyMessage **reply,
+ GError **error);
+void mi2_client_start_listening (Mi2Client *self);
+void mi2_client_stop_listening (Mi2Client *self);
+void mi2_client_insert_breakpoint_async (Mi2Client *self,
+ Mi2Breakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gint mi2_client_insert_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
+void mi2_client_remove_breakpoint_async (Mi2Client *self,
+ gint breakpoint_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_remove_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
diff --git a/contrib/mi2/test-client.c b/contrib/mi2/test-client.c
index 045e578..a8fe18e 100644
--- a/contrib/mi2/test-client.c
+++ b/contrib/mi2/test-client.c
@@ -30,7 +30,7 @@ create_io_stream_to_gdb (void)
subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
&error,
- "gdb", "--interpreter", "mi2",
+ "gdb", "--interpreter", "mi2", "ls",
NULL);
g_assert_no_error (error);
g_assert (subprocess);
@@ -66,23 +66,64 @@ event (Mi2Client *client,
}
static void
+breakpoint_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Mi2Client *client = (Mi2Client *)object;
+ g_autoptr(GError) error = NULL;
+ gboolean r;
+
+ g_assert (MI2_IS_CLIENT (client));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ r = mi2_client_insert_breakpoint_finish (client, result, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (r, ==, TRUE);
+}
+
+static void
stack_info_frame_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
Mi2Client *client = (Mi2Client *)object;
g_autoptr(GError) error = NULL;
+ g_autoptr(Mi2Breakpoint) breakpoint = NULL;
gboolean r;
g_assert (MI2_IS_CLIENT (client));
g_assert (G_IS_ASYNC_RESULT (result));
- r = mi2_client_exec_finish (client, result, &error);
+ r = mi2_client_exec_finish (client, result, NULL, &error);
g_assert_error (error, MI2_ERROR, MI2_ERROR_UNKNOWN_ERROR);
g_assert_cmpstr (error->message, ==, "No registers.");
g_assert_cmpint (r, ==, FALSE);
- g_main_loop_quit (main_loop);
+ breakpoint = mi2_breakpoint_new ();
+ mi2_breakpoint_set_function (breakpoint, "main");
+
+ mi2_client_insert_breakpoint_async (client,
+ breakpoint,
+ NULL,
+ breakpoint_cb,
+ NULL);
+}
+
+static void
+on_breakpoint_inserted (Mi2Client *client,
+ Mi2Breakpoint *breakpoint,
+ gpointer user_data)
+{
+ g_print ("breakpoint added: %d\n", mi2_breakpoint_get_id (breakpoint));
+}
+
+static void
+on_breakpoint_removed (Mi2Client *client,
+ gint breakpoint_id,
+ gpointer user_data)
+{
+ g_print ("breakpoint removed: %d\n", breakpoint_id);
}
gint
@@ -99,10 +140,13 @@ main (gint argc,
g_signal_connect (client, "log", G_CALLBACK (log_handler), NULL);
g_signal_connect (client, "event::thread-group-added", G_CALLBACK (thread_group_added), NULL);
g_signal_connect (client, "event", G_CALLBACK (event), NULL);
+ g_signal_connect (client, "breakpoint-inserted", G_CALLBACK (on_breakpoint_inserted), NULL);
+ g_signal_connect (client, "breakpoint-removed", G_CALLBACK (on_breakpoint_removed), NULL);
mi2_client_start_listening (client);
mi2_client_exec_async (client,
+ /* converted to -stack-info-frame */
"stack-info-frame",
NULL,
stack_info_frame_cb,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]