summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog37
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am6
-rw-r--r--src/analysis/binary.c87
-rw-r--r--src/analysis/binary.h18
-rw-r--r--src/dialogs/binparts.c604
-rw-r--r--src/dialogs/binparts.h42
-rw-r--r--src/dlg_sections.c218
-rw-r--r--src/dlg_sections.h42
-rw-r--r--src/editor.c69
-rw-r--r--src/format/elf/elf.c15
-rw-r--r--src/format/elf/section.c2
-rw-r--r--src/format/part.c19
-rw-r--r--src/format/part.h3
-rw-r--r--src/project.c4
15 files changed, 872 insertions, 295 deletions
diff --git a/ChangeLog b/ChangeLog
index c869692..6d4fcd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+09-11-19 Cyrille Bagard <nocbos@gmail.com>
+
+ * configure.ac:
+ Add the new Makefile from the 'src/dialogs/Makefile' directory to
+ AC_CONFIG_FILES.
+
+ * src/analysis/binary.c:
+ * src/analysis/binary.h:
+ Handle several kinds of binary parts.
+
+ * src/dialogs/binparts.c:
+ * src/dialogs/binparts.h:
+ New entries: create a dialog window to select binary parts to disassemble.
+
+ * src/dlg_sections.c:
+ * src/dlg_sections.h:
+ Moved entries: see the src/dialogs/binparts.[ch] files.
+
+ * src/editor.c:
+ Update code and add menus.
+
+ * src/format/elf/elf.c:
+ Load the name of sections.
+
+ * src/format/elf/section.c:
+ Typo: add a 'FIXME' comment.
+
+ * src/format/part.c:
+ * src/format/part.h:
+ Provide a way to retrieve the name of a binary part.
+
+ * src/Makefile.am:
+ Add dialogs/libdialogs.a to openida_LDADD.
+
+ * src/project.c:
+ Fix a bug when saving projects.
+
09-11-07 Cyrille Bagard <nocbos@gmail.com>
* configure.ac:
diff --git a/configure.ac b/configure.ac
index d340b3c..11a178d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,6 +246,7 @@ AC_CONFIG_FILES([Makefile
src/debug/Makefile
src/debug/ptrace/Makefile
src/debug/remgdb/Makefile
+ src/dialogs/Makefile
src/format/Makefile
src/format/dwarf/Makefile
src/format/elf/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 7e819de..e848c2b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -73,7 +73,6 @@ liboidaplugin_la_LIBADD = \
openida_SOURCES = \
configuration.h configuration.c \
- dlg_sections.h dlg_sections.c \
editor.h editor.c \
main.c \
params.h params.c \
@@ -99,7 +98,8 @@ openida_LDFLAGS = $(LIBGTK_LIBS) -L/usr/X11R6/lib -ldl -lm $(LIBXML_LIBS) `pkg-c
openida_LDADD = $(LIBINTL) \
debug/libdebug.a \
debug/remgdb/libdebugremgdb.a \
- debug/ptrace/libdebugptrace.a
+ debug/ptrace/libdebugptrace.a \
+ dialogs/libdialogs.a
@@ -109,4 +109,4 @@ openida_LDADD = $(LIBINTL) \
# gtkext doit être traité en premier, à cause des marshals GLib
-SUBDIRS = glibext gtkext analysis arch format common debug graph panels plugins
+SUBDIRS = glibext gtkext analysis arch format common debug dialogs graph panels plugins
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 97b916e..d2c7f3e 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -136,6 +136,10 @@ struct _GOpenidaBinary
GExeFormat *format; /* Format du binaire */
GArchProcessor *proc; /* Architecture du binaire */
+ BinaryPartModel model; /* Modèle de sélection */
+ GBinPart **parts[BPM_COUNT]; /* Parties binaires à analyser */
+ size_t parts_count[BPM_COUNT]; /* Quantité de ces parties */
+
GRenderingLine *lines; /* Lignes de rendu en place */
GRenderingOptions *options; /* Options de désassemblage */
@@ -549,6 +553,9 @@ static void limit_all_routines(GRenderingLine *lines, GBinRoutine **routines, si
start = g_binary_routine_get_address(routines[i]);
line = g_rendering_line_find_by_address(lines, NULL, start);
+ /* Si le symbole est hors du code analysé (routine de PLT par exemple) */
+ if (line == NULL) continue;
+
last = find_best_ending_address_for_routine(line, i, starts, lengths, count);
line = g_rendering_line_find_by_address(lines, NULL, last);
@@ -821,6 +828,17 @@ bool g_openida_binary_save(const GOpenidaBinary *binary, xmlDocPtr xdoc, xmlXPat
free(access);
+
+
+ access = strdup(path);
+ access = stradd(access, "/Filename2");
+
+ result &= add_content_to_node(xdoc, context, access, binary->filename);
+
+ free(access);
+
+
+
return result;
}
@@ -828,6 +846,55 @@ bool g_openida_binary_save(const GOpenidaBinary *binary, xmlDocPtr xdoc, xmlXPat
/******************************************************************************
* *
+* Paramètres : binary = élément binaire à consulter. *
+* parts = liste des zones binaires à analyser. *
+* model = modèle de sélection des zones. *
+* count = quantité de zones listées. *
+* *
+* Description : Définit les parties de binaire à analyser. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_openida_binary_set_parts(GOpenidaBinary *binary, BinaryPartModel model, GBinPart **parts, size_t count)
+{
+ qsort(parts, count, sizeof(GBinPart *), g_binary_part_compare);
+
+ binary->parts[model] = parts;
+ binary->parts_count[model] = count;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = élément binaire à consulter. *
+* model = modèle de sélection des zones. [OUT] *
+* count = quantité de zones listées. [OUT] *
+* *
+* Description : Fournit les parties de binaire analysées. *
+* *
+* Retour : Zones binaires à analyser. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinPart **g_openida_binary_get_parts(const GOpenidaBinary *binary, BinaryPartModel *model, size_t *count)
+{
+ *model = binary->model;
+ *count = binary->parts_count;
+
+ return binary->parts;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : binary = élément binaire à traiter. *
* *
* Description : Lance l'analyse d'un élément binaire chargé. *
@@ -847,8 +914,24 @@ void g_openida_binary_analyse(GOpenidaBinary *binary)
queue = get_work_queue();
- parts = g_exe_format_get_parts(binary->format, &parts_count);
- qsort(parts, parts_count, sizeof(GBinPart *), g_binary_part_compare);
+ if (binary->parts[binary->model] != NULL)
+ {
+ parts = binary->parts[binary->model];
+ parts_count = binary->parts_count[binary->model];
+ }
+ else
+ {
+ if (binary->parts[BPM_DEFAULT] != NULL)
+ {
+ parts = binary->parts[BPM_DEFAULT];
+ parts_count = binary->parts_count[BPM_DEFAULT];
+ }
+ else
+ {
+ parts = g_exe_format_get_parts(binary->format, &parts_count);
+ qsort(parts, parts_count, sizeof(GBinPart *), g_binary_part_compare);
+ }
+ }
disass = g_delayed_disassembly_new(binary, parts, parts_count);
diff --git a/src/analysis/binary.h b/src/analysis/binary.h
index ac5af77..d195fef 100644
--- a/src/analysis/binary.h
+++ b/src/analysis/binary.h
@@ -50,6 +50,18 @@ typedef struct _GOpenidaBinary GOpenidaBinary;
typedef struct _GOpenidaBinaryClass GOpenidaBinaryClass;
+/* Modèle de sélection des parties */
+typedef enum _BinaryPartModel
+{
+ BPM_DEFAULT, /* Selon le modèle par défaut */
+ BPM_ROUTINES, /* Sélection par les routines */
+ BPM_USER, /* Définitions utilisateur */
+
+ BPM_COUNT
+
+} BinaryPartModel;
+
+
/* Indique le type défini pour une description de fichier binaire. */
GType g_openida_binary_get_type(void);
@@ -62,6 +74,12 @@ GOpenidaBinary *g_openida_binary_new_from_xml(xmlXPathContextPtr, const char *);
/* Ecrit une sauvegarde du binaire dans un fichier XML. */
bool g_openida_binary_save(const GOpenidaBinary *, xmlDocPtr, xmlXPathContextPtr, const char *);
+/* Définit les parties de binaire à analyser. */
+void g_openida_binary_set_parts(GOpenidaBinary *, BinaryPartModel, GBinPart **, size_t);
+
+/* Fournit les parties de binaire analysées. */
+GBinPart **g_openida_binary_get_parts(const GOpenidaBinary *, BinaryPartModel *, size_t *);
+
/* Lance l'analyse d'un élément binaire chargé. */
void g_openida_binary_analyse(GOpenidaBinary *);
diff --git a/src/dialogs/binparts.c b/src/dialogs/binparts.c
new file mode 100644
index 0000000..1135348
--- /dev/null
+++ b/src/dialogs/binparts.c
@@ -0,0 +1,604 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dlg_sections.h - boîte de dialogue permettant une sélection des sections
+ *
+ * Copyright (C) 2008 Cyrille Bagard
+ *
+ * This file is part of OpenIDA.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "binparts.h"
+
+
+#include "../format/format.h"
+#include "../gtkext/easygtk.h"
+
+
+
+#define _(str) str
+
+
+
+/* Colonnes de la liste des symboles */
+typedef enum _PartsColumn
+{
+ PTC_ACTIVE, /* Zone de code active ? */
+ PTC_NAME, /* Désignation humaine */
+ PTC_START, /* Adresse de départ */
+ PTC_END, /* Adresse d'arrivée (exclue) */
+
+ PTC_COUNT /* Nombre de colonnes */
+
+} PartsColumn;
+
+
+
+/* Mémoire d'un modèle */
+typedef struct _parts_model
+{
+ gboolean *selected; /* Sélection ou non de parties */
+ size_t count; /* Qté. de prises en compte */
+
+} parts_model;
+
+
+
+
+
+/* Charge les sections sélectionnées pour le projet courant. */
+void load_project_sections(void *, GObject *);
+
+
+
+
+
+/* Affiche les parties désassemblées par défaut. */
+static void load_default_parts(GObject *);
+
+/* Affiche les parties désassemblées selon les routines. */
+static void load_routines_parts(GObject *);
+
+
+
+/* Réagit à un changement de modèle. */
+static void on_model_change(GtkComboBox *, GObject *);
+
+/* Réagit à un changement de sélection de partie. */
+static void on_part_selection_toggle(GtkCellRendererToggle *, gchar *, GObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = informations sur le binaire actuellement ouvert. *
+* *
+* Description : Construit la fenêtre de sélection des sections. *
+* *
+* Retour : Adresse de la fenêtre mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkWidget *create_sections_dialog(GOpenidaBinary *binary)
+{
+ GtkWidget *result; /* Fenêtre à renvoyer */
+ GObject *ref; /* Espace de référencements */
+
+
+
+
+
+ GtkWidget *vbox1;
+ //GtkWidget *hbox1;
+
+
+ GtkWidget *label; /* Etiquette à afficher */
+
+
+ GtkWidget *combobox;
+
+ GtkWidget *alignment; /* Adaptation de disposition */
+ GtkWidget *frame; /* Support avec encadrement */
+
+ GtkWidget *vbox2;
+ GtkWidget *hbox2;
+ GtkWidget *comboboxentry;
+ GtkWidget *hbox3;
+ GtkWidget *scrolledwindow1;
+
+ GtkTreeStore *store; /* Modèle de gestion */
+ GtkWidget *treeview; /* Affichage de la liste */
+ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */
+ GtkTreeViewColumn *column; /* Colonne de la liste */
+
+
+ GtkWidget *vbuttonbox1;
+ GtkWidget *hbuttonbox1;
+
+ GtkWidget *button; /* Bouton de commande */
+
+ result = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_size_request(result, 600, 400);
+ gtk_container_set_border_width(GTK_CONTAINER(result), 8);
+ gtk_window_set_title(GTK_WINDOW(result), _("Sections selection"));
+ gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER);
+ gtk_window_set_default_size(GTK_WINDOW(result), 600, 400);
+ gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ ref= G_OBJECT(result);
+ g_object_set_data(ref, "binary", binary);
+
+ vbox1 = gtk_vbox_new(FALSE, 8);
+ gtk_widget_show(vbox1);
+ gtk_container_add(GTK_CONTAINER(result), vbox1);
+
+ /*
+ hbox1 = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(hbox1);
+ gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
+
+ label = qck_create_label(NULL, NULL, _("Binary :"));
+ gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
+
+ combobox = gtk_combo_box_new_text();
+ gtk_widget_show(combobox);
+ gtk_box_pack_start(GTK_BOX(hbox1), combobox, TRUE, TRUE, 0);
+ */
+
+ frame = qck_create_frame(_("<b>Content to display</b>"), &alignment, 4, 4, 12, 0);
+ gtk_box_pack_start(GTK_BOX(vbox1), frame, TRUE, TRUE, 0);
+
+
+
+
+ vbox2 = gtk_vbox_new(FALSE, 8);
+ gtk_widget_show(vbox2);
+ gtk_container_add(GTK_CONTAINER(alignment), vbox2);
+
+ hbox2 = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(hbox2);
+ gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
+
+ label = qck_create_label(NULL, NULL, _("Model :"));
+ gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
+
+ comboboxentry = qck_create_combobox(ref, "models", G_CALLBACK(NULL), NULL);
+ gtk_box_pack_start(GTK_BOX(hbox2), comboboxentry, TRUE, TRUE, 0);
+
+
+ button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
+ gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
+
+ button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
+ gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
+
+
+
+
+ hbox3 = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(hbox3);
+ gtk_box_pack_start(GTK_BOX(vbox2), hbox3, TRUE, TRUE, 0);
+
+ scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_show(scrolledwindow1);
+ gtk_box_pack_start(GTK_BOX(hbox3), scrolledwindow1, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_SHADOW_IN);
+
+
+
+
+
+
+ store = gtk_tree_store_new(PTC_COUNT, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ g_object_set_data(ref, "store", store);
+
+ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ gtk_widget_show(treeview);
+ gtk_container_add(GTK_CONTAINER(scrolledwindow1), treeview);
+
+ g_object_unref(G_OBJECT(store));
+ /*
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_visible(column, FALSE);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+ gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
+ */
+
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_cell_renderer_toggle_set_activatable(GTK_CELL_RENDERER_TOGGLE(renderer), TRUE);
+ column = gtk_tree_view_column_new_with_attributes(_("Active"), renderer, "active", PTC_ACTIVE, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+ g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(on_part_selection_toggle), ref);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", PTC_NAME, NULL);
+ gtk_tree_view_column_set_expand(column, TRUE);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(_("Start"), renderer, "text", PTC_START, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(_("End"), renderer, "text", PTC_END, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+
+
+
+
+
+
+ vbuttonbox1 = gtk_vbutton_box_new();
+ gtk_widget_show(vbuttonbox1);
+ gtk_box_pack_start(GTK_BOX(hbox3), vbuttonbox1, FALSE, FALSE, 0);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1), GTK_BUTTONBOX_SPREAD);
+
+
+
+
+ button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
+ gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
+
+ button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
+ gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
+
+
+
+
+
+ hbuttonbox1 = gtk_hbutton_box_new();
+ gtk_widget_show(hbuttonbox1);
+ gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, FALSE, FALSE, 0);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox1), GTK_BUTTONBOX_END);
+
+
+ button = qck_create_button_from_stock(NULL, NULL, "gtk-ok", G_CALLBACK(NULL), NULL);
+ gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
+
+ button = qck_create_button_from_stock(NULL, NULL, "gtk-cancel", G_CALLBACK(NULL), NULL);
+ gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
+
+
+
+
+
+
+ g_signal_connect(G_OBJECT(comboboxentry), "changed", G_CALLBACK(on_model_change), ref);
+
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), _("Default"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), _("Routines"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), _("User"));
+
+ return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : project = informations sur le project actuellement ouvert. *
+* ref = espace de référencement principal. *
+* *
+* Description : Charge les sections sélectionnées pour le projet courant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void load_project_sections(void *project, GObject *ref)
+{
+
+
+
+ /*
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("Never automatically"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("When the window gets the focus"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("On click on the window"));
+
+ */
+
+}
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : ref = espace de référencement principal. *
+* *
+* Description : Affiche les parties désassemblées par défaut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void load_default_parts(GObject *ref)
+{
+ GOpenidaBinary *binary; /* Binaire à traiter */
+ GtkTreeStore *store; /* Modèle de gestion */
+ GExeFormat *format; /* Format associé au binaire */
+ GArchProcessor *proc; /* Architecture utilisée */
+ GBinPart **parts; /* Parties d'élément binaire */
+ size_t parts_count; /* Nombre de ces parties */
+ parts_model *model; /* Mémoire du modèle */
+ bool exist; /* Mémoire présente ? */
+ size_t i; /* Boucle de parcours */
+ off_t size; /* Taille de la partie */
+ vmpa_t addr; /* Adresse de départ */
+ char start[VMPA_MAX_SIZE]; /* Version humainement lisible */
+ char end[VMPA_MAX_SIZE]; /* Version humainement lisible */
+ GtkTreeIter iter; /* Point d'insertion */
+
+ binary = G_OPENIDA_BINARY(g_object_get_data(ref, "binary"));
+ store = GTK_TREE_STORE(g_object_get_data(ref, "store"));
+
+ format = g_openida_binary_get_format(binary);
+ proc = get_arch_processor_from_format(format);
+
+ parts = g_exe_format_get_parts(format, &parts_count);
+ qsort(parts, parts_count, sizeof(GBinPart *), g_binary_part_compare);
+
+ model = (parts_model *)g_object_get_data(ref, "default_model");
+ exist = (model != NULL);
+
+ if (!exist)
+ {
+ model = (parts_model *)calloc(1, sizeof(parts_model));
+ g_object_set_data(ref, "default_model", model);
+
+ model->selected = (gboolean *)calloc(parts_count, sizeof(gboolean));
+ model->count = parts_count;
+
+ }
+
+ for (i = 0; i < parts_count; i++)
+ {
+ g_binary_part_get_values(parts[i], NULL, &size, &addr);
+
+ vmpa_to_string(addr, g_arch_processor_get_memory_size(proc), start);
+ vmpa_to_string(addr + size, g_arch_processor_get_memory_size(proc), end);
+
+ if (!exist)
+ model->selected[i] = TRUE;
+
+ gtk_tree_store_append(store, &iter, NULL);
+ gtk_tree_store_set(store, &iter,
+ PTC_ACTIVE, model->selected[i],
+ PTC_NAME, g_binary_part_get_name(parts[i]),
+ PTC_START, start,
+ PTC_END, end,
+ -1);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : ref = espace de référencement principal. *
+* *
+* Description : Affiche les parties désassemblées selon les routines. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void load_routines_parts(GObject *ref)
+{
+ GOpenidaBinary *binary; /* Binaire à traiter */
+ GtkTreeStore *store; /* Modèle de gestion */
+ GExeFormat *format; /* Format associé au binaire */
+ GArchProcessor *proc; /* Architecture utilisée */
+ GBinRoutine **routines; /* Liste des routines trouvées */
+ size_t routines_count; /* Nombre de ces routines */
+ parts_model *model; /* Mémoire du modèle */
+ bool exist; /* Mémoire présente ? */
+ size_t i; /* Boucle de parcours */
+ vmpa_t addr; /* Adresse à transcrire */
+ char start[VMPA_MAX_SIZE]; /* Version humainement lisible */
+ char end[VMPA_MAX_SIZE]; /* Version humainement lisible */
+ GtkTreeIter iter; /* Point d'insertion */
+
+ binary = G_OPENIDA_BINARY(g_object_get_data(ref, "binary"));
+ store = GTK_TREE_STORE(g_object_get_data(ref, "store"));
+
+ format = g_openida_binary_get_format(binary);
+ proc = get_arch_processor_from_format(format);
+
+ routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count);
+ qsort(routines, routines_count, sizeof(GBinRoutine *), g_binary_routine_compare);
+
+ model = (parts_model *)g_object_get_data(ref, "routines_model");
+ exist = (model != NULL);
+
+ if (!exist)
+ {
+ model = (parts_model *)calloc(1, sizeof(parts_model));
+ g_object_set_data(ref, "routines_model", model);
+
+ model->selected = (gboolean *)calloc(routines_count, sizeof(gboolean));
+ model->count = routines_count;
+
+ }
+
+ for (i = 0; i < routines_count; i++)
+ {
+ addr = g_binary_routine_get_address(routines[i]);
+ vmpa_to_string(addr, g_arch_processor_get_memory_size(proc), start);
+
+ addr += g_binary_routine_get_size(routines[i]);
+ vmpa_to_string(addr, g_arch_processor_get_memory_size(proc), end);
+
+ if (!exist)
+ model->selected[i] = TRUE;
+
+ gtk_tree_store_append(store, &iter, NULL);
+ gtk_tree_store_set(store, &iter,
+ PTC_ACTIVE, model->selected[i],
+ PTC_NAME, g_binary_routine_get_name(routines[i]),
+ PTC_START, start,
+ PTC_END, end,
+ -1);
+
+ }
+
+}
+
+
+
+
+
+static void user_function(GtkButton *button, GObject *ref)
+{
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : combo = liste des modèles proposés. *
+* ref = espace de référencement principal. *
+* *
+* Description : Réagit à un changement de modèle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_model_change(GtkComboBox *combo, GObject *ref)
+{
+ gint index; /* Indice du nouveau modèle */
+ GtkTreeStore *store; /* Modèle de gestion */
+
+ store = GTK_TREE_STORE(g_object_get_data(ref, "store"));
+ gtk_tree_store_clear(store);
+
+ index = gtk_combo_box_get_active(combo);
+
+ switch (index)
+ {
+ case BPM_DEFAULT:
+ load_default_parts(ref);
+ break;
+
+ case BPM_ROUTINES:
+ load_routines_parts(ref);
+ break;
+
+ case BPM_USER:
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : renderer = cellule de rendu à mettre à jour. *
+* path = chemin menant à la ligne concernée. *
+* ref = espace de référencement principal. *
+* *
+* Description : Réagit à un changement de sélection de partie. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_part_selection_toggle(GtkCellRendererToggle *renderer, gchar *path, GObject *ref)
+{
+ GtkTreeModel *model; /* Modèle de représentation */
+ GtkTreeIter iter; /* Lieu de la mise à jour */
+ gboolean state; /* Etat de la sélection */
+ GtkComboBox *combo; /* Liste de tous les modèles */
+ gint index; /* Indice du modèle courant */
+ parts_model *list; /* Mémorisation des sélections */
+
+
+ printf("path :: %s\n", path);
+
+ model = GTK_TREE_MODEL(g_object_get_data(ref, "store"));
+
+ if (gtk_tree_model_get_iter_from_string(model, &iter, path))
+ {
+ gtk_tree_model_get(model, &iter, PTC_ACTIVE, &state, -1);
+
+ combo = GTK_COMBO_BOX(g_object_get_data(ref, "models"));
+ index = gtk_combo_box_get_active(combo);
+
+ switch (index)
+ {
+ case BPM_DEFAULT:
+ list = (parts_model *)g_object_get_data(ref, "default_model");
+ break;
+
+ case BPM_ROUTINES:
+ list = (parts_model *)g_object_get_data(ref, "routines_model");
+ break;
+
+ case BPM_USER:
+ break;
+
+ }
+
+ list->selected[atoi(path)] = !state;
+
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+ PTC_ACTIVE, !state,
+ -1);
+
+ }
+
+}
diff --git a/src/dialogs/binparts.h b/src/dialogs/binparts.h
new file mode 100644
index 0000000..dd7fa5e
--- /dev/null
+++ b/src/dialogs/binparts.h
@@ -0,0 +1,42 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * dlg_sections.h - prototypes pour la boîte de dialogue permettant une sélection des sections
+ *
+ * Copyright (C) 2008 Cyrille Bagard
+ *
+ * This file is part of OpenIDA.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DLG_SECTIONS_H
+#define _DLG_SECTIONS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../analysis/binary.h"
+
+
+
+/* Construit la fenêtre de sélection des sections. */
+GtkWidget *create_sections_dialog(GOpenidaBinary *);
+
+
+
+
+
+#endif /* _DLG_SECTIONS_H */
diff --git a/src/dlg_sections.c b/src/dlg_sections.c
index 44a00a7..e69de29 100644
--- a/src/dlg_sections.c
+++ b/src/dlg_sections.c
@@ -1,218 +0,0 @@
-
-/* OpenIDA - Outil d'analyse de fichiers binaires
- * dlg_sections.h - boîte de dialogue permettant une sélection des sections
- *
- * Copyright (C) 2008 Cyrille Bagard
- *
- * This file is part of OpenIDA.
- *
- * OpenIDA 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.
- *
- * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "dlg_sections.h"
-
-
-#include "gtkext/easygtk.h"
-
-
-
-#define _(str) str
-
-
-
-
-/* Charge les sections sélectionnées pour le projet courant. */
-void load_project_sections(openida_project *, GObject *);
-
-
-
-
-/******************************************************************************
-* *
-* Paramètres : project = informations sur le project actuellement ouvert. *
-* *
-* Description : Construit la fenêtre de sélection des sections. *
-* *
-* Retour : Adresse de la fenêtre mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GtkWidget *create_sections_dialog(openida_project *project)
-{
- GtkWidget *result; /* Fenêtre à renvoyer */
-
-
-
-
-
- GtkWidget *vbox1;
- GtkWidget *hbox1;
-
-
- GtkWidget *label; /* Etiquette à afficher */
-
-
- GtkWidget *combobox1;
-
- GtkWidget *alignment; /* Adaptation de disposition */
- GtkWidget *frame; /* Support avec encadrement */
-
- GtkWidget *vbox2;
- GtkWidget *hbox2;
- GtkWidget *comboboxentry1;
- GtkWidget *hbox3;
- GtkWidget *scrolledwindow1;
- GtkWidget *treeview1;
- GtkWidget *vbuttonbox1;
- GtkWidget *hbuttonbox1;
-
- GtkWidget *button; /* Bouton de commande */
-
- result = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_widget_set_size_request(result, 400, 300);
- gtk_container_set_border_width(GTK_CONTAINER(result), 8);
- gtk_window_set_title(GTK_WINDOW(result), _("Sections selection"));
- gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER);
- gtk_window_set_default_size(GTK_WINDOW(result), 500, 400);
- gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG);
-
- vbox1 = gtk_vbox_new(FALSE, 8);
- gtk_widget_show(vbox1);
- gtk_container_add(GTK_CONTAINER(result), vbox1);
-
- hbox1 = gtk_hbox_new(FALSE, 8);
- gtk_widget_show(hbox1);
- gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
-
- label = qck_create_label(NULL, NULL, _("Binary :"));
- gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
-
- combobox1 = gtk_combo_box_new_text();
- gtk_widget_show(combobox1);
- gtk_box_pack_start(GTK_BOX(hbox1), combobox1, TRUE, TRUE, 0);
-
-
- frame = qck_create_frame(_("<b>Content to display</b>"), &alignment, 4, 4, 12, 0);
- gtk_box_pack_start(GTK_BOX(vbox1), frame, TRUE, TRUE, 0);
-
-
-
-
- vbox2 = gtk_vbox_new(FALSE, 8);
- gtk_widget_show(vbox2);
- gtk_container_add(GTK_CONTAINER(alignment), vbox2);
-
- hbox2 = gtk_hbox_new(FALSE, 8);
- gtk_widget_show(hbox2);
- gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
-
- label = qck_create_label(NULL, NULL, _("Model :"));
- gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
-
- comboboxentry1 = qck_create_combobox(NULL, NULL, G_CALLBACK(NULL), NULL);
- gtk_box_pack_start(GTK_BOX(hbox2), comboboxentry1, TRUE, TRUE, 0);
-
-
- button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
- gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
-
- button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
- gtk_box_pack_start(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
-
-
-
-
- hbox3 = gtk_hbox_new(FALSE, 8);
- gtk_widget_show(hbox3);
- gtk_box_pack_start(GTK_BOX(vbox2), hbox3, TRUE, TRUE, 0);
-
- scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_show(scrolledwindow1);
- gtk_box_pack_start(GTK_BOX(hbox3), scrolledwindow1, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_SHADOW_IN);
-
- treeview1 = gtk_tree_view_new();
- gtk_widget_show(treeview1);
- gtk_container_add(GTK_CONTAINER(scrolledwindow1), treeview1);
-
- vbuttonbox1 = gtk_vbutton_box_new();
- gtk_widget_show(vbuttonbox1);
- gtk_box_pack_start(GTK_BOX(hbox3), vbuttonbox1, FALSE, FALSE, 0);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1), GTK_BUTTONBOX_SPREAD);
-
-
-
-
- button = qck_create_button_with_img(NULL, NULL, "gtk-add", G_CALLBACK(NULL), NULL);
- gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
-
- button = qck_create_button_with_img(NULL, NULL, "gtk-remove", G_CALLBACK(NULL), NULL);
- gtk_container_add(GTK_CONTAINER(vbuttonbox1), button);
-
-
-
-
-
- hbuttonbox1 = gtk_hbutton_box_new();
- gtk_widget_show(hbuttonbox1);
- gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, FALSE, FALSE, 0);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox1), GTK_BUTTONBOX_END);
-
-
- button = qck_create_button_from_stock(NULL, NULL, "gtk-ok", G_CALLBACK(NULL), NULL);
- gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
-
- button = qck_create_button_from_stock(NULL, NULL, "gtk-cancel", G_CALLBACK(NULL), NULL);
- gtk_container_add(GTK_CONTAINER(hbuttonbox1), button);
-
- return result;
-
-}
-
-
-
-
-
-
-
-/******************************************************************************
-* *
-* Paramètres : project = informations sur le project actuellement ouvert. *
-* ref = espace de référencement principal. *
-* *
-* Description : Charge les sections sélectionnées pour le projet courant. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void load_project_sections(openida_project *project, GObject *ref)
-{
-
-
-
- /*
- gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("Never automatically"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("When the window gets the focus"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), _("On click on the window"));
-
- */
-
-}
diff --git a/src/dlg_sections.h b/src/dlg_sections.h
index 2541d2b..e69de29 100644
--- a/src/dlg_sections.h
+++ b/src/dlg_sections.h
@@ -1,42 +0,0 @@
-
-/* OpenIDA - Outil d'analyse de fichiers binaires
- * dlg_sections.h - prototypes pour la boîte de dialogue permettant une sélection des sections
- *
- * Copyright (C) 2008 Cyrille Bagard
- *
- * This file is part of OpenIDA.
- *
- * OpenIDA 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.
- *
- * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _DLG_SECTIONS_H
-#define _DLG_SECTIONS_H
-
-
-#include <gtk/gtk.h>
-
-
-#include "project.h"
-
-
-
-/* Construit la fenêtre de sélection des sections. */
-GtkWidget *create_sections_dialog(openida_project *);
-
-
-
-
-
-#endif /* _DLG_SECTIONS_H */
diff --git a/src/editor.c b/src/editor.c
index 5cdd4df..eed0868 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -39,8 +39,8 @@
/** exemple GTK **/
+#include "project.h"
-#include "dlg_sections.h"
#include "analysis/binary.h"
#include "gtkext/easygtk.h"
#include "gtkext/gtkextstatusbar.h"
@@ -49,6 +49,7 @@
#include "gtkext/gtkdockpanel.h"
#include "debug/debuggers.h"
+#include "dialogs/binparts.h"
#include "panels/panel.h"
@@ -106,15 +107,16 @@ void mcb_project_remove_binary(GtkMenuItem *, gpointer);
-/* Affiche la boîte de sélection des sections. */
-void mcb_select_sections(GtkMenuItem *, gpointer);
-
/* Met à jour le contenu du menu 'Projet'. */
void reload_menu_project(GObject *);
+/* Réagit avec le menu "Binaire -> Sélectionner les parties...". */
+static void mcb_binary_select_parts(GtkMenuItem *, GObject *);
+
+
/*Réagit avec le menu "Débogage -> Démarrer". */
void mcb_debug_start(GtkCheckMenuItem *, gpointer);
@@ -309,7 +311,16 @@ GtkWidget *create_editor(void)
submenuitem = qck_create_menu_separator();
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
- submenuitem = qck_create_menu_item(NULL, NULL, _("Select sections..."), G_CALLBACK(mcb_select_sections), NULL);
+
+
+ menuitem = gtk_menu_item_new_with_mnemonic(_("_Binary"));
+ gtk_widget_show(menuitem);
+ gtk_container_add(GTK_CONTAINER(menuboard), menuitem);
+
+ menubar = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menubar);
+
+ submenuitem = qck_create_menu_item(NULL, NULL, _("Select parts..."), G_CALLBACK(mcb_binary_select_parts), ref);
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
@@ -932,28 +943,6 @@ void mcb_project_remove_binary(GtkMenuItem *menuitem, gpointer data)
-/******************************************************************************
-* *
-* Paramètres : menuitem = élément de menu sélectionné. *
-* data = adresse de l'espace de référencement global. *
-* *
-* Description : Affiche la boîte de sélection des sections. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void mcb_select_sections(GtkMenuItem *menuitem, gpointer data)
-{
- GtkWidget *dialog; /* Boîte de dialogue à montrer */
-
- dialog = create_sections_dialog(create_empty_openida_project(G_OBJECT(data))/* FIXME */);
- gtk_widget_show(dialog);
-
-}
-
@@ -1016,6 +1005,32 @@ void reload_menu_project(GObject *ref)
+/******************************************************************************
+* *
+* Paramètres : menuitem = élément de menu sélectionné. *
+* ref = adresse de l'espace de référencement global. *
+* *
+* Description : Réagit avec le menu "Binaire -> Sélectionner les parties...".*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void mcb_binary_select_parts(GtkMenuItem *menuitem, GObject *ref)
+{
+ GOpenidaBinary *binary; /* Binaire courant à l'écran */
+ GtkWidget *dialog; /* Boîte de dialogue à montrer */
+
+ binary = G_OPENIDA_BINARY(g_object_get_data(ref, "current_binary"));
+
+ dialog = create_sections_dialog(binary);
+ gtk_widget_show(dialog);
+
+}
+
+
void debugger_stopped_cb(GBinaryDebugger *debugger, uint64_t last, uint64_t cur, gpointer data)
{
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index 34c7521..f32bce7 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -407,14 +407,19 @@ static GBinPart **g_elf_format_get_parts(const GElfFormat *format, size_t *count
{
GBinPart **result; /* Tableau à retourner */
uint16_t i; /* Boucle de parcours */
+ elf_shdr strings; /* Section des descriptions */
+ bool has_strings; /* Section trouvée ? */
elf_shdr section; /* En-tête de section ELF */
GBinPart *part; /* Partie à intégrer à la liste*/
+ const char *name; /* Nom trouvé ou NULL */
off_t offset; /* Début de part de programme */
elf_phdr phdr; /* En-tête de programme ELF */
result = NULL;
*count = 0;
+ has_strings = find_elf_section_by_index(format, format->header.e_shstrndx, &strings);
+
/* Première tentative : les sections */
for (i = 0; i < format->header.e_shnum; i++)
@@ -427,7 +432,15 @@ static GBinPart **g_elf_format_get_parts(const GElfFormat *format, size_t *count
{
part = g_binary_part_new();
- /* TODO : nom, droits/type */
+ if (has_strings)
+ {
+ name = extract_name_from_elf_string_section(format, &strings,
+ ELF_SHDR(format, section, sh_name));
+
+ if (name != NULL)
+ g_binary_part_set_name(part, name);
+
+ }
g_binary_part_set_values(part,
ELF_SHDR(format, section, sh_offset),
diff --git a/src/format/elf/section.c b/src/format/elf/section.c
index e019648..f837dbf 100644
--- a/src/format/elf/section.c
+++ b/src/format/elf/section.c
@@ -92,6 +92,8 @@ bool find_elf_section_by_name(const GElfFormat *format, const char *name, elf_sh
secname = extract_name_from_elf_string_section(format, &strings,
ELF_SHDR(format, *section, sh_name));
+ /* FIXME : if secname == NULL */
+
result = (strcmp(name, secname) == 0);
}
diff --git a/src/format/part.c b/src/format/part.c
index 2096c6d..d21cd87 100644
--- a/src/format/part.c
+++ b/src/format/part.c
@@ -145,6 +145,25 @@ void g_binary_part_set_name(GBinPart *part, const char *name)
/******************************************************************************
* *
+* Paramètres : part = description de partie à mettre à jour. *
+* *
+* Description : Fournit la description attribuée à une partie de code. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_binary_part_get_name(const GBinPart *part)
+{
+ return part->name;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : part = description de partie à mettre à jour. *
* offset = position de la section à conserver. *
* size = taille de la section à conserver. *
diff --git a/src/format/part.h b/src/format/part.h
index aec324d..ff18fc9 100644
--- a/src/format/part.h
+++ b/src/format/part.h
@@ -57,6 +57,9 @@ GBinPart *g_binary_part_new(void);
/* Attribue une description humaine à une partie de code. */
void g_binary_part_set_name(GBinPart *, const char *);
+/* Fournit la description attribuée à une partie de code. */
+const char *g_binary_part_get_name(const GBinPart *);
+
/* Définit les valeurs utiles d'une partie de code. */
void g_binary_part_set_values(GBinPart *, off_t, off_t, vmpa_t);
diff --git a/src/project.c b/src/project.c
index 2b70a47..1366abf 100644
--- a/src/project.c
+++ b/src/project.c
@@ -402,9 +402,9 @@ bool g_openida_project_save(openida_project *project, const char *filename)
/* Sauvegarde finale */
- result &= save_xml_file(xdoc, filename);
+ result &= save_xml_file(xdoc, filename != NULL ? filename : project->filename);
- if (result)
+ if (result && filename != NULL)
{
if (project->filename != NULL) free(project->filename);
project->filename = strdup(filename);