/* OpenIDA - Outil d'analyse de fichiers binaires
* gtkgraphview.c - affichage de morceaux de code sous forme graphique
*
* Copyright (C) 2009 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* OpenIDA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* OpenIDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "gtkgraphview.h"
#include "gtkbinview-int.h"
#include "gtkblockview.h"
#include "../format/format.h"
#include "../graph/layout.h"
#include
/* Représentation de code binaire sous forme graphique (instace) */
struct _GtkGraphView
{
GtkBinView parent; /* A laisser en premier */
vmpa_t start; /* Début de la portion vue */
vmpa_t end; /* Fin de la portion affichée */
GtkBinView **childs; /* Liste des sous-blocs */
size_t childs_count; /* Taille de cette liste */
GtkLinkRenderer **links; /* Liste des liens graphiques */
size_t links_count; /* Nombre de ces liens */
};
/* Représentation de code binaire sous forme graphique (classe) */
struct _GtkGraphViewClass
{
GtkBinViewClass parent; /* A laisser en premier */
};
/* Initialise la classe générique des graphiques de code. */
static void gtk_graph_view_class_init(GtkGraphViewClass *);
/* Initialise une instance d'afficheur de code en graphique. */
static void gtk_graph_view_init(GtkGraphView *);
/* Met à jour l'affichage de la vue sous forme graphique. */
static gboolean gtk_graph_view_expose(GtkGraphView *, GdkEventExpose *);
/* Supprime tout contenu de l'afficheur de code en graphique. */
static void gtk_graph_view_reset(GtkGraphView *);
/* Définit les lignes du graphique de représentation. */
static void gtk_graph_view_set_rendering_lines(GtkGraphView *, GRenderingLine *, GRenderingLine *);
/* Réagit à la sélection externe d'une adresse. */
static void gtk_graph_view_define_main_address(GtkGraphView *, vmpa_t);
/* Indique la position d'affichage d'une adresse donnée. */
static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *, vmpa_t, gint *, gint *);
/* Définit la liste complète des éléments du futur graphique. */
static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *, GRenderingLine *, GRenderingLine *, size_t *);
/* Détermine le type du composant d'affichage en graphique. */
G_DEFINE_TYPE(GtkGraphView, gtk_graph_view, GTK_TYPE_BIN_VIEW)
/******************************************************************************
* *
* Paramètres : klass = classe GTK à initialiser. *
* *
* Description : Initialise la classe générique des graphiques de code. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_graph_view_class_init(GtkGraphViewClass *klass)
{
GtkWidgetClass *widget_class; /* Classe version Widget */
widget_class = (GtkWidgetClass *)klass;
widget_class->expose_event = gtk_graph_view_expose;
}
/******************************************************************************
* *
* Paramètres : view = instance GTK à initialiser. *
* *
* Description : Initialise une instance d'afficheur de code en graphique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_graph_view_init(GtkGraphView *view)
{
GtkBinView *binview; /* Instance parente */
binview = GTK_BIN_VIEW(view);
binview->set_lines = (set_rendering_lines_fc)gtk_graph_view_set_rendering_lines;
binview->define_address = (define_main_address_fc)gtk_graph_view_define_main_address;
binview->get_coordinates = (get_addr_coordinates_fc)gtk_graph_view_get_address_coordinates;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouveau composant pour l'affichage en graphique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget* gtk_graph_view_new(void)
{
return g_object_new(GTK_TYPE_GRAPH_VIEW, NULL);
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à redessiner. *
* event = informations liées à l'événement. *
* *
* Description : Met à jour l'affichage de la vue sous forme graphique. *
* *
* Retour : FALSE pour poursuivre la propagation de l'événement. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_graph_view_expose(GtkGraphView *view, GdkEventExpose *event)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < view->links_count; i++)
gtk_link_renderer_draw(view->links[i],
GDK_DRAWABLE(GTK_WIDGET(view)->window),
GTK_BIN_VIEW(view)->gc);
return FALSE;
}
/******************************************************************************
* *
* Paramètres : view = instance GTK à réinitialiser. *
* *
* Description : Supprime tout contenu de l'afficheur de code en graphique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_graph_view_reset(GtkGraphView *view)
{
size_t i; /* Boucle de parcours */
view->start = 0;
view->end = 0;
for (i = 0; i < view->links_count; i++)
gtk_object_destroy(view->links[i]);
if (view->links_count > 0)
{
free(view->links);
view->links = NULL;
view->links_count = 0;
}
for (i = 0; i < view->childs_count; i++)
gtk_widget_destroy(view->childs[i]);
if (view->childs_count > 0)
{
free(view->childs);
view->childs = NULL;
view->childs_count = 0;
}
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à mettre à jour. *
* lines = informations à intégrer. *
* last = dernière ligne à intégrer ou NULL pour toutes. *
* *
* Description : Définit les lignes du graphique de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_graph_view_set_rendering_lines(GtkGraphView *view, GRenderingLine *lines, GRenderingLine *last)
{
gtk_graph_view_reset(view);
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à mettre à jour. *
* addr = adresse sélectionnée de manière externe. *
* *
* Description : Réagit à la sélection externe d'une adresse. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr)
{
GExeFormat *format; /* Type de fichier chargé */
GBinRoutine **routines; /* Liste des routines trouvées */
size_t routines_count; /* Nombre de ces routines */
size_t i; /* Boucle de parcours */
vmpa_t start; /* Début d'une routine */
vmpa_t end; /* Fin d'une routine */
GRenderingLine *first; /* Première ligne à traiter */
GRenderingLine *last; /* Dernière ligne à traiter */
if (!(view->start <= addr && addr < view->end))
{
gtk_graph_view_reset(view);
format = g_openida_binary_get_format(GTK_BIN_VIEW(view)->binary);
routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count);
for (i = 0; i < routines_count; i++)
{
start = g_binary_routine_get_address(routines[i]);
end = start + g_binary_routine_get_size(routines[i]);
if (start <= addr && addr < end)
{
view->start = start;
view->end = end;
first = g_rendering_line_find_by_address(GTK_BIN_VIEW(view)->lines, GTK_BIN_VIEW(view)->last, start);
last = g_rendering_line_find_by_address(GTK_BIN_VIEW(view)->lines, GTK_BIN_VIEW(view)->last, end - 1);
view->childs = gtk_graph_view_load_nodes(GTK_BIN_VIEW(view)->binary, first, last, &view->childs_count);
build_graph_view(GTK_FIXED(view), view->childs, view->childs_count);
break;
}
}
}
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à consulter. *
* addr = adresse à présenter à l'écran. *
* x = position horizontale au sein du composant. [OUT] *
* y = position verticale au sein du composant. [OUT] *
* *
* Description : Indique la position d'affichage d'une adresse donnée. *
* *
* Retour : TRUE si l'adresse fait partie du composant, FALSE sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *view, vmpa_t addr, gint *x, gint *y)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
result = false;
*x = 0;
*y = 0;
for (i = 0; i < view->childs_count && !result; i++)
if (view->childs[i]->get_coordinates(view->childs[i], addr, x, y))
{
*x += GTK_WIDGET(view->childs[i])->allocation.x;
*y += GTK_WIDGET(view->childs[i])->allocation.y;
result = true;
}
return result;
}
/******************************************************************************
* *
* Paramètres : binary = contenu binaire à l'origine des lignes. *
* first = première ligne à analyser. *
* last = dernière ligne à analyser. *
* count = nombre d'éléments créés. [OUT] *
* *
* Description : Définit la liste complète des éléments du futur graphique. *
* *
* Retour : Liste d'éléments du graphique à placer. *
* *
* Remarques : - *
* *
******************************************************************************/
static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRenderingLine *first, GRenderingLine *last, size_t *count)
{
GtkBinView **result; /* Liste à retourner */
GRenderingLine *begin; /* Début d'un groupe de lignes */
GRenderingLine *end; /* Fin d'un groupe de lignes */
GRenderingLine *iter; /* Boucle de parcours */
result = NULL;
*count = 0;
begin = NULL;
for (iter = first; iter != NULL; iter = g_rendering_line_get_next_iter(first, iter, last))
{
if (begin != NULL && g_rendering_line_has_sources(iter))
{
result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *));
result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH));
gtk_widget_show(GTK_WIDGET(result[*count - 1]));
gtk_bin_view_show_border(result[*count - 1], true);
gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end);
begin = NULL;
}
if (begin == NULL) begin = iter;
end = iter;
if (g_rendering_line_has_destinations(iter))
{
result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *));
result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH));
gtk_widget_show(GTK_WIDGET(result[*count - 1]));
gtk_bin_view_show_border(result[*count - 1], true);
gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end);
begin = NULL;
}
}
if (begin != NULL)
{
result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *));
result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH));
gtk_widget_show(GTK_WIDGET(result[*count - 1]));
gtk_bin_view_show_border(result[*count - 1], true);
gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end);
}
return result;
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à mettre à jour. *
* links = liens graphiques entre les blocs à intégrer. *
* count = quantité de ces liens graphiques. *
* *
* Description : Définit les liens graphiques à présenter avec la vue. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_graph_view_attach_links(GtkGraphView *view, GtkLinkRenderer **links, size_t count)
{
view->links = links;
view->links_count = count;
}