Commit 27af0636 authored by Christian Hergert's avatar Christian Hergert

debugger: add minimal debugger API

This is an initial implementation to provide a debugger API to Builder.  It is
not complete, but should be considered a technology preview as we complete the
feature-set that users come to expect from debugger tooling.

It should, however, give you an idea of where we are going with things, even if
UI and APIs should change a bit in the upcoming months.

Debuggers should implement the IdeDebugger API (which is a base class to make
things more convenient). A reference implementation using GDB will be provided
in a forth-coming commit.

Most operations are asynchronous, as debuggers can be very slow given some
hardware configurations.

Of note, we do not yet have support for diving into varibles such as fields,
variable hover, or data visualizers. These features and more avanced ones such
as server-side variables will come in the form of a future release, such as
GNOME 3.28.
parent 2c2440f5
......@@ -12,6 +12,8 @@
<file compressed="true">scalable/actions/builder-view-bottom-pane-symbolic.svg</file>
<file compressed="true">scalable/actions/builder-view-left-pane-symbolic.svg</file>
<file compressed="true">scalable/actions/builder-view-right-pane-symbolic.svg</file>
<file compressed="true">scalable/actions/builder-debugger-symbolic.svg</file>
<file compressed="true">scalable/actions/debug-breakpoint-symbolic.svg</file>
<file compressed="true">scalable/actions/debug-continue-symbolic.svg</file>
<file compressed="true">scalable/actions/debug-execute-from-cursor-symbolic.svg</file>
<file compressed="true">scalable/actions/debug-execute-to-cursor-symbolic.svg</file>
......
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:cc='http://creativecommons.org/ns#' xmlns:dc='http://purl.org/dc/elements/1.1/' sodipodi:docname='nemiver-symbolic.svg' height='16' id='svg7384' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' xmlns:osb='http://www.openswatchbook.org/uri/2009/osb' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:svg='http://www.w3.org/2000/svg' version='1.1' inkscape:version='0.91 r13725' width='16' xmlns='http://www.w3.org/2000/svg'>
<metadata id='metadata90'>
<rdf:RDF>
<cc:Work rdf:about=''>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage'/>
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview inkscape:bbox-paths='true' bordercolor='#666666' borderopacity='1' inkscape:current-layer='layer9' inkscape:cx='5.1146516' inkscape:cy='-47.54864' gridtolerance='10' inkscape:guide-bbox='true' guidetolerance='10' id='namedview88' inkscape:object-nodes='false' inkscape:object-paths='false' objecttolerance='10' pagecolor='#555753' inkscape:pageopacity='1' inkscape:pageshadow='2' showborder='false' showgrid='false' showguides='true' inkscape:snap-bbox='true' inkscape:snap-bbox-midpoints='false' inkscape:snap-global='true' inkscape:snap-grids='true' inkscape:snap-nodes='true' inkscape:snap-others='false' inkscape:snap-to-guides='true' inkscape:window-height='1376' inkscape:window-maximized='1' inkscape:window-width='2560' inkscape:window-x='0' inkscape:window-y='27' inkscape:zoom='4'>
<inkscape:grid empspacing='2' enabled='true' id='grid4866' originx='-162' originy='-382' snapvisiblegridlinesonly='true' spacingx='1px' spacingy='1px' type='xygrid' visible='true'/>
</sodipodi:namedview>
<title id='title9167'>Gnome Symbolic Icon Theme</title>
<defs id='defs7386'>
<linearGradient id='linearGradient7212' osb:paint='solid'>
<stop id='stop7214' offset='0' style='stop-color:#000000;stop-opacity:1;'/>
</linearGradient>
</defs>
<g inkscape:groupmode='layer' id='layer9' inkscape:label='apps' style='display:inline' transform='translate(-403.0002,165)'>
<path inkscape:connector-curvature='0' d='m 409.46895,-165 c -0.25969,0 -0.46875,0.20906 -0.46875,0.46875 l 0,1.875 c -1.03854,0.49004 -1.79689,1.48201 -1.96875,2.65625 l 6.9375,0 c -0.17186,-1.17424 -0.93021,-2.16621 -1.96875,-2.65625 l 0,-1.875 c 0,-0.25969 -0.20906,-0.46875 -0.46875,-0.46875 z m 0.0312,1 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2.5,5 0,1 4.5,0 c 0.26179,3e-5 0.49997,0.23821 0.5,0.5 l 0,6 c -3e-5,0.26179 -0.23821,0.49997 -0.5,0.5 l -4.5,0 0,0.96875 c 0,0.57402 0.45723,1.03125 1.03125,1.03125 l 4.9375,0 c 0.57402,0 1.03125,-0.45723 1.03125,-1.03125 l 0,-8.96875 z m 0,2 0,5 4,0 0,-5 z' id='rect7914' sodipodi:nodetypes='ssccccsssssssscccccccssssccccccc' style='fill:#bebebe;fill-opacity:1;stroke:none'/>
</g>
</svg>
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg xmlns:cc='http://creativecommons.org/ns#' xmlns:dc='http://purl.org/dc/elements/1.1/' height='16' id='svg5082' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 16.000141 16' width='16.000141' xmlns='http://www.w3.org/2000/svg'>
<defs id='defs5084'/>
<metadata id='metadata5087'>
<rdf:RDF>
<cc:Work rdf:about=''>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage'/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id='layer1' transform='translate(-11.999858,172)'>
<path d='m 14,-169 c -0.833333,0 -1.525274,0.56422 -1.769531,1.05273 C 11.986212,-167.45875 12,-167 12,-167 v 6 c 0,0.83333 0.56422,1.52527 1.052734,1.76953 C 13.541248,-158.98621 14,-159 14,-159 h 9.761719 c 0.301837,-6e-5 0.587504,-0.13643 0.777343,-0.37109 l 3.238282,-4 c 0.296658,-0.3668 0.296658,-0.89102 0,-1.25782 l -3.238282,-4 c -0.189839,-0.23466 -0.475506,-0.37103 -0.777343,-0.37109 z' id='path1053' style='color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#555555;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate'/>
<path d='m 14,-169 c -0.833333,0 -1.525274,0.56422 -1.769531,1.05273 C 11.986212,-167.45875 12,-167 12,-167 v 6 c 0,0.83333 0.56422,1.52527 1.052734,1.76953 C 13.541248,-158.98621 14,-159 14,-159 h 9.761719 c 0.301837,-6e-5 0.587504,-0.13643 0.777343,-0.37109 l 3.238282,-4 c 0.296658,-0.3668 0.296658,-0.89102 0,-1.25782 l -3.238282,-4 c -0.189839,-0.23466 -0.475506,-0.37103 -0.777343,-0.37109 z' id='path4505' style='color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#555555;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate'/>
</g>
</svg>
......@@ -63,11 +63,14 @@
#define TAG_NOTE "diagnostician::note"
#define TAG_SNIPPET_TAB_STOP "snippet::tab-stop"
#define TAG_DEFINITION "action::hover-definition"
#define TAG_CURRENT_BKPT "debugger::current-breakpoint"
#define DEPRECATED_COLOR "#babdb6"
#define ERROR_COLOR "#ff0000"
#define NOTE_COLOR "#708090"
#define WARNING_COLOR "#fcaf3e"
#define CURRENT_BKPT_FG "#fffffe"
#define CURRENT_BKPT_BG "#fcaf3e"
typedef struct
{
......@@ -1033,6 +1036,14 @@ ide_buffer_notify_style_scheme (IdeBuffer *self,
apply_style (GET_TAG (TAG_DEFINITION),
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
if (!ide_source_style_scheme_apply_style (style_scheme,
TAG_CURRENT_BKPT,
GET_TAG (TAG_CURRENT_BKPT)))
apply_style (GET_TAG (TAG_CURRENT_BKPT),
"paragraph-background", CURRENT_BKPT_BG,
"foreground", CURRENT_BKPT_FG,
NULL);
}
#undef GET_TAG
......@@ -1289,6 +1300,10 @@ ide_buffer_init_tags (IdeBuffer *self)
gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (self), TAG_DEFINITION,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (self), TAG_CURRENT_BKPT,
"paragraph-background", CURRENT_BKPT_BG,
"foreground", CURRENT_BKPT_FG,
NULL);
g_signal_connect_object (tag_table,
"tag-added",
......
[Plugin]
Module=debugger
Name=Debugger
Description=Debugger integration for Builder
Authors=Christian Hergert <chergert@redhat.com>
Copyright=Copyright © 2017 Christian Hergert
Depends=editor
Builtin=true
Hidden=true
Embedded=ide_debugger_register_types
<?xml version="1.0"?>
<interface>
<menu id="run-menu">
<section id="run-menu-section">
<item>
<attribute name="id">debugger-run-handler</attribute>
<attribute name="after">default-run-handler</attribute>
<attribute name="action">run-manager.run-with-handler</attribute>
<attribute name="target">debugger</attribute>
<attribute name="label" translatable="yes">Run with Debugger</attribute>
<attribute name="verb-icon-name">builder-debugger-symbolic</attribute>
<attribute name="accel">F5</attribute>
</item>
</section>
</menu>
</interface>
This diff is collapsed.
/* ide-debug-manager.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ide-object.h"
#include "debugger/ide-debugger-breakpoints.h"
G_BEGIN_DECLS
#define IDE_TYPE_DEBUG_MANAGER (ide_debug_manager_get_type())
G_DECLARE_FINAL_TYPE (IdeDebugManager, ide_debug_manager, IDE, DEBUG_MANAGER, IdeObject)
IdeDebugger *ide_debug_manager_get_debugger (IdeDebugManager *self);
gboolean ide_debug_manager_get_active (IdeDebugManager *self);
gboolean ide_debug_manager_start (IdeDebugManager *self,
IdeRunner *runner,
GError **error);
void ide_debug_manager_stop (IdeDebugManager *self);
IdeDebuggerBreakpoints *ide_debug_manager_get_breakpoints_for_file (IdeDebugManager *self,
GFile *file);
G_END_DECLS
/* ide-debugger-actions.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-debugger-actions"
#include "ide-debugger-private.h"
typedef struct _IdeDebuggerActionEntry IdeDebuggerActionEntry;
typedef void (*IdeDebuggerActionHandler) (IdeDebugger *debugger,
const IdeDebuggerActionEntry *entry,
GVariant *param);
struct _IdeDebuggerActionEntry
{
const gchar *action_name;
IdeDebuggerActionHandler handler;
gint movement;
gint running_state;
};
enum {
RUNNING_STARTED = 1,
RUNNING_NOT_STARTED = 1 << 1,
RUNNING_ACTIVE = 1 << 2,
RUNNING_NOT_ACTIVE = 1 << 3,
};
static gboolean
check_running_state (IdeDebugger *self,
gint state)
{
if (state & RUNNING_STARTED)
{
if (!_ide_debugger_get_has_started (self))
return FALSE;
}
if (state & RUNNING_NOT_STARTED)
{
if (_ide_debugger_get_has_started (self))
return FALSE;
}
if (state & RUNNING_ACTIVE)
{
if (!ide_debugger_get_is_running (self))
return FALSE;
}
if (state & RUNNING_NOT_ACTIVE)
{
if (ide_debugger_get_is_running (self))
return FALSE;
}
return TRUE;
}
static void
ide_debugger_actions_movement (IdeDebugger *self,
const IdeDebuggerActionEntry *entry,
GVariant *param)
{
g_assert (IDE_IS_DEBUGGER (self));
g_assert (entry != NULL);
ide_debugger_move_async (self, entry->movement, NULL, NULL, NULL);
}
static void
ide_debugger_actions_stop (IdeDebugger *self,
const IdeDebuggerActionEntry *entry,
GVariant *param)
{
g_assert (IDE_IS_DEBUGGER (self));
g_assert (entry != NULL);
ide_debugger_interrupt_async (self, NULL, NULL, NULL, NULL);
}
static IdeDebuggerActionEntry action_info[] = {
{ "start", ide_debugger_actions_movement, IDE_DEBUGGER_MOVEMENT_START, RUNNING_NOT_STARTED },
{ "stop", ide_debugger_actions_stop, -1, RUNNING_STARTED | RUNNING_ACTIVE },
{ "continue", ide_debugger_actions_movement, IDE_DEBUGGER_MOVEMENT_CONTINUE, RUNNING_STARTED | RUNNING_NOT_ACTIVE },
{ "step-in", ide_debugger_actions_movement, IDE_DEBUGGER_MOVEMENT_STEP_IN, RUNNING_STARTED | RUNNING_NOT_ACTIVE },
{ "step-over", ide_debugger_actions_movement, IDE_DEBUGGER_MOVEMENT_STEP_OVER, RUNNING_STARTED | RUNNING_NOT_ACTIVE },
{ "finish", ide_debugger_actions_movement, IDE_DEBUGGER_MOVEMENT_FINISH, RUNNING_STARTED | RUNNING_NOT_ACTIVE },
};
static gboolean
ide_debugger_get_action_enabled (GActionGroup *group,
const gchar *action_name)
{
IdeDebugger *self = IDE_DEBUGGER (group);
for (guint i = 0; i < G_N_ELEMENTS (action_info); i++)
{
const IdeDebuggerActionEntry *entry = &action_info[i];
if (g_strcmp0 (entry->action_name, action_name) == 0)
return check_running_state (self, entry->running_state);
}
return FALSE;
}
void
_ide_debugger_update_actions (IdeDebugger *self)
{
g_assert (IDE_IS_DEBUGGER (self));
for (guint i = 0; i < G_N_ELEMENTS (action_info); i++)
{
const IdeDebuggerActionEntry *entry = &action_info[i];
gboolean enabled;
enabled = ide_debugger_get_action_enabled (G_ACTION_GROUP (self), entry->action_name);
g_action_group_action_enabled_changed (G_ACTION_GROUP (self), entry->action_name, enabled);
}
}
static gboolean
ide_debugger_has_action (GActionGroup *group,
const gchar *action_name)
{
g_assert (IDE_IS_DEBUGGER (group));
g_assert (action_name != NULL);
for (guint i = 0; i < G_N_ELEMENTS (action_info); i++)
{
const IdeDebuggerActionEntry *entry = &action_info[i];
if (g_strcmp0 (action_name, entry->action_name) == 0)
return TRUE;
}
return FALSE;
}
static gchar **
ide_debugger_list_actions (GActionGroup *group)
{
GPtrArray *ar = g_ptr_array_new ();
for (guint i = 0; i < G_N_ELEMENTS (action_info); i++)
g_ptr_array_add (ar, g_strdup (action_info[i].action_name));
g_ptr_array_add (ar, NULL);
return (gchar **)g_ptr_array_free (ar, FALSE);
}
static gpointer
null_return_func (void)
{
return NULL;
}
static void
ide_debugger_activate_action (GActionGroup *group,
const gchar *action_name,
GVariant *parameter)
{
IdeDebugger *self = IDE_DEBUGGER (group);
g_assert (IDE_IS_DEBUGGER (self));
g_assert (action_name != NULL);
for (guint i = 0; i < G_N_ELEMENTS (action_info); i++)
{
const IdeDebuggerActionEntry *entry = &action_info[i];
if (g_strcmp0 (entry->action_name, action_name) == 0)
{
entry->handler (self, entry, parameter);
break;
}
}
}
void
_ide_debugger_class_init_actions (GActionGroupInterface *iface)
{
iface->has_action = ide_debugger_has_action;
iface->list_actions = ide_debugger_list_actions;
iface->get_action_enabled = ide_debugger_get_action_enabled;
iface->activate_action = ide_debugger_activate_action;
iface->get_action_parameter_type = (gpointer)null_return_func;
iface->get_action_state_type = (gpointer)null_return_func;
iface->get_action_state_hint = (gpointer)null_return_func;
iface->get_action_state = (gpointer)null_return_func;
}
/* ide-debugger-address-map.c
*
* Copyright (C) 2016-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-debugger-address-map"
#include "ide-debugger-address-map.h"
struct _IdeDebuggerAddressMap
{
GSequence *seq;
GStringChunk *chunk;
};
static inline gint
uint64cmp (guint64 a,
guint64 b)
{
if (a < b)
return -1;
else if (a > b)
return 1;
else
return 0;
}
static gint
ide_debugger_address_map_entry_compare (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
const IdeDebuggerAddressMapEntry *entry_a = a;
const IdeDebuggerAddressMapEntry *entry_b = b;
return uint64cmp (entry_a->start, entry_b->start);
}
static gint
ide_debugger_address_map_entry_compare_in_range (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
const IdeDebuggerAddressMapEntry *entry_a = a;
const IdeDebuggerAddressMapEntry *entry_b = b;
/*
* entry_b is the needle for the search.
* Only entry_b->start is set.
*/
if ((entry_b->start >= entry_a->start) && (entry_b->start < entry_a->end))
return 0;
return uint64cmp (entry_a->start, entry_b->start);
}
static void
ide_debugger_address_map_entry_free (gpointer data)
{
IdeDebuggerAddressMapEntry *entry = data;
if (entry != NULL)
g_slice_free (IdeDebuggerAddressMapEntry, entry);
}
/**
* ide_debugger_address_map:
*
* Creates a new #IdeDebuggerAddressMap.
*
* The map is used to track the locations of mapped files in the inferiors
* address space. This allows relatively quick lookup to determine what file
* contains a given execution address (instruction pointer, etc).
*
* See also: ide_debugger_address_map_free()
*
* Returns: (transfer full): A new #IdeDebuggerAddressMap
*
* Since: 3.26
*/
IdeDebuggerAddressMap *
ide_debugger_address_map_new (void)
{
IdeDebuggerAddressMap *ret;
ret = g_slice_new (IdeDebuggerAddressMap);
ret->seq = g_sequence_new (ide_debugger_address_map_entry_free);
ret->chunk = g_string_chunk_new (4096);
return ret;
}
/**
* ide_debugger_address_map_free:
* @self: a #IdeDebuggerAddressMap
*
* Frees all memory associated with @self.
*
* Since: 3.26
*/
void
ide_debugger_address_map_free (IdeDebuggerAddressMap *self)
{
if (self != NULL)
{
g_sequence_free (self->seq);
g_string_chunk_free (self->chunk);
g_slice_free (IdeDebuggerAddressMap, self);
}
}
/**
* ide_debugger_address_map_insert:
* @self: a #IdeDebuggerAddressMap
* @map: the map entry to insert
*
* Inserts a new map entry as specified by @entry.
*
* The contents of @entry are copied and therefore do not need to be kept
* around after calling this function.
*
* See also: ide_debugger_address_map_remove()
*
* Since: 3.26
*/
void
ide_debugger_address_map_insert (IdeDebuggerAddressMap *self,
const IdeDebuggerAddressMapEntry *entry)
{
IdeDebuggerAddressMapEntry real = { 0 };
g_return_if_fail (self != NULL);
g_return_if_fail (entry != NULL);
real.filename = g_string_chunk_insert_const (self->chunk, entry->filename);
real.start = entry->start;
real.end = entry->end;
real.offset = entry->offset;
g_sequence_insert_sorted (self->seq,
g_slice_dup (IdeDebuggerAddressMapEntry, &real),
ide_debugger_address_map_entry_compare,
NULL);
}
/**
* ide_debugger_address_map_lookup:
* @self: a #IdeDebuggerAddressMap
* @address: an address to locate the containing map
*
* Attempts to locate which #IdeDebuggerAddressMapEntry contains @address within
* the region specified by #IdeDebuggerAddressMapEntry.start and
* #IdeDebuggerAddressMapEntry.end.
*
* Returns: (nullable): An #IdeDebuggerAddressMapEntry or %NULL
*
* Since: 3.26
*/
const IdeDebuggerAddressMapEntry *
ide_debugger_address_map_lookup (const IdeDebuggerAddressMap *self,
guint64 address)
{
IdeDebuggerAddressMapEntry entry = { NULL, 0, address, 0 };
GSequenceIter *iter;
g_return_val_if_fail (self != NULL, NULL);
iter = g_sequence_lookup (self->seq,
&entry,
ide_debugger_address_map_entry_compare_in_range,
NULL);
if (iter == NULL || g_sequence_iter_is_end (iter))
return NULL;
return g_sequence_get (iter);
}
/**
* ide_debugger_address_map_remove:
* @self: a #IdeDebuggerAddressMap
* @address: the address contained in the map
*
* Removes the entry found containing @address.
*
* Since: 3.26
*/
gboolean
ide_debugger_address_map_remove (IdeDebuggerAddressMap *self,
IdeDebuggerAddress address)
{
IdeDebuggerAddressMapEntry entry = { NULL, 0, address, 0 };
GSequenceIter *iter;
g_return_val_if_fail (self != NULL, FALSE);
iter = g_sequence_lookup (self->seq,
&entry,
ide_debugger_address_map_entry_compare_in_range,
NULL);
if (iter == NULL || g_sequence_iter_is_end (iter))
return FALSE;
g_sequence_remove (iter);
return TRUE;
}
/* ide-debugger-address-map.h
*
* Copyright (C) 2016-2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ide-debugger-types.h"
G_BEGIN_DECLS
typedef struct _IdeDebuggerAddressMap IdeDebuggerAddressMap;
typedef struct
{
/*
* The file on disk that is mapped and the offset within the file.
*/
const gchar *filename;
guint64 offset;
/*
* The range within the processes address space. We only support up to 64-bit
* address space for local and remote debugging.
*/
IdeDebuggerAddress start;
IdeDebuggerAddress end;
} IdeDebuggerAddressMapEntry;
IdeDebuggerAddressMap *ide_debugger_address_map_new (void);
void ide_debugger_address_map_insert (IdeDebuggerAddressMap *self,
const IdeDebuggerAddressMapEntry *entry);
gboolean ide_debugger_address_map_remove (IdeDebuggerAddressMap *self,
IdeDebuggerAddress address);
const IdeDebuggerAddressMapEntry *ide_debugger_address_map_lookup (const IdeDebuggerAddressMap *self,
IdeDebuggerAddress address);
void ide_debugger_address_map_free (IdeDebuggerAddressMap *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeDebuggerAddressMap, ide_debugger_address_map_free)
G_END_DECLS
This diff is collapsed.
/* ide-debugger-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/>.
*/
#pragma once
#include <glib-object.h>
#include "ide-debugger-frame.h"
#include "ide-debugger-types.h"
G_BEGIN_DECLS
#define IDE_TYPE_DEBUGGER_BREAKPOINT (ide_debugger_breakpoint_get_type())
G_DECLARE_DERIVABLE_TYPE (IdeDebuggerBreakpoint, ide_debugger_breakpoint, IDE, DEBUGGER_BREAKPOINT, GObject)
struct _IdeDebuggerBreakpointClass
{
GObjectClass parent_class;
void (*reset) (IdeDebuggerBreakpoint *self);