2076 lines
64 KiB
C
2076 lines
64 KiB
C
|
/* ide-debugger.c
|
||
|
*
|
||
|
* Copyright 2017-2019 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/>.
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
*/
|
||
|
|
||
|
#define G_LOG_DOMAIN "ide-debugger"
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include "ide-debugger.h"
|
||
|
#include "ide-debugger-address-map-private.h"
|
||
|
#include "ide-debugger-private.h"
|
||
|
|
||
|
/**
|
||
|
* SECTION:ide-debugger
|
||
|
* @title: IdeDebugger
|
||
|
* @short_description: Base class for debugger implementations
|
||
|
*
|
||
|
* The IdeDebugger abstract base class is used by debugger implementations.
|
||
|
* They should bridge their backend-specific features into those supported
|
||
|
* by the API using the series of "emit" functions provided as part of
|
||
|
* this class.
|
||
|
*
|
||
|
* For example, when the inferior creates a new thread, the debugger
|
||
|
* implementation should call ide_debugger_emit_thread_added().
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
gchar *display_name;
|
||
|
GListStore *breakpoints;
|
||
|
GListStore *threads;
|
||
|
GListStore *thread_groups;
|
||
|
IdeDebuggerThread *selected;
|
||
|
IdeDebuggerAddressMap *map;
|
||
|
guint has_started : 1;
|
||
|
guint is_running : 1;
|
||
|
} IdeDebuggerPrivate;
|
||
|
|
||
|
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))
|
||
|
|
||
|
enum {
|
||
|
PROP_0,
|
||
|
PROP_DISPLAY_NAME,
|
||
|
PROP_SELECTED_THREAD,
|
||
|
N_PROPS
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
LOG,
|
||
|
|
||
|
THREAD_GROUP_ADDED,
|
||
|
THREAD_GROUP_EXITED,
|
||
|
THREAD_GROUP_REMOVED,
|
||
|
THREAD_GROUP_STARTED,
|
||
|
|
||
|
THREAD_ADDED,
|
||
|
THREAD_REMOVED,
|
||
|
THREAD_SELECTED,
|
||
|
|
||
|
BREAKPOINT_ADDED,
|
||
|
BREAKPOINT_MODIFIED,
|
||
|
BREAKPOINT_REMOVED,
|
||
|
|
||
|
RUNNING,
|
||
|
STOPPED,
|
||
|
|
||
|
LIBRARY_LOADED,
|
||
|
LIBRARY_UNLOADED,
|
||
|
|
||
|
N_SIGNALS
|
||
|
};
|
||
|
|
||
|
static GParamSpec *properties [N_PROPS];
|
||
|
static guint signals [N_SIGNALS];
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_breakpoint_added (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_debug ("Added breakpoint %s",
|
||
|
ide_debugger_breakpoint_get_id (breakpoint));
|
||
|
|
||
|
g_list_store_insert_sorted (priv->breakpoints,
|
||
|
breakpoint,
|
||
|
(GCompareDataFunc)ide_debugger_breakpoint_compare,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_breakpoint_removed (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
guint n_items;
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_debug ("Removed breakpoint %s",
|
||
|
ide_debugger_breakpoint_get_id (breakpoint));
|
||
|
|
||
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (priv->breakpoints));
|
||
|
|
||
|
for (guint i = 0; i < n_items; i++)
|
||
|
{
|
||
|
g_autoptr(IdeDebuggerBreakpoint) element = NULL;
|
||
|
|
||
|
element = g_list_model_get_item (G_LIST_MODEL (priv->breakpoints), i);
|
||
|
|
||
|
g_assert (element != NULL);
|
||
|
g_assert (IDE_IS_DEBUGGER_BREAKPOINT (element));
|
||
|
|
||
|
if (breakpoint == element)
|
||
|
break;
|
||
|
|
||
|
if (ide_debugger_breakpoint_compare (breakpoint, element) == 0)
|
||
|
{
|
||
|
g_list_store_remove (priv->breakpoints, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_breakpoint_modified (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_debug ("Modified breakpoint %s (%s)",
|
||
|
ide_debugger_breakpoint_get_id (breakpoint),
|
||
|
ide_debugger_breakpoint_get_enabled (breakpoint) ? "enabled" : "disabled");
|
||
|
|
||
|
/*
|
||
|
* If we add API to GListStore, we could make this a single
|
||
|
* operation instead of 2 signal emissions.
|
||
|
*/
|
||
|
ide_debugger_real_breakpoint_removed (self, breakpoint);
|
||
|
ide_debugger_real_breakpoint_added (self, breakpoint);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_thread_group_added (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_debug ("Added thread group %s",
|
||
|
ide_debugger_thread_group_get_id (thread_group));
|
||
|
|
||
|
g_list_store_insert_sorted (priv->thread_groups,
|
||
|
thread_group,
|
||
|
(GCompareDataFunc)ide_debugger_thread_group_compare,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_thread_group_removed (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
guint n_items;
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_debug ("Removed thread group %s",
|
||
|
ide_debugger_thread_group_get_id (thread_group));
|
||
|
|
||
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (priv->thread_groups));
|
||
|
|
||
|
for (guint i = 0; i < n_items; i++)
|
||
|
{
|
||
|
g_autoptr(IdeDebuggerThreadGroup) element = NULL;
|
||
|
|
||
|
element = g_list_model_get_item (G_LIST_MODEL (priv->thread_groups), i);
|
||
|
|
||
|
g_assert (element != NULL);
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD_GROUP (element));
|
||
|
|
||
|
if (thread_group == element)
|
||
|
break;
|
||
|
|
||
|
if (ide_debugger_thread_group_compare (thread_group, element) == 0)
|
||
|
{
|
||
|
g_list_store_remove (priv->thread_groups, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_thread_added (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
g_debug ("Added thread %s", ide_debugger_thread_get_id (thread));
|
||
|
|
||
|
g_list_store_insert_sorted (priv->threads,
|
||
|
thread,
|
||
|
(GCompareDataFunc)ide_debugger_thread_compare,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_thread_removed (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
guint n_items;
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
g_debug ("Removed thread %s", ide_debugger_thread_get_id (thread));
|
||
|
|
||
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (priv->threads));
|
||
|
|
||
|
for (guint i = 0; i < n_items; i++)
|
||
|
{
|
||
|
g_autoptr(IdeDebuggerThread) element = NULL;
|
||
|
|
||
|
element = g_list_model_get_item (G_LIST_MODEL (priv->threads), i);
|
||
|
|
||
|
g_assert (element != NULL);
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD (element));
|
||
|
|
||
|
if (thread == element)
|
||
|
break;
|
||
|
|
||
|
if (ide_debugger_thread_compare (thread, element) == 0)
|
||
|
{
|
||
|
g_list_store_remove (priv->threads, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_running (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
|
||
|
priv->is_running = TRUE;
|
||
|
priv->has_started = TRUE;
|
||
|
|
||
|
_ide_debugger_update_actions (self);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_stopped (IdeDebugger *self,
|
||
|
IdeDebuggerStopReason stop_reason,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_STOP_REASON (stop_reason));
|
||
|
g_assert (!breakpoint || IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
/* We might need to eventually track this by thread group */
|
||
|
priv->is_running = FALSE;
|
||
|
|
||
|
if (IDE_DEBUGGER_STOP_IS_TERMINAL (stop_reason))
|
||
|
priv->has_started = FALSE;
|
||
|
|
||
|
_ide_debugger_update_actions (self);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_thread_selected (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
if (g_set_object (&priv->selected, thread))
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED_THREAD]);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_finalize (GObject *object)
|
||
|
{
|
||
|
IdeDebugger *self = (IdeDebugger *)object;
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_clear_pointer (&priv->map, ide_debugger_address_map_free);
|
||
|
g_clear_pointer (&priv->display_name, g_free);
|
||
|
g_clear_object (&priv->breakpoints);
|
||
|
g_clear_object (&priv->threads);
|
||
|
g_clear_object (&priv->thread_groups);
|
||
|
g_clear_object (&priv->selected);
|
||
|
|
||
|
G_OBJECT_CLASS (ide_debugger_parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
ide_debugger_real_get_can_move (IdeDebugger *self,
|
||
|
IdeDebuggerMovement movement)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER_MOVEMENT (movement), FALSE);
|
||
|
|
||
|
switch (movement)
|
||
|
{
|
||
|
case IDE_DEBUGGER_MOVEMENT_START:
|
||
|
return !ide_debugger_get_is_running (self);
|
||
|
|
||
|
case IDE_DEBUGGER_MOVEMENT_FINISH:
|
||
|
case IDE_DEBUGGER_MOVEMENT_CONTINUE:
|
||
|
case IDE_DEBUGGER_MOVEMENT_STEP_IN:
|
||
|
case IDE_DEBUGGER_MOVEMENT_STEP_OVER:
|
||
|
return _ide_debugger_get_has_started (self) &&
|
||
|
!ide_debugger_get_is_running (self);
|
||
|
|
||
|
default:
|
||
|
g_return_val_if_reached (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_library_loaded (IdeDebugger *self,
|
||
|
IdeDebuggerLibrary *library)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
IdeDebuggerAddressMapEntry entry = { 0 };
|
||
|
GPtrArray *ranges;
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_LIBRARY (library));
|
||
|
|
||
|
/* We don't yet have this information */
|
||
|
entry.offset = 0;
|
||
|
entry.filename = ide_debugger_library_get_target_name (library);
|
||
|
|
||
|
ranges = ide_debugger_library_get_ranges (library);
|
||
|
|
||
|
if (ranges != NULL)
|
||
|
{
|
||
|
for (guint i = 0; i < ranges->len; i++)
|
||
|
{
|
||
|
const IdeDebuggerAddressRange *range = g_ptr_array_index (ranges, i);
|
||
|
|
||
|
entry.start = range->from;
|
||
|
entry.end = range->to;
|
||
|
|
||
|
ide_debugger_address_map_insert (priv->map, &entry);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_real_library_unloaded (IdeDebugger *self,
|
||
|
IdeDebuggerLibrary *library)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
GPtrArray *ranges;
|
||
|
|
||
|
g_assert (IDE_IS_DEBUGGER (self));
|
||
|
g_assert (IDE_IS_DEBUGGER_LIBRARY (library));
|
||
|
|
||
|
ranges = ide_debugger_library_get_ranges (library);
|
||
|
|
||
|
if (ranges != NULL)
|
||
|
{
|
||
|
for (guint i = 0; i < ranges->len; i++)
|
||
|
{
|
||
|
const IdeDebuggerAddressRange *range = g_ptr_array_index (ranges, i);
|
||
|
|
||
|
ide_debugger_address_map_remove (priv->map, range->from);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_get_property (GObject *object,
|
||
|
guint prop_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
IdeDebugger *self = IDE_DEBUGGER (object);
|
||
|
|
||
|
switch (prop_id)
|
||
|
{
|
||
|
case PROP_DISPLAY_NAME:
|
||
|
g_value_set_string (value, ide_debugger_get_display_name (self));
|
||
|
break;
|
||
|
|
||
|
case PROP_SELECTED_THREAD:
|
||
|
g_value_set_object (value, ide_debugger_get_selected_thread (self));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_set_property (GObject *object,
|
||
|
guint prop_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
IdeDebugger *self = IDE_DEBUGGER (object);
|
||
|
|
||
|
switch (prop_id)
|
||
|
{
|
||
|
case PROP_DISPLAY_NAME:
|
||
|
ide_debugger_set_display_name (self, g_value_get_string (value));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_class_init (IdeDebuggerClass *klass)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
|
||
|
object_class->finalize = ide_debugger_finalize;
|
||
|
object_class->get_property = ide_debugger_get_property;
|
||
|
object_class->set_property = ide_debugger_set_property;
|
||
|
|
||
|
klass->breakpoint_added = ide_debugger_real_breakpoint_added;
|
||
|
klass->breakpoint_modified = ide_debugger_real_breakpoint_modified;
|
||
|
klass->breakpoint_removed = ide_debugger_real_breakpoint_removed;
|
||
|
klass->disassemble_async = _ide_debugger_real_disassemble_async;
|
||
|
klass->disassemble_finish = _ide_debugger_real_disassemble_finish;
|
||
|
klass->get_can_move = ide_debugger_real_get_can_move;
|
||
|
klass->interrupt_async = _ide_debugger_real_interrupt_async;
|
||
|
klass->interrupt_finish = _ide_debugger_real_interrupt_finish;
|
||
|
klass->library_loaded = ide_debugger_real_library_loaded;
|
||
|
klass->library_unloaded = ide_debugger_real_library_unloaded;
|
||
|
klass->list_frames_async = _ide_debugger_real_list_frames_async;
|
||
|
klass->list_frames_finish = _ide_debugger_real_list_frames_finish;
|
||
|
klass->list_locals_async = _ide_debugger_real_list_locals_async;
|
||
|
klass->list_locals_finish = _ide_debugger_real_list_locals_finish;
|
||
|
klass->list_params_async = _ide_debugger_real_list_params_async;
|
||
|
klass->list_params_finish = _ide_debugger_real_list_params_finish;
|
||
|
klass->list_registers_async = _ide_debugger_real_list_registers_async;
|
||
|
klass->list_registers_finish = _ide_debugger_real_list_registers_finish;
|
||
|
klass->modify_breakpoint_async = _ide_debugger_real_modify_breakpoint_async;
|
||
|
klass->modify_breakpoint_finish = _ide_debugger_real_modify_breakpoint_finish;
|
||
|
klass->running = ide_debugger_real_running;
|
||
|
klass->send_signal_async = _ide_debugger_real_send_signal_async;
|
||
|
klass->send_signal_finish = _ide_debugger_real_send_signal_finish;
|
||
|
klass->stopped = ide_debugger_real_stopped;
|
||
|
klass->thread_added = ide_debugger_real_thread_added;
|
||
|
klass->thread_group_added = ide_debugger_real_thread_group_added;
|
||
|
klass->thread_group_removed = ide_debugger_real_thread_group_removed;
|
||
|
klass->thread_removed = ide_debugger_real_thread_removed;
|
||
|
klass->thread_selected = ide_debugger_real_thread_selected;
|
||
|
klass->interpret_async = _ide_debugger_real_interpret_async;
|
||
|
klass->interpret_finish = _ide_debugger_real_interpret_finish;
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger:display-name:
|
||
|
*
|
||
|
* The "display-name" property is used by UI to when it is necessary
|
||
|
* to display the name of the debugger. You might set this to "GNU Debugger"
|
||
|
* or "Python Debugger", etc.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_DISPLAY_NAME] =
|
||
|
g_param_spec_string ("display-name",
|
||
|
"Display Name",
|
||
|
"The name of the debugger to use in various UI components",
|
||
|
NULL,
|
||
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger:selected-thread:
|
||
|
*
|
||
|
* The currently selected thread.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_SELECTED_THREAD] =
|
||
|
g_param_spec_object ("selected-thread",
|
||
|
"Selected Thread",
|
||
|
"The currently selected thread",
|
||
|
IDE_TYPE_DEBUGGER_THREAD,
|
||
|
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||
|
|
||
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::log:
|
||
|
* @self: An #IdeDebugger.
|
||
|
* @stream: the stream to append to.
|
||
|
* @content: the contents for the stream.
|
||
|
*
|
||
|
* The "log" signal is emitted when there is new content to be
|
||
|
* appended to one of the streams.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [LOG] =
|
||
|
g_signal_new ("log",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, log),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE,
|
||
|
2,
|
||
|
IDE_TYPE_DEBUGGER_STREAM,
|
||
|
G_TYPE_BYTES | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-group-added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* This signal is emitted when a thread-group has been added.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_GROUP_ADDED] =
|
||
|
g_signal_new ("thread-group-added",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_group_added),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE,
|
||
|
1,
|
||
|
IDE_TYPE_DEBUGGER_THREAD_GROUP);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-group-removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* This signal is emitted when a thread-group has been removed.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_GROUP_REMOVED] =
|
||
|
g_signal_new ("thread-group-removed",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_group_removed),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE,
|
||
|
1,
|
||
|
IDE_TYPE_DEBUGGER_THREAD_GROUP);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-group-started:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* This signal is emitted when a thread-group has been started.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_GROUP_STARTED] =
|
||
|
g_signal_new ("thread-group-started",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_group_started),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE,
|
||
|
1,
|
||
|
IDE_TYPE_DEBUGGER_THREAD_GROUP);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-group-exited:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* This signal is emitted when a thread-group has exited.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_GROUP_EXITED] =
|
||
|
g_signal_new ("thread-group-exited",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_group_exited),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_THREAD_GROUP);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* The signal is emitted when a thread is added to the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_ADDED] =
|
||
|
g_signal_new ("thread-added",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_added),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_THREAD);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* The signal is emitted when a thread is removed from the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_REMOVED] =
|
||
|
g_signal_new ("thread-removed",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_removed),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_THREAD);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::thread-selected:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* The signal is emitted when a thread is selected in the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [THREAD_SELECTED] =
|
||
|
g_signal_new ("thread-selected",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, thread_selected),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_THREAD);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::breakpoint-added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* The "breakpoint-added" signal is emitted when a breakpoint has been
|
||
|
* added to the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [BREAKPOINT_ADDED] =
|
||
|
g_signal_new ("breakpoint-added",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, breakpoint_added),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::breakpoint-removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* The "breakpoint-removed" signal is emitted when a breakpoint has been
|
||
|
* removed from the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [BREAKPOINT_REMOVED] =
|
||
|
g_signal_new ("breakpoint-removed",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, breakpoint_removed),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::breakpoint-modified:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* The "breakpoint-modified" signal is emitted when a breakpoint has been
|
||
|
* modified by the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [BREAKPOINT_MODIFIED] =
|
||
|
g_signal_new ("breakpoint-modified",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, breakpoint_modified),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_BREAKPOINT);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::running:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* This signal is emitted when the debugger starts or resumes executing
|
||
|
* the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [RUNNING] =
|
||
|
g_signal_new ("running",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, running),
|
||
|
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::stopped:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @stop_reason: An #IdeDebuggerStopReason
|
||
|
* @breakpoint: (nullable): An #IdeDebuggerBreakpoint if any
|
||
|
*
|
||
|
* This signal is emitted when the debugger has stopped executing the
|
||
|
* inferior for a variety of reasons.
|
||
|
*
|
||
|
* If possible, the debugger implementation will provide the breakpoint of
|
||
|
* the location the debugger stopped. That location may not always be
|
||
|
* representable by source in the project (such as memory address based
|
||
|
* breakpoints).
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [STOPPED] =
|
||
|
g_signal_new ("stopped",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, stopped),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE,
|
||
|
2,
|
||
|
IDE_TYPE_DEBUGGER_STOP_REASON,
|
||
|
IDE_TYPE_DEBUGGER_BREAKPOINT);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::library-loaded:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @library: An #IdeDebuggerLibrary
|
||
|
*
|
||
|
* This signal is emitted when a library has been loaded by the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [LIBRARY_LOADED] =
|
||
|
g_signal_new ("library-loaded",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, library_loaded),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_LIBRARY);
|
||
|
|
||
|
/**
|
||
|
* IdeDebugger::library-unloaded:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @library: An #IdeDebuggerLibrary
|
||
|
*
|
||
|
* This signal is emitted when a library has been unloaded by the debugger.
|
||
|
* Generally, this means that the library was a module and loaded in such a
|
||
|
* way that allowed unloading.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
signals [LIBRARY_UNLOADED] =
|
||
|
g_signal_new ("library-unloaded",
|
||
|
G_TYPE_FROM_CLASS (klass),
|
||
|
G_SIGNAL_RUN_LAST,
|
||
|
G_STRUCT_OFFSET (IdeDebuggerClass, library_unloaded),
|
||
|
NULL, NULL, NULL,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_DEBUGGER_LIBRARY);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_debugger_init (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
priv->breakpoints = g_list_store_new (IDE_TYPE_DEBUGGER_BREAKPOINT);
|
||
|
priv->map = ide_debugger_address_map_new ();
|
||
|
priv->thread_groups = g_list_store_new (IDE_TYPE_DEBUGGER_THREAD_GROUP);
|
||
|
priv->threads = g_list_store_new (IDE_TYPE_DEBUGGER_THREAD);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_display_name:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* Gets the display name for the debugger as the user should see it in various
|
||
|
* UI components.
|
||
|
*
|
||
|
* Returns: The display name for the debugger
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
const gchar *
|
||
|
ide_debugger_get_display_name (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
return priv->display_name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_set_display_name:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* Sets the #IdeDebugger:display-name property.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_set_display_name (IdeDebugger *self,
|
||
|
const gchar *display_name)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
|
||
|
if (g_strcmp0 (priv->display_name, display_name) != 0)
|
||
|
{
|
||
|
g_free (priv->display_name);
|
||
|
priv->display_name = g_strdup (display_name);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_can_move:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @movement: the movement to check
|
||
|
*
|
||
|
* Checks to see if the debugger can make the movement matching @movement.
|
||
|
*
|
||
|
* Returns: %TRUE if @movement can be performed.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_get_can_move (IdeDebugger *self,
|
||
|
IdeDebuggerMovement movement)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
|
||
|
if (IDE_DEBUGGER_GET_CLASS (self)->get_can_move)
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->get_can_move (self, movement);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_move_async:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @movement: An #IdeDebuggerMovement
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: (scope async) (closure user_data): A callback to call upon
|
||
|
* completion of the operation.
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Advances the debugger to the next breakpoint or until the debugger stops.
|
||
|
* @movement should describe the type of movement to perform.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_move_async (IdeDebugger *self,
|
||
|
IdeDebuggerMovement movement,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_MOVEMENT (movement));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->move_async (self, movement, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_move_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult provided to the callback
|
||
|
* @error: A location for a #GError, or %NULL
|
||
|
*
|
||
|
* Notifies that the movement request has been submitted to the debugger.
|
||
|
*
|
||
|
* Note that this does not indicate that the movement has completed successfully,
|
||
|
* only that the command has be submitted.
|
||
|
*
|
||
|
* Returns: %TRUE if successful, otherwise %FALSE
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_move_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->move_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_log:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* Emits the "log" signal.
|
||
|
*
|
||
|
* Debugger implementations should use this to notify any listeners
|
||
|
* that incoming log information has been recieved.
|
||
|
*
|
||
|
* Use the #IdeDebuggerStream to denote the particular stream.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_log (IdeDebugger *self,
|
||
|
IdeDebuggerStream stream,
|
||
|
GBytes *content)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_STREAM (stream));
|
||
|
g_return_if_fail (content != NULL);
|
||
|
|
||
|
g_signal_emit (self, signals [LOG], 0, stream, content);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_thread_group_added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* Debugger implementations should call this to notify that a thread group has
|
||
|
* been added to the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_group_added (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_GROUP_ADDED], 0, thread_group);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_thread_group_removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* Debugger implementations should call this to notify that a thread group has
|
||
|
* been removed from the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_group_removed (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_GROUP_REMOVED], 0, thread_group);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_thread_group_started:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* Debugger implementations should call this to notify that a thread group has
|
||
|
* started executing.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_group_started (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_GROUP_STARTED], 0, thread_group);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_thread_group_exited:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread_group: an #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* Debugger implementations should call this to notify that a thread group has
|
||
|
* exited.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_group_exited (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_GROUP_EXITED], 0, thread_group);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_thread_added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* Emits the #IdeDebugger::thread-added signal notifying that a new thread
|
||
|
* has been added to the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_added (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_ADDED], 0, thread);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_thread_removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* Emits the #IdeDebugger::thread-removed signal notifying that a thread has
|
||
|
* been removed to the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_removed (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_REMOVED], 0, thread);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_thread_selected:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
*
|
||
|
* Emits the #IdeDebugger::thread-selected signal notifying that a thread
|
||
|
* has been set as the current debugging thread.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_thread_selected (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
|
||
|
g_signal_emit (self, signals [THREAD_SELECTED], 0, thread);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_breakpoint_added:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* Emits the #IdeDebugger::breakpoint-added signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when a new breakpoint
|
||
|
* has been registered with the debugger.
|
||
|
*
|
||
|
* If a breakpoint has changed, you should use
|
||
|
* ide_debugger_emit_breakpoint_modified() to notify of the modification.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_breakpoint_added (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_signal_emit (self, signals [BREAKPOINT_ADDED], 0, breakpoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_breakpoint_removed:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* Emits the #IdeDebugger::breakpoint-removed signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when a breakpoint has been removed
|
||
|
* either manually or automatically by the debugger.
|
||
|
*
|
||
|
* If a breakpoint has changed, you should use
|
||
|
* ide_debugger_emit_breakpoint_modified() to notify of the modification.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_breakpoint_removed (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_signal_emit (self, signals [BREAKPOINT_REMOVED], 0, breakpoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_breakpoint_modified:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @breakpoint: an #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* Emits the #IdeDebugger::breakpoint-modified signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when a breakpoint has changed
|
||
|
* in the underlying debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_breakpoint_modified (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_signal_emit (self, signals [BREAKPOINT_MODIFIED], 0, breakpoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_running:
|
||
|
* @self: an #IdeDebugger
|
||
|
*
|
||
|
* Emits the "running" signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when the debugger has started
|
||
|
* or restarted executing the inferior.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_running (IdeDebugger *self)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
|
||
|
g_signal_emit (self, signals [RUNNING], 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_stopped:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @stop_reason: the reason the debugger stopped
|
||
|
* @breakpoint: the breakpoint representing the stop location
|
||
|
*
|
||
|
* Emits the "stopped" signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when the debugger has stopped
|
||
|
* and include the reason and location of the stop.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_stopped (IdeDebugger *self,
|
||
|
IdeDebuggerStopReason stop_reason,
|
||
|
IdeDebuggerBreakpoint *breakpoint)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_STOP_REASON (stop_reason));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
|
||
|
g_signal_emit (self, signals [STOPPED], 0, stop_reason, breakpoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_library_loaded:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @library: an #IdeDebuggerLibrary
|
||
|
*
|
||
|
* Emits the "library-loaded" signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when the debugger has loaded
|
||
|
* a new library.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_library_loaded (IdeDebugger *self,
|
||
|
IdeDebuggerLibrary *library)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_LIBRARY (library));
|
||
|
|
||
|
g_signal_emit (self, signals [LIBRARY_LOADED], 0, library);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_emit_library_unloaded:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @library: an #IdeDebuggerLibrary
|
||
|
*
|
||
|
* Emits the "library-unloaded" signal.
|
||
|
*
|
||
|
* Debugger implementations should call this when the debugger has unloaded a
|
||
|
* library.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_emit_library_unloaded (IdeDebugger *self,
|
||
|
IdeDebuggerLibrary *library)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_LIBRARY (library));
|
||
|
|
||
|
g_signal_emit (self, signals [LIBRARY_UNLOADED], 0, library);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_breakpoints_async:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
||
|
* @callback: a callback to call upon completion
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Asynchronously requests the list of current breakpoints from the debugger.
|
||
|
*
|
||
|
* #IdeDebugger implementations must implement the virtual function
|
||
|
* for this method.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_list_breakpoints_async (IdeDebugger *self,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->list_breakpoints_async (self, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_breakpoints_finish:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @result: a #GAsyncResult provided to the async callback
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Gets the list of breakpoints from the debugger.
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerBreakpoint): a #GPtrArray
|
||
|
* of breakpoints that are registered with the debugger.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_list_breakpoints_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->list_breakpoints_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_insert_breakpoint_async:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @breakpoint: An #IdeDebuggerBreakpoint
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: an async callback to complete the operation
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that a breakpoint is added to the debugger.
|
||
|
*
|
||
|
* This asynchronous function may complete before the breakpoint has been
|
||
|
* registered in the debugger. Debugger implementations will emit
|
||
|
* #IdeDebugger::breakpoint-added when a breakpoint has been registered.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_insert_breakpoint_async (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->insert_breakpoint_async (self,
|
||
|
breakpoint,
|
||
|
cancellable,
|
||
|
callback,
|
||
|
user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_insert_breakpoint_finish:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @result: a #GAsyncResult or %NULL
|
||
|
* @error: a #GError, or %NULL
|
||
|
*
|
||
|
* Completes a request to asynchronously insert a breakpoint.
|
||
|
*
|
||
|
* See also: ide_debugger_insert_breakpoint_async()
|
||
|
*
|
||
|
* Returns: %TRUE if the command was submitted successfully; otherwise %FALSE
|
||
|
* and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_insert_breakpoint_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->insert_breakpoint_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_remove_breakpoint_async:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @breakpoint: An #IdeDebuggerBreakpoint
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: an async callback to complete the operation
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that a breakpoint is removed from the debugger.
|
||
|
*
|
||
|
* This asynchronous function may complete before the breakpoint has been
|
||
|
* removed by the debugger. Debugger implementations will emit
|
||
|
* #IdeDebugger::breakpoint-removed when a breakpoint has been removed.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_remove_breakpoint_async (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpoint *breakpoint,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->remove_breakpoint_async (self,
|
||
|
breakpoint,
|
||
|
cancellable,
|
||
|
callback,
|
||
|
user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_remove_breakpoint_finish:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @result: a #GAsyncResult or %NULL
|
||
|
* @error: a #GError, or %NULL
|
||
|
*
|
||
|
* Completes a request to asynchronously remove a breakpoint.
|
||
|
*
|
||
|
* See also: ide_debugger_remove_breakpoint_async()
|
||
|
*
|
||
|
* Returns: %TRUE if the command was submitted successfully; otherwise %FALSE and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_remove_breakpoint_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->remove_breakpoint_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_modify_breakpoint_async:
|
||
|
* @self: An #IdeDebugger
|
||
|
* @change: An #IdeDebuggerBreakpointChange
|
||
|
* @breakpoint: An #IdeDebuggerBreakpoint
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: an async callback to complete the operation
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that a breakpoint is modified by the debugger backend.
|
||
|
*
|
||
|
* Specify @change for how to modify the breakpoint.
|
||
|
*
|
||
|
* This asynchronous function may complete before the breakpoint has been
|
||
|
* modified by the debugger. Debugger implementations will emit
|
||
|
* #IdeDebugger::breakpoint-modified when a breakpoint has been removed.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_modify_breakpoint_async (IdeDebugger *self,
|
||
|
IdeDebuggerBreakpointChange change,
|
||
|
IdeDebuggerBreakpoint *breakpoint,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT_CHANGE (change));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_BREAKPOINT (breakpoint));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->modify_breakpoint_async (self,
|
||
|
change,
|
||
|
breakpoint,
|
||
|
cancellable,
|
||
|
callback,
|
||
|
user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_modify_breakpoint_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to modify a breakpoint.
|
||
|
*
|
||
|
* Note that this only completes the submission of the request, if you need to
|
||
|
* know when the breakpoint has been modified, listen to the
|
||
|
* #IdeDebugger::breakpoint-modified signal.
|
||
|
*
|
||
|
* Returns: %TRUE if successful; otherwise %FALSE and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_modify_breakpoint_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->modify_breakpoint_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_breakpoints:
|
||
|
* @self: An #IdeDebugger
|
||
|
*
|
||
|
* Gets the breakpoints for the #IdeDebugger.
|
||
|
*
|
||
|
* Contrast this to ide_debugger_list_breakpoints_async() which will query
|
||
|
* the debugger backend for breakpoints. This #GListModel containing
|
||
|
* #IdeDebuggerBreakpoint instances is updated as necessary by listening
|
||
|
* to various breakpoint related signals on the #IdeDebugger instance.
|
||
|
*
|
||
|
* This is primarily out of convenience to be used by UI which wants to
|
||
|
* display information on breakpoints.
|
||
|
*
|
||
|
* Returns: (transfer none) (not nullable): a #GListModel of #IdeDebuggerBreakpoint
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GListModel *
|
||
|
ide_debugger_get_breakpoints (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
return G_LIST_MODEL (priv->breakpoints);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_thread_groups:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* Gets the thread groups that have been registered by the debugger.
|
||
|
*
|
||
|
* The resulting #GListModel accuracy is based on the #IdeDebugger
|
||
|
* implementation emitting varous thread-group modification signals correctly.
|
||
|
*
|
||
|
* Returns: (transfer none) (not nullable): a #GListModel of #IdeDebuggerThreadGroup
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GListModel *
|
||
|
ide_debugger_get_thread_groups (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
return G_LIST_MODEL (priv->thread_groups);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_threads:
|
||
|
* @self: a #IdeDebugger
|
||
|
*
|
||
|
* Gets the threads that have been registered by the debugger.
|
||
|
*
|
||
|
* The resulting #GListModel accuracy is based on the #IdeDebugger
|
||
|
* implementation emitting varous thread modification signals correctly.
|
||
|
*
|
||
|
* Returns: (transfer none) (not nullable): a #GListModel of #IdeDebuggerThread
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GListModel *
|
||
|
ide_debugger_get_threads (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
return G_LIST_MODEL (priv->threads);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ide_debugger_list_frames_async (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->list_frames_async (self, thread, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_frames_finish:
|
||
|
*
|
||
|
*
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerFrame) (nullable): An
|
||
|
* array of debugger frames or %NULL and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_list_frames_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->list_frames_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_get_selected_thread:
|
||
|
* @self: An #IdeDebugger
|
||
|
*
|
||
|
* Gets the current selected thread by the debugger.
|
||
|
*
|
||
|
* Returns: (transfer none) (nullable): An #IdeDebuggerThread or %NULL
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
IdeDebuggerThread *
|
||
|
ide_debugger_get_selected_thread (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
return priv->selected;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_interrupt_async:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @thread_group: (nullable): An #IdeDebuggerThreadGroup
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: (closure user_data): a callback to execute upon completion
|
||
|
* @user_data: closure data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that the debugger interrupts execution of a thread
|
||
|
* group. Thread groups are a collection of threads that are executed or
|
||
|
* stopped together and on gdb on Linux, this is the default for all threads in
|
||
|
* the process.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_interrupt_async (IdeDebugger *self,
|
||
|
IdeDebuggerThreadGroup *thread_group,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (!thread_group || IDE_IS_DEBUGGER_THREAD_GROUP (thread_group));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->interrupt_async (self, thread_group, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
ide_debugger_interrupt_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->interrupt_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
ide_debugger_get_is_running (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
|
||
|
return priv->is_running;
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
_ide_debugger_get_has_started (IdeDebugger *self)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
|
||
|
return priv->has_started;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ide_debugger_send_signal_async (IdeDebugger *self,
|
||
|
gint signum,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->send_signal_async (self, signum, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
ide_debugger_send_signal_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->send_signal_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_locate_binary_at_address:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @address: the address within the inferior process space
|
||
|
*
|
||
|
* Attempts to locate the binary that contains a given address.
|
||
|
*
|
||
|
* @address should be an address within the inferiors process space.
|
||
|
*
|
||
|
* This works by keeping track of libraries as they are loaded and unloaded and
|
||
|
* their associated file mappings.
|
||
|
*
|
||
|
* Currently, the filename will match the name in the inferior mount namespace,
|
||
|
* but that may change based on future design changes.
|
||
|
*
|
||
|
* Returns: the filename of the binary or %NULL
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
const gchar *
|
||
|
ide_debugger_locate_binary_at_address (IdeDebugger *self,
|
||
|
IdeDebuggerAddress address)
|
||
|
{
|
||
|
IdeDebuggerPrivate *priv = ide_debugger_get_instance_private (self);
|
||
|
const IdeDebuggerAddressMapEntry *entry;
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
|
||
|
entry = ide_debugger_address_map_lookup (priv->map, address);
|
||
|
|
||
|
if (entry != NULL)
|
||
|
return entry->filename;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_locals_async:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
* @frame: an #IdeDebuggerFrame
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: A callback to call once the operation has finished
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Requests the debugger backend to list the locals that are available to the
|
||
|
* given @frame of @thread.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_list_locals_async (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread,
|
||
|
IdeDebuggerFrame *frame,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_FRAME (frame));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->list_locals_async (self,
|
||
|
thread,
|
||
|
frame,
|
||
|
cancellable,
|
||
|
callback,
|
||
|
user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_locals_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_debugger_list_locals_async().
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerVariable): a #GPtrArray of
|
||
|
* #IdeDebuggerVariable if successful; otherwise %NULL and error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_list_locals_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->list_locals_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_params_async:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @thread: an #IdeDebuggerThread
|
||
|
* @frame: an #IdeDebuggerFrame
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: A callback to call once the operation has finished
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Requests the debugger backend to list the parameters to the given stack
|
||
|
* frame.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_list_params_async (IdeDebugger *self,
|
||
|
IdeDebuggerThread *thread,
|
||
|
IdeDebuggerFrame *frame,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_THREAD (thread));
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER_FRAME (frame));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->list_params_async (self,
|
||
|
thread,
|
||
|
frame,
|
||
|
cancellable,
|
||
|
callback,
|
||
|
user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_params_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_debugger_list_params_async().
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerVariable): a #GPtrArray of
|
||
|
* #IdeDebuggerVariable if successful; otherwise %NULL and error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_list_params_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->list_params_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_registers_async:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: A callback to call once the operation has finished
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Requests the list of registers and their values.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_list_registers_async (IdeDebugger *self,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->list_registers_async (self, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_list_registers_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_debugger_list_registers_async().
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerRegister): a #GPtrArray of
|
||
|
* #IdeDebuggerRegister if successful; otherwise %NULL and error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_list_registers_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->list_registers_finish (self, result, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_disassemble_async:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @range: an #IdeDebuggerAddressRange to disassemble
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: A callback to call once the operation has finished
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Disassembles the address range requested.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_disassemble_async (IdeDebugger *self,
|
||
|
const IdeDebuggerAddressRange *range,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (range != NULL);
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->disassemble_async (self, range, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_disassemble_finish:
|
||
|
* @self: a #IdeDebugger
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_debugger_disassemble_async().
|
||
|
*
|
||
|
* Returns: (transfer full) (element-type Ide.DebuggerInstruction): a #GPtrArray
|
||
|
* of #IdeDebuggerInstruction if successful; otherwise %NULL and error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GPtrArray *
|
||
|
ide_debugger_disassemble_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), NULL);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
||
|
|
||
|
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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_prepare (IdeDebugger *self,
|
||
|
IdeRunner *runner)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (IDE_IS_RUNNER (runner));
|
||
|
|
||
|
if (IDE_DEBUGGER_GET_CLASS (self)->prepare)
|
||
|
IDE_DEBUGGER_GET_CLASS (self)->prepare (self, runner);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_interpret_async:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @command: a command to execute
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: a callback to execute, or %NULL
|
||
|
* @user_data: user data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that the debugger interpret the command.
|
||
|
*
|
||
|
* This is used by the interactive-console to submit commands to the debugger
|
||
|
* that are in the native syntax of that debugger.
|
||
|
*
|
||
|
* The debugger is expected to return any textual output via the
|
||
|
* IdeDebugger::log signal.
|
||
|
*
|
||
|
* Call ide_debugger_interpret_finish() from @callback to determine if the
|
||
|
* command was interpreted.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_debugger_interpret_async (IdeDebugger *self,
|
||
|
const gchar *command,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_DEBUGGER (self));
|
||
|
g_return_if_fail (command != NULL);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->interpret_async (self, command, cancellable, callback, user_data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_debugger_interpret_finish:
|
||
|
* @self: an #IdeDebugger
|
||
|
* @result: a #GAsyncResult provided to callback
|
||
|
* @error: a location for a #GError, or %NULL
|
||
|
*
|
||
|
* Retrieves the result of the asynchronous operation to interpret a debugger
|
||
|
* command.
|
||
|
*
|
||
|
* Returns: %TRUE if the command was interpreted, otherwise %FALSE and
|
||
|
* @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_debugger_interpret_finish (IdeDebugger *self,
|
||
|
GAsyncResult *result,
|
||
|
GError **error)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
|
||
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||
|
|
||
|
return IDE_DEBUGGER_GET_CLASS (self)->interpret_finish (self, result, error);
|
||
|
}
|