summaryrefslogtreecommitdiff
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
parente554e315b762d564b4e370fa77a26ef6a4a67ccc (diff)
Listed all errors occurred while loading a binary file.
-rw-r--r--ChangeLog47
-rw-r--r--pixmaps/Makefile.am7
-rw-r--r--pixmaps/error_cpu.pngbin0 -> 694 bytes
-rw-r--r--pixmaps/error_cpu.xcfbin0 -> 4482 bytes
-rw-r--r--pixmaps/error_display.pngbin0 -> 874 bytes
-rw-r--r--pixmaps/error_display.xcfbin0 -> 1519 bytes
-rw-r--r--pixmaps/error_file.pngbin0 -> 402 bytes
-rw-r--r--pixmaps/error_file.xcfbin0 -> 1588 bytes
-rw-r--r--src/analysis/disass/area.c18
-rw-r--r--src/arch/vmpa.c42
-rw-r--r--src/arch/vmpa.h10
-rw-r--r--src/core/core.c4
-rw-r--r--src/format/format.h4
-rw-r--r--src/gui/core/panels.c4
-rw-r--r--src/gui/panels/Makefile.am2
-rw-r--r--src/gui/panels/bintree.c2
-rw-r--r--src/gui/panels/bintree.ui4
-rw-r--r--src/gui/panels/errors.c956
-rw-r--r--src/gui/panels/errors.h62
-rw-r--r--src/gui/panels/errors.ui132
-rw-r--r--src/gui/panels/gresource.xml1
21 files changed, 1284 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 1718899..3a61cbe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,50 @@
+17-08-13 Cyrille Bagard <nocbos@gmail.com>
+
+ * 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 <nocbos@gmail.com>
* 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
--- /dev/null
+++ b/pixmaps/error_cpu.png
Binary files differ
diff --git a/pixmaps/error_cpu.xcf b/pixmaps/error_cpu.xcf
new file mode 100644
index 0000000..5643d77
--- /dev/null
+++ b/pixmaps/error_cpu.xcf
Binary files differ
diff --git a/pixmaps/error_display.png b/pixmaps/error_display.png
new file mode 100644
index 0000000..afeee7c
--- /dev/null
+++ b/pixmaps/error_display.png
Binary files differ
diff --git a/pixmaps/error_display.xcf b/pixmaps/error_display.xcf
new file mode 100644
index 0000000..0769faf4
--- /dev/null
+++ b/pixmaps/error_display.xcf
Binary files differ
diff --git a/pixmaps/error_file.png b/pixmaps/error_file.png
new file mode 100644
index 0000000..b269b8a
--- /dev/null
+++ b/pixmaps/error_file.png
Binary files differ
diff --git a/pixmaps/error_file.xcf b/pixmaps/error_file.xcf
new file mode 100644
index 0000000..4a4e410
--- /dev/null
+++ b/pixmaps/error_file.xcf
Binary files 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 <limits.h>
-#include <malloc.h>
#include <stdbool.h>
#include <stdint.h>
@@ -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 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.18.3 -->
+<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkAdjustment" id="adjustment1">
@@ -10,7 +10,7 @@
<object class="GtkImage" id="collapse_img">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="pixbuf">../../../pixmaps/tbutton_collapse.png</property>
+ <property name="pixbuf">../../../pixmaps/tbutton_expand.png</property>
</object>
<object class="GtkImage" id="expand_img">
<property name="visible">True</property>
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);
+
+ }
+
+}
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 <i18n.h>
+
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkListStore" id="store">
+ <columns>
+ <!-- column-name icon -->
+ <column type="CairoSurface"/>
+ <!-- column-name phys -->
+ <column type="gchararray"/>
+ <!-- column-name virt -->
+ <column type="gchararray"/>
+ <!-- column-name desc -->
+ <column type="gchararray"/>
+ <!-- column-name visible -->
+ <column type="gboolean"/>
+ <!-- column-name origin -->
+ <column type="gboolean"/>
+ <!-- column-name errno -->
+ <column type="guint"/>
+ <!-- column-name addr -->
+ <column type="vmpa_t"/>
+ </columns>
+ </object>
+ <object class="GtkTreeModelFilter" id="filter">
+ <property name="child_model">store</property>
+ </object>
+ <object class="GtkOffscreenWindow">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkToggleButton" id="format">
+ <property name="label" translatable="yes">Format</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="active">True</property>
+ <signal name="toggled" handler="on_error_filter_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="disass">
+ <property name="label" translatable="yes">Assembly</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="active">True</property>
+ <signal name="toggled" handler="on_error_filter_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="output">
+ <property name="label" translatable="yes">Output</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="active">True</property>
+ <signal name="toggled" handler="on_error_filter_toggled" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="opacity">0.5</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">filter</property>
+ <property name="headers_visible">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection">
+ <signal name="changed" handler="on_error_selection_changed" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
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 @@
<file compressed="true">../../../pixmaps/tbutton_collapse.png</file>
<file compressed="true">../../../pixmaps/tbutton_expand.png</file>
<file compressed="true">bintree.ui</file>
+ <file compressed="true">errors.ui</file>
<file compressed="true">welcome.ui</file>
</gresource>
</gresources>