865 lines
23 KiB
C
865 lines
23 KiB
C
/* $Id$ */
|
|
static char const _debugger_copyright[] =
|
|
"Copyright © 2015 Pierre Pronchery <khorben@defora.org>";
|
|
static char const _debugger_license[] =
|
|
"Redistribution and use in source and binary forms, with or without\n"
|
|
"modification, are permitted provided that the following conditions\n"
|
|
"are met:\n"
|
|
"1. Redistributions of source code must retain the above copyright\n"
|
|
" notice, this list of conditions and the following disclaimer.\n"
|
|
"2. Redistributions in binary form must reproduce the above copyright\n"
|
|
" notice, this list of conditions and the following disclaimer in the\n"
|
|
" documentation and/or other materials provided with the distribution.\n"
|
|
"3. Neither the name of the authors nor the names of the contributors\n"
|
|
" may be used to endorse or promote products derived from this software\n"
|
|
" without specific prior written permission.\n"
|
|
"THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND\n"
|
|
"ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
|
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
|
"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE\n"
|
|
"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
|
|
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
|
|
"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
|
|
"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"
|
|
"LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"
|
|
"OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"
|
|
"SUCH DAMAGE.";
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <libintl.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include <Desktop.h>
|
|
#include "debugger.h"
|
|
#include "../config.h"
|
|
#define _(string) gettext(string)
|
|
#define N_(string) (string)
|
|
|
|
#ifndef PROGNAME
|
|
# define PROGNAME "debugger"
|
|
#endif
|
|
#ifndef PREFIX
|
|
# define PREFIX "/usr/local"
|
|
#endif
|
|
#ifndef LIBDIR
|
|
# define LIBDIR PREFIX "/lib"
|
|
#endif
|
|
|
|
|
|
/* Debugger */
|
|
/* private */
|
|
/* types */
|
|
enum { RV_NAME = 0, RV_VALUE, RV_VALUE_DISPLAY };
|
|
#define RV_LAST RV_VALUE_DISPLAY
|
|
#define RV_COUNT (RV_LAST + 1)
|
|
|
|
struct _Debugger
|
|
{
|
|
/* backend */
|
|
DebuggerBackendHelper bhelper;
|
|
Plugin * bplugin;
|
|
DebuggerBackendDefinition * bdefinition;
|
|
DebuggerBackend * backend;
|
|
|
|
/* debug */
|
|
DebuggerDebugHelper dhelper;
|
|
Plugin * dplugin;
|
|
DebuggerDebugDefinition * ddefinition;
|
|
DebuggerDebug * debug;
|
|
|
|
/* child */
|
|
char * filename;
|
|
|
|
/* widgets */
|
|
GtkWidget * window;
|
|
/* toolbar */
|
|
/* disassembly */
|
|
GtkWidget * das_view;
|
|
/* registers */
|
|
GtkWidget * reg_view;
|
|
/* statusbar */
|
|
GtkWidget * statusbar;
|
|
};
|
|
|
|
|
|
/* prototypes */
|
|
/* accessors */
|
|
static void _debugger_set_sensitive_toolbar(Debugger * debugger, gboolean run,
|
|
gboolean debug);
|
|
|
|
/* useful */
|
|
static gboolean _debugger_confirm(Debugger * debugger, char const * message);
|
|
static gboolean _debugger_confirm_close(Debugger * debugger);
|
|
static gboolean _debugger_confirm_reset(Debugger * debugger);
|
|
|
|
/* helpers */
|
|
static int _debugger_helper_error(Debugger * debugger, int code,
|
|
char const * format, ...);
|
|
/* backend */
|
|
static void _debugger_helper_backend_set_registers(Debugger * debugger,
|
|
AsmArchRegister const * registers, size_t registers_cnt);
|
|
|
|
/* callbacks */
|
|
static void _debugger_on_about(gpointer data);
|
|
static void _debugger_on_close(gpointer data);
|
|
static gboolean _debugger_on_closex(gpointer data);
|
|
static void _debugger_on_continue(gpointer data);
|
|
static void _debugger_on_next(gpointer data);
|
|
static void _debugger_on_open(gpointer data);
|
|
static void _debugger_on_pause(gpointer data);
|
|
static void _debugger_on_run(gpointer data);
|
|
static void _debugger_on_step(gpointer data);
|
|
static void _debugger_on_stop(gpointer data);
|
|
|
|
|
|
/* constants */
|
|
static char const * _debugger_authors[] =
|
|
{
|
|
"Pierre Pronchery <khorben@defora.org>",
|
|
NULL
|
|
};
|
|
|
|
static DesktopMenu const _debugger_menu_file[] =
|
|
{
|
|
{ N_("_Open..."), G_CALLBACK(_debugger_on_open), GTK_STOCK_OPEN,
|
|
GDK_CONTROL_MASK, GDK_KEY_O },
|
|
{ "", NULL, NULL, 0, 0 },
|
|
{ N_("_Close"), G_CALLBACK(_debugger_on_close), GTK_STOCK_CLOSE,
|
|
GDK_CONTROL_MASK, GDK_KEY_W },
|
|
{ NULL, NULL, NULL, 0, 0 }
|
|
};
|
|
|
|
static DesktopMenu const _debugger_menu_help[] =
|
|
{
|
|
#if GTK_CHECK_VERSION(2, 6, 0)
|
|
{ N_("_About"), G_CALLBACK(_debugger_on_about), GTK_STOCK_ABOUT, 0, 0 },
|
|
#else
|
|
{ N_("_About"), G_CALLBACK(_debugger_on_about), NULL, 0, 0 },
|
|
#endif
|
|
{ NULL, NULL, NULL, 0, 0 }
|
|
};
|
|
|
|
static DesktopMenubar const _debugger_menubar[] =
|
|
{
|
|
{ N_("_File"), _debugger_menu_file },
|
|
{ N_("_Help"), _debugger_menu_help },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
|
|
/* variables */
|
|
#define DEBUGGER_TOOLBAR_RUN 2
|
|
#define DEBUGGER_TOOLBAR_CONTINUE 4
|
|
#define DEBUGGER_TOOLBAR_PAUSE 5
|
|
#define DEBUGGER_TOOLBAR_STOP 6
|
|
#define DEBUGGER_TOOLBAR_STEP 7
|
|
#define DEBUGGER_TOOLBAR_NEXT 8
|
|
static DesktopToolbar _debugger_toolbar[] =
|
|
{
|
|
{ N_("Open"), G_CALLBACK(_debugger_on_open), GTK_STOCK_OPEN,
|
|
GDK_CONTROL_MASK, GDK_KEY_O, NULL },
|
|
{ "", NULL, NULL, 0, 0, NULL },
|
|
{ N_("Run"), G_CALLBACK(_debugger_on_run), GTK_STOCK_EXECUTE, 0,
|
|
GDK_KEY_F10, NULL },
|
|
{ "", NULL, NULL, 0, 0, NULL },
|
|
{ N_("Continue"), G_CALLBACK(_debugger_on_continue),
|
|
GTK_STOCK_MEDIA_PLAY, 0, GDK_KEY_F9, NULL },
|
|
{ N_("Pause"), G_CALLBACK(_debugger_on_pause),
|
|
GTK_STOCK_MEDIA_PAUSE, 0, 0, NULL },
|
|
{ N_("Stop"), G_CALLBACK(_debugger_on_stop),
|
|
GTK_STOCK_MEDIA_STOP, 0, GDK_KEY_F11, NULL },
|
|
{ N_("Step"), G_CALLBACK(_debugger_on_step),
|
|
GTK_STOCK_MEDIA_FORWARD, 0, 0, NULL },
|
|
{ N_("Next"), G_CALLBACK(_debugger_on_next),
|
|
GTK_STOCK_MEDIA_NEXT, 0, 0, NULL },
|
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
|
};
|
|
|
|
|
|
/* XXX load at run-time */
|
|
#include "backend/asm.c"
|
|
#include "debug/ptrace.c"
|
|
|
|
|
|
/* public */
|
|
/* functions */
|
|
/* debugger_new */
|
|
Debugger * debugger_new(void)
|
|
{
|
|
Debugger * debugger;
|
|
GtkAccelGroup * accel;
|
|
GtkWidget * vbox;
|
|
GtkWidget * paned;
|
|
GtkWidget * widget;
|
|
GtkListStore * store;
|
|
GtkTreeViewColumn * column;
|
|
|
|
if((debugger = object_new(sizeof(*debugger))) == NULL)
|
|
return NULL;
|
|
/* backend */
|
|
debugger->bhelper.debugger = debugger;
|
|
debugger->bhelper.error = _debugger_helper_error;
|
|
debugger->bhelper.set_registers
|
|
= _debugger_helper_backend_set_registers;
|
|
debugger->bplugin = NULL;
|
|
debugger->bdefinition = &_asm_definition; /* XXX */
|
|
debugger->backend = NULL;
|
|
/* debug */
|
|
debugger->dhelper.debugger = debugger;
|
|
debugger->dhelper.error = _debugger_helper_error;
|
|
debugger->dplugin = NULL;
|
|
debugger->ddefinition = NULL;
|
|
debugger->debug = NULL;
|
|
/* child */
|
|
debugger->filename = NULL;
|
|
/* check for errors */
|
|
if((debugger->backend = debugger->bdefinition->init(&debugger->bhelper))
|
|
== NULL)
|
|
{
|
|
debugger_delete(debugger);
|
|
return NULL;
|
|
}
|
|
/* widgets */
|
|
accel = gtk_accel_group_new();
|
|
debugger->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_add_accel_group(GTK_WINDOW(debugger->window), accel);
|
|
gtk_window_set_default_size(GTK_WINDOW(debugger->window), 640, 480);
|
|
gtk_window_set_title(GTK_WINDOW(debugger->window), _("Debugger"));
|
|
g_signal_connect_swapped(debugger->window, "delete-event", G_CALLBACK(
|
|
_debugger_on_closex), debugger);
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
|
#else
|
|
vbox = gtk_vbox_new(FALSE, 0);
|
|
#endif
|
|
/* menubar */
|
|
widget = desktop_menubar_create(_debugger_menubar, debugger, accel);
|
|
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
|
/* toolbar */
|
|
widget = desktop_toolbar_create(_debugger_toolbar, debugger, accel);
|
|
g_object_unref(accel);
|
|
_debugger_set_sensitive_toolbar(debugger, FALSE, FALSE);
|
|
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
|
/* view */
|
|
paned = gtk_hpaned_new();
|
|
/* assembly */
|
|
debugger->das_view = gtk_text_view_new();
|
|
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(debugger->das_view),
|
|
FALSE);
|
|
gtk_text_view_set_editable(GTK_TEXT_VIEW(debugger->das_view), FALSE);
|
|
gtk_paned_add1(GTK_PANED(paned), debugger->das_view);
|
|
/* registers */
|
|
widget = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
store = gtk_list_store_new(RV_COUNT,
|
|
G_TYPE_STRING, /* name */
|
|
G_TYPE_UINT64, /* value */
|
|
G_TYPE_STRING); /* value (string) */
|
|
debugger->reg_view = gtk_tree_view_new_with_model(
|
|
GTK_TREE_MODEL(store));
|
|
column = gtk_tree_view_column_new_with_attributes(_("Register"),
|
|
gtk_cell_renderer_text_new(), "text", RV_NAME, NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(debugger->reg_view), column);
|
|
column = gtk_tree_view_column_new_with_attributes(_("Value"),
|
|
gtk_cell_renderer_text_new(), "text", RV_VALUE_DISPLAY,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(debugger->reg_view), column);
|
|
gtk_container_add(GTK_CONTAINER(widget), debugger->reg_view);
|
|
gtk_paned_add2(GTK_PANED(paned), widget);
|
|
gtk_paned_set_position(GTK_PANED(paned), 380);
|
|
gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0);
|
|
/* statusbar */
|
|
debugger->statusbar = gtk_statusbar_new();
|
|
gtk_box_pack_start(GTK_BOX(vbox), debugger->statusbar, FALSE, TRUE, 0);
|
|
gtk_container_add(GTK_CONTAINER(debugger->window), vbox);
|
|
gtk_widget_show_all(debugger->window);
|
|
return debugger;
|
|
}
|
|
|
|
|
|
/* debugger_delete */
|
|
void debugger_delete(Debugger * debugger)
|
|
{
|
|
if(debugger_is_running(debugger))
|
|
debugger_stop(debugger);
|
|
free(debugger->filename);
|
|
gtk_widget_destroy(debugger->window);
|
|
object_delete(debugger);
|
|
}
|
|
|
|
|
|
/* accessors */
|
|
/* debugger_is_opened */
|
|
int debugger_is_opened(Debugger * debugger)
|
|
{
|
|
if(debugger_is_running(debugger))
|
|
return TRUE;
|
|
/* FIXME really implement */
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* debugger_is_running */
|
|
int debugger_is_running(Debugger * debugger)
|
|
{
|
|
return (debugger->debug != NULL) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/* useful */
|
|
/* debugger_close */
|
|
int debugger_close(Debugger * debugger)
|
|
{
|
|
GtkTextBuffer * tbuf;
|
|
GtkTreeModel * model;
|
|
|
|
if(debugger_is_opened(debugger) == FALSE)
|
|
return 0;
|
|
tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger->das_view));
|
|
gtk_text_buffer_set_text(tbuf, "", 0);
|
|
model = gtk_tree_view_get_model(GTK_TREE_VIEW(debugger->reg_view));
|
|
gtk_list_store_clear(GTK_LIST_STORE(model));
|
|
/* FIXME really implement */
|
|
free(debugger->filename);
|
|
debugger->filename = NULL;
|
|
gtk_window_set_title(GTK_WINDOW(debugger->window), _("Debugger"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* debugger_continue */
|
|
int debugger_continue(Debugger * debugger)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
|
#endif
|
|
if(debugger_is_running(debugger) == FALSE)
|
|
return 0;
|
|
return debugger->ddefinition->_continue(debugger->debug);
|
|
}
|
|
|
|
|
|
/* debugger_error */
|
|
static int _error_text(char const * message, int ret);
|
|
|
|
int debugger_error(Debugger * debugger, char const * message, int ret)
|
|
{
|
|
const unsigned int flags = GTK_DIALOG_MODAL
|
|
| GTK_DIALOG_DESTROY_WITH_PARENT;
|
|
GtkWidget * widget;
|
|
|
|
if(debugger == NULL)
|
|
return _error_text(message, ret);
|
|
widget = gtk_message_dialog_new(GTK_WINDOW(debugger->window), flags,
|
|
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
|
#if GTK_CHECK_VERSION(2, 6, 0)
|
|
"%s", _("Error"));
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(widget),
|
|
#endif
|
|
"%s", message);
|
|
gtk_window_set_title(GTK_WINDOW(widget), _("Error"));
|
|
gtk_dialog_run(GTK_DIALOG(widget));
|
|
gtk_widget_destroy(widget);
|
|
return ret;
|
|
}
|
|
|
|
static int _error_text(char const * message, int ret)
|
|
{
|
|
fprintf(stderr, "%s: %s\n", PROGNAME, message);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* debugger_next */
|
|
int debugger_next(Debugger * debugger)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
|
#endif
|
|
if(debugger_is_running(debugger) == FALSE)
|
|
return 0;
|
|
return debugger->ddefinition->next(debugger->debug);
|
|
}
|
|
|
|
|
|
/* debugger_open */
|
|
int debugger_open(Debugger * debugger, char const * arch, char const * format,
|
|
char const * filename)
|
|
{
|
|
String * s;
|
|
|
|
if(_debugger_confirm_close(debugger) == FALSE)
|
|
return -1;
|
|
if(filename == NULL)
|
|
return debugger_open_dialog(debugger, arch, format);
|
|
if(debugger_close(debugger) != 0)
|
|
return -debugger_error(debugger, error_get(), 1);
|
|
if((debugger->filename = strdup(filename)) == NULL)
|
|
return -1;
|
|
if(debugger->bdefinition->open(debugger->backend, arch, format,
|
|
filename) != 0)
|
|
{
|
|
free(debugger->filename);
|
|
debugger->filename = NULL;
|
|
return -debugger_error(debugger, error_get(), 1);
|
|
}
|
|
if((s = string_new_append(_("Debugger"), " - ", filename, NULL))
|
|
!= NULL)
|
|
gtk_window_set_title(GTK_WINDOW(debugger->window), s);
|
|
string_delete(s);
|
|
_debugger_set_sensitive_toolbar(debugger, TRUE, FALSE);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* debugger_open_dialog */
|
|
static void _open_dialog_type(GtkWidget * combobox, char const * type,
|
|
char const * value);
|
|
|
|
int debugger_open_dialog(Debugger * debugger, char const * arch,
|
|
char const * format)
|
|
{
|
|
int ret = 0;
|
|
GtkWidget * dialog;
|
|
GtkWidget * vbox;
|
|
GtkWidget * hbox;
|
|
GtkWidget * awidget;
|
|
GtkWidget * fwidget;
|
|
GtkWidget * widget;
|
|
GtkFileFilter * filter;
|
|
char * a = NULL;
|
|
char * f = NULL;
|
|
char * filename = NULL;
|
|
|
|
if(_debugger_confirm_close(debugger) == FALSE)
|
|
return -1;
|
|
dialog = gtk_file_chooser_dialog_new(_("Open file..."),
|
|
GTK_WINDOW(debugger->window),
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
|
|
#if GTK_CHECK_VERSION(2, 14, 0)
|
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
#else
|
|
vbox = GTK_DIALOG(dialog)->vbox;
|
|
#endif
|
|
/* arch */
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
|
#else
|
|
hbox = gtk_hbox_new(FALSE, 4);
|
|
#endif
|
|
awidget = gtk_combo_box_new_text();
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(awidget), _("Auto-detect"));
|
|
_open_dialog_type(awidget, "arch", arch);
|
|
gtk_box_pack_end(GTK_BOX(hbox), awidget, FALSE, TRUE, 0);
|
|
widget = gtk_label_new(_("Architecture:"));
|
|
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
|
/* format */
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
|
#else
|
|
hbox = gtk_hbox_new(FALSE, 4);
|
|
#endif
|
|
fwidget = gtk_combo_box_new_text();
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(fwidget), _("Auto-detect"));
|
|
_open_dialog_type(fwidget, "format", format);
|
|
gtk_box_pack_end(GTK_BOX(hbox), fwidget, FALSE, TRUE, 0);
|
|
widget = gtk_label_new(_("File format:"));
|
|
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
|
gtk_widget_show_all(vbox);
|
|
/* executable files */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("Executable files"));
|
|
gtk_file_filter_add_mime_type(filter, "application/x-executable");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
/* all files */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("All files"));
|
|
gtk_file_filter_add_pattern(filter, "*");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
if(gtk_combo_box_get_active(GTK_COMBO_BOX(awidget)) == 0)
|
|
a = NULL;
|
|
else
|
|
a = gtk_combo_box_get_active_text(GTK_COMBO_BOX(
|
|
awidget));
|
|
if(gtk_combo_box_get_active(GTK_COMBO_BOX(fwidget)) == 0)
|
|
f = NULL;
|
|
else
|
|
f = gtk_combo_box_get_active_text(GTK_COMBO_BOX(
|
|
fwidget));
|
|
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(
|
|
dialog));
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
if(filename != NULL)
|
|
ret = debugger_open(debugger, a, f, filename);
|
|
g_free(a);
|
|
g_free(f);
|
|
g_free(filename);
|
|
return ret;
|
|
}
|
|
|
|
static void _open_dialog_type(GtkWidget * combobox, char const * type,
|
|
char const * value)
|
|
{
|
|
char * path;
|
|
DIR * dir;
|
|
struct dirent * de;
|
|
#ifdef __APPLE__
|
|
char const ext[] = ".dylib";
|
|
#else
|
|
char const ext[] = ".so";
|
|
#endif
|
|
size_t len;
|
|
int i;
|
|
int active = 0;
|
|
|
|
if((path = g_build_filename(LIBDIR, "Asm", type, NULL)) == NULL)
|
|
return;
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s(%s) \"%s\"\n", __func__, type, path);
|
|
#endif
|
|
dir = opendir(path);
|
|
g_free(path);
|
|
if(dir == NULL)
|
|
return;
|
|
for(i = 0; (de = readdir(dir)) != NULL; i++)
|
|
{
|
|
if(strcmp(de->d_name, ".") == 0
|
|
|| strcmp(de->d_name, "..") == 0)
|
|
continue;
|
|
if((len = strlen(de->d_name)) < sizeof(ext))
|
|
continue;
|
|
if(strcmp(&de->d_name[len - sizeof(ext) + 1], ext) != 0)
|
|
continue;
|
|
de->d_name[len - sizeof(ext) + 1] = '\0';
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), de->d_name);
|
|
if(value != NULL && strcmp(de->d_name, value) == 0)
|
|
active = i;
|
|
}
|
|
closedir(dir);
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), active);
|
|
}
|
|
|
|
|
|
/* debugger_pause */
|
|
int debugger_pause(Debugger * debugger)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
|
#endif
|
|
if(debugger_is_running(debugger) == FALSE)
|
|
return 0;
|
|
return debugger->ddefinition->pause(debugger->debug);
|
|
}
|
|
|
|
|
|
/* debugger_run */
|
|
int debugger_run(Debugger * debugger, ...)
|
|
{
|
|
int ret;
|
|
va_list ap;
|
|
|
|
va_start(ap, debugger);
|
|
ret = debugger_runv(debugger, ap);
|
|
va_end(ap);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* debugger_runv */
|
|
int debugger_runv(Debugger * debugger, va_list ap)
|
|
{
|
|
int ret;
|
|
|
|
if(_debugger_confirm_reset(debugger) == FALSE)
|
|
return -1;
|
|
if(debugger_stop(debugger) != 0)
|
|
return -1;
|
|
debugger->ddefinition = &_ptrace_definition; /* XXX */
|
|
if((debugger->debug = debugger->ddefinition->init(&debugger->dhelper))
|
|
== NULL)
|
|
{
|
|
debugger_stop(debugger);
|
|
return -1;
|
|
}
|
|
if((ret = debugger->ddefinition->start(debugger->debug, ap)) == 0)
|
|
_debugger_set_sensitive_toolbar(debugger, TRUE, TRUE);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* debugger_step */
|
|
int debugger_step(Debugger * debugger)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
|
#endif
|
|
if(debugger_is_running(debugger) == FALSE)
|
|
return 0;
|
|
return debugger->ddefinition->step(debugger->debug);
|
|
}
|
|
|
|
|
|
/* debugger_stop */
|
|
int debugger_stop(Debugger * debugger)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
|
#endif
|
|
if(debugger_is_running(debugger) == FALSE)
|
|
return 0;
|
|
debugger->ddefinition->stop(debugger->debug);
|
|
debugger->ddefinition->destroy(debugger->debug);
|
|
debugger->debug = NULL;
|
|
debugger->ddefinition = NULL;
|
|
if(debugger->dplugin != NULL)
|
|
plugin_delete(debugger->dplugin);
|
|
debugger->dplugin = NULL;
|
|
_debugger_set_sensitive_toolbar(debugger, TRUE, FALSE);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* private */
|
|
/* functions */
|
|
/* accessors */
|
|
/* debugger_set_sensitive_toolbar */
|
|
static void _debugger_set_sensitive_toolbar(Debugger * debugger, gboolean run,
|
|
gboolean debug)
|
|
{
|
|
const unsigned int widgets[] =
|
|
{
|
|
DEBUGGER_TOOLBAR_CONTINUE,
|
|
DEBUGGER_TOOLBAR_PAUSE,
|
|
DEBUGGER_TOOLBAR_STOP,
|
|
DEBUGGER_TOOLBAR_STEP,
|
|
DEBUGGER_TOOLBAR_NEXT
|
|
};
|
|
size_t i;
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(
|
|
_debugger_toolbar[DEBUGGER_TOOLBAR_RUN].widget),
|
|
run);
|
|
for(i = 0; i < sizeof(widgets) / sizeof(*widgets); i++)
|
|
gtk_widget_set_sensitive(GTK_WIDGET(
|
|
_debugger_toolbar[widgets[i]].widget),
|
|
debug);
|
|
}
|
|
|
|
|
|
/* useful */
|
|
/* debugger_confirm */
|
|
static gboolean _debugger_confirm(Debugger * debugger, char const * message)
|
|
{
|
|
const unsigned int flags = GTK_DIALOG_MODAL
|
|
| GTK_DIALOG_DESTROY_WITH_PARENT;
|
|
GtkWidget * widget;
|
|
int res;
|
|
|
|
widget = gtk_message_dialog_new(GTK_WINDOW(debugger->window), flags,
|
|
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
|
|
#if GTK_CHECK_VERSION(2, 6, 0)
|
|
"%s", _("Question"));
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(widget),
|
|
#endif
|
|
"%s", message);
|
|
gtk_window_set_title(GTK_WINDOW(widget), _("Question"));
|
|
res = gtk_dialog_run(GTK_DIALOG(widget));
|
|
gtk_widget_destroy(widget);
|
|
return (res == GTK_RESPONSE_YES) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
/* debugger_confirm_close */
|
|
static gboolean _debugger_confirm_close(Debugger * debugger)
|
|
{
|
|
if(debugger_is_opened(debugger)
|
|
&& _debugger_confirm(debugger, _(
|
|
"A file is already opened.\n"
|
|
"Would you like to close it?\n"
|
|
"Any progress will be lost.")) == FALSE)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* debugger_confirm_reset */
|
|
static gboolean _debugger_confirm_reset(Debugger * debugger)
|
|
{
|
|
if(debugger_is_running(debugger)
|
|
&& _debugger_confirm(debugger, _(
|
|
"A process is being debugged already\n"
|
|
"Would you like to restart it?\n"
|
|
"Any progress will be lost.")) == FALSE)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* helpers */
|
|
/* debugger_helper_error */
|
|
static int _debugger_helper_error(Debugger * debugger, int code,
|
|
char const * format, ...)
|
|
{
|
|
va_list ap;
|
|
int size;
|
|
char * message;
|
|
|
|
va_start(ap, format);
|
|
size = vsnprintf(NULL, 0, format, ap);
|
|
message = (size >= 0) ? malloc(size + 1) : NULL;
|
|
if(message != NULL)
|
|
vsnprintf(message, size + 1, format, ap);
|
|
va_end(ap);
|
|
if(message == NULL)
|
|
return code;
|
|
debugger_error(debugger, message, code);
|
|
free(message);
|
|
return code;
|
|
}
|
|
|
|
|
|
/* helpers: backend */
|
|
/* debugger_helper_backend_set_registers */
|
|
static void _debugger_helper_backend_set_registers(Debugger * debugger,
|
|
AsmArchRegister const * registers, size_t registers_cnt)
|
|
{
|
|
GtkTreeModel * model;
|
|
size_t i;
|
|
GtkTreeIter iter;
|
|
|
|
model = gtk_tree_view_get_model(GTK_TREE_VIEW(debugger->reg_view));
|
|
gtk_list_store_clear(GTK_LIST_STORE(model));
|
|
for(i = 0; i < registers_cnt; i++)
|
|
{
|
|
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
|
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
|
|
RV_NAME, registers[i].name, -1);
|
|
}
|
|
}
|
|
|
|
|
|
/* callbacks */
|
|
/* debugger_on_about */
|
|
static void _debugger_on_about(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
GtkWidget * dialog;
|
|
|
|
dialog = desktop_about_dialog_new();
|
|
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
|
|
debugger->window));
|
|
desktop_about_dialog_set_authors(dialog, _debugger_authors);
|
|
desktop_about_dialog_set_comments(dialog,
|
|
_("Debugger for the DeforaOS desktop"));
|
|
desktop_about_dialog_set_copyright(dialog, _debugger_copyright);
|
|
desktop_about_dialog_set_logo_icon_name(dialog,
|
|
"applications-development");
|
|
desktop_about_dialog_set_license(dialog, _debugger_license);
|
|
desktop_about_dialog_set_name(dialog, _("Debugger"));
|
|
desktop_about_dialog_set_version(dialog, VERSION);
|
|
desktop_about_dialog_set_website(dialog,
|
|
"http://www.defora.org/");
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
|
|
/* debugger_on_close */
|
|
static void _debugger_on_close(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
if(debugger_is_running(debugger))
|
|
debugger_stop(debugger);
|
|
gtk_main_quit();
|
|
}
|
|
|
|
|
|
/* debugger_on_closex */
|
|
static gboolean _debugger_on_closex(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
_debugger_on_close(debugger);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* debugger_on_continue */
|
|
static void _debugger_on_continue(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_continue(debugger);
|
|
}
|
|
|
|
|
|
/* debugger_on_next */
|
|
static void _debugger_on_next(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_next(debugger);
|
|
}
|
|
|
|
|
|
/* debugger_on_open */
|
|
static void _debugger_on_open(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_open_dialog(debugger, NULL, NULL);
|
|
}
|
|
|
|
|
|
/* debugger_on_pause */
|
|
static void _debugger_on_pause(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_pause(debugger);
|
|
}
|
|
|
|
|
|
/* debugger_on_run */
|
|
static void _debugger_on_run(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_run(debugger, debugger->filename, NULL);
|
|
}
|
|
|
|
|
|
/* debugger_on_step */
|
|
static void _debugger_on_step(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_step(debugger);
|
|
}
|
|
|
|
|
|
/* debugger_on_stop */
|
|
static void _debugger_on_stop(gpointer data)
|
|
{
|
|
Debugger * debugger = data;
|
|
|
|
debugger_stop(debugger);
|
|
}
|