From f7c1c34cb54b239586bf431b1749759baee9493e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 20 Sep 2009 13:22:53 +0000 Subject: Rewritten the work queue and fixed thread concurrency. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@117 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 49 +++ Makefile.am | 2 +- src/analysis/Makefile.am | 1 - src/analysis/binary.c | 562 ++++++++++++++++++++++++++++++++-- src/analysis/delayed.c | 714 -------------------------------------------- src/analysis/delayed.h | 97 ------ src/analysis/line-int.h | 1 + src/analysis/line.c | 39 +++ src/analysis/line.h | 6 + src/glibext/delayed-int.h | 41 +-- src/glibext/delayed.c | 319 ++++++++++++++++++-- src/glibext/delayed.h | 12 +- src/gtkext/gtkbinview-int.h | 4 + src/gtkext/gtkbinview.c | 8 + src/gtkext/gtkblockview.c | 326 ++++++++++++++++---- src/gtkext/gtkgraphview.c | 80 ++++- src/main.c | 4 +- src/plugins/pglist.c | 2 +- src/project.c | 95 +++++- src/project.h | 2 +- src/shell.c | 4 +- 21 files changed, 1389 insertions(+), 979 deletions(-) delete mode 100644 src/analysis/delayed.c delete mode 100644 src/analysis/delayed.h diff --git a/ChangeLog b/ChangeLog index a0e9573..b2fb0ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +09-09-20 Cyrille Bagard + + * Makefile.am: + Fix compilation order. + + * src/analysis/binary.c: + Process the disassembly here and use the new queue to push works. + + * src/analysis/delayed.c: + * src/analysis/delayed.h: + Deleted entries. Their content is merged with src/analysis/binary.c. + + * src/analysis/line.c: + * src/analysis/line.h: + Add functions to retrieve the last line of a list and the length of a line. + + * src/analysis/line-int.h: + Define the lines_list_last() macro. + + * src/analysis/Makefile.am: + Remove the delayed.[ch] files from libanalysis_la_SOURCES. + + * src/glibext/delayed.c: + * src/glibext/delayed.h: + * src/glibext/delayed-int.h: + Improved heavyly the work queue: it is now more generic and creates thread pools. + + * src/gtkext/gtkbinview.c: + * src/gtkext/gtkbinview-int.h: + Create a signal called "lines-set". + + * src/gtkext/gtkblockview.c: + * src/gtkext/gtkgraphview.c: + Use threads to build the views. The caller has now to carefully wait + the end of the building. + + * src/main.c: + Init the generic work queue instead of the disassembly one. + + * src/plugins/pglist.c: + Disable plugins again. + + * src/project.c: + * src/project.h: + Update code for building view and fix the concurrency between the threads. + + * src/shell.c: + Keep the standard output clean. + 09-09-19 Cyrille Bagard * configure.ac: diff --git a/Makefile.am b/Makefile.am index b0caf58..a28f09b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ EXTRA_DIST = config.rpath config.rpath config.rpath ChangeLog -SUBDIRS = pixmaps plugins src +SUBDIRS = pixmaps src plugins ACLOCAL_AMFLAGS = -I m4 diff --git a/src/analysis/Makefile.am b/src/analysis/Makefile.am index d7c694b..7dca420 100755 --- a/src/analysis/Makefile.am +++ b/src/analysis/Makefile.am @@ -3,7 +3,6 @@ noinst_LTLIBRARIES = libanalysis.la libanalysis_la_SOURCES = \ binary.h binary.c \ - delayed.h delayed.c \ exporter-int.h \ exporter.h exporter.c \ line-int.h \ diff --git a/src/analysis/binary.c b/src/analysis/binary.c index c991125..4fe8f06 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -35,13 +35,12 @@ #include -#include "delayed.h" #include "line_code.h" /* TODO : supprimer ? */ #include "line_comment.h" /* TODO : supprimer ? */ #include "line_prologue.h" #include "prototype.h" #include "../common/extstr.h" -#include "../glibext/delayed.h" +#include "../glibext/delayed-int.h" #include "../format/format.h" #include "../panels/log.h" #include "../plugins/pglist.h" @@ -58,6 +57,71 @@ +/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ + + +#define G_TYPE_DELAYED_DISASSEMBLY g_delayed_disassembly_get_type() +#define G_DELAYED_DISASSEMBLY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_disassembly_get_type(), GDelayedDisassembly)) +#define G_IS_DELAYED_DISASSEMBLY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_disassembly_get_type())) +#define G_DELAYED_DISASSEMBLY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_DISASSEMBLY, GDelayedDisassemblyClass)) +#define G_IS_DELAYED_DISASSEMBLY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_DISASSEMBLY)) +#define G_DELAYED_DISASSEMBLY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_DISASSEMBLY, GDelayedDisassemblyClass)) + + +/* Ensembles binaires à désassembler (instance) */ +typedef struct _GDelayedDisassembly +{ + GDelayedWork parent; /* A laisser en premier */ + + GOpenidaBinary *binary; /* Destinataire final */ + + GBinPart **parts; /* Parties binaires à traiter */ + size_t count; /* Nombre de ces parties */ + + GRenderingLine *lines; /* Lignes de rendu résultantes */ + +} GDelayedDisassembly; + +/* Ensembles binaires à désassembler (classe) */ +typedef struct _GDelayedDisassemblyClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +} GDelayedDisassemblyClass; + + +/* Indique le type défini pour les tâches de désassemblage différé. */ +static GType g_delayed_disassembly_get_type(void); + +/* Initialise la classe des tâches de désassemblage différé. */ +static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *); + +/* Initialise une tâche de désassemblage différé. */ +static void g_delayed_disassembly_init(GDelayedDisassembly *); + +/* Crée une tâche de désassemblage différé. */ +static GDelayedDisassembly *g_delayed_disassembly_new(GOpenidaBinary *, GBinPart **, size_t); + +/* Assure le désassemblage en différé. */ +static void g_delayed_disassembly_process(GDelayedDisassembly *, GtkExtStatusBar *); + +/* Procède au désassemblage basique d'un contenu binaire. */ +static GRenderingLine *disassemble_binary_parts(GDelayedDisassembly *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); + +/* Etablit les liens entres les différentes lignes de code. */ +static void establish_links_between_lines(GRenderingLine *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); + +/* S'assure que toutes les routines ont une taille définie. */ +static void limit_all_routines(GRenderingLine *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); + +/* Cherche l'adresse de fin d'une routine. */ +static vmpa_t find_best_ending_address_for_routine(GRenderingLine *, size_t, const vmpa_t *, const off_t *, size_t); + + + + + + /* Description de fichier binaire (instance) */ struct _GOpenidaBinary @@ -102,7 +166,470 @@ bin_t *map_binary_file(const char *, off_t *); GRenderingLine *build_binary_prologue(const char *, const uint8_t *, off_t); /* Acquitte la fin d'un désasemblage différé et complet. */ -void ack_completed_disassembly(GDisassManager *, GOpenidaBinary *, GRenderingLine *, GOpenidaBinary *); +void ack_completed_disassembly(GDelayedDisassembly *, GOpenidaBinary *); + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* DESASSEMBLAGE DE BINAIRE DIFFERE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour les tâches de désassemblage différé. */ +G_DEFINE_TYPE(GDelayedDisassembly, g_delayed_disassembly, G_TYPE_DELAYED_WORK); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches de désassemblage différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : disass = instance à initialiser. * +* * +* Description : Initialise une tâche de désassemblage différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_disassembly_init(GDelayedDisassembly *disass) +{ + G_DELAYED_WORK(disass)->run = (run_task_fc)g_delayed_disassembly_process; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = binaire chargé en attente des résultats. * +* parts = parties binaires à désassembler. * +* count = nombre de parties à traiter. * +* * +* Description : Crée une tâche de désassemblage différé. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDelayedDisassembly *g_delayed_disassembly_new(GOpenidaBinary *binary, GBinPart **parts, size_t count) +{ + GDelayedDisassembly *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_DELAYED_DISASSEMBLY, NULL); + + result->binary = binary; + + result->parts = parts; + result->count = count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : disass = analyse à mener. * +* statusbar = barre de statut à tenir informée. * +* * +* Description : Assure le désassemblage en différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar) +{ + GBinRoutine **routines; /* Liste des routines trouvées */ + size_t routines_count; /* Nombre de ces routines */ + guint id; /* Identifiant de statut */ + + routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->binary->format), &routines_count); + qsort(routines, routines_count, sizeof(GBinRoutine *), g_binary_routine_rcompare); + + /* Première étape */ + + id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true); + + disass->lines = disassemble_binary_parts(disass, routines, routines_count, statusbar, id); + + gtk_extended_status_bar_remove(statusbar, id); + + /* Seconde étape */ + + id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true); + + establish_links_between_lines(disass->lines, routines, routines_count, statusbar, id); + + gtk_extended_status_bar_remove(statusbar, id); + + /* Troisième étape */ + + id = gtk_extended_status_bar_push(statusbar, _("Finding remaining limits..."), true); + + limit_all_routines(disass->lines, routines, routines_count, statusbar, id); + + gtk_extended_status_bar_remove(statusbar, id); + +} + + +/****************************************************************************** +* * +* Paramètres : disass = tâche à l'origine du traitement. * +* routines = prototypes existants à insérer. * +* count = quantité de ces prototypes. * +* statusbar = barre de statut avec progression à mettre à jour.* +* id = identifiant du message affiché à l'utilisateur. * +* * +* Description : Procède au désassemblage basique d'un contenu binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GRenderingLine *disassemble_binary_parts(GDelayedDisassembly *disass, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) +{ + GRenderingLine *result; /* Ligne de rendu à retourner */ + GArchProcessor *proc; /* Architecture du binaire */ + GRenderingOptions *options; /* Options de désassemblage */ + bin_t *bin_data; /* Données binaires à lire */ + size_t i; /* Boucle de parcours #1 */ + off_t sum; /* Somme de toutes les tailles */ + off_t done; /* Quantité déjà traitée */ + off_t pos; /* Début d'une zone binaire */ + off_t len; /* Taille de cette même zone */ + vmpa_t base; /* Adresse de la zone binaire */ + off_t start; /* Conservation du pt de départ*/ + vmpa_t addr; /* Adresse d'une instruction */ + GArchInstruction *instr; /* Instruction décodée */ + GRenderingLine *line; /* Nouvelle ligne de rendu */ + size_t k; /* Boucle de parcours #2 */ + uint64_t routine_offset; /* Point de départ de routine */ + char *routine_desc; /* Prototype d'une routine */ + + result = NULL; + + proc = get_arch_processor_from_format(g_openida_binary_get_format(disass->binary)); + options = g_openida_binary_get_options(disass->binary); + bin_data = g_openida_binary_get_data(disass->binary, NULL); + + /* Préparation du suivi de la progression */ + + sum = 0; + + for (i = 0; i < disass->count; i++) + { + g_binary_part_get_values(disass->parts[i], NULL, &len, NULL); + sum += len; + } + + done = 0; + + for (i = 0; i < disass->count; i++) + { + g_binary_part_get_values(disass->parts[i], &pos, &len, &base); + + /* Décodage des instructions */ + + start = pos; + pos = 0; + + while (pos < len) + { + addr = base + pos; + + instr = g_arch_processor_decode_instruction(proc, &bin_data[start], + &pos, len, start, addr); + + line = g_code_line_new(addr, instr, options); + g_rendering_line_add_to_lines(&result, line); + + if (pos < len) + gtk_extended_status_bar_update_activity(statusbar, id, (done + pos) * 1.0 / sum); + + } + + done += len; + gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); + + /* Ajout des prototypes de fonctions */ + + for (k = 0; k < count; k++) + { + routine_offset = g_binary_routine_get_address(routines[k]); + + if (!(base <= routine_offset && routine_offset < (base + len))) continue; + + routine_desc = g_binary_routine_to_string(routines[k]); + + line = g_comment_line_new(routine_offset, routine_desc, options); + g_rendering_line_insert_into_lines(&result, line, true); + + free(routine_desc); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : lines = lignes de rendu à relier. * +* routines = prototypes existants à insérer. * +* count = quantité de ces prototypes. * +* statusbar = barre de statut avec progression à mettre à jour.* +* id = identifiant du message affiché à l'utilisateur. * +* * +* Description : Etablit les liens entres les différentes lignes de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void establish_links_between_lines(GRenderingLine *lines, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) +{ + size_t i; /* Boucle de parcours */ + vmpa_t start; /* Adresse de départ */ + vmpa_t end; /* Adresse de fin */ + GRenderingLine *iter; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction à ausculter */ + vmpa_t addr; /* Adresse référencée */ + InstructionLinkType type; /* Type de référence */ + GRenderingLine *target; /* Ligne visée par la référence*/ + + for (i = 0; i < count; i++) + { + start = g_binary_routine_get_address(routines[i]); + end = start + g_binary_routine_get_size(routines[i]); + + for (iter = g_rendering_line_find_by_address(lines, NULL, start); + iter != NULL; + iter = g_rendering_line_get_next_iter(lines, iter, NULL)) + { + /* Si on sort de la zone... */ + if (get_rendering_line_address(iter) >= end) break; + + /* On ne traite que du code ici ! */ + if (!G_IS_CODE_LINE(iter)) continue; + + instr = g_code_line_get_instruction(G_CODE_LINE(iter)); + type = g_arch_instruction_get_link(instr, &addr); + + switch (type) + { + case ILT_NONE: + break; + + case ILT_JUMP: + + target = g_rendering_line_find_by_address(lines, NULL, addr); + + if (target != NULL) + g_rendering_line_link_with(iter, target, type); + + break; + + case ILT_JUMP_IF_FALSE: + break; + + case ILT_JUMP_IF_TRUE: + + target = g_rendering_line_find_by_address(lines, NULL, addr); + + if (target != NULL) + { + g_rendering_line_link_with(iter, target, type); + + target = g_rendering_line_get_next_iter(lines, iter, NULL); + if (target != NULL) + g_rendering_line_link_with(iter, target, ILT_JUMP_IF_FALSE); + + } + + break; + + case ILT_CALL: + + target = g_rendering_line_find_by_address(lines, NULL, addr); + + if (target != NULL) + g_rendering_line_link_with(iter, target, type); + + break; + + } + + } + + gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : lines = lignes de rendu à parcourir. * +* routines = prototypes existants à insérer. * +* count = quantité de ces prototypes. * +* statusbar = barre de statut avec progression à mettre à jour.* +* id = identifiant du message affiché à l'utilisateur. * +* * +* Description : S'assure que toutes les routines ont une taille définie. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void limit_all_routines(GRenderingLine *lines, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) +{ + size_t i; /* Boucle de parcours */ + vmpa_t *starts; /* Adresses de départ */ + off_t *lengths; /* Tailles des routines */ + GRenderingLine *line; /* Ligne de départ / d'arrivée */ + vmpa_t start; /* Adresse de début de routine */ + vmpa_t last; /* Meilleur dernière adresse */ + GArchInstruction *instr; /* Instruction à ausculter */ + off_t length; /* Taille du code */ + + if (count == 0) return; + + starts = (vmpa_t *)calloc(count, sizeof(vmpa_t)); + lengths = (off_t *)calloc(count, sizeof(off_t)); + + for (i = 0; i < count; i++) + { + starts[i] = g_binary_routine_get_address(routines[i]); + lengths[i] = g_binary_routine_get_size(routines[i]); + + gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / (count * 2)); + + } + + for (i = 0; i < count; i++) + { + if (lengths[i] > 0) continue; + + start = g_binary_routine_get_address(routines[i]); + line = g_rendering_line_find_by_address(lines, NULL, start); + + last = find_best_ending_address_for_routine(line, i, starts, lengths, count); + + line = g_rendering_line_find_by_address(lines, NULL, last); + line = g_rendering_line_loop_for_code(line, NULL); + + instr = g_code_line_get_instruction(G_CODE_LINE(line)); + g_arch_instruction_get_location(instr, NULL, &length, NULL); + + lengths[i] = last - start + length; + g_binary_routine_set_size(routines[i], lengths[i]); + + gtk_extended_status_bar_update_activity(statusbar, id, (i + 1 + count) * 1.0 / (count * 2)); + + } + + free(starts); + free(lengths); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne de départ du parcours. * +* index = indice de la routine traitée dans la liste. * +* starts = adresse de départ des autres routines. * +* lengths = taille des différentes routines, valides ou nulles.* +* count = quantité de routines présentes. * +* * +* Description : Cherche l'adresse de fin d'une routine. * +* * +* Retour : Plus grande adresse de dernière instruction de routine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static vmpa_t find_best_ending_address_for_routine(GRenderingLine *line, size_t index, const vmpa_t *starts, const off_t *lengths, size_t count) +{ + vmpa_t result; /* Haute adresse à remonter */ + GRenderingLine *iter; /* Boucle de parcours #1 */ + vmpa_t candidate; /* Candidat potentiel */ + size_t i; /* Boucle de parcours #2 */ + GArchInstruction *instr; /* Instruction à ausculter */ + + result = starts[index]; + + for (iter = line; iter != NULL; iter = g_rendering_line_get_next_iter(line, iter, NULL)) + { + if (!G_IS_CODE_LINE(iter)) continue; + + candidate = get_rendering_line_address(iter); + + /* Regarde si on n'empiète pas sur une autre routine */ + + for (i = 0; i < count; i++) + { + if (i == index) continue; + + if (starts[i] <= candidate && candidate < (starts[i] + lengths[i])) + break; + + } + + if (i != count) break; + else result = candidate; + + /* Retour de fonction ? */ + + instr = g_code_line_get_instruction(G_CODE_LINE(iter)); + if (g_arch_instruction_is_return(instr)) break; + + } + + return result; + +} + + + + @@ -313,22 +840,22 @@ bool g_openida_binary_save(const GOpenidaBinary *binary, xmlDocPtr xdoc, xmlXPat void g_openida_binary_analyse(GOpenidaBinary *binary) { - GDisassManager *manager; /* Gestionnaire de différés */ + GWorkQueue *queue; /* Gestionnaire de différés */ GBinPart **parts; /* Parties d'élément binaire */ size_t parts_count; /* Nombre de ces parties */ GDelayedDisassembly *disass; /* Désassemblage à mener */ - manager = get_disassembly_manager(); + queue = get_work_queue(); parts = g_exe_format_get_parts(binary->format, &parts_count); qsort(parts, parts_count, sizeof(GBinPart *), g_binary_part_compare); disass = g_delayed_disassembly_new(binary, parts, parts_count); - g_signal_connect(manager, "disassembly-completed", + g_signal_connect(disass, "work-completed", G_CALLBACK(ack_completed_disassembly), binary); - g_delayed_queue_schedule_work(G_WORK_QUEUE(manager), G_DELAYED_WORK(disass)); + g_work_queue_schedule_work(queue, G_DELAYED_WORK(disass)); } @@ -591,10 +1118,8 @@ GRenderingLine *build_binary_prologue(const char *filename, const uint8_t *data, /****************************************************************************** * * -* Paramètres : manager = gestionnaire des traitements en parallèle. * -* binary = binaire dont le contenu est à analyser. * -* lines = lignes de rendu produites par le désasemblage. * -* user = élément binaire à l'origine du traitement. * +* Paramètres : disass = travail de désassemblage mené à bien. * +* binary = représentation de binaire à l'origine de l'opérat°. * * * * Description : Acquitte la fin d'un désasemblage différé et complet. * * * @@ -604,25 +1129,22 @@ GRenderingLine *build_binary_prologue(const char *filename, const uint8_t *data, * * ******************************************************************************/ -void ack_completed_disassembly(GDisassManager *manager, GOpenidaBinary *binary, GRenderingLine *lines, GOpenidaBinary *user) +void ack_completed_disassembly(GDelayedDisassembly *disass, GOpenidaBinary *binary) { GRenderingLine *line; /* "Première" ligne de rendu */ GPluginModule **pglist; /* Liste de greffons */ size_t pgcount; /* Taille de cette liste */ size_t i; /* Boucle de parcours */ - /* Si ce n'est pas pour nous... */ - if (binary != user) return; + binary->lines = disass->lines; - binary->lines = lines; - - line = g_rendering_line_find_by_address(lines, NULL, + line = g_rendering_line_find_by_address(disass->lines, NULL, g_exe_format_get_entry_point(binary->format)); if (line != NULL) g_rendering_line_add_flag(line, RLF_ENTRY_POINT); @@ -641,12 +1163,6 @@ void ack_completed_disassembly(GDisassManager *manager, GOpenidaBinary *binary, /* On réintègre le flot premier */ - gdk_threads_enter(); - g_signal_emit_by_name(binary, "disassembly-done"); - gdk_flush (); - - gdk_threads_leave(); - } diff --git a/src/analysis/delayed.c b/src/analysis/delayed.c deleted file mode 100644 index 0d02d39..0000000 --- a/src/analysis/delayed.c +++ /dev/null @@ -1,714 +0,0 @@ - -/* OpenIDA - Outil d'analyse de fichiers binaires - * delayed.c - gestion des actions d'analyse différées - * - * 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 "delayed.h" - - -#include "line_code.h" -#include "line_comment.h" -#include "../common/dllist.h" -#include "../format/format.h" -#include "../glibext/delayed-int.h" -#include "../gtkext/gtkextstatusbar.h" -#include "../gtkext/iodamarshal.h" - - - -#ifndef _ -# define _(str) (str) -#endif - - - - -/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ - - -/* Ensembles binaires à désassembler (instance) */ -struct _GDelayedDisassembly -{ - GDelayedWork parent; /* A laisser en premier */ - - GOpenidaBinary *binary; /* Destinataire final */ - - GBinPart **parts; /* Parties binaires à traiter */ - size_t count; /* Nombre de ces parties */ - -}; - -/* Ensembles binaires à désassembler (classe) */ -struct _GDelayedDisassemblyClass -{ - GDelayedWorkClass parent; /* A laisser en premier */ - -}; - - -/* Initialise la classe des tâches de désassemblage différé. */ -static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *); - -/* Initialise une tâche de désassemblage différé. */ -static void g_delayed_disassembly_init(GDelayedDisassembly *); - - - -/* ------------------------- GESTION DES ANALYSES DIFFEREES ------------------------- */ - - -/* Gestionnaire des analyses différées (instance) */ -struct _GDisassManager -{ - GWorkQueue parent; /* A laisser en premier */ - - GtkExtStatusBar *statusbar; /* Barre de statut principale */ - -}; - -/* Gestionnaire des analyses différées (classe) */ -struct _GDisassManagerClass -{ - GWorkQueueClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* disassembly_completed) (GDisassManager *, GOpenidaBinary *, GRenderingLine *); - -}; - - -/* Initialise la classe des gestionnaires d'analyses différées. */ -static void g_disassembly_manager_class_init(GDisassManagerClass *); - -/* Initialise un gestionnaire d'analyses différées. */ -static void g_disassembly_manager_init(GDisassManager *); - -/* Crée un gestionnaire d'analyses différées. */ -static GDisassManager *g_disassembly_manager_new(GObject *); - -/* Assure le désassemblage en différé. */ -static void process_disassemblies(GDisassManager *, GDelayedDisassembly *); - -/* Procède au désassemblage basique d'un contenu binaire. */ -static GRenderingLine *disassemble_binary_parts(GDelayedDisassembly *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); - -/* Etablit les liens entres les différentes lignes de code. */ -static void establish_links_between_lines(GRenderingLine *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); - -/* S'assure que toutes les routines ont une taille définie. */ -static void limit_all_routines(GRenderingLine *, GBinRoutine **, size_t, GtkExtStatusBar *, guint); - -/* Cherche l'adresse de fin d'une routine. */ -static vmpa_t find_best_ending_address_for_routine(GRenderingLine *, size_t, const vmpa_t *, const off_t *, size_t); - - - -/* ---------------------------------------------------------------------------------- */ -/* DESASSEMBLAGE DE BINAIRE DIFFERE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les tâches de désassemblage différé. */ -G_DEFINE_TYPE(GDelayedDisassembly, g_delayed_disassembly, G_TYPE_DELAYED_WORK); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des tâches de désassemblage différé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *klass) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : disass = instance à initialiser. * -* * -* Description : Initialise une tâche de désassemblage différé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_delayed_disassembly_init(GDelayedDisassembly *disass) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : binary = binaire chargé en attente des résultats. * -* parts = parties binaires à désassembler. * -* count = nombre de parties à traiter. * -* * -* Description : Crée une tâche de désassemblage différé. * -* * -* Retour : Tâche créée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GDelayedDisassembly *g_delayed_disassembly_new(GOpenidaBinary *binary, GBinPart **parts, size_t count) -{ - GDelayedDisassembly *result; /* Tâche à retourner */ - - result = g_object_new(G_TYPE_DELAYED_DISASSEMBLY, NULL); - - result->binary = binary; - - result->parts = parts; - result->count = count; - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* GESTION DES ANALYSES DIFFEREES */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour le gestionnaire des analyses différées. */ -G_DEFINE_TYPE(GDisassManager, g_disassembly_manager, G_TYPE_WORK_QUEUE); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des gestionnaires d'analyses différées. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_disassembly_manager_class_init(GDisassManagerClass *klass) -{ - g_signal_new("disassembly-completed", - G_TYPE_DISASS_MANAGER, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GDisassManagerClass, disassembly_completed), - NULL, NULL, - g_cclosure_user_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, G_TYPE_OPENIDA_BINARY, G_TYPE_RENDERING_LINE); - -} - - -/****************************************************************************** -* * -* Paramètres : manager = instance à initialiser. * -* * -* Description : Initialise un gestionnaire d'analyses différées. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_disassembly_manager_init(GDisassManager *manager) -{ - GWorkQueue *parent; /* Instance parente */ - - parent = G_WORK_QUEUE(manager); - - parent->process = (process_work_fc)process_disassemblies; - -} - - -/****************************************************************************** -* * -* Paramètres : ref = espace de référencements global. * -* * -* Description : Crée un gestionnaire d'analyses différées. * -* * -* Retour : Gestionnaire mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GDisassManager *g_disassembly_manager_new(GObject *ref) -{ - GDisassManager *result; /* Adresse à retourner */ - - result = g_object_new(G_TYPE_DISASS_MANAGER, NULL); - - result->statusbar = g_object_get_data(ref, "statusbar"); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : manager = gestionnaire des actions à mener. * -* disass = analyse à mener. * -* * -* Description : Assure le désassemblage en différé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void process_disassemblies(GDisassManager *manager, GDelayedDisassembly *disass) -{ - GBinRoutine **routines; /* Liste des routines trouvées */ - size_t routines_count; /* Nombre de ces routines */ - guint id; /* Identifiant de statut */ - GRenderingLine *lines; /* Nouvelles lignes de rendu */ - - routines = g_binary_format_get_routines(G_BIN_FORMAT(g_openida_binary_get_format(disass->binary)), &routines_count); - qsort(routines, routines_count, sizeof(GBinRoutine *), g_binary_routine_rcompare); - - /* Première étape */ - - id = gtk_extended_status_bar_push(manager->statusbar, _("Disassembling..."), true); - - lines = disassemble_binary_parts(disass, routines, routines_count, manager->statusbar, id); - - gtk_extended_status_bar_remove(manager->statusbar, id); - - /* Seconde étape */ - - id = gtk_extended_status_bar_push(manager->statusbar, _("Establishing links..."), true); - - establish_links_between_lines(lines, routines, routines_count, manager->statusbar, id); - - gtk_extended_status_bar_remove(manager->statusbar, id); - - /* Troisième étape */ - - id = gtk_extended_status_bar_push(manager->statusbar, _("Finding remaining limits..."), true); - - limit_all_routines(lines, routines, routines_count, manager->statusbar, id); - - gtk_extended_status_bar_remove(manager->statusbar, id); - - /* Fin */ - - g_signal_emit_by_name(manager, "disassembly-completed", disass->binary, lines); - -} - - -/****************************************************************************** -* * -* Paramètres : disass = tâche à l'origine du traitement. * -* routines = prototypes existants à insérer. * -* count = quantité de ces prototypes. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Procède au désassemblage basique d'un contenu binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GRenderingLine *disassemble_binary_parts(GDelayedDisassembly *disass, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) -{ - GRenderingLine *result; /* Ligne de rendu à retourner */ - GArchProcessor *proc; /* Architecture du binaire */ - GRenderingOptions *options; /* Options de désassemblage */ - bin_t *bin_data; /* Données binaires à lire */ - size_t i; /* Boucle de parcours #1 */ - off_t sum; /* Somme de toutes les tailles */ - off_t done; /* Quantité déjà traitée */ - off_t pos; /* Début d'une zone binaire */ - off_t len; /* Taille de cette même zone */ - vmpa_t base; /* Adresse de la zone binaire */ - off_t start; /* Conservation du pt de départ*/ - vmpa_t addr; /* Adresse d'une instruction */ - GArchInstruction *instr; /* Instruction décodée */ - GRenderingLine *line; /* Nouvelle ligne de rendu */ - size_t k; /* Boucle de parcours #2 */ - uint64_t routine_offset; /* Point de départ de routine */ - char *routine_desc; /* Prototype d'une routine */ - - result = NULL; - - proc = get_arch_processor_from_format(g_openida_binary_get_format(disass->binary)); - options = g_openida_binary_get_options(disass->binary); - bin_data = g_openida_binary_get_data(disass->binary, NULL); - - /* Préparation du suivi de la progression */ - - sum = 0; - - for (i = 0; i < disass->count; i++) - { - g_binary_part_get_values(disass->parts[i], NULL, &len, NULL); - sum += len; - } - - done = 0; - - for (i = 0; i < disass->count; i++) - { - g_binary_part_get_values(disass->parts[i], &pos, &len, &base); - - /* Décodage des instructions */ - - start = pos; - pos = 0; - - while (pos < len) - { - addr = base + pos; - - instr = g_arch_processor_decode_instruction(proc, &bin_data[start], - &pos, len, start, addr); - - line = g_code_line_new(addr, instr, options); - g_rendering_line_add_to_lines(&result, line); - - if (pos < len) - gtk_extended_status_bar_update_activity(statusbar, id, (done + pos) * 1.0 / sum); - - } - - done += len; - gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); - - /* Ajout des prototypes de fonctions */ - - for (k = 0; k < count; k++) - { - routine_offset = g_binary_routine_get_address(routines[k]); - - if (!(base <= routine_offset && routine_offset < (base + len))) continue; - - routine_desc = g_binary_routine_to_string(routines[k]); - - line = g_comment_line_new(routine_offset, routine_desc, options); - g_rendering_line_insert_into_lines(&result, line, true); - - free(routine_desc); - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : lines = lignes de rendu à relier. * -* routines = prototypes existants à insérer. * -* count = quantité de ces prototypes. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Etablit les liens entres les différentes lignes de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void establish_links_between_lines(GRenderingLine *lines, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) -{ - size_t i; /* Boucle de parcours */ - vmpa_t start; /* Adresse de départ */ - vmpa_t end; /* Adresse de fin */ - GRenderingLine *iter; /* Boucle de parcours */ - GArchInstruction *instr; /* Instruction à ausculter */ - vmpa_t addr; /* Adresse référencée */ - InstructionLinkType type; /* Type de référence */ - GRenderingLine *target; /* Ligne visée par la référence*/ - - for (i = 0; i < count; i++) - { - start = g_binary_routine_get_address(routines[i]); - end = start + g_binary_routine_get_size(routines[i]); - - for (iter = g_rendering_line_find_by_address(lines, NULL, start); - iter != NULL; - iter = g_rendering_line_get_next_iter(lines, iter, NULL)) - { - /* Si on sort de la zone... */ - if (get_rendering_line_address(iter) >= end) break; - - /* On ne traite que du code ici ! */ - if (!G_IS_CODE_LINE(iter)) continue; - - instr = g_code_line_get_instruction(G_CODE_LINE(iter)); - type = g_arch_instruction_get_link(instr, &addr); - - switch (type) - { - case ILT_NONE: - break; - - case ILT_JUMP: - - target = g_rendering_line_find_by_address(lines, NULL, addr); - - if (target != NULL) - g_rendering_line_link_with(iter, target, type); - - break; - - case ILT_JUMP_IF_FALSE: - break; - - case ILT_JUMP_IF_TRUE: - - target = g_rendering_line_find_by_address(lines, NULL, addr); - - if (target != NULL) - { - g_rendering_line_link_with(iter, target, type); - - target = g_rendering_line_get_next_iter(lines, iter, NULL); - if (target != NULL) - g_rendering_line_link_with(iter, target, ILT_JUMP_IF_FALSE); - - } - - break; - - case ILT_CALL: - - target = g_rendering_line_find_by_address(lines, NULL, addr); - - if (target != NULL) - g_rendering_line_link_with(iter, target, type); - - break; - - } - - } - - gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : lines = lignes de rendu à parcourir. * -* routines = prototypes existants à insérer. * -* count = quantité de ces prototypes. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : S'assure que toutes les routines ont une taille définie. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void limit_all_routines(GRenderingLine *lines, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, guint id) -{ - size_t i; /* Boucle de parcours */ - vmpa_t *starts; /* Adresses de départ */ - off_t *lengths; /* Tailles des routines */ - GRenderingLine *line; /* Ligne de départ / d'arrivée */ - vmpa_t start; /* Adresse de début de routine */ - vmpa_t last; /* Meilleur dernière adresse */ - GArchInstruction *instr; /* Instruction à ausculter */ - off_t length; /* Taille du code */ - - if (count == 0) return; - - starts = (vmpa_t *)calloc(count, sizeof(vmpa_t)); - lengths = (off_t *)calloc(count, sizeof(off_t)); - - for (i = 0; i < count; i++) - { - starts[i] = g_binary_routine_get_address(routines[i]); - lengths[i] = g_binary_routine_get_size(routines[i]); - - gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / (count * 2)); - - } - - for (i = 0; i < count; i++) - { - if (lengths[i] > 0) continue; - - start = g_binary_routine_get_address(routines[i]); - line = g_rendering_line_find_by_address(lines, NULL, start); - - last = find_best_ending_address_for_routine(line, i, starts, lengths, count); - - line = g_rendering_line_find_by_address(lines, NULL, last); - line = g_rendering_line_loop_for_code(line, NULL); - - instr = g_code_line_get_instruction(G_CODE_LINE(line)); - g_arch_instruction_get_location(instr, NULL, &length, NULL); - - lengths[i] = last - start + length; - g_binary_routine_set_size(routines[i], lengths[i]); - - gtk_extended_status_bar_update_activity(statusbar, id, (i + 1 + count) * 1.0 / (count * 2)); - - } - - free(starts); - free(lengths); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne de départ du parcours. * -* index = indice de la routine traitée dans la liste. * -* starts = adresse de départ des autres routines. * -* lengths = taille des différentes routines, valides ou nulles.* -* count = quantité de routines présentes. * -* * -* Description : Cherche l'adresse de fin d'une routine. * -* * -* Retour : Plus grande adresse de dernière instruction de routine. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static vmpa_t find_best_ending_address_for_routine(GRenderingLine *line, size_t index, const vmpa_t *starts, const off_t *lengths, size_t count) -{ - vmpa_t result; /* Haute adresse à remonter */ - GRenderingLine *iter; /* Boucle de parcours #1 */ - vmpa_t candidate; /* Candidat potentiel */ - size_t i; /* Boucle de parcours #2 */ - GArchInstruction *instr; /* Instruction à ausculter */ - - result = starts[index]; - - for (iter = line; iter != NULL; iter = g_rendering_line_get_next_iter(line, iter, NULL)) - { - if (!G_IS_CODE_LINE(iter)) continue; - - candidate = get_rendering_line_address(iter); - - /* Regarde si on n'empiète pas sur une autre routine */ - - for (i = 0; i < count; i++) - { - if (i == index) continue; - - if (starts[i] <= candidate && candidate < (starts[i] + lengths[i])) - break; - - } - - if (i != count) break; - else result = candidate; - - /* Retour de fonction ? */ - - instr = g_code_line_get_instruction(G_CODE_LINE(iter)); - if (g_arch_instruction_is_return(instr)) break; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : manager = nouveau gestionnaire à mémoriser ou NULL. * -* * -* Description : Fournit le gestionnaire d'analyse en différé courant. * -* * -* Retour : Gestionnaire d'analyse en différé courant. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GDisassManager *_get_disassembly_manager(GDisassManager *manager) -{ - static GDisassManager *result = NULL; /* Singleton à retourner */ - - if (manager != NULL) - result = manager; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : ref = espace de référencements global. * -* * -* Description : Procède au chargement du gestionnaire d'analyse différées. * -* * -* Retour : true pour indiquer un chargement réussi, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool init_disassembly_manager(GObject *ref) -{ - GDisassManager *manager; /* Singleton à mettre en place */ - - manager = g_disassembly_manager_new(ref); - - if (manager != NULL) - _get_disassembly_manager(manager); - - return (manager != NULL); - -} diff --git a/src/analysis/delayed.h b/src/analysis/delayed.h deleted file mode 100644 index c543f0b..0000000 --- a/src/analysis/delayed.h +++ /dev/null @@ -1,97 +0,0 @@ - -/* OpenIDA - Outil d'analyse de fichiers binaires - * delayed.h - prototypes pour la gestion des actions d'analyse différées - * - * 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 . - */ - - -#ifndef _ANALYSIS_DELAYED_H -#define _ANALYSIS_DELAYED_H - - -#include -#include - - -#include "binary.h" - - -#include "../format/exe_format.h" /* TODO : Voir pour n'include que GBinPart */ - - - -/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ - - -#define G_TYPE_DELAYED_DISASSEMBLY g_delayed_disassembly_get_type() -#define G_DELAYED_DISASSEMBLY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_disassembly_get_type(), GDelayedDisassembly)) -#define G_IS_DELAYED_DISASSEMBLY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_disassembly_get_type())) -#define G_DELAYED_DISASSEMBLY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_DISASSEMBLY, GDelayedDisassemblyClass)) -#define G_IS_DELAYED_DISASSEMBLY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_DISASSEMBLY)) -#define G_DELAYED_DISASSEMBLY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_DISASSEMBLY, GDelayedDisassemblyClass)) - - -/* Ensembles binaires à désassembler (instance) */ -typedef struct _GDelayedDisassembly GDelayedDisassembly; - -/* Ensembles binaires à désassembler (classe) */ -typedef struct _GDelayedDisassemblyClass GDelayedDisassemblyClass; - - - -/* Indique le type défini pour les tâches de désassemblage différé. */ -GType g_delayed_disassembly_get_type(void); - -/* Crée une tâche de désassemblage différé. */ -GDelayedDisassembly *g_delayed_disassembly_new(GOpenidaBinary *, GBinPart **, size_t); - - - -/* ------------------------- GESTION DES ANALYSES DIFFEREES ------------------------- */ - - -#define G_TYPE_DISASS_MANAGER g_disassembly_manager_get_type() -#define G_DISASS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_disassembly_manager_get_type(), GDisassManager)) -#define G_IS_DISASS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_disassembly_manager_get_type())) -#define G_DISASS_MANAGER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_disassembly_manager_get_type(), GDisassManagerIface)) -#define G_DISASS_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DISASS_MANAGER, GDisassManagerClass)) - - -/* Gestionnaire des analyses différées (instance) */ -typedef struct _GDisassManager GDisassManager; - -/* Gestionnaire des analyses différées (classe) */ -typedef struct _GDisassManagerClass GDisassManagerClass; - - -#define get_disassembly_manager() _get_disassembly_manager(NULL) - - -/* Indique le type défini pour le gestionnaire des analyses différées. */ -GType g_disassembly_manager_get_type(void); - -/* Fournit le gestionnaire d'analyse en différé courant. */ -GDisassManager *_get_disassembly_manager(GDisassManager *); - -/* Procède au chargement du gestionnaire d'analyse différées. */ -bool init_disassembly_manager(GObject *); - - - -#endif /* _ANALYSIS_DELAYED_H */ diff --git a/src/analysis/line-int.h b/src/analysis/line-int.h index bc7d848..a78d8b2 100644 --- a/src/analysis/line-int.h +++ b/src/analysis/line-int.h @@ -55,6 +55,7 @@ struct _GRenderingLine }; +#define lines_list_last(head) dl_list_last(head, GRenderingLine, link) #define lines_list_next_iter(iter, head) dl_list_next_iter(iter, head, GRenderingLine, link) #define lines_list_add_tail(new, head) dl_list_add_tail(new, head, GRenderingLine, link) #define lines_list_splice_before(pos, head1, head2) dl_list_splice_before(pos, head1, head2, GRenderingLine, link) diff --git a/src/analysis/line.c b/src/analysis/line.c index a810b1f..507597c 100644 --- a/src/analysis/line.c +++ b/src/analysis/line.c @@ -131,6 +131,25 @@ vmpa_t get_rendering_line_address(const GRenderingLine *line) * * * Paramètres : line = ligne dont les informations sont à consulter. * * * +* Description : Fournit la longueur du code représenté par une ligne. * +* * +* Retour : Taille du code représenté (0 si aucun). * +* * +* Remarques : - * +* * +******************************************************************************/ + +off_t get_rendering_line_length(const GRenderingLine *line) +{ + return line->length; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne dont les informations sont à consulter. * +* * * Description : Fournit le type d'une ligne. * * * * Retour : Type de la ligne fournie. * @@ -443,6 +462,26 @@ GRenderingLine *g_rendering_line_get_next_iter(GRenderingLine *lines, const GRen /****************************************************************************** * * +* Paramètres : lines = liste de lignes de représentation à actualiser. * +* last = dernière élément imposé du parcours ou NULL. * +* * +* Description : Fournit le dernier élément d'une liste de lignes. * +* * +* Retour : Dernier élément de la liste. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRenderingLine *g_rendering_line_get_last_iter(GRenderingLine *lines, GRenderingLine *last) +{ + return (last != NULL ? last : lines_list_last(lines)); + +} + + +/****************************************************************************** +* * * Paramètres : lines = liste de lignes à parcourir. * * last = dernière élément imposé du parcours ou NULL. * * addr = position en mémoire ou physique à chercher. * diff --git a/src/analysis/line.h b/src/analysis/line.h index 7455371..20d6234 100644 --- a/src/analysis/line.h +++ b/src/analysis/line.h @@ -75,6 +75,9 @@ GType g_rendering_line_get_type(void); /* Fournit l'adresse physique ou en mémoire d'une ligne. */ vmpa_t get_rendering_line_address(const GRenderingLine *); +/* Fournit la longueur du code représenté par une ligne. */ +off_t get_rendering_line_length(const GRenderingLine *); + /* Fournit le type d'une ligne. */ RenderingLineType get_rendering_line_type(const GRenderingLine *); @@ -116,6 +119,9 @@ void g_rendering_line_insert_into_lines(GRenderingLine **, GRenderingLine *, boo /* Fournit l'élement suivant un autre pour un parcours. */ GRenderingLine *g_rendering_line_get_next_iter(GRenderingLine *, const GRenderingLine *, const GRenderingLine *); +/* Fournit le dernier élément d'une liste de lignes. */ +GRenderingLine *g_rendering_line_get_last_iter(GRenderingLine *, GRenderingLine *); + /* Recherche une ligne d'après sa position en mémoire/physique. */ GRenderingLine *g_rendering_line_find_by_address(GRenderingLine *, const GRenderingLine *, vmpa_t); diff --git a/src/glibext/delayed-int.h b/src/glibext/delayed-int.h index 7fb8f3a..b2e2b23 100644 --- a/src/glibext/delayed-int.h +++ b/src/glibext/delayed-int.h @@ -25,12 +25,17 @@ #include "../common/dllist.h" +#include "../gtkext/gtkextstatusbar.h" /* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ +/* Traite un travail programmé. */ +typedef void (* run_task_fc) (GDelayedWork *, GtkExtStatusBar *); + + /* Travail différé (instance) */ struct _GDelayedWork { @@ -38,6 +43,8 @@ struct _GDelayedWork DL_LIST_ITEM(link); /* Lien vers les maillons */ + run_task_fc run; /* Traitement externalisé */ + }; /* Travail différé (classe) */ @@ -45,38 +52,12 @@ struct _GDelayedWorkClass { GObjectClass parent; /* A laisser en premier */ -}; - - -#define delayed_work_list_add_tail(new, head) dl_list_add_tail(new, head, GDelayedWork, link) -#define delayed_work_list_del(item, head) dl_list_del(item, head, GDelayedWork, link) - - - -/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ - + /* Signaux */ -/* Effectue le traitement d'une tâche donnée. */ -typedef void (* process_work_fc) (GWorkQueue *, GDelayedWork *); - - -/* Gestionnaire des travaux différés (instance) */ -struct _GWorkQueue -{ - GObject parent; /* A laisser en premier */ - - GDelayedWork *works; /* Tâches à mener à bien */ - GMutex *mutex; /* Verrou pour l'accès */ - GCond *cond; /* Réveil pour un traitement */ - - GThread *thread; /* Procédure de traitement */ - process_work_fc process; /* Coeur du traitement */ + void (* work_completed) (GDelayedWork *); }; -/* Gestionnaire des travaux différés (classe) */ -struct _GWorkQueueClass -{ - GObjectClass parent; /* A laisser en premier */ -}; +#define delayed_work_list_add_tail(new, head) dl_list_add_tail(new, head, GDelayedWork, link) +#define delayed_work_list_del(item, head) dl_list_del(item, head, GDelayedWork, link) diff --git a/src/glibext/delayed.c b/src/glibext/delayed.c index 4388b2c..8f23538 100644 --- a/src/glibext/delayed.c +++ b/src/glibext/delayed.c @@ -24,6 +24,9 @@ #include "delayed.h" +#include + + #include "delayed-int.h" @@ -37,20 +40,96 @@ static void g_delayed_work_class_init(GDelayedWorkClass *); /* Initialise une instance de travail différé. */ static void g_delayed_work_init(GDelayedWork *); +/* Mène l'opération programmée. */ +static void g_delayed_work_process(GDelayedWork *, GtkExtStatusBar *); + + + +/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */ + + +#define G_TYPE_TYPED_QUEUE g_typed_queue_get_type() +#define G_TYPED_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_typed_queue_get_type(), GTypedQueue)) +#define G_IS_TYPED_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_typed_queue_get_type())) +#define G_TYPED_QUEUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TYPED_QUEUE, GTypedQueueClass)) +#define G_IS_TYPED_QUEUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TYPED_QUEUE)) +#define G_TYPED_QUEUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TYPED_QUEUE, GTypedQueueClass)) + + +/* File de traitement pour un type donné (instance) */ +typedef struct _GTypedQueue +{ + GObject parent; /* A laisser en premier */ + + GType type; /* Type de travaux menés */ + + GtkExtStatusBar *statusbar; /* Barre de statut principale */ + + GDelayedWork *works; /* Tâches à mener à bien */ + GMutex *mutex; /* Verrou pour l'accès */ + GCond *cond; /* Réveil pour un traitement */ + + GThread *thread; /* Procédure de traitement */ + +} GTypedQueue; + +/* File de traitement pour un type donné (classe) */ +typedef struct _GTypedQueueClass +{ + GObjectClass parent; /* A laisser en premier */ + +} GTypedQueueClass; + + +/* Indique le type défini pour les travaux typés. */ +static GType g_typed_queue_get_type(void); + +/* Initialise la classe des travaux typés. */ +static void g_typed_queue_class_init(GTypedQueueClass *); + +/* Initialise une instance de gestionnaire de travaux typés. */ +static void g_typed_queue_init(GTypedQueue *); + +/* Crée un nouveau thread dédié à un type de travaux donné. */ +static GTypedQueue *g_typed_queue_new(GType, GtkExtStatusBar *); + +/* Place une nouvelle tâche en attente dans une file dédiée. */ +static void g_typed_queue_schedule(GTypedQueue *, GDelayedWork *); + +/* Assure le traitement en différé. */ +static void *g_typed_queue_process(GTypedQueue *); + /* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ +/* Gestionnaire des travaux différés (instance) */ +struct _GWorkQueue +{ + GObject parent; /* A laisser en premier */ + + GtkExtStatusBar *statusbar; /* Barre de statut principale */ + + GTypedQueue **threads; /* Files de traitement */ + size_t threads_count; /* Nombre de files internes */ + +}; + +/* Gestionnaire des travaux différés (classe) */ +struct _GWorkQueueClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + /* Initialise la classe des travaux différés. */ static void g_work_queue_class_init(GWorkQueueClass *); /* Initialise une instance de gestionnaire de travaux différés. */ static void g_work_queue_init(GWorkQueue *); -/* Assure le traitement en différé. */ -static void *g_work_queue_process(GWorkQueue *); - /* ---------------------------------------------------------------------------------- */ @@ -76,6 +155,13 @@ G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT); static void g_delayed_work_class_init(GDelayedWorkClass *klass) { + g_signal_new("work-completed", + G_TYPE_DELAYED_WORK, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GDelayedWorkClass, work_completed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } @@ -98,21 +184,43 @@ static void g_delayed_work_init(GDelayedWork *work) } +/****************************************************************************** +* * +* Paramètres : work = travail à effectuer. * +* statusbar = barre de statut à tenir informée. * +* * +* Description : Mène l'opération programmée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_work_process(GDelayedWork *work, GtkExtStatusBar *statusbar) +{ + work->run(work, statusbar); + + g_signal_emit_by_name(work, "work-completed"); + +} + + /* ---------------------------------------------------------------------------------- */ -/* TRAITEMENT DE TACHES DIFFEREES */ +/* THREAD DE TRAITEMENTS DEDIES */ /* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour le gestionnaire des travaux différés. */ -G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); +/* Indique le type défini pour les travaux typés. */ +G_DEFINE_TYPE(GTypedQueue, g_typed_queue, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des travaux différés. * +* Description : Initialise la classe des travaux typés. * * * * Retour : - * * * @@ -120,7 +228,7 @@ G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_work_queue_class_init(GWorkQueueClass *klass) +static void g_typed_queue_class_init(GTypedQueueClass *klass) { } @@ -130,7 +238,7 @@ static void g_work_queue_class_init(GWorkQueueClass *klass) * * * Paramètres : queue = instance à initialiser. * * * -* Description : Initialise une instance de gestionnaire de travaux différés. * +* Description : Initialise une instance de gestionnaire de travaux typés. * * * * Retour : - * * * @@ -138,23 +246,23 @@ static void g_work_queue_class_init(GWorkQueueClass *klass) * * ******************************************************************************/ -static void g_work_queue_init(GWorkQueue *queue) +static void g_typed_queue_init(GTypedQueue *queue) { GError *error; /* Bilan de création de thread */ queue->mutex = g_mutex_new(); if (queue->mutex == NULL) - goto gwqi_error; + goto gtqi_error; queue->cond = g_cond_new(); if (queue->cond == NULL) - goto gwqi_error; + goto gtqi_error; - queue->thread = g_thread_create((GThreadFunc)g_work_queue_process, queue, FALSE, &error); + queue->thread = g_thread_create((GThreadFunc)g_typed_queue_process, queue, FALSE, &error); if (!queue->thread) - goto gwqi_error; + goto gtqi_error; - gwqi_error: + gtqi_error: /* TODO */ return; @@ -163,6 +271,59 @@ static void g_work_queue_init(GWorkQueue *queue) /****************************************************************************** * * +* Paramètres : type = type dont seront marqués tous les travaux donnés.* +* statusbar = barre de statut à tenir informée. * +* * +* Description : Crée un nouveau thread dédié à un type de travaux donné. * +* * +* Retour : Structure associée au thread mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GTypedQueue *g_typed_queue_new(GType type, GtkExtStatusBar *statusbar) +{ + GTypedQueue *result; /* Traiteur à retourner */ + + result = g_object_new(G_TYPE_TYPED_QUEUE, NULL); + + result->type = type; + result->statusbar = statusbar; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : queue = gestionnaire des actions à mener. * +* work = nouvelle tâche à programmer, puis effectuer. * +* * +* Description : Place une nouvelle tâche en attente dans une file dédiée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_typed_queue_schedule(GTypedQueue *queue, GDelayedWork *work) +{ + g_mutex_lock(queue->mutex); + + delayed_work_list_add_tail(work, &queue->works); + + g_cond_signal(queue->cond); + + g_mutex_unlock(queue->mutex); + +} + + +/****************************************************************************** +* * * Paramètres : queue = gestionnaire des actions à mener. * * * * Description : Assure le traitement en différé. * @@ -173,7 +334,7 @@ static void g_work_queue_init(GWorkQueue *queue) * * ******************************************************************************/ -static void *g_work_queue_process(GWorkQueue *queue) +static void *g_typed_queue_process(GTypedQueue *queue) { GDelayedWork *work; /* Traitement à mener */ @@ -189,7 +350,7 @@ static void *g_work_queue_process(GWorkQueue *queue) g_mutex_unlock(queue->mutex); - queue->process(queue, work); + g_delayed_work_process(work, queue->statusbar); /* TODO : delete work */ @@ -200,10 +361,108 @@ static void *g_work_queue_process(GWorkQueue *queue) } + +/* ---------------------------------------------------------------------------------- */ +/* TRAITEMENT DE TACHES DIFFEREES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour le gestionnaire des travaux différés. */ +G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des travaux différés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_work_queue_class_init(GWorkQueueClass *klass) +{ + +} + + /****************************************************************************** * * -* Paramètres : queu = gestionnaire des actions à mener. * -* work = nouvelle tâche à programmer, puis effectuer. * +* Paramètres : queue = instance à initialiser. * +* * +* Description : Initialise une instance de gestionnaire de travaux différés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_work_queue_init(GWorkQueue *queue) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : ref = espace de référencements global. * +* * +* Description : Procède au chargement du gestionnaire d'analyse différées. * +* * +* Retour : true pour indiquer un chargement réussi, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool init_work_queue(GObject *ref) +{ + GWorkQueue *queue; /* Singleton à mettre en place */ + + queue = g_object_new(G_TYPE_WORK_QUEUE, NULL); + + queue->statusbar = g_object_get_data(ref, "statusbar"); + + if (queue != NULL) + _get_work_queue(queue); + + return (queue != NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : queue = nouveau gestionnaire à mémoriser ou NULL. * +* * +* Description : Fournit le gestionnaire de traitements parallèles courant. * +* * +* Retour : Gestionnaire de traitements parallèles courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWorkQueue *_get_work_queue(GWorkQueue *queue) +{ + static GWorkQueue *result = NULL; /* Singleton à retourner */ + + if (queue != NULL) + result = queue; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : queue = gestionnaire des actions à mener. * +* work = nouvelle tâche à programmer, puis effectuer. * * * * Description : Place une nouvelle tâche en attente. * * * @@ -213,14 +472,26 @@ static void *g_work_queue_process(GWorkQueue *queue) * * ******************************************************************************/ -void g_delayed_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work) +void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work) { - g_mutex_lock(queue->mutex); + GType target; /* Type de travail à ajouter */ + size_t i; /* Boucle de traitement */ - delayed_work_list_add_tail(work, &queue->works); + target = G_TYPE_FROM_INSTANCE(work); - g_cond_signal(queue->cond); + for (i = 0; i < queue->threads_count; i++) + if (queue->threads[i]->type == target) break; - g_mutex_unlock(queue->mutex); + if (i == queue->threads_count) + { + queue->threads_count++; + queue->threads = (GTypedQueue **)realloc(queue->threads, + queue->threads_count * sizeof(GTypedQueue *)); + + queue->threads[i] = g_typed_queue_new(target, queue->statusbar); + + } + + g_typed_queue_schedule(queue->threads[i], work); } diff --git a/src/glibext/delayed.h b/src/glibext/delayed.h index d1e3967..501bb7f 100644 --- a/src/glibext/delayed.h +++ b/src/glibext/delayed.h @@ -26,6 +26,7 @@ #include +#include @@ -70,11 +71,20 @@ typedef struct _GWorkQueue GWorkQueue; typedef struct _GWorkQueueClass GWorkQueueClass; +#define get_work_queue() _get_work_queue(NULL) + + /* Indique le type défini pour le gestionnaire des travaux différés. */ GType g_work_queue_get_type(void); +/* Procède au chargement du gestionnaire d'analyse différées. */ +bool init_work_queue(GObject *); + +/* Fournit le gestionnaire de traitements parallèles courant. */ +GWorkQueue *_get_work_queue(GWorkQueue *); + /* Place une nouvelle tâche en attente. */ -void g_delayed_queue_schedule_work(GWorkQueue *, GDelayedWork *); +void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *); diff --git a/src/gtkext/gtkbinview-int.h b/src/gtkext/gtkbinview-int.h index 0e38c57..e785bab 100644 --- a/src/gtkext/gtkbinview-int.h +++ b/src/gtkext/gtkbinview-int.h @@ -66,6 +66,10 @@ struct _GtkBinViewClass { GtkFixedClass parent; /* A laisser en premier */ + /* Signaux */ + + void (* lines_set) (GtkBinView *); + }; diff --git a/src/gtkext/gtkbinview.c b/src/gtkext/gtkbinview.c index 696799b..147a59c 100644 --- a/src/gtkext/gtkbinview.c +++ b/src/gtkext/gtkbinview.c @@ -68,6 +68,14 @@ static void gtk_binview_class_init(GtkBinViewClass *class) widget_class->realize = gtk_bin_view_realize; widget_class->expose_event = gtk_bin_view_expose; + g_signal_new("lines-set", + GTK_TYPE_BIN_VIEW, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GtkBinViewClass, lines_set), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + } diff --git a/src/gtkext/gtkblockview.c b/src/gtkext/gtkblockview.c index 23f86ce..ac06af3 100644 --- a/src/gtkext/gtkblockview.c +++ b/src/gtkext/gtkblockview.c @@ -35,10 +35,63 @@ #include "support.h" #include "../analysis/exporter.h" #include "../common/dllist.h" +#include "../glibext/delayed-int.h" -#define MARGIN_SPACE 4 /* TODO : delete me ! */ +#ifndef _ +# define _(str) str +#endif + + + + +/* -------------------------- INSERTION DIFFEREE DE LIGNES -------------------------- */ + + +#define G_TYPE_DELAYED_INSERTION g_delayed_insertion_get_type() +#define G_DELAYED_INSERTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_insertion_get_type(), GDelayedInsertion)) +#define G_IS_DELAYED_INSERTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_insertion_get_type())) +#define G_DELAYED_INSERTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_INSERTION, GDelayedInsertionClass)) +#define G_IS_DELAYED_INSERTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_INSERTION)) +#define G_DELAYED_INSERTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_INSERTION, GDelayedInsertionClass)) + + +/* Ensembles binaires à désassembler (instance) */ +typedef struct _GDelayedInsertion +{ + GDelayedWork parent; /* A laisser en premier */ + + GtkBlockView *view; /* Visualisation à constituer */ + + size_t lengths[SAR_COUNT]; /* Différentes tailles de zone */ + +} GDelayedInsertion; + +/* Ensembles binaires à désassembler (classe) */ +typedef struct _GDelayedInsertionClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +} GDelayedInsertionClass; + + +/* Indique le type défini pour les tâches d'insertions différées. */ +static GType g_delayed_insertion_get_type(void); + +/* Initialise la classe des tâches d'insertions différées. */ +static void g_delayed_insertion_class_init(GDelayedInsertionClass *); + +/* Initialise une tâche d'insertions différées. */ +static void g_delayed_insertion_init(GDelayedInsertion *); + +/* Crée une tâche d'insertions différées. */ +static GDelayedInsertion *g_delayed_insertion_new(GtkBlockView *); + +/* Assure des insertion de lignes en différé. */ +static void g_delayed_insertion_process(GDelayedInsertion *, GtkExtStatusBar *); + + @@ -76,6 +129,8 @@ struct _GtkBlockViewClass + + static void gtk_text_view2_set_attributes_from_style (GtkTextAttributes *values, GtkStyle *style) @@ -108,6 +163,8 @@ static void gtk_block_view_realize(GtkWidget *); /* Définit les lignes du bloc de représentation. */ static void gtk_block_view_set_rendering_lines(GtkBlockView *, GRenderingLine *, GRenderingLine *); +/* Achève la construction de la visualisation des lignes. */ +static void gtk_block_view_complete_building_content(GDelayedInsertion *, GtkBlockView *); @@ -150,6 +207,171 @@ static void gtk_block_view_destroy(GtkObject *object); + + +/* ---------------------------------------------------------------------------------- */ +/* INSERTION DIFFEREE DE LIGNES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour les tâches d'insertions différées. */ +G_DEFINE_TYPE(GDelayedInsertion, g_delayed_insertion, G_TYPE_DELAYED_WORK); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches d'insertions différées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_insertion_class_init(GDelayedInsertionClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : insertion = instance à initialiser. * +* * +* Description : Initialise une tâche d'insertions différées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_insertion_init(GDelayedInsertion *insertion) +{ + G_DELAYED_WORK(insertion)->run = (run_task_fc)g_delayed_insertion_process; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation de lignes à constituer. * +* * +* Description : Crée une tâche d'insertions différées. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDelayedInsertion *g_delayed_insertion_new(GtkBlockView *view) +{ + GDelayedInsertion *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_DELAYED_INSERTION, NULL); + + result->view = view; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : insertion = insertions de lignes à mener. * +* statusbar = barre de statut à tenir informée. * +* * +* Description : Assure des insertion de lignes en différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_insertion_process(GDelayedInsertion *insertion, GtkExtStatusBar *statusbar) +{ + GtkBlockView *view; /* Visualisation à constituer */ + GRenderingLine *lines; /* Liste de lignes à intégrer */ + GRenderingLine *last; /* Dernière ligne ou NULL */ + vmpa_t start; /* Adresse de début de parcours*/ + vmpa_t end; /* Adresse de fin de parcours */ + guint id; /* Identifiant de statut */ + GRenderingLine *iter; /* Boucle de parcours */ + GtkTextIter pos; /* Point d'insertion */ + GtkTextMark *mark; /* Marquage de ligne associée */ + vmpa_t done; /* Quantité déjà parcourue */ + + view = insertion->view; + + lines = GTK_BIN_VIEW(view)->lines; + last = GTK_BIN_VIEW(view)->last; + + iter = g_rendering_line_loop_for_code(lines, last); + start = get_rendering_line_address(lines); + + iter = g_rendering_line_get_last_iter(lines, last); + end = get_rendering_line_address(iter) + get_rendering_line_length(iter) - start; + + insertion->lengths[SAR_ADDRESS] = 0; + insertion->lengths[SAR_CODE] = 0; + insertion->lengths[SAR_INSTRUCTION] = 0; + + id = gtk_extended_status_bar_push(statusbar, _("Inserting lines..."), true); + + for (iter = lines; + iter != NULL; + iter = g_rendering_line_get_next_iter(lines, iter, last)) + { + g_signal_connect(iter, "rendering-line-flags-changed", + G_CALLBACK(gtk_block_view_update_margin), view); + + gdk_threads_enter(); + + if (iter != lines) + { + gtk_text_buffer_get_end_iter(view->buffer, &pos); + gtk_text_buffer_insert_with_tags(view->buffer, &pos, "\n", 1, NULL); + } + + gtk_text_buffer_get_end_iter(view->buffer, &pos); + + mark = gtk_text_buffer_create_mark(view->buffer, NULL, &pos, TRUE); + g_object_set_data(G_OBJECT(mark), "line", iter); + + g_content_exporter_add_to_gtk_buffer(G_CONTENT_EXPORTER(iter), view->rendering, + view->buffer, &pos, insertion->lengths); + + gdk_flush (); + gdk_threads_leave(); + + done = get_rendering_line_address(iter) + get_rendering_line_length(iter) - start; + gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / end); + + } + + gtk_extended_status_bar_remove(statusbar, id); + +} + + + + + + + + + + + + + + + /* Détermine le type du composant d'affichage en block. */ G_DEFINE_TYPE(GtkBlockView, gtk_block_view, GTK_TYPE_BIN_VIEW) @@ -571,43 +793,6 @@ static gboolean gtk_block_view_expose(GtkWidget *widget, GdkEventExpose *event) /* Impression du désassemblage */ - -#if 0 - gdk_window_begin_paint_region(GDK_DRAWABLE(widget->window), event->region); - - gdk_gc_set_clip_region(bview->gc, event->region); - - gdk_gc_get_values(bview->gc, &values); - - gdk_color_white(gtk_widget_get_colormap(widget), &white); - gdk_gc_set_foreground(bview->gc, &white); - - gtk_widget_get_size_request(widget, &width, &height); - - gdk_draw_rectangle(GDK_DRAWABLE(widget->window), bview->gc, - TRUE, 0, 0, width, height); - - gdk_gc_set_foreground(bview->gc, &values.foreground); - /* - y = event->area.y; - iter = g_rendering_line_find_by_y(bview->lines, bview->last, &y); - - y = event->area.y - y; - - for ( ; iter != NULL && y < (event->area.y + event->area.height); - iter = g_rendering_line_get_next_iter(bview->lines, iter, bview->last)) - { - g_rendering_line_draw(iter, GDK_DRAWABLE(widget->window), bview->gc, - MARGIN_SPACE, 2 * MARGIN_SPACE + GTK_BLOCK_VIEW(bview)->line_height, - y, GTK_BLOCK_VIEW(bview)->line_height, GTK_BLOCK_VIEW(bview)->rendering); - - y += GTK_BLOCK_VIEW(bview)->line_height; - - } - */ - gdk_window_end_paint(GDK_DRAWABLE(widget->window)); -#endif - gtk_text_layout_set_screen_width (GTK_BLOCK_VIEW(bview)->layout, MAX (1, 1000)); @@ -730,40 +915,48 @@ void gtk_block_view_set_format(GtkBlockView *view, const exe_format *format) static void gtk_block_view_set_rendering_lines(GtkBlockView *view, GRenderingLine *lines, GRenderingLine *last) { - size_t lengths[SAR_COUNT]; /* Différentes tailles de zone */ - GRenderingLine *iter; /* Boucle de parcours */ - GtkTextIter pos; /* Point d'insertion */ - GtkTextMark *mark; /* Marquage de ligne associée */ - PangoTabArray *tabs; /* Tailles de tabulation */ - GdkRectangle rect; /* Zone d'un point */ + GWorkQueue *queue; /* Gestionnaire de différés */ + GDelayedInsertion *insertion; /* Insertions à mener */ - lengths[SAR_ADDRESS] = 0; - lengths[SAR_CODE] = 0; - lengths[SAR_INSTRUCTION] = 0; + queue = get_work_queue(); - for (iter = GTK_BIN_VIEW(view)->lines; - iter != NULL; - iter = g_rendering_line_get_next_iter(GTK_BIN_VIEW(view)->lines, iter, GTK_BIN_VIEW(view)->last)) - { - g_signal_connect(iter, "rendering-line-flags-changed", - G_CALLBACK(gtk_block_view_update_margin), view); + insertion = g_delayed_insertion_new(view); - if (iter != GTK_BIN_VIEW(view)->lines) - { - gtk_text_buffer_get_end_iter(view->buffer, &pos); - gtk_text_buffer_insert_with_tags(view->buffer, &pos, "\n", 1, NULL); - } + g_signal_connect(insertion, "work-completed", + G_CALLBACK(gtk_block_view_complete_building_content), view); - gtk_text_buffer_get_end_iter(view->buffer, &pos); + g_work_queue_schedule_work(queue, G_DELAYED_WORK(insertion)); - mark = gtk_text_buffer_create_mark(view->buffer, NULL, &pos, TRUE); - g_object_set_data(G_OBJECT(mark), "line", iter); +} - g_content_exporter_add_to_gtk_buffer(G_CONTENT_EXPORTER(iter), view->rendering, - view->buffer, &pos, lengths); - } +/****************************************************************************** +* * +* Paramètres : insertion = travail d'insertion effectué. * +* view = composant GTK à mettre à jour. * +* * +* Description : Achève la construction de la visualisation des lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_block_view_complete_building_content(GDelayedInsertion *insertion, GtkBlockView *view) +{ + size_t lengths[SAR_COUNT]; /* Différentes tailles de zone */ + GtkTextIter pos; /* Point d'insertion */ + PangoTabArray *tabs; /* Tailles de tabulation */ + GdkRectangle rect; /* Zone d'un point */ + + lengths[SAR_ADDRESS] = insertion->lengths[SAR_ADDRESS]; + lengths[SAR_CODE] = insertion->lengths[SAR_CODE]; + lengths[SAR_INSTRUCTION] = insertion->lengths[SAR_INSTRUCTION]; + gdk_threads_enter(); + + gtk_text_buffer_get_end_iter(view->buffer, &pos); gtk_text_layout_move_iter_visually(view->layout, &pos, -1); gtk_text_layout_get_iter_location(view->layout, &pos, &rect); @@ -808,6 +1001,11 @@ static void gtk_block_view_set_rendering_lines(GtkBlockView *view, GRenderingLin gtk_block_view_recompute_size_request(view); + gdk_flush (); + gdk_threads_leave(); + + g_signal_emit_by_name(view, "lines-set"); + } diff --git a/src/gtkext/gtkgraphview.c b/src/gtkext/gtkgraphview.c index cc2d930..d62cc33 100644 --- a/src/gtkext/gtkgraphview.c +++ b/src/gtkext/gtkgraphview.c @@ -45,6 +45,10 @@ struct _GtkGraphView GtkBinView **childs; /* Liste des sous-blocs */ size_t childs_count; /* Taille de cette liste */ + size_t ready; /* Construction complète */ + GMutex *mutex; /* Accès à la variable */ + GCond *cond; /* Attente de changement */ + GtkLinkRenderer **links; /* Liste des liens graphiques */ size_t links_count; /* Nombre de ces liens */ @@ -80,7 +84,10 @@ static void gtk_graph_view_define_main_address(GtkGraphView *, vmpa_t); 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 *); +static GtkBinView **gtk_graph_view_load_nodes(GtkGraphView *, GOpenidaBinary *, GRenderingLine *, GRenderingLine *); + +/* Prend note de la fin d'une construction d'une visualisation. */ +static void notify_graph_view(GtkBinView *, GtkGraphView *); /* Détermine le type du composant d'affichage en graphique. */ @@ -132,6 +139,9 @@ static void gtk_graph_view_init(GtkGraphView *view) 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; + view->mutex = g_mutex_new(); + view->cond = g_cond_new(); + } @@ -255,6 +265,8 @@ static void gtk_graph_view_set_rendering_lines(GtkGraphView *view, GRenderingLin { gtk_graph_view_reset(view); + g_signal_emit_by_name(view, "lines-set"); + } @@ -308,7 +320,7 @@ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr) 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); + view->childs = gtk_graph_view_load_nodes(view, GTK_BIN_VIEW(view)->binary, first, last); build_graph_view(GTK_FIXED(view), view->childs, view->childs_count); @@ -363,10 +375,10 @@ static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *view, vmp /****************************************************************************** * * -* Paramètres : binary = contenu binaire à l'origine des lignes. * +* Paramètres : view = composant d'affichage GTK à mettre à jour. * +* 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. * * * @@ -376,16 +388,28 @@ static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *view, vmp * * ******************************************************************************/ -static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRenderingLine *first, GRenderingLine *last, size_t *count) +static GtkBinView **gtk_graph_view_load_nodes(GtkGraphView *view, GOpenidaBinary *binary, GRenderingLine *first, GRenderingLine *last) { GtkBinView **result; /* Liste à retourner */ + size_t *count; /* Nombre d'éléments créés. */ GRenderingLine *begin; /* Début d'un groupe de lignes */ GRenderingLine *end; /* Fin d'un groupe de lignes */ GRenderingLine *iter; /* Boucle de parcours */ result = NULL; + + view->ready = 0; + + count = &view->childs_count; *count = 0; + /** + * Comme la fonction est appelée depuis un événement et utilise des threads et GTK, + * on doit lever temporairement le verrou GDK. + */ + gdk_flush (); + gdk_threads_leave(); + begin = NULL; for (iter = first; iter != NULL; iter = g_rendering_line_get_next_iter(first, iter, last)) @@ -395,7 +419,8 @@ static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRendering 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])); + + g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); @@ -412,7 +437,8 @@ static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRendering 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])); + + g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); @@ -428,13 +454,22 @@ static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRendering 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])); + + g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); } + /* Attente de la fin de construction */ + g_mutex_lock(view->mutex); + while (view->ready < *count) + g_cond_wait(view->cond, view->mutex); + g_mutex_unlock(view->mutex); + + gdk_threads_enter(); + return result; @@ -443,6 +478,35 @@ static GtkBinView **gtk_graph_view_load_nodes(GOpenidaBinary *binary, GRendering /****************************************************************************** * * +* Paramètres : view = composant d'affichage prêt à utilisation. * +* parent = composant d'affichage supérieur. * +* * +* Description : Prend note de la fin d'une construction d'une visualisation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void notify_graph_view(GtkBinView *view, GtkGraphView *parent) +{ + g_mutex_lock(parent->mutex); + + parent->ready++; + + g_cond_signal(parent->cond); + g_mutex_unlock(parent->mutex); + + g_signal_handlers_disconnect_by_func(view, G_CALLBACK(notify_graph_view), parent); + + gtk_widget_show(GTK_WIDGET(view)); + +} + + +/****************************************************************************** +* * * Paramètres : view = composant GTK à mettre à jour. * * links = liens graphiques entre les blocs à intégrer. * * count = quantité de ces liens graphiques. * diff --git a/src/main.c b/src/main.c index 41ea7ce..a3fa5ae 100644 --- a/src/main.c +++ b/src/main.c @@ -31,11 +31,11 @@ #include "editor.h" #include "params.h" #include "project.h" -#include "analysis/delayed.h" #include "analysis/exporter.h" #include "arch/processor.h" #include "format/format.h" #include "format/mangling/demangler.h" +#include "glibext/delayed.h" #include "gtkext/support.h" #include "plugins/pglist.h" @@ -112,7 +112,7 @@ int main(int argc, char **argv) editor = create_editor(); gtk_widget_show(editor); - init_disassembly_manager(G_OBJECT(editor)); + init_work_queue(G_OBJECT(editor)); init_all_plugins(G_OBJECT(editor)); diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c index 6d47f57..6725fd8 100644 --- a/src/plugins/pglist.c +++ b/src/plugins/pglist.c @@ -77,7 +77,7 @@ bool init_all_plugins(GObject *ref) { _list.ref = ref; - browse_directory_for_plugins(&_list, PACKAGE_SOURCE_DIR "/plugins"); + browse_directory_for_plugins(&_list, PACKAGE_SOURCE_DIR "/plugins.disabled"); return true; diff --git a/src/project.c b/src/project.c index cf76a33..14261f3 100644 --- a/src/project.c +++ b/src/project.c @@ -44,6 +44,10 @@ typedef struct _loaded_binary { GOpenidaBinary *binary; /* Binaire en question */ + bool lines_set; /* Construction complète */ + GMutex *mutex; /* Accès à la variable */ + GCond *cond; /* Attente de changement */ + GtkWidget *views[BVW_COUNT]; /* Composants pour l'affichage */ } loaded_binary; @@ -52,6 +56,9 @@ typedef struct _loaded_binary /* Met en place un nouveau binaire pour un projet. */ loaded_binary *load_openida_binary(GOpenidaBinary *); +/* Prend note de la fin d'une construction d'une visualisation. */ +static void notify_loaded_binary(GtkBinView *, loaded_binary *); + /* Fournit un support d'affichage donné pour un binaire chargé. */ GtkWidget *get_loaded_binary_view(const loaded_binary *, BinaryView); @@ -68,6 +75,7 @@ struct openida_project loaded_binary **binaries; /* Fichiers binaires associés */ size_t binaries_count; /* Nombre de ces fichiers */ + GMutex *mutex; /* Modification de la liste */ @@ -108,8 +116,15 @@ loaded_binary *load_openida_binary(GOpenidaBinary *binary) result->binary = binary; + result->mutex = g_mutex_new(); + result->cond = g_cond_new(); + for (i = 0; i < BVW_COUNT; i++) { + /* Préparation du support */ + + gdk_threads_enter(); + scrolledwindow = qck_create_scrolled_window(NULL, NULL); switch (i) @@ -123,15 +138,37 @@ loaded_binary *load_openida_binary(GOpenidaBinary *binary) break; } + gdk_flush (); + gdk_threads_leave(); + + result->lines_set = false; + + g_signal_connect(view, "lines-set", G_CALLBACK(notify_loaded_binary), result); + gtk_bin_view_set_rendering_lines(GTK_BIN_VIEW(view), binary, g_openida_binary_get_lines(binary), NULL); + /* Attente de la fin de construction */ + g_mutex_lock(result->mutex); + while (!result->lines_set) + g_cond_wait(result->cond, result->mutex); + g_mutex_unlock(result->mutex); + + g_signal_handlers_disconnect_by_func(view, G_CALLBACK(notify_loaded_binary), result); + + /* Intégration finale */ + + gdk_threads_enter(); + gtk_widget_show(view); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow), view); result->views[i] = scrolledwindow; + gdk_flush (); + gdk_threads_leave(); + } return result; @@ -139,8 +176,29 @@ loaded_binary *load_openida_binary(GOpenidaBinary *binary) } +/****************************************************************************** +* * +* Paramètres : view = composant d'affichage prêt à utilisation. * +* binary = binaire chargé et encadré. * +* * +* Description : Prend note de la fin d'une construction d'une visualisation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void notify_loaded_binary(GtkBinView *view, loaded_binary *binary) +{ + g_mutex_lock(binary->mutex); + binary->lines_set = true; + g_cond_signal(binary->cond); + g_mutex_unlock(binary->mutex); + +} @@ -220,8 +278,16 @@ openida_project *create_empty_openida_project(GObject *ref) result->ref = ref; + result->mutex = g_mutex_new(); + if (result->mutex == NULL) + goto crop_error; + return result; + crop_error: + + return NULL; + } @@ -402,18 +468,28 @@ bool has_storing_filename(const openida_project *project) * * * Description : Attache un fichier donné à un projet donné. * * * -* Retour : - * +* Retour : Emplacement de l'élément créé. * * * * Remarques : - * * * ******************************************************************************/ -void attach_binary_to_openida_project(openida_project *project, GOpenidaBinary *binary) +size_t attach_binary_to_openida_project(openida_project *project, GOpenidaBinary *binary) { + size_t result; /* Indice à retourner */ + + g_mutex_lock(project->mutex); + project->binaries = (loaded_binary **)realloc(project->binaries, - ++project->binaries_count * sizeof(loaded_binary *)); + ++project->binaries_count * sizeof(loaded_binary *)); + + result = project->binaries_count - 1; + + g_mutex_unlock(project->mutex); - project->binaries[project->binaries_count - 1] = load_openida_binary(binary); + project->binaries[result] = load_openida_binary(binary); + + return result; } @@ -679,11 +755,7 @@ void display_new_binary_of_openida_project(GOpenidaBinary *binary, openida_proje GtkDockItem *ditem; /* Panneau avec ses infos. */ GtkBinView *binview; /* Affichage à faire défiler */ - - - - attach_binary_to_openida_project(project, binary); - index = project->binaries_count - 1; + index = attach_binary_to_openida_project(project, binary); dpanel = GTK_DOCK_PANEL(g_object_get_data(project->ref, "binpanel")); @@ -691,10 +763,13 @@ void display_new_binary_of_openida_project(GOpenidaBinary *binary, openida_proje title = g_openida_binary_to_string(binary); + gdk_threads_enter(); + ditem = gtk_dock_item_new(strrchr(title, '/') + 1, view); gtk_dock_item_set_desc(ditem, title); gtk_dock_panel_add_item(dpanel, ditem); - + gdk_flush (); + gdk_threads_leave(); } diff --git a/src/project.h b/src/project.h index 815d922..cf4c9e2 100644 --- a/src/project.h +++ b/src/project.h @@ -76,7 +76,7 @@ bool has_storing_filename(const openida_project *); /* Attache un fichier donné à un projet donné. */ -void attach_binary_to_openida_project(openida_project *, GOpenidaBinary *); +size_t attach_binary_to_openida_project(openida_project *, GOpenidaBinary *); /* Détache un fichier donné à un projet donné. */ void detach_binary_to_openida_project(openida_project *, GOpenidaBinary *); diff --git a/src/shell.c b/src/shell.c index 2d3420f..76e26bb 100644 --- a/src/shell.c +++ b/src/shell.c @@ -105,8 +105,8 @@ GtkWidget *build_shell_panel(GObject *ref) vte_terminal_set_cursor_blinks(VTE_TERMINAL(term), TRUE); -#if 0 - vte_terminal_fork_command (term, "/bin/sh", NULL, NULL, "/", 0, 0, 0); +#if 1 + //vte_terminal_fork_command (term, "/bin/sh", NULL, NULL, "/", 0, 0, 0); return result; #endif -- cgit v0.11.2-87-g4458