From f0ef296d23bcefffcfc292c5d8e6143d700f46fc Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 13 Aug 2017 21:19:40 +0200 Subject: Listed all errors occurred while loading a binary file. --- ChangeLog | 47 +++ pixmaps/Makefile.am | 7 +- pixmaps/error_cpu.png | Bin 0 -> 694 bytes pixmaps/error_cpu.xcf | Bin 0 -> 4482 bytes pixmaps/error_display.png | Bin 0 -> 874 bytes pixmaps/error_display.xcf | Bin 0 -> 1519 bytes pixmaps/error_file.png | Bin 0 -> 402 bytes pixmaps/error_file.xcf | Bin 0 -> 1588 bytes src/analysis/disass/area.c | 18 + src/arch/vmpa.c | 42 ++ src/arch/vmpa.h | 10 +- src/core/core.c | 4 + src/format/format.h | 4 +- src/gui/core/panels.c | 4 + src/gui/panels/Makefile.am | 2 + src/gui/panels/bintree.c | 2 +- src/gui/panels/bintree.ui | 4 +- src/gui/panels/errors.c | 956 +++++++++++++++++++++++++++++++++++++++++++ src/gui/panels/errors.h | 62 +++ src/gui/panels/errors.ui | 132 ++++++ src/gui/panels/gresource.xml | 1 + 21 files changed, 1284 insertions(+), 11 deletions(-) create mode 100644 pixmaps/error_cpu.png create mode 100644 pixmaps/error_cpu.xcf create mode 100644 pixmaps/error_display.png create mode 100644 pixmaps/error_display.xcf create mode 100644 pixmaps/error_file.png create mode 100644 pixmaps/error_file.xcf create mode 100644 src/gui/panels/errors.c create mode 100644 src/gui/panels/errors.h create mode 100644 src/gui/panels/errors.ui diff --git a/ChangeLog b/ChangeLog index 1718899..3a61cbe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,50 @@ +17-08-13 Cyrille Bagard + + * pixmaps/Makefile.am: + Define ERROR_ICONS and extend oidapix_DATA. + + * pixmaps/error_cpu.png: + * pixmaps/error_cpu.xcf: + * pixmaps/error_display.png: + * pixmaps/error_display.xcf: + * pixmaps/error_file.png: + * pixmaps/error_file.xcf: + New entries: create new pictures for errors. + + * src/analysis/disass/area.c: + Collect disassembling errors. + + * src/arch/vmpa.c: + * src/arch/vmpa.h: + Replace some macros by functions. + + * src/core/core.c: + Register the vmpa_t structures as boxed type for GLib. + + * src/format/format.h: + Typo. + + * src/gui/core/panels.c: + Register the new error panel. + + * src/gui/panels/Makefile.am: + Add the 'errors.ui' file to UI_FILES and the 'errors.[ch]' files to + libguipanels_la_SOURCES. + + * src/gui/panels/bintree.c: + Typo. + + * src/gui/panels/bintree.ui: + Automatic update by Glade. + + * src/gui/panels/errors.c: + * src/gui/panels/errors.h: + * src/gui/panels/errors.ui: + New entries: list all errors occurred while loading a binary file. + + * src/gui/panels/gresource.xml: + Register the 'errors.ui' file. + 17-08-12 Cyrille Bagard * src/analysis/contents/file.c: diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index 26f3b5f..bb1a7b5 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -28,6 +28,11 @@ LIST_ICONS = \ symbol_package.png \ symbol_routine_classic.png +ERROR_ICONS = \ + error_cpu.png \ + error_display.png \ + error_file.png + MISC = \ chrysalide-full.png \ welcome.png @@ -50,4 +55,4 @@ EXTRA_DIST = \ oidapixdir = $(datadir)/openida -oidapix_DATA = $(APP_ICONS) $(REVISION_PIX) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(MISC) +oidapix_DATA = $(APP_ICONS) $(REVISION_PIX) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(MISC) diff --git a/pixmaps/error_cpu.png b/pixmaps/error_cpu.png new file mode 100644 index 0000000..5c40947 Binary files /dev/null and b/pixmaps/error_cpu.png differ diff --git a/pixmaps/error_cpu.xcf b/pixmaps/error_cpu.xcf new file mode 100644 index 0000000..5643d77 Binary files /dev/null and b/pixmaps/error_cpu.xcf differ diff --git a/pixmaps/error_display.png b/pixmaps/error_display.png new file mode 100644 index 0000000..afeee7c Binary files /dev/null and b/pixmaps/error_display.png differ diff --git a/pixmaps/error_display.xcf b/pixmaps/error_display.xcf new file mode 100644 index 0000000..0769faf4 Binary files /dev/null and b/pixmaps/error_display.xcf differ diff --git a/pixmaps/error_file.png b/pixmaps/error_file.png new file mode 100644 index 0000000..b269b8a Binary files /dev/null and b/pixmaps/error_file.png differ diff --git a/pixmaps/error_file.xcf b/pixmaps/error_file.xcf new file mode 100644 index 0000000..4a4e410 Binary files /dev/null and b/pixmaps/error_file.xcf differ diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c index b76b5ec..7939290 100644 --- a/src/analysis/disass/area.c +++ b/src/analysis/disass/area.c @@ -985,12 +985,15 @@ static void fill_mem_area(mem_area *area, mem_area *list, size_t count, GProcCon { const vmpa2t *addr; /* Début de la zone à traiter */ phys_t len; /* Taille de la zone à remplir */ + bool err_trigger; /* Présence d'une instruction */ phys_t i; /* Boucle de parcours */ vmpa2t start; /* Adresse de départ de combles*/ addr = get_mrange_addr(&area->range); len = get_mrange_length(&area->range); + err_trigger = true; + for (i = 0; i < len; i++) { if (is_range_empty_in_mem_area(area, i, 1)) @@ -1002,10 +1005,25 @@ static void fill_mem_area(mem_area *area, mem_area *list, size_t count, GProcCon load_code_from_mem_area(area, list, count, ctx, &start, false, status, id); if (is_range_empty_in_mem_area(area, i, 1)) + { + if (area->is_exec && err_trigger) + { + g_arch_processor_add_error(area->proc, APE_DISASSEMBLY, &start, + _("Unable to disassemble code instruction")); + + err_trigger = false; + + } + load_data_from_mem_area(area, ctx, &start, status, id); + } + } + else + err_trigger = true; + assert(is_range_busy_in_mem_area(area, i, 1)); } diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index dc1804c..6db62cc 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -106,6 +106,48 @@ vmpa2t *make_vmpa(phys_t phy, virt_t virt) /****************************************************************************** * * +* Paramètres : src = position à dupliquer. * +* * +* Description : Copie une localisation dans l'adressage mémoire. * +* * +* Retour : Adressage alloué en mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +vmpa2t *dup_vmpa(const vmpa2t *src) +{ + vmpa2t *result; /* Structure à retourner */ + + result = make_vmpa(get_phy_addr(src), get_virt_addr(src)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : addr = position à traiter. * +* * +* Description : Supprime une localisation de l'espace mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_vmpa(vmpa2t *addr) +{ + free(addr); + +} + + +/****************************************************************************** +* * * Paramètres : dest = structure de destination pour la copie. * * src = structure de source pour la copie. * * * diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 48f61a8..871e282 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -26,7 +26,6 @@ #include -#include #include #include @@ -82,7 +81,11 @@ void init_vmpa(vmpa2t *, phys_t, virt_t); /* Crée une localisation dans l'adressage mémoire. */ vmpa2t *make_vmpa(phys_t, virt_t); -#define delete_vmpa(a) free(a) +/* Copie une localisation dans l'adressage mémoire. */ +vmpa2t *dup_vmpa(const vmpa2t *); + +/* Supprime une localisation de l'espace mémoire. */ +void delete_vmpa(vmpa2t *); /* Copie la définition d'un adressage dans un autre. */ void copy_vmpa(vmpa2t *, const vmpa2t *); @@ -109,9 +112,6 @@ int cmp_vmpa(const vmpa2t *, const vmpa2t *); #define reset_virt_addr(a) (a)->virtual = VMPA_NO_VIRTUAL -#define dup_vmpa(src) \ - make_vmpa(get_phy_addr(src), get_virt_addr(src)) - /* Décalle une position d'une certaine quantité. */ void advance_vmpa(vmpa2t *, phys_t); diff --git a/src/core/core.c b/src/core/core.c index 9750fc6..6ba54c1 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -78,6 +78,10 @@ bool load_all_basic_components(void) result &= (ensure_path_exists(cfgdir) == 0); free(cfgdir); + g_boxed_type_register_static("vmpa_t", + (GBoxedCopyFunc)dup_vmpa, + (GBoxedFreeFunc)delete_vmpa); + result &= load_main_config_parameters(); SSL_load_error_strings(); diff --git a/src/format/format.h b/src/format/format.h index 3c1bbea..09ac07a 100644 --- a/src/format/format.h +++ b/src/format/format.h @@ -119,8 +119,8 @@ typedef enum _BinaryFormatError /* Protège ou lève la protection de l'accès aux erreurs. */ void g_binary_format_lock_unlock_errors(GBinFormat *, bool); -#define g_binary_format_lock_errors(p) g_binary_format_lock_unlock_errors(p, true) -#define g_binary_format_unlock_errors(p) g_binary_format_lock_unlock_errors(p, false) +#define g_binary_format_lock_errors(f) g_binary_format_lock_unlock_errors(f, true) +#define g_binary_format_unlock_errors(f) g_binary_format_lock_unlock_errors(f, false) /* Etend la liste des soucis détectés avec de nouvelles infos. */ void g_binary_format_add_error(GBinFormat *, BinaryFormatError, const vmpa2t *, const char *); diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index 3d1a512..38a2c43 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -27,6 +27,7 @@ #include "../panels/bintree.h" #include "../panels/bookmarks.h" +#include "../panels/errors.h" #include "../panels/glance.h" #include "../panels/history.h" #include "../panels/log.h" @@ -91,6 +92,9 @@ void load_main_panels(GObject *ref) item = g_bintree_panel_new(); register_panel_item(item, ref, config); + item = g_error_panel_new(); + register_panel_item(item, ref, config); + } diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index 7dc1cc5..506ae38 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -5,11 +5,13 @@ noinst_LTLIBRARIES = libguipanels.la UI_FILES = \ bintree.ui \ + errors.ui \ welcome.ui libguipanels_la_SOURCES = \ bintree.h bintree.c \ bookmarks.h bookmarks.c \ + errors.h errors.c \ glance.h glance.c \ history.h history.c \ log.h log.c \ diff --git a/src/gui/panels/bintree.c b/src/gui/panels/bintree.c index 9963f94..1fa0cfe 100644 --- a/src/gui/panels/bintree.c +++ b/src/gui/panels/bintree.c @@ -199,7 +199,7 @@ static void g_bintree_panel_init(GBintreePanel *panel) g_object_ref(G_OBJECT(base->widget)); gtk_widget_unparent(base->widget); - /* Liste des projets récents */ + /* Liste des portions binaires */ treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->builder, "treeview")); diff --git a/src/gui/panels/bintree.ui b/src/gui/panels/bintree.ui index 678cc56..aa5a112 100644 --- a/src/gui/panels/bintree.ui +++ b/src/gui/panels/bintree.ui @@ -1,5 +1,5 @@ - + @@ -10,7 +10,7 @@ True False - ../../../pixmaps/tbutton_collapse.png + ../../../pixmaps/tbutton_expand.png True 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 +#include +#include + + +#include + + +#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, _("There is no error to display here."), + 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, _("%zu registered error%s, %zu 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); + + } + +} diff --git a/src/gui/panels/errors.h b/src/gui/panels/errors.h new file mode 100644 index 0000000..02451ee --- /dev/null +++ b/src/gui/panels/errors.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * errors.h - prototypes pour le 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 + */ + + +#ifndef _GUI_PANELS_ERRORS_H +#define _GUI_PANELS_ERRORS_H + + +#include + + +#include "panel.h" + + + +#define PANEL_ERRORS_ID _("Errors") + + +#define G_TYPE_ERROR_PANEL g_error_panel_get_type() +#define G_ERROR_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ERROR_PANEL, GErrorPanel)) +#define G_IS_ERROR_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ERROR_PANEL)) +#define G_ERROR_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ERROR_PANEL, GErrorPanelClass)) +#define G_IS_ERROR_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ERROR_PANEL)) +#define G_ERROR_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ERROR_PANEL, GErrorPanelClass)) + + +/* Panneau de présentation des erreurs recontrées (instance) */ +typedef struct _GErrorPanel GErrorPanel; + +/* Panneau de présentation des erreurs recontrées (classe) */ +typedef struct _GErrorPanelClass GErrorPanelClass; + + +/* Indique le type défini pour un panneau d'affichage des erreurs. */ +GType g_error_panel_get_type(void); + +/* Crée un panneau présentant la liste des erreurs rencontrées. */ +GPanelItem *g_error_panel_new(void); + + + +#endif /* _GUI_PANELS_ERRORS_H */ diff --git a/src/gui/panels/errors.ui b/src/gui/panels/errors.ui new file mode 100644 index 0000000..82a1a05 --- /dev/null +++ b/src/gui/panels/errors.ui @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + store + + + False + + + True + False + vertical + + + True + False + 8 + + + Format + True + True + True + True + + + + False + True + 0 + + + + + Assembly + True + True + True + True + + + + False + True + 1 + + + + + Output + True + True + True + True + + + + False + True + 2 + + + + + True + False + 0.5 + + + False + True + 3 + + + + + False + True + 0 + + + + + True + True + in + + + True + True + filter + False + + + + + + + + + + True + True + 1 + + + + + + diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml index a14b8ae..64a6036 100644 --- a/src/gui/panels/gresource.xml +++ b/src/gui/panels/gresource.xml @@ -4,6 +4,7 @@ ../../../pixmaps/tbutton_collapse.png ../../../pixmaps/tbutton_expand.png bintree.ui + errors.ui welcome.ui -- cgit v0.11.2-87-g4458