summaryrefslogtreecommitdiff
path: root/src/gtkext/graph/cluster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext/graph/cluster.c')
-rw-r--r--src/gtkext/graph/cluster.c1330
1 files changed, 1330 insertions, 0 deletions
diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c
new file mode 100644
index 0000000..4c92718
--- /dev/null
+++ b/src/gtkext/graph/cluster.c
@@ -0,0 +1,1330 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cluster.c - mise en place de graphiques
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "cluster.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../gtkblockview.h"
+#include "../gtkbufferview.h"
+#include "../gtkviewpanel.h"
+#include "../../common/sort.h"
+
+
+
+/* Définition du tracé d'un lien */
+typedef struct _link_def
+{
+ InstructionLinkType type; /* Complexité du tracé */
+
+ GdkPoint y; /* Position des décrochages */
+
+ GdkPoint end; /* Point d'arrivée final */
+
+ GGraphEdge *edge; /* Lien complet en préparation */
+
+} link_def;
+
+/* Découpage vertical */
+typedef struct _graph_rank
+{
+ unsigned int level; /* Niveau des blocs */
+
+ GGraphCluster **clusters; /* Ensembles de blocs */
+ size_t count; /* Nombre de ces ensembles */
+
+} graph_rank;
+
+/* Mise en disposition de blocs en graphique (instance) */
+struct _GGraphCluster
+{
+ GObject parent; /* A laisser en premier */
+
+
+ ////////////////////////////////////////
+ gint top_margin[2]; /* Espaces gauches et droites */
+ gint left_margin; /* Espaces remontant à gauche */
+ gint right_margin; /* Espaces remontant à droite */
+ ////////////////////////////////////////
+
+
+ link_def **top_anchors; /* Accroches supérieures */
+ size_t ta_count; /* Quantité de ces accroches */
+
+ GBasicBlock *block; /* Bloc d'origine représenté */
+ GtkWidget *view; /* Vue graphique associée */
+ GtkAllocation alloc; /* Emplacement final du bloc */
+
+ GdkPoint **bottom_anchors; /* Accroches inférieures */
+ size_t ba_count; /* Quantité de ces accroches */
+
+ graph_rank *ranks; /* Répartition verticale */
+ size_t ranks_count; /* Nombre de divisions */
+
+};
+
+/* Mise en disposition de blocs en graphique (classe) */
+struct _GGraphClusterClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Espace minimal horizontal entre les blocs */
+#define HORIZONTAL_MARGIN 20
+
+/* Espace minimal vertical entre les blocs */
+#define VERTICAL_MARGIN 30
+
+/* Espace minimal entre les liens */
+#define LINK_MARGIN 10
+
+
+/* Initialise la classe des mises en disposition graphique. */
+static void g_graph_cluster_class_init(GGraphClusterClass *);
+
+/* Initialise une mise en disposition de blocs en graphique. */
+static void g_graph_cluster_init(GGraphCluster *);
+
+/* Supprime toutes les références externes. */
+static void g_graph_cluster_dispose(GGraphCluster *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_graph_cluster_finalize(GGraphCluster *);
+
+/* Complète un graphique avec un sous-ensemble de blocs. */
+static void g_graph_cluster_add_sub(GGraphCluster *, GGraphCluster *, GBasicBlock *);
+
+/* Organisation la disposition d'un ensemble de blocs basiques. */
+static void g_graph_cluster_dispatch_x(GGraphCluster *);
+
+/* Détermine une position pour un ensemble de blocs basiques. */
+//static void g_graph_cluster_set_x(GGraphCluster *, gint);
+
+/* Décalle vers la droite un ensemble de blocs basiques. */
+static void g_graph_cluster_offset_x(GGraphCluster *, gint);
+
+/* Décalle vers le bas un ensemble de blocs basiques. */
+static void g_graph_cluster_set_y(GGraphCluster *, gint);
+
+
+
+
+
+/* Recherche le bloc basique à l'extrémité d'un lien. */
+//static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *, const GArchInstruction *);
+
+/* Met en place les embryons de liens nécessaires. */
+static void g_graph_cluster_define_links(GGraphCluster *, GHashTable *);
+
+/* Détermine les positions de tous les liens en place. */
+static void g_graph_cluster_compute_link_positions(GGraphCluster *);
+
+/* Applique les positions calculées pour chaque lien graphique. */
+static void g_graph_cluster_resolve_links(const GGraphCluster *);
+
+
+
+
+
+
+/* Indique le type définit par la GLib pour les mises en disposition graphique. */
+G_DEFINE_TYPE(GGraphCluster, g_graph_cluster, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des mises en disposition graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_class_init(GGraphClusterClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_graph_cluster_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_graph_cluster_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = instance à initialiser. *
+* *
+* Description : Initialise une mise en disposition de blocs en graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_init(GGraphCluster *cluster)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_dispose(GGraphCluster *cluster)
+{
+ g_object_unref(G_OBJECT(cluster->block));
+ g_object_unref(G_OBJECT(cluster->view));
+
+ G_OBJECT_CLASS(g_graph_cluster_parent_class)->dispose(G_OBJECT(cluster));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_finalize(GGraphCluster *cluster)
+{
+ G_OBJECT_CLASS(g_graph_cluster_parent_class)->finalize(G_OBJECT(cluster));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire charger dont le code est à représenter.*
+* list = ensemble de blocs basiques à manipuler. *
+* index = indice du bloc principal à mettre en place. *
+* highlighted = gestionnaire de surbrillance pour segments. *
+* *
+* Description : Construit un graphique à partir de blocs basiques. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphCluster *g_graph_cluster_new(GLoadedBinary *binary, const GBlockList *list, size_t index, segcnt_list *highlighted)
+{
+ GGraphCluster *result; /* Structure à retourner */
+ vmpa2t first; /* Début d'un groupe de lignes */
+ vmpa2t last; /* Fin d'un groupe de lignes */
+ GCodeBuffer *buffer; /* Tampon brut à découper */
+ GBufferView *view; /* Partie affichée du tampon */
+ GtkRequisition requisition; /* Taille à l'écran actuelle */
+
+ result = g_object_new(G_TYPE_GRAPH_CLUSTER, NULL);
+
+ /* Encapsulation du bloc d'entrée */
+
+ result->block = g_block_list_get_block(list, index);
+ g_object_ref(G_OBJECT(result->block));
+
+ result->view = gtk_block_view_new();
+
+ gtk_widget_show(result->view);
+ gtk_view_panel_attach_binary(GTK_VIEW_PANEL(result->view), binary, BVW_GRAPH);
+
+ gtk_view_panel_show_border(GTK_VIEW_PANEL(result->view), true);
+
+ /* Restriction au bloc basique */
+
+ g_basic_block_get_boundary_addresses(result->block, &first, &last);
+
+ buffer = g_loaded_binary_get_disassembled_buffer(binary);
+
+ view = g_buffer_view_new(buffer, highlighted);
+ g_buffer_view_restrict(view, &first, &last);
+ gtk_buffer_view_attach_buffer(GTK_BUFFER_VIEW(result->view), view);
+
+ /* Détermination d'une position initiale centrée */
+
+ gtk_widget_get_preferred_size(result->view, NULL, &requisition);
+
+ result->alloc.x = -requisition.width / 2;
+ result->alloc.y = 0;
+
+ result->alloc.width = requisition.width;
+ result->alloc.height = requisition.height;
+
+ printf("BLOCK INIT :: %d <> %d\n", result->alloc.x, result->alloc.width);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à compléter. *
+* sub = sous-ensemble à intégrer. *
+* block = bloc basique de départ du sous-ensemble. *
+* *
+* Description : Complète un graphique avec un sous-ensemble de blocs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_add_sub(GGraphCluster *cluster, GGraphCluster *sub, GBasicBlock *block)
+{
+ unsigned int level; /* Niveau du nouvel ensemble */
+ size_t i; /* Boucle de parcours */
+ graph_rank new; /* Nouvel étage à insérer */
+ graph_rank *rank; /* Nouvel étage à compléter */
+
+ level = g_basic_block_get_rank(block);
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ if (cluster->ranks[i].level == level)
+ break;
+
+ if (i == cluster->ranks_count)
+ {
+ new.level = level;
+
+ new.clusters = (GGraphCluster **)calloc(1, sizeof(GGraphCluster *));
+ new.count = 1;
+
+ new.clusters[0] = sub;
+
+ int cmp_graph_rank(const graph_rank *a, const graph_rank *b)
+ {
+ if (a->level < b->level)
+ return -1;
+
+ else if (a->level > b->level)
+ return 1;
+
+ else
+ return 0;
+
+ }
+
+ cluster->ranks = qinsert(cluster->ranks, &cluster->ranks_count,
+ sizeof(graph_rank), (__compar_fn_t)cmp_graph_rank, &new);
+
+ }
+
+ else
+ {
+ rank = &cluster->ranks[i];
+
+ rank->count++;
+ rank->clusters = (GGraphCluster **)realloc(rank->clusters,
+ sizeof(GGraphCluster *) * rank->count);
+
+ rank->clusters[rank->count - 1] = sub;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à manipuler. *
+* *
+* Description : Organisation la disposition d'un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
+{
+ size_t k; /* Boucle de parcours #1 */
+ size_t rcount; /* Nombre d'ensembles présents */
+ size_t mid; /* Position centrale de départ */
+ gint start; /* Position initiale de départ */
+
+ void place_sub(GGraphCluster **iter, size_t loop, gint base, int dir)
+ {
+ size_t i; /* Boucle de parcours #2 */
+ GtkAllocation needed; /* Taille requise */
+
+ assert(dir == -1 || dir == 1);
+
+ for (i = 0; i < loop; i++, iter += dir)
+ {
+ g_graph_cluster_dispatch_x(*iter);
+
+ g_graph_cluster_compute_needed_alloc(*iter, &needed);
+
+ if (dir > 0)
+ g_graph_cluster_offset_x(*iter, base - needed.x);
+ else
+ g_graph_cluster_offset_x(*iter, base - needed.x - needed.width);
+
+ base += dir * (needed.width + HORIZONTAL_MARGIN);
+
+ }
+
+ }
+
+
+
+
+ for (k = 0; k < cluster->ranks_count; k++)
+ {
+ rcount = cluster->ranks[k].count;
+
+ if (rcount % 2 == 1)
+ {
+ if (rcount > 1)
+ {
+ mid = rcount / 2;
+
+ start = cluster->ranks[k].clusters[mid]->alloc.x - HORIZONTAL_MARGIN;
+
+ place_sub(cluster->ranks[k].clusters + mid - 1, mid, start, -1);
+
+ start *= -1;
+
+ place_sub(cluster->ranks[k].clusters + mid + 1, mid, start, 1);
+
+ }
+
+ }
+
+ else
+ {
+ mid = rcount / 2 - 1;
+
+ start = - HORIZONTAL_MARGIN / 2;
+
+ place_sub(cluster->ranks[k].clusters + mid, mid + 1, start, -1);
+
+ start *= -1;
+
+ place_sub(cluster->ranks[k].clusters + mid + 1, mid + 1, start, 1);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* x = position finale sur l'axe des abscisses. *
+* *
+* Description : Détermine une position pour un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+/*
+static void g_graph_cluster_set_x(GGraphCluster *cluster, gint x)
+{
+ g_graph_cluster_offset_x(cluster, -cluster->alloc.x);
+
+ g_graph_cluster_offset_x(cluster, x);
+
+}
+*/
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* offset = décallage à appliquer. *
+* *
+* Description : Décalle vers la droite un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
+{
+ size_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
+
+ cluster->alloc.x += offset;
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_offset_x(cluster->ranks[i].clusters[j], offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* base = position ordonnée à appliquer. *
+* *
+* Description : Décalle vers le bas un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base)
+{
+ size_t i; /* Boucle de parcours #1 */
+ gint max; /* Hauteur maximale rencontrée */
+ size_t j; /* Boucle de parcours #2 */
+ GGraphCluster *sub; /* Sous-ensemble traité */
+ GtkAllocation alloc; /* Allocation courante */
+
+ cluster->alloc.y = base;
+
+ base += cluster->alloc.height;
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ {
+ base += VERTICAL_MARGIN;
+
+ max = 0;
+
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ {
+ sub = cluster->ranks[i].clusters[j];
+
+ g_graph_cluster_set_y(sub, base);
+
+ g_graph_cluster_compute_needed_alloc(sub, &alloc);
+
+ if ((alloc.y + alloc.height) > max)
+ max = alloc.y + alloc.height;
+
+ }
+
+ base = max;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = encapsulation à consulter. *
+* alloc = emplacement idéal pour l'affichage. *
+* *
+* Description : Détermine l'emplacement requis d'un ensemble de blocs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAllocation *alloc)
+{
+ GtkAllocation needed; /* Taille requise */
+ size_t i; /* Boucle de parcours */
+ size_t rcount; /* Nombre d'ensembles présents */
+
+ *alloc = cluster->alloc;
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ {
+ rcount = cluster->ranks[i].count;
+
+ switch (rcount)
+ {
+ case 1:
+
+ g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[0], &needed);
+
+ if (needed.x < alloc->x)
+ {
+ alloc->width += (alloc->x + needed.x);
+ alloc->x = needed.x;
+ }
+
+ if ((needed.x + needed.width) > (alloc->x + alloc->width))
+ alloc->width += needed.x + needed.width - alloc->x - alloc->width;
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if ((i + 1) == cluster->ranks_count)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ break;
+
+ default:
+
+ assert(rcount >= 2);
+
+ g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[0], &needed);
+
+ if (needed.x < alloc->x)
+ {
+ alloc->width += (alloc->x + needed.x);
+ alloc->x = needed.x;
+ }
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if ((i + 1) == cluster->ranks_count)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ g_graph_cluster_compute_needed_alloc(cluster->ranks[i].clusters[rcount - 1], &needed);
+
+ if ((needed.x + needed.width) > (alloc->x + alloc->width))
+ alloc->width += needed.x + needed.width - alloc->x - alloc->width;
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if ((i + 1) == cluster->ranks_count)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ break;
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = encapsulation à traiter. *
+* view = support de destination finale. *
+* *
+* Description : Dispose chaque noeud sur la surface de destination donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_cluster_place(GGraphCluster *cluster, GtkGraphView *view)
+{
+ size_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
+
+ g_object_ref(G_OBJECT(cluster->view));
+ gtk_graph_view_put(view, cluster->view, &cluster->alloc);
+
+ for (i = 0; i < cluster->ta_count; i++)
+ {
+ g_object_ref(G_OBJECT(cluster->top_anchors[i]->edge));
+ gtk_graph_view_add_edge(view, cluster->top_anchors[i]->edge);
+ }
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_place(cluster->ranks[i].clusters[j], view);
+
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à consulter ou remonter. *
+* first = première instruction du bloc basique recherché. *
+* *
+* Description : Recherche le bloc basique à l'extrémité d'un lien. *
+* *
+* Retour : Bloc graphique de destination pour un lien ou NULL si échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+#if 0
+static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *cluster, const GArchInstruction *first)
+{
+ GGraphCluster *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ const graph_rank *rank; /* Confort d'accès */
+ size_t j; /* Boucle de parcours #2 */
+ GArchInstruction *instr; /* Instruction à comparer */
+
+ result = NULL;
+
+ for (i = 0; i < cluster->ranks_count && result == NULL; i++)
+ {
+ rank = &cluster->ranks[i];
+
+ for (j = 0; j < rank->count && result == NULL; j++)
+ {
+ g_basic_block_get_boundary(rank->clusters[j]->block, &instr, NULL);
+
+ if (instr == first)
+ result = rank->clusters[j];
+
+ }
+
+ }
+
+ return result;
+
+}
+#endif
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* all = table regroupant tous les groupes créés. *
+* *
+* Description : Met en place les embryons de liens nécessaires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all)
+{
+ GArchInstruction *last; /* Dernière instruction du bloc*/
+ GArchInstruction **dests; /* Instr. visée par une autre */
+ InstructionLinkType *types; /* Type de lien entre lignes */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t i; /* Boucle de parcours #1 */
+ GGraphCluster *target; /* Bloc ciblé par un lien */
+ GdkPoint *start; /* Point de départ d'un lien */
+ link_def *end; /* Définitions d'arrivée */
+ size_t j; /* Boucle de parcours #2 */
+
+ /* Au niveau du bloc courant */
+
+ g_basic_block_get_boundary(cluster->block, NULL, &last);
+
+ g_arch_instruction_rlock_dest(last);
+ dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL);
+
+ for (i = 0; i < dcount; i++)
+ switch (types[i])
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+
+ target = G_GRAPH_CLUSTER(g_hash_table_lookup(all, dests[i]));
+ assert(target != NULL);
+
+ /* Point de départ */
+
+ start = (GdkPoint *)calloc(1, sizeof(GdkPoint));
+
+ cluster->bottom_anchors = (GdkPoint **)realloc(cluster->bottom_anchors,
+ ++cluster->ba_count * sizeof(GdkPoint *));
+ cluster->bottom_anchors[cluster->ba_count - 1] = start;
+
+ /* Point d'arrivée */
+
+ end = (link_def *)calloc(1, sizeof(link_def));
+
+ target->top_anchors = (link_def **)realloc(target->top_anchors,
+ ++target->ta_count * sizeof(link_def *));
+ target->top_anchors[target->ta_count - 1] = end;
+
+ /* Etablissement d'un embryon de lien */
+
+ end->type = types[i];
+
+ if (types[i] == ILT_JUMP_IF_TRUE)
+ end->edge = g_graph_edge_new_true(start, &end->y, &end->end);
+
+ else if (types[i] == ILT_JUMP_IF_FALSE)
+ end->edge = g_graph_edge_new_false(start, &end->y, &end->end);
+
+ else
+ end->edge = g_graph_edge_new(start, &end->y, &end->end);
+
+ break;
+
+
+ case ILT_LOOP:
+
+ /* TODO */
+ assert(false);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ g_arch_instruction_runlock_dest(last);
+
+ /* Propagation de la mise en place */
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_define_links(cluster->ranks[i].clusters[j], all);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* *
+* Description : Détermine les positions de tous les liens en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_compute_link_positions(GGraphCluster *cluster)
+{
+ gint mid_x; /* Abscisse centrale */
+ size_t half; /* Indice de répartition égale */
+ gint y; /* Ordonnée d'application */
+
+ size_t i; /* Boucle de parcours #1 */
+ GdkPoint *pt; /* Point à actualiser */
+ size_t j; /* Boucle de parcours #2 */
+
+
+
+ mid_x = cluster->alloc.x + (cluster->alloc.width / 2);
+
+ /* Du côté des départs... */
+
+ if (cluster->ba_count > 0)
+ {
+ half = cluster->ba_count / 2;
+
+ y = cluster->alloc.y + cluster->alloc.height;
+
+ if (cluster->ba_count % 2 == 1)
+ {
+ for (i = half; i > 0; i--)
+ {
+ pt = cluster->bottom_anchors[i - 1];
+
+ pt->x = mid_x - (half - i + 1) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ pt = cluster->bottom_anchors[half];
+
+ pt->x = mid_x;
+ pt->y = y;
+
+ for (i = half + 1; i < cluster->ba_count; i++)
+ {
+ pt = cluster->bottom_anchors[i];
+
+ pt->x = mid_x + (i - half) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ }
+
+ else
+ {
+ for (i = half; i > 0; i--)
+ {
+ pt = cluster->bottom_anchors[i - 1];
+
+ pt->x = mid_x - LINK_MARGIN / 2 - (half - i) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ for (i = half; i < cluster->ba_count; i++)
+ {
+ pt = cluster->bottom_anchors[i];
+
+ pt->x = mid_x + LINK_MARGIN / 2 + (half - i) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ }
+
+ }
+
+ /* Du côté des arrivées... */
+
+ if (cluster->ta_count > 0)
+ {
+ half = cluster->ta_count / 2;
+
+ y = cluster->alloc.y;
+
+ if (cluster->ta_count % 2 == 1)
+ {
+ for (i = half; i > 0; i--)
+ {
+ pt = &cluster->top_anchors[i - 1]->end;
+
+ pt->x = mid_x - (half - i + 1) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ pt = &cluster->top_anchors[half]->end;
+
+ pt->x = mid_x;
+ pt->y = y;
+
+ for (i = half + 1; i < cluster->ta_count; i++)
+ {
+ pt = &cluster->top_anchors[i]->end;
+
+ pt->x = mid_x + (i - half) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ }
+
+ else
+ {
+ for (i = half; i > 0; i--)
+ {
+ pt = &cluster->top_anchors[i - 1]->end;
+
+ pt->x = mid_x - LINK_MARGIN / 2 - (half - i) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ for (i = half; i < cluster->ta_count; i++)
+ {
+ pt = &cluster->top_anchors[i]->end;
+
+ pt->x = mid_x + LINK_MARGIN / 2 + (half - i) * LINK_MARGIN;
+ pt->y = y;
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+ for (i = 0; i < cluster->ta_count; i++)
+ cluster->top_anchors[i]->y.y = cluster->top_anchors[i]->end.y - 18;
+
+
+
+
+
+
+
+ }
+
+ /* Propagation des déterminations */
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_compute_link_positions(cluster->ranks[i].clusters[j]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* *
+* Description : Applique les positions calculées pour chaque lien graphique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_resolve_links(const GGraphCluster *cluster)
+{
+ size_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
+
+ for (i = 0; i < cluster->ta_count; i++)
+ g_graph_edge_resolve(cluster->top_anchors[i]->edge);
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_resolve_links(cluster->ranks[i].clusters[j]);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* Liste de blocs restants à traiter */
+typedef struct _pending_blocks
+{
+ size_t count; /* Taille de la liste */
+ GBasicBlock *list[0]; /* Liste de blocs à traiter */
+
+} pending_blocks;
+
+
+
+
+
+/* Met en place un ensemble de blocs sous forme graphique. */
+static GGraphCluster *setup_graph_clusters(GLoadedBinary *, const GBlockList *, size_t , segcnt_list *, pending_blocks *, GHashTable *);
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire charger dont le code est à représenter.*
+* list = ensemble de blocs basiques à manipuler. *
+* index = indice du bloc principal à mettre en place. *
+* highlighted = gestionnaire de surbrillance pour segments. *
+* pending = liste de blocs restant à traiter. [OUT] *
+* all = table regroupant tous les groupes créés. *
+* *
+* Description : Met en place un ensemble de blocs sous forme graphique. *
+* *
+* Retour : Ensemble de blocs mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GGraphCluster *setup_graph_clusters(GLoadedBinary *binary, const GBlockList *list, size_t index, segcnt_list *highlighted, pending_blocks *pending, GHashTable *all)
+{
+ GGraphCluster *result; /* Instance nouvelle à renvoyer*/
+ GBasicBlock *block; /* Bloc à manipuler */
+ GArchInstruction *first; /* Première instruction du bloc*/
+ GArchInstruction *last; /* Dernière instruction du bloc*/
+#ifndef NDEBUG
+ gboolean new; /* Bloc déjà traité ? */
+#endif
+ GArchInstruction **dests; /* Instr. visée par une autre */
+ InstructionLinkType *types; /* Type de lien entre lignes */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t i; /* Boucle de parcours #1 */
+ GBasicBlock *target; /* Bloc ciblé par un lien */
+ size_t j; /* Boucle de parcours #2 */
+ bool changed; /* Un ajout a été effectué ? */
+ const bitfield_t *dominators; /* Blocs dominant ce même bloc */
+ size_t next; /* Indice du prochain bloc */
+ GGraphCluster *sub; /* Sous-ensemble à intégrer */
+
+ result = g_graph_cluster_new(binary, list, index, highlighted);
+
+ block = g_block_list_get_block(list, index);
+
+ g_basic_block_get_boundary(block, &first, &last);
+
+#ifndef NDEBUG
+ new = g_hash_table_insert(all, first, result);
+ assert(new);
+#else
+ g_hash_table_insert(all, first, result);
+#endif
+
+ /* Détermination des blocs suivants */
+
+ g_arch_instruction_rlock_dest(last);
+ dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL);
+
+ printf(" ... block=%p dest=%zu\n", block, dcount);
+
+ for (i = 0; i < dcount; i++)
+ switch (types[i])
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+
+ target = g_block_list_find_by_starting_instr(list, dests[i]);
+
+ /**
+ * Les sauts ne se font pas toujours à l'intérieur d'une même fonction.
+ * Par exemple sous ARM :
+ *
+ * 00008358 <call_gmon_start>:
+ * ....
+ * 8362: f7ff bfcf b.w 8304 <_init+0x38>
+ * ....
+ *
+ */
+
+ printf(" NEW BLK :: %d -> %p\n", types[i], target);
+
+ if (target != NULL)
+ {
+ for (j = 0; j < pending->count; j++)
+ if (pending->list[j] == target)
+ break;
+
+ if (j == pending->count)
+ {
+ assert((pending->count + 1) < g_block_list_count_blocks(list));
+ pending->list[pending->count++] = target;
+ printf(" --push-- %d -> %p\n", types[i], target);
+ }
+
+ do
+ {
+ size_t k;
+ printf(" --stack-- ");
+ for (k = 0; k < pending->count; k++)
+ printf("%p ", pending->list[k]);
+ printf("\n");
+ }
+ while (0);
+
+
+
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ g_arch_instruction_runlock_dest(last);
+
+ /* Intégration de tous les blocs en attente */
+
+ do
+ {
+ changed = false;
+
+ for (i = 0; i < pending->count && !changed; i++)
+ {
+ block = pending->list[i];
+ dominators = g_basic_block_get_domination(block);
+
+ if (test_in_bit_field(dominators, index, 1))
+ {
+ /* Dépilement */
+
+ changed = true;
+
+ if ((i + 1) < pending->count)
+ memmove(&pending->list[i], &pending->list[i + 1],
+ (pending->count - i - 1) * sizeof(GBasicBlock *));
+
+ pending->count--;
+
+ /* Intégration */
+
+ next = g_block_list_get_index(list, block);
+ assert(next < g_block_list_count_blocks(list));
+
+ printf(" --pop-- block=%p index=%zu\n", block, next);
+
+ sub = setup_graph_clusters(binary, list, next, highlighted, pending, all);
+
+ g_graph_cluster_add_sub(result, sub, block);
+
+ }
+
+ }
+
+ }
+ while (changed);
+
+ return result;
+
+}
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : blocks = ensemble des blocs basiques déjà découpés. *
+* views = morceaux de code à afficher de façon organisée. *
+* count = quantité de ces morceaux de code. *
+* *
+* Description : Construit un graphique à partir de blocs basiques. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *list, segcnt_list *highlighted)
+{
+ GGraphCluster *result; /* Structure à retourner */
+ GHashTable *all; /* Collection des créations */
+ size_t count; /* Taille de la liste de blocs */
+ pending_blocks *pending; /* Suivi des blocs à traiter */
+ GtkAllocation needed; /* Taille requise */
+
+
+ all = g_hash_table_new(NULL, NULL);
+
+ count = g_block_list_count_blocks(list);
+
+ pending = (pending_blocks *)calloc(1, sizeof(pending_blocks) + count * sizeof(GBasicBlock *));
+
+
+
+
+ do
+ {
+ size_t i;
+ GBasicBlock *block;
+ const bitfield_t *domination;
+
+ printf("DBG // count : %zu\n", count);
+
+ for (i = 0; i < count; i++)
+ {
+ block = g_block_list_get_block(list, i);
+ domination = g_basic_block_get_domination(block);
+
+ printf("DBG // block [%zu] : 0x%08lx -- rank = %u\n",
+ i, gfw(domination), g_basic_block_get_rank(block));
+
+ }
+
+ fflush(NULL);
+
+ }
+ while (0);
+
+
+
+
+
+ result = setup_graph_clusters(binary, list, 0, highlighted, pending, all);
+
+ free(pending);
+
+ g_graph_cluster_define_links(result, all);
+
+ /* Positionnements dans l'espace */
+
+ g_graph_cluster_dispatch_x(result);
+
+ g_graph_cluster_set_y(result, 0);
+
+ /* Réajustement vers la droite */
+
+ g_graph_cluster_compute_needed_alloc(result, &needed);
+
+ g_graph_cluster_offset_x(result, -needed.x);
+
+ /* Application finale sur les liens */
+
+ g_graph_cluster_compute_link_positions(result);
+
+ g_graph_cluster_resolve_links(result);
+
+
+
+
+ g_hash_table_unref(all);
+
+
+ return result;
+
+
+}