352 lines
9.9 KiB
C
352 lines
9.9 KiB
C
/* $Id$ */
|
|
/* Copyright (c) 2015-2020 Pierre Pronchery <khorben@defora.org> */
|
|
/* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the authors nor the names of the contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE. */
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <libintl.h>
|
|
#include <gtk/gtk.h>
|
|
#include <System.h>
|
|
#include <Desktop.h>
|
|
#include <Devel/Asm.h>
|
|
#include "../backend.h"
|
|
#include "../debugger.h"
|
|
#include "../../config.h"
|
|
#define _(string) gettext(string)
|
|
|
|
#ifndef PREFIX
|
|
# define PREFIX "/usr/local"
|
|
#endif
|
|
#ifndef LIBDIR
|
|
# define LIBDIR PREFIX "/lib"
|
|
#endif
|
|
|
|
|
|
/* asm */
|
|
/* private */
|
|
typedef struct _DebuggerBackend AsmBackend;
|
|
|
|
struct _DebuggerBackend
|
|
{
|
|
DebuggerBackendHelper const * helper;
|
|
Asm * a;
|
|
AsmCode * code;
|
|
|
|
guint source;
|
|
};
|
|
|
|
|
|
/* prototypes */
|
|
/* plug-in */
|
|
static AsmBackend * _asm_init(DebuggerBackendHelper const * helper);
|
|
static void _asm_destroy(AsmBackend * backend);
|
|
static int _asm_open(AsmBackend * backend, char const * arch,
|
|
char const * format, char const * filename);
|
|
static char * _asm_open_dialog(AsmBackend * backend, GtkWidget * window,
|
|
char const * arch, char const * format);
|
|
static int _asm_close(AsmBackend * backend);
|
|
static char const * _asm_arch_get_name(AsmBackend * backend);
|
|
static char const * _asm_format_get_name(AsmBackend * backend);
|
|
|
|
|
|
/* constants */
|
|
DebuggerBackendDefinition backend =
|
|
{
|
|
"asm",
|
|
NULL,
|
|
LICENSE_BSD3_FLAGS,
|
|
_asm_init,
|
|
_asm_destroy,
|
|
_asm_open,
|
|
_asm_open_dialog,
|
|
_asm_close,
|
|
_asm_arch_get_name,
|
|
_asm_format_get_name
|
|
};
|
|
|
|
|
|
/* protected */
|
|
/* functions */
|
|
/* plug-in */
|
|
/* asm_init */
|
|
static AsmBackend * _asm_init(DebuggerBackendHelper const * helper)
|
|
{
|
|
AsmBackend * backend;
|
|
|
|
if((backend = object_new(sizeof(*backend))) == NULL)
|
|
return NULL;
|
|
backend->helper = helper;
|
|
backend->a = NULL;
|
|
backend->code = NULL;
|
|
backend->source = 0;
|
|
return backend;
|
|
}
|
|
|
|
|
|
/* asm_destroy */
|
|
static void _asm_destroy(AsmBackend * backend)
|
|
{
|
|
_asm_close(backend);
|
|
object_delete(backend);
|
|
}
|
|
|
|
|
|
/* asm_open */
|
|
/* callbacks */
|
|
static gboolean _open_on_idle(gpointer data);
|
|
|
|
static int _asm_open(AsmBackend * backend, char const * arch,
|
|
char const * format, char const * filename)
|
|
{
|
|
if(_asm_close(backend) != 0)
|
|
return -1;
|
|
if((backend->a = asm_new(arch, format)) == NULL)
|
|
return -1;
|
|
if((backend->code = asm_open_deassemble(backend->a, filename, TRUE))
|
|
== NULL)
|
|
{
|
|
asm_delete(backend->a);
|
|
backend->a = NULL;
|
|
return -1;
|
|
}
|
|
else
|
|
backend->source = g_idle_add(_open_on_idle, backend);
|
|
return 0;
|
|
}
|
|
|
|
static gboolean _open_on_idle(gpointer data)
|
|
{
|
|
AsmBackend * backend = data;
|
|
AsmArchRegister const * registers;
|
|
size_t cnt = 0;
|
|
|
|
backend->source = 0;
|
|
if((registers = asmcode_get_arch_registers(backend->code)) != NULL)
|
|
for(cnt = 0; registers[cnt].name != NULL; cnt++);
|
|
backend->helper->set_registers(backend->helper->debugger, registers,
|
|
cnt);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* asm_open_dialog */
|
|
static void _open_dialog_type(GtkWidget * combobox, char const * type,
|
|
char const * value);
|
|
|
|
static char * _asm_open_dialog(AsmBackend * backend, GtkWidget * window,
|
|
char const * arch, char const * format)
|
|
{
|
|
GtkWidget * dialog;
|
|
GtkWidget * vbox;
|
|
GtkWidget * hbox;
|
|
GtkWidget * awidget;
|
|
GtkWidget * fwidget;
|
|
GtkWidget * widget;
|
|
GtkFileFilter * filter;
|
|
char * a = NULL;
|
|
char * f = NULL;
|
|
char * filename = NULL;
|
|
(void) backend;
|
|
|
|
dialog = gtk_file_chooser_dialog_new(_("Open file..."),
|
|
(window != NULL) ? GTK_WINDOW(window) : NULL,
|
|
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 */
|
|
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
awidget = gtk_combo_box_text_new();
|
|
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(awidget),
|
|
_("Auto-detect"));
|
|
#else
|
|
awidget = gtk_combo_box_new_text();
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(awidget), _("Auto-detect"));
|
|
#endif
|
|
_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 */
|
|
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
fwidget = gtk_combo_box_text_new();
|
|
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fwidget),
|
|
_("Auto-detect"));
|
|
#else
|
|
fwidget = gtk_combo_box_new_text();
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(fwidget), _("Auto-detect"));
|
|
#endif
|
|
_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);
|
|
/* core files */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("Core files"));
|
|
gtk_file_filter_add_mime_type(filter, "application/x-core");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
/* 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);
|
|
/* java classes */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("Java classes"));
|
|
gtk_file_filter_add_mime_type(filter, "application/x-java");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
/* objects */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("Objects"));
|
|
gtk_file_filter_add_mime_type(filter, "application/x-object");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
/* shared objects */
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, _("Shared objects"));
|
|
gtk_file_filter_add_mime_type(filter, "application/x-sharedlib");
|
|
gtk_file_chooser_add_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
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
a = gtk_combo_box_text_get_active_text(
|
|
GTK_COMBO_BOX_TEXT(awidget));
|
|
#else
|
|
a = gtk_combo_box_get_active_text(GTK_COMBO_BOX(
|
|
awidget));
|
|
#endif
|
|
if(gtk_combo_box_get_active(GTK_COMBO_BOX(fwidget)) == 0)
|
|
f = NULL;
|
|
else
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
f = gtk_combo_box_text_get_active_text(
|
|
GTK_COMBO_BOX_TEXT(fwidget));
|
|
#else
|
|
f = gtk_combo_box_get_active_text(GTK_COMBO_BOX(
|
|
fwidget));
|
|
#endif
|
|
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(
|
|
dialog));
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
g_free(a);
|
|
g_free(f);
|
|
return filename;
|
|
}
|
|
|
|
static void _open_dialog_type(GtkWidget * combobox, char const * type,
|
|
char const * value)
|
|
{
|
|
char * path;
|
|
DIR * dir;
|
|
struct dirent * de;
|
|
#if defined(__APPLE__)
|
|
char const ext[] = ".dylib";
|
|
#elif defined(__WIN32__)
|
|
char const ext[] = ".dll";
|
|
#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';
|
|
#if GTK_CHECK_VERSION(2, 24, 0)
|
|
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combobox),
|
|
de->d_name);
|
|
#else
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), de->d_name);
|
|
#endif
|
|
if(value != NULL && strcmp(de->d_name, value) == 0)
|
|
active = i;
|
|
}
|
|
closedir(dir);
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), active);
|
|
}
|
|
|
|
|
|
/* asm_close */
|
|
static int _asm_close(AsmBackend * backend)
|
|
{
|
|
if(backend->source != 0)
|
|
g_source_remove(backend->source);
|
|
backend->source = 0;
|
|
if(backend->a != NULL)
|
|
asm_delete(backend->a);
|
|
backend->a = NULL;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* asm_arch_get_name */
|
|
static char const * _asm_arch_get_name(AsmBackend * backend)
|
|
{
|
|
return asmcode_get_arch(backend->code);
|
|
}
|
|
|
|
|
|
/* asm_format_get_name */
|
|
static char const * _asm_format_get_name(AsmBackend * backend)
|
|
{
|
|
return asmcode_get_format(backend->code);
|
|
}
|