summaryrefslogtreecommitdiff
path: root/src/gui/panels/errors.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2017-08-13 19:19:40 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2017-08-13 19:19:40 (GMT)
commitf0ef296d23bcefffcfc292c5d8e6143d700f46fc (patch)
treecb40f1ce46810ed4e8e45c21481f415f2917ebc8 /src/gui/panels/errors.c
parente554e315b762d564b4e370fa77a26ef6a4a67ccc (diff)
Listed all errors occurred while loading a binary file.
Diffstat (limited to 'src/gui/panels/errors.c')
-rw-r--r--src/gui/panels/errors.c956
1 files changed, 956 insertions, 0 deletions
diff --git a/src/gui/panels/errors.c b/src/gui/panels/errors.c
new file mode 100644
index 0000000..7d7226f
--- /dev/null
+++ b/src/gui/panels/errors.c
@@ -0,0 +1,956 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * errors.c - panneau listant les erreurs au désassemblage
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "errors.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdio.h>
+
+
+#include <i18n.h>
+
+
+#include "panel-int.h"
+#include "../../format/format.h"
+#include "../../gtkext/support.h"
+
+
+
+/* Origine de la dernière ouverture/fermeture reproductible */
+typedef enum _UserActionType
+{
+ UAT_COLLAPSE, /* Fermeture totale */
+ UAT_EXPAND, /* Ouverture totale */
+ UAT_DEPTH, /* Descente contrôlée */
+
+} UserActionType;
+
+
+/* Panneau de présentation des erreurs recontrées (instance) */
+struct _GErrorPanel
+{
+ GPanelItem parent; /* A laisser en premier */
+
+ GtkBuilder *builder; /* Constructeur utilisé */
+
+ GLoadedBinary *binary; /* Binaire représenté */
+
+ size_t count; /* Nombre de soucis présents */
+ size_t kept; /* Nombre d'éléments affichés */
+
+};
+
+/* Panneau de présentation des erreurs recontrées (classe) */
+struct _GErrorPanelClass
+{
+ GPanelItemClass parent; /* A laisser en premier */
+
+ cairo_surface_t *format_img; /* Image pour les formats */
+ cairo_surface_t *disass_img; /* Image pour les architectures*/
+ cairo_surface_t *output_img; /* Image pour les impressions */
+
+};
+
+
+/* Colonnes de la liste des messages */
+typedef enum _ErrorTreeColumn
+{
+ ETC_ICON, /* Image de représentation */
+ ETC_PHYS, /* Position physique */
+ ETC_VIRT, /* Position virtuelle */
+ ETC_DESC, /* Description humaine */
+
+ ETC_VISIBLE, /* Correspondance établie ? */
+ ETC_ORIGIN, /* Source du soucis remonté */
+ ETC_ERRNO, /* Code d'erreur associé */
+ ETC_ADDR /* Position représentée */
+
+} BinaryTreeColumn;
+
+
+/* Manipulation des erreurs de façon générique */
+typedef struct _error_desc_t
+{
+ union
+ {
+ unsigned int type; /* Type de soucis #0 */
+ BinaryFormatError ftype; /* Type de soucis #1 */
+ ArchProcessingError ptype; /* Type de soucis #2 */
+
+ };
+
+ vmpa2t addr; /* Localisation d'un problème */
+ char *desc; /* Description dudit problème */
+
+} error_desc_t;
+
+
+/* Initialise la classe des panneaux d'affichage des erreurs. */
+static void g_error_panel_class_init(GErrorPanelClass *);
+
+/* Initialise une instance de panneau d'affichage des erreurs. */
+static void g_error_panel_init(GErrorPanel *);
+
+/* Supprime toutes les références externes. */
+static void g_error_panel_dispose(GErrorPanel *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_error_panel_finalize(GErrorPanel *);
+
+/* Organise le tri des erreurs présentées. */
+static gint sort_errors_in_panel(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gpointer);
+
+/* Réagit à un changement d'affichage principal de contenu. */
+static void update_panel_with_binary_errors(GErrorPanel *, GLoadedBinary *);
+
+/* Effectue la mise à jour du contenu du panneau d'erreurs. */
+static void update_error_panel(GErrorPanel *, GtkStatusStack *, activity_id_t);
+
+/* Actualise l'affichage des erreurs sur la base des filtres. */
+static void on_error_filter_toggled(GtkToggleButton *, GErrorPanel *);
+
+/* Filtre l'affichage du contenu du panneau d'erreurs. */
+static void filter_error_panel(GErrorPanel *, GtkStatusStack *, activity_id_t);
+
+/* Affiche un petit résumé concis des soucis remontés. */
+static void update_error_panel_summary(GPanelUpdate *, GErrorPanel *);
+
+/* Réagit au changement de sélection des portions. */
+static void on_error_selection_changed(GtkTreeSelection *, GErrorPanel *);
+
+
+
+/* Indique le type défini pour un panneau d'affichage des erreurs. */
+G_DEFINE_TYPE(GErrorPanel, g_error_panel, G_TYPE_PANEL_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des panneaux d'affichage des erreurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_error_panel_class_init(GErrorPanelClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GEditorItemClass *editem; /* Encore une autre vision... */
+ gchar *filename; /* Chemin d'accès à utiliser */
+ GPanelItemClass *panel; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_error_panel_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_error_panel_finalize;
+
+ editem = G_EDITOR_ITEM_CLASS(klass);
+
+ editem->update_binary = (update_item_binary_fc)update_panel_with_binary_errors;
+
+ filename = find_pixmap_file("error_file.png");
+ assert(filename != NULL);
+
+ klass->format_img = cairo_image_surface_create_from_png(filename);
+
+ filename = find_pixmap_file("error_cpu.png");
+ assert(filename != NULL);
+
+ klass->disass_img = cairo_image_surface_create_from_png(filename);
+
+ filename = find_pixmap_file("error_display.png");
+ assert(filename != NULL);
+
+ klass->output_img = cairo_image_surface_create_from_png(filename);
+
+ g_free(filename);
+
+ panel = G_PANEL_ITEM_CLASS(klass);
+
+ panel->unique = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance à initialiser. *
+* *
+* Description : Initialise une instance de panneau d'affichage des erreurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_error_panel_init(GErrorPanel *panel)
+{
+ GEditorItem *base; /* Version basique d'instance */
+ GPanelItem *pitem; /* Version parente du panneau */
+ GtkTreeSortable *store; /* Gestionnaire des données */
+ GtkTreeModelFilter *filter; /* Filtre pour l'arborescence */
+ GtkTreeView *treeview; /* Affichage de la liste */
+ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */
+ GtkTreeViewColumn *column; /* Colonne de la liste */
+
+ /* Eléments de base */
+
+ base = G_EDITOR_ITEM(panel);
+
+ base->name = PANEL_ERRORS_ID;
+
+ pitem = G_PANEL_ITEM(panel);
+
+ pitem->personality = PIP_SINGLETON;
+ pitem->lname = _("Disassembling errors");
+ pitem->dock_at_startup = true;
+ pitem->path = strdup("S");
+
+ /* Compléments propres */
+
+ panel->binary = NULL;
+
+ /* Représentation graphique */
+
+ panel->builder = gtk_builder_new_from_resource("/org/chrysalide/gui/panels/errors.ui");
+
+ base->widget = GTK_WIDGET(gtk_builder_get_object(panel->builder, "box"));
+ g_object_ref(G_OBJECT(base->widget));
+ gtk_widget_unparent(base->widget);
+
+ store = GTK_TREE_SORTABLE(gtk_builder_get_object(panel->builder, "store"));
+ gtk_tree_sortable_set_sort_func(store, ETC_ADDR, sort_errors_in_panel, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id(store, ETC_ADDR, GTK_SORT_ASCENDING);
+
+ filter = GTK_TREE_MODEL_FILTER(gtk_builder_get_object(panel->builder, "filter"));
+ gtk_tree_model_filter_set_visible_column(filter, ETC_VISIBLE);
+
+ /* Liste des erreurs relevées */
+
+ treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->builder, "treeview"));
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(treeview, column);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column, renderer, "markup", ETC_PHYS);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(treeview, column);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column, renderer, "markup", ETC_VIRT);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(treeview, column);
+
+ renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute(column, renderer, "surface", ETC_ICON);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_end(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column, renderer, "markup", ETC_DESC);
+
+ /* Connexion des signaux */
+
+ gtk_builder_add_callback_symbols(panel->builder,
+ "gtk_tree_view_collapse_all", G_CALLBACK(gtk_tree_view_collapse_all),
+ "gtk_tree_view_expand_all", G_CALLBACK(gtk_tree_view_expand_all),
+ "on_error_filter_toggled", G_CALLBACK(on_error_filter_toggled),
+ "on_error_selection_changed", G_CALLBACK(on_error_selection_changed),
+ NULL);
+
+ gtk_builder_connect_signals(panel->builder, panel);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_error_panel_dispose(GErrorPanel *panel)
+{
+ g_object_unref(G_OBJECT(panel->builder));
+
+ if (panel->binary != NULL)
+ g_object_unref(G_OBJECT(panel->binary));
+
+ G_OBJECT_CLASS(g_error_panel_parent_class)->dispose(G_OBJECT(panel));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_error_panel_finalize(GErrorPanel *panel)
+{
+ G_OBJECT_CLASS(g_error_panel_parent_class)->finalize(G_OBJECT(panel));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un panneau présentant la liste des erreurs rencontrées. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPanelItem *g_error_panel_new(void)
+{
+ GErrorPanel *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_ERROR_PANEL, NULL);
+
+ return G_PANEL_ITEM(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : model = gestionnaire de données. *
+* a = premier élément à traiter. *
+* b = second élément à traiter. *
+* data = donnée non utilisée ici. *
+* *
+* Description : Organise le tri des erreurs présentées. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gint sort_errors_in_panel(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
+{
+ gint result; /* Bilan à faire remonter */
+ vmpa2t *addr_a; /* Localisation de A */
+ vmpa2t *addr_b; /* Localisation de B */
+
+ gtk_tree_model_get(model, a, ETC_ADDR, &addr_a, -1);
+ gtk_tree_model_get(model, b, ETC_ADDR, &addr_b, -1);
+
+ result = cmp_vmpa(addr_a, addr_b);
+
+ delete_vmpa(addr_a);
+ delete_vmpa(addr_b);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à mettre à jour. *
+* binary = nouvelle instance de binaire analysé. *
+* *
+* Description : Réagit à un changement d'affichage principal de contenu. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_panel_with_binary_errors(GErrorPanel *panel, GLoadedBinary *binary)
+{
+ GtkListStore *store; /* Modèle de gestion */
+ GBinFormat *format; /* Format du binaire */
+ size_t fcount; /* Quantité d'erreurs #1 */
+ GArchProcessor *proc; /* Architecture du binaire */
+ size_t pcount; /* Quantité d'erreurs #2 */
+ GPanelUpdate *update; /* Procédure de mise à jour */
+
+ /* Réinitialisation */
+
+ if (panel->binary != NULL)
+ g_object_unref(G_OBJECT(panel->binary));
+
+ panel->binary = binary;
+
+ if (panel->binary != NULL)
+ g_object_ref(G_OBJECT(panel->binary));
+
+ store = GTK_LIST_STORE(gtk_builder_get_object(panel->builder, "store"));
+
+ gtk_list_store_clear(store);
+
+ /* Actualisation de l'affichage */
+
+ if (binary != NULL)
+ {
+ format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+ g_binary_format_lock_errors(format);
+ fcount = g_binary_format_count_errors(format);
+ g_binary_format_unlock_errors(format);
+
+ g_object_unref(G_OBJECT(format));
+
+ proc = g_loaded_binary_get_processor(binary);
+
+ g_arch_processor_lock_errors(proc);
+ pcount = g_arch_processor_count_errors(proc);
+ g_arch_processor_unlock_errors(proc);
+
+ g_object_unref(G_OBJECT(proc));
+
+ }
+
+ else
+ {
+ fcount = 0;
+ pcount = 0;
+ }
+
+ update = g_panel_update_new(G_PANEL_ITEM(panel),
+ _("Loading errors occurred during the disassembling process..."),
+ fcount + pcount,
+ (pu_fallback_cb)update_error_panel);
+
+ g_signal_connect(update, "work-completed", G_CALLBACK(update_error_panel_summary), panel);
+
+ if (get_work_queue() != NULL) /* FIXME */
+ g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(update), DEFAULT_WORK_GROUP);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à mettre à jour. *
+* status = barre de statut à tenir informée. *
+* id = identifiant pour le suivi de la progression. *
+* *
+* Description : Effectue la mise à jour du contenu du panneau d'erreurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_error_panel(GErrorPanel *panel, GtkStatusStack *status, activity_id_t id)
+{
+ GtkTreeView *treeview; /* Arborescence graphique */
+ GtkTreeModel *model; /* Source de données associée */
+ GtkListStore *store; /* Modèle de gestion */
+ GBinFormat *format; /* Format du binaire */
+ size_t fcount; /* Quantité d'erreurs #1 */
+ GArchProcessor *proc; /* Architecture du binaire */
+ size_t pcount; /* Quantité d'erreurs #2 */
+ GtkToggleButton *button; /* Bouton à manipuler */
+ gboolean show_format; /* Affichages liés au format */
+ gboolean show_disass; /* Affichages liés à l'arch. */
+ gboolean show_output; /* Affichages liés à la sortie */
+ size_t count; /* Nombre de soucis présents */
+ size_t kept; /* Nombre d'éléments affichés */
+ GtkTreeIter iter; /* Point d'insertion */
+ size_t i; /* Boucle de parcours */
+ error_desc_t error; /* Description de soucis */
+#ifndef NDEBUG
+ bool ret; /* Bilan d'une récupération */
+#endif
+
+ /* Basculement de l'affichage hors ligne */
+
+ treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->builder, "treeview"));
+
+ model = gtk_tree_view_get_model(treeview);
+ g_object_ref(G_OBJECT(model));
+
+ gtk_tree_view_set_model(treeview, NULL);
+
+ store = GTK_LIST_STORE(gtk_builder_get_object(panel->builder, "store"));
+
+ /* Recensement initial */
+
+ if (panel->binary != NULL)
+ {
+ format = G_BIN_FORMAT(g_loaded_binary_get_format(panel->binary));
+
+ g_binary_format_lock_errors(format);
+
+ fcount = g_binary_format_count_errors(format);
+
+ proc = g_loaded_binary_get_processor(panel->binary);
+
+ g_arch_processor_lock_errors(proc);
+
+ pcount = g_arch_processor_count_errors(proc);
+
+ }
+
+ /* S'il n'y a aucun soucis à remonter... */
+
+ if (panel->binary == NULL || (fcount + pcount) == 0)
+ {
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "format"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+ show_format = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "disass"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+ show_disass = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "output"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+ show_output = gtk_toggle_button_get_active(button);
+
+ gtk_list_store_append(store, &iter);
+
+ gtk_list_store_set(store, &iter,
+ ETC_ICON, NULL,
+ ETC_PHYS, _("<i>There is no error to display here.</i>"),
+ ETC_VIRT, NULL,
+ ETC_DESC, NULL,
+ ETC_VISIBLE, TRUE,
+ -1);
+
+ count = 0;
+ kept = 0;
+
+ }
+
+ /* Sinon on dresse la liste des doléances ! */
+
+ else
+ {
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "format"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
+ show_format = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "disass"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
+ show_disass = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "output"));
+ gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
+ show_output = gtk_toggle_button_get_active(button);
+
+
+ gboolean is_error_visible(const error_desc_t *e, bool fmt)
+ {
+ gboolean visible; /* Etat à retourner */
+
+ visible = FALSE;
+
+ if (fmt)
+ {
+ if (show_format && e->ftype == BFE_STRUCTURE)
+ visible = TRUE;
+
+ }
+
+ else
+ {
+ if (show_disass && e->ptype == APE_DISASSEMBLY)
+ visible = TRUE;
+
+ else if (show_output && e->ptype == APE_LABEL)
+ visible = TRUE;
+
+ }
+
+ return visible;
+
+ }
+
+ cairo_surface_t *get_error_icon(const error_desc_t *e, bool fmt)
+ {
+ cairo_surface_t *icon; /* Image associée à renvoyer */
+
+ icon = NULL;
+
+ if (fmt)
+ {
+ if (show_format && e->ftype == BFE_STRUCTURE)
+ icon = G_ERROR_PANEL_GET_CLASS(panel)->format_img;
+
+ }
+
+ else
+ {
+ if (show_disass && e->ptype == APE_DISASSEMBLY)
+ icon = G_ERROR_PANEL_GET_CLASS(panel)->disass_img;
+
+ else if (show_output && e->ptype == APE_LABEL)
+ icon = G_ERROR_PANEL_GET_CLASS(panel)->output_img;
+
+ }
+
+ return icon;
+
+ }
+
+ void add_error(const error_desc_t *e, bool fmt)
+ {
+ VMPA_BUFFER(phys); /* Décalage physique */
+ VMPA_BUFFER(virt); /* Position virtuelle */
+ gboolean state; /* Bilan d'un filtrage */
+
+ vmpa2_phys_to_string(&e->addr, MDS_UNDEFINED, phys, NULL);
+ vmpa2_virt_to_string(&e->addr, MDS_UNDEFINED, virt, NULL);
+
+ state = is_error_visible(e, fmt);
+
+ gtk_list_store_append(store, &iter);
+
+ gtk_list_store_set(store, &iter,
+ ETC_ICON, get_error_icon(e, fmt),
+ ETC_PHYS, phys,
+ ETC_VIRT, virt,
+ ETC_DESC, e->desc,
+ ETC_VISIBLE, state,
+ ETC_ORIGIN, fmt,
+ ETC_ERRNO, e->type,
+ ETC_ADDR, &e->addr,
+ -1);
+
+ count++;
+
+ if (state)
+ kept++;
+
+ }
+
+
+ count = 0;
+ kept = 0;
+
+ for (i = 0; i < fcount; i++)
+ {
+ /* On remet à zéro tous les octets de l'union ! */
+ error.type = 0;
+
+#ifndef NDEBUG
+ ret = g_binary_format_get_error(format, i, &error.ftype, &error.addr, &error.desc);
+ assert(ret);
+#else
+ g_binary_format_get_error(format, i, &error.ftype, &error.addr, &error.desc);
+#endif
+
+ add_error(&error, true);
+
+ free(error.desc);
+
+ gtk_status_stack_update_activity_value(status, id, 1);
+
+ }
+
+ for (i = 0; i < pcount; i++)
+ {
+ /* On remet à zéro tous les octets de l'union ! */
+ error.type = 0;
+
+#ifndef NDEBUG
+ ret = g_arch_processor_get_error(proc, i, &error.ptype, &error.addr, &error.desc);
+ assert(ret);
+#else
+ g_arch_processor_get_error(proc, i, &error.ptype, &error.addr, &error.desc);
+#endif
+
+ add_error(&error, false);
+
+ free(error.desc);
+
+ gtk_status_stack_update_activity_value(status, id, 1);
+
+ }
+
+ }
+
+ if (panel->binary != NULL)
+ {
+ g_arch_processor_unlock_errors(proc);
+
+ g_object_unref(G_OBJECT(proc));
+
+ g_binary_format_unlock_errors(format);
+
+ g_object_unref(G_OBJECT(format));
+
+ }
+
+ panel->count = count;
+ panel->kept = kept;
+
+ /* Basculement de l'affichage en ligne */
+
+ gtk_tree_view_set_model(treeview, model);
+
+ g_object_unref(G_OBJECT(model));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton à l'origine de l'opération. *
+* panel = panneau contenant les informations globales. *
+* *
+* Description : Actualise l'affichage des erreurs sur la base des filtres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_error_filter_toggled(GtkToggleButton *button, GErrorPanel *panel)
+{
+ GPanelUpdate *update; /* Procédure de mise à jour */
+
+ update = g_panel_update_new(G_PANEL_ITEM(panel),
+ _("Filtering errors occurred during the disassembling process..."),
+ panel->count,
+ (pu_fallback_cb)filter_error_panel);
+
+ g_signal_connect(update, "work-completed", G_CALLBACK(update_error_panel_summary), panel);
+
+ g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(update), DEFAULT_WORK_GROUP);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à mettre à jour. *
+* status = barre de statut à tenir informée. *
+* id = identifiant pour le suivi de la progression. *
+* *
+* Description : Filtre l'affichage du contenu du panneau d'erreurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void filter_error_panel(GErrorPanel *panel, GtkStatusStack *status, activity_id_t id)
+{
+ GtkTreeView *treeview; /* Arborescence graphique */
+ GtkTreeModel *model; /* Source de données associée */
+ GtkTreeModel *store; /* Modèle de gestion */
+ GtkToggleButton *button; /* Bouton à manipuler */
+ gboolean show_format; /* Affichages liés au format */
+ gboolean show_disass; /* Affichages liés à l'arch. */
+ gboolean show_output; /* Affichages liés à la sortie */
+ size_t kept; /* Nombre d'éléments affichés */
+ GtkTreeIter iter; /* Boucle de parcours */
+ gboolean valid; /* Validité du point courant */
+ gboolean format; /* Origine du soucis remonté */
+ guint errno; /* Code d'erreur associé */
+ gboolean state; /* Bilan d'un filtrage */
+
+ /* Basculement de l'affichage hors ligne */
+
+ treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->builder, "treeview"));
+
+ model = gtk_tree_view_get_model(treeview);
+ g_object_ref(G_OBJECT(model));
+
+ gtk_tree_view_set_model(treeview, NULL);
+
+ store = GTK_TREE_MODEL(gtk_builder_get_object(panel->builder, "store"));
+
+ /* Actualisation des données */
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "format"));
+ show_format = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "disass"));
+ show_disass = gtk_toggle_button_get_active(button);
+
+ button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "output"));
+ show_output = gtk_toggle_button_get_active(button);
+
+
+ gboolean is_error_visible(bool fmt, unsigned int type)
+ {
+ gboolean visible; /* Etat à retourner */
+
+ visible = FALSE;
+
+ if (fmt)
+ {
+ if (show_format && type == BFE_STRUCTURE)
+ visible = TRUE;
+
+ }
+
+ else
+ {
+ if (show_disass && type == APE_DISASSEMBLY)
+ visible = TRUE;
+
+ else if (show_output && type == APE_LABEL)
+ visible = TRUE;
+
+ }
+
+ return visible;
+
+ }
+
+
+ kept = 0;
+
+ for (valid = gtk_tree_model_get_iter_first(store, &iter);
+ valid;
+ valid = gtk_tree_model_iter_next(store, &iter))
+ {
+ gtk_tree_model_get(store, &iter, ETC_ORIGIN, &format, ETC_ERRNO, &errno, -1);
+
+ state = is_error_visible(format, errno);
+
+ gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+ ETC_VISIBLE, state,
+ -1);
+
+ if (state)
+ kept++;
+
+ gtk_status_stack_update_activity_value(status, id, 1);
+
+ }
+
+ panel->kept = kept;
+
+ /* Basculement de l'affichage en ligne */
+
+ gtk_tree_view_set_model(treeview, model);
+
+ g_object_unref(G_OBJECT(model));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : update = tâche venant de se terminer. *
+* panel = structure contenant les informations maîtresses. *
+* *
+* Description : Affiche un petit résumé concis des soucis remontés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_error_panel_summary(GPanelUpdate *update, GErrorPanel *panel)
+{
+ GtkLabel *summary; /* Etiquette à mettre à jour */
+ char *msg; /* Bilan à faire afficher */
+
+ summary = GTK_LABEL(gtk_builder_get_object(panel->builder, "summary"));
+
+ if (panel->count == 0)
+ gtk_label_set_markup(summary, NULL);
+
+ else
+ {
+ asprintf(&msg, _("<b>%zu</b> registered error%s, <b>%zu</b> displayed"),
+ panel->count, panel->count > 1 ? "s" : "", panel->kept);
+
+ gtk_label_set_markup(summary, msg);
+
+ }
+
+ free(msg);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : selection = sélection modifiée. *
+* panel = structure contenant les informations maîtresses. *
+* *
+* Description : Réagit au changement de sélection des portions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_error_selection_changed(GtkTreeSelection *selection, GErrorPanel *panel)
+{
+ GtkTreeIter iter; /* Point de sélection */
+ GtkTreeModel *model; /* Modèle de gestion */
+ vmpa2t *addr; /* Localisation à suivre */
+ GtkDisplayPanel *display; /* Afficheur effectif de code */
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ gtk_tree_model_get(model, &iter, ETC_ADDR, &addr, -1);
+
+ display = g_editor_item_get_current_view(G_EDITOR_ITEM(panel));
+ gtk_display_panel_request_move(display, addr);
+
+ delete_vmpa(addr);
+
+ }
+
+}