/* Chrysalide - Outil d'analyse de fichiers binaires * project.c - gestion d'un groupe de fichiers binaires * * Copyright (C) 2008-2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "project.h" #include #include #include #include #include #include "../common/xml.h" #include "../core/formats.h" #include "../core/params.h" #include "../glibext/signal.h" #include "../gtkext/easygtk.h" #include "../glibext/delayed-int.h" #include "../gtkext/gtkblockview.h" #include "../gtkext/gtkgraphview.h" #include "../gtkext/gtksourceview.h" #include "../gui/core/panels.h" #include "../gui/panels/log.h" #include "../gui/panels/panel.h" /* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */ /* Conservation d'un contenu chargé */ typedef struct _loaded_content { GBinContent *content; /* Contenu binaire en place */ ProjectContentState state; /* Renseigne le type de contenu*/ } loaded_content; /* Conservation d'un binaire chargé */ typedef struct _loaded_binary { GLoadedBinary *binary; /* Binaire en question */ GPanelItem **items; /* Supports d'affichage final */ size_t count; /* Nombre de ces supports */ } loaded_binary; /* Projet d'étude regroupant les binaires analysés (instance) */ struct _GStudyProject { GObject parent; /* A laisser en premier */ GObject *ref; /* Espace de référencement */ char *filename; /* Lieu d'enregistrement */ loaded_content *contents; /* Contenus binaires chargés */ size_t contents_count; /* Nombre de ces contenus */ GMutex cnt_mutex; /* Modification de la liste */ loaded_binary **binaries; /* Fichiers binaires associés */ size_t binaries_count; /* Nombre de ces fichiers */ GMutex bin_mutex; /* Modification de la liste */ }; /* Projet d'étude regroupant les binaires analysés (classe) */ struct _GStudyProjectClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des projets d'étude. */ static void g_study_project_class_init(GStudyProjectClass *); /*Initialise une instance de projet d'étude. */ static void g_study_project_init(GStudyProject *); /* Supprime de l'écran un projet en place. */ static void g_study_project_hide(const GStudyProject *); /* ----------------------- VUES ET BASCULEMENT ENTRE LES VUES ----------------------- */ /* Met en place un ensemble de vues pour un binaire. */ GPanelItem *_setup_new_panel_item_for_binary(GStudyProject *, GLoadedBinary *, BinaryView, GtkViewPanel **); /* ----------------------- AMORCE POUR CHARGEMENT DE CONTENUS ----------------------- */ /* Ensembles binaires à désassembler (instance) */ struct _GDelayedStudy { GDelayedWork parent; /* A laisser en premier */ GStudyProject *project; /* Projet de rattachement */ GBinContent *content; /* Contenu binaire à traiter */ ProjectContentState state; /* Renseigne le type de contenu*/ bool only_preload; /* Enregistrement seulement ? */ }; /* Ensembles binaires à désassembler (classe) */ struct _GDelayedStudyClass { GDelayedWorkClass parent; /* A laisser en premier */ }; /* Initialise la classe des intégrations de binaires à étudier. */ static void g_delayed_study_class_init(GDelayedStudyClass *); /* Initialise une intégration de binaire à étudier. */ static void g_delayed_study_init(GDelayedStudy *); /* Supprime toutes les références externes. */ static void g_delayed_study_dispose(GDelayedStudy *); /* Procède à la libération totale de la mémoire. */ static void g_delayed_study_finalize(GDelayedStudy *); /* Prépare une intégration de binaire au projet courant. */ static void g_delayed_study_process(GDelayedStudy *, GtkStatusStack *); /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'UN PROJET INTERNE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un projet d'étude. */ G_DEFINE_TYPE(GStudyProject, g_study_project, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des projets d'étude. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_study_project_class_init(GStudyProjectClass *klass) { } /****************************************************************************** * * * Paramètres : project = instance à initialiser. * * * * Description : Initialise une instance de projet d'étude. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_study_project_init(GStudyProject *project) { g_mutex_init(&project->cnt_mutex); g_mutex_init(&project->bin_mutex); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau projet vierge. * * * * Retour : Instance mise en place. * * * * Remarques : - * * * ******************************************************************************/ GStudyProject *g_study_project_new(GObject *ref) { GStudyProject *result; /* Composant à retourner */ result = g_object_new(G_TYPE_STUDY_PROJECT, NULL); g_object_ref(ref); result->ref = ref; return result; } /****************************************************************************** * * * Paramètres : filename = chemin d'accès au fichier à charger. * * * * Description : Crée un projet à partir du contenu XML d'un fichier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ GStudyProject *g_study_project_open(GObject *ref, const char *filename) { GStudyProject *result; /* Adresse à retourner */ xmlDocPtr xdoc; /* Structure XML chargée */ xmlXPathContextPtr context; /* Contexte pour les XPath */ unsigned int root_contents; /* Quantité de contenus majeurs*/ GAsyncQueue *sema; /* Sémaphore taisant son nom */ xmlXPathObjectPtr xobject; /* Cible d'une recherche */ unsigned int i; /* Boucle de parcours */ size_t access_len; /* Taille d'un chemin interne */ char *access; /* Chemin pour une sous-config.*/ GBinContent *content; /* Contenu binaire retrouvé */ long state; /* Etat de ce contenu binaire */ bool status; /* Bilan d'une lecture */ GDelayedStudy *dstudy; /* Etude complémentaire à mener*/ GLoadedBinary *binary; /* Représentation à intégrer */ if (!open_xml_file(filename, &xdoc, &context)) return NULL; result = g_study_project_new(ref); result->filename = strdup(filename); /* Préparations aux traitements parallèles */ root_contents = 0; sema = g_async_queue_new(); void ack_content_processing(GDelayedStudy *dstudy, GAsyncQueue *aqueue) { g_async_queue_push(aqueue, GINT_TO_POINTER(1)); } /* Chargement des contenus binaires attachés */ xobject = get_node_xpath_object(context, "/ChrysalideProject/Contents/Content"); for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) { access_len = strlen("/ChrysalideProject/Contents/Content[position()=") + SIZE_T_MAXLEN + strlen("]") + 1; access = calloc(access_len, sizeof(char)); snprintf(access, access_len, "/ChrysalideProject/Contents/Content[position()=%u]", i + 1); content = g_binary_content_new_from_xml(context, access, filename); status = get_node_prop_long_value(context, access, "state", &state); free(access); if (content == NULL) { log_variadic_message(LMT_ERROR, _("Unable to load the binary content #%u ; skipping..."), i); continue; } if (!status) { log_variadic_message(LMT_ERROR, _("Bad state for content '%s' ; skipping..."), g_binary_content_describe(content, true)); continue; } /* Le contenu peut être un conteneur ? */ if (state == PCS_ROOT) { dstudy = g_delayed_study_new(result, content, state); g_signal_connect(dstudy, "work-completed", G_CALLBACK(ack_content_processing), sema); g_delayed_study_preload_only(dstudy); root_contents++; study_new_content(dstudy); } } if(xobject != NULL) xmlXPathFreeObject(xobject); /* Attente pour la réception de contenus supplémentaires éventuels */ for (i = 0; i < root_contents; i++) g_async_queue_pop(sema); g_async_queue_unref(sema); /* Chargement des binaires analysés */ xobject = get_node_xpath_object(context, "/ChrysalideProject/Binaries/Binary"); for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++) { access_len = strlen("/ChrysalideProject/Binaries/Binary[position()=") + SIZE_T_MAXLEN + strlen("]") + 1; access = calloc(access_len, sizeof(char)); snprintf(access, access_len, "/ChrysalideProject/Binaries/Binary[position()=%u]", i + 1); binary = g_loaded_binary_new_from_xml(context, access, result); free(access); if (binary != NULL) { g_signal_connect_to_main(binary, "disassembly-done", G_CALLBACK(g_study_project_add_loaded_binary), result, g_cclosure_marshal_VOID__VOID); g_loaded_binary_analyse(binary); } } if(xobject != NULL) xmlXPathFreeObject(xobject); /* Fin du chargement */ close_xml_file(xdoc, context); return result; } /****************************************************************************** * * * Paramètres : project = project à sauvegarder. * * filename = nom de fichier à utiliser ou NULL pour l'existant.* * * * Description : Procède à l'enregistrement d'un projet donné. * * * * Retour : true si l'enregistrement s'est déroule sans encombre. * * * * Remarques : - * * * ******************************************************************************/ bool g_study_project_save(GStudyProject *project, const char *filename) { bool result; /* Bilan à retourner */ xmlDocPtr xdoc; /* Document XML à créer */ xmlXPathContextPtr context; /* Contexte pour les recherches*/ const char *final; /* Lieu d'enregistrement final */ size_t i; /* Boucle de parcours */ size_t access_len; /* Taille d'un chemin interne */ char *access; /* Chemin pour une sous-config.*/ result = create_new_xml_file(&xdoc, &context); result &= (ensure_node_exist(xdoc, context, "/ChrysalideProject") != NULL); final = filename != NULL ? filename : project->filename; /* Enregistrement des contenus binaires attachés */ for (i = 0; i < project->contents_count && result; i++) { if (project->contents[i].state == PCS_INTERNAL) continue; access_len = strlen("/ChrysalideProject/Contents/Content[position()=") + SIZE_T_MAXLEN + strlen("]") + 1; access = calloc(access_len, sizeof(char)); snprintf(access, access_len, "/ChrysalideProject/Contents/Content[position()=%zu]", i + 1); result = g_binary_content_save(project->contents[i].content, xdoc, context, access, final); if (result) result = add_long_attribute_to_node(xdoc, context, access, "state", project->contents[i].state); free(access); } /* Enregistrement des binaires analysés */ for (i = 0; i < project->binaries_count && result; i++) { access_len = strlen("/ChrysalideProject/Binaries/Binary[position()=") + SIZE_T_MAXLEN + strlen("]") + 1; access = calloc(access_len, sizeof(char)); snprintf(access, access_len, "/ChrysalideProject/Binaries/Binary[position()=%zu]", i + 1); result = g_loaded_binary_save(project->binaries[i]->binary, xdoc, context, access); free(access); } /* Sauvegarde finale */ result &= save_xml_file(xdoc, final); if (result && filename != NULL) { if (project->filename != NULL) free(project->filename); project->filename = strdup(filename); } close_xml_file(xdoc, context); return result; } /****************************************************************************** * * * Paramètres : project = project à consulter. * * * * Description : Indique le chemin du fichier destiné à la sauvegarde. * * * * Retour : Chemin de fichier pour l'enregistrement ou NULL si indéfini. * * * * Remarques : - * * * ******************************************************************************/ const char *g_study_project_get_filename(const GStudyProject *project) { return project->filename; } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * * content = contenu binaire à mémoriser pour le projet. * * state = état du contenu à conserver. * * * * Description : Assure l'intégration d'un contenu binaire dans un projet. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_study_project_add_binary_content(GStudyProject *project, GBinContent *content, ProjectContentState state) { loaded_content *new; /* Nouveau contenu à définir */ g_mutex_lock(&project->cnt_mutex); project->contents = (loaded_content *)realloc(project->contents, ++project->contents_count * sizeof(loaded_content)); new = &project->contents[project->contents_count - 1]; g_object_ref(G_OBJECT(content)); new->content = content; new->state = state; g_mutex_unlock(&project->cnt_mutex); } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * * hash = empreinte du contenu à retrouver. * * * * Description : Recherche un contenu binaire du projet selon son empreinte. * * * * Retour : Contenu avec propriété transférée ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBinContent *g_study_project_find_binary_content_by_hash(GStudyProject *project, const char *hash) { GBinContent *result; /* Trouvaille à retourner */ size_t i; /* Boucle de parcours */ GBinContent *iter; /* Contenu binaire analysé */ const gchar *other; /* Autre empreinte à comparer */ result = NULL; g_mutex_lock(&project->cnt_mutex); for (i = 0; i < project->contents_count && result == NULL; i++) { iter = project->contents[i].content; other = g_binary_content_get_checksum(iter); if (strcmp(hash, other) == 0) { g_object_ref(G_OBJECT(iter)); result = iter; } } g_mutex_unlock(&project->cnt_mutex); return result; } /****************************************************************************** * * * Paramètres : binary = élément binaire tout juste désassemblé. * * project = projet dont le contenu est à compléter. * * * * Description : Assure l'intégration d'un élément binaire dans un projet. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_study_project_add_loaded_binary(GLoadedBinary *binary, GStudyProject *project) { g_study_project_attach_binary(project, binary); } /****************************************************************************** * * * Paramètres : project = project à effacer de la mémoire. * * binary = fichier binaire à associer au projet actuel. * * * * Description : Attache un fichier donné à un projet donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_study_project_attach_binary(GStudyProject *project, GLoadedBinary *binary) { loaded_binary *new; /* Nouveau binaire à présenter */ GtkViewPanel *view; /* Composant d'affichage */ GPanelItem *panel; /* Nouveau panneau associé */ /* Mise en place */ new = (loaded_binary *)calloc(1, sizeof(loaded_binary)); new->binary = binary; /* Enregistrement dans le projet */ g_mutex_lock(&project->bin_mutex); project->binaries = (loaded_binary **)realloc(project->binaries, ++project->binaries_count * sizeof(loaded_binary *)); project->binaries[project->binaries_count - 1] = new; /* Premier affichage */ gboolean scroll_for_the_first_time(GtkWidget *widget, GdkEvent *event, GLoadedBinary *binary) { GBinFormat *format; /* Format associé au binaire */ GBinSymbol *symbol; /* Point d'entrée trouvé */ const mrange_t *range; /* Emplacement de ce point */ g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(scroll_for_the_first_time), binary); format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); /* TODO : se rabattre sur des symboles identifiés comme point d'entrée si on ne trouve pas les principaux ci dessous */ if (g_binary_format_find_symbol_by_label(format, "main", &symbol) || g_binary_format_find_symbol_by_label(format, "_start", &symbol) || g_binary_format_find_symbol_by_label(format, "entry_point", &symbol)) { range = g_binary_symbol_get_range(symbol); gtk_view_panel_request_move(GTK_VIEW_PANEL(widget), get_mrange_addr(range)); } return FALSE; } panel = _setup_new_panel_item_for_binary(project, binary, BVW_BLOCK, &view); g_mutex_unlock(&project->bin_mutex); g_signal_connect(view, "size-allocate", G_CALLBACK(scroll_for_the_first_time), binary); g_panel_item_dock(panel); update_project_area(project); } /****************************************************************************** * * * Paramètres : project = project à effacer de la mémoire. * * binary = fichier binaire à dissocier au projet actuel. * * * * Description : Détache un fichier donné à un projet donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_study_project_detach_binary(GStudyProject *project, GLoadedBinary *binary) { //GtkDockPanel *dpanel; /* Support de panneaux */ //GDockItem *ditem; /* Support d'affichage utilisé */ size_t i; /* Boucle de parcours */ //dpanel = GTK_DOCK_PANEL(g_object_get_data(project->ref, "binpanel")); //ditem = gtk_dock_panel_get_item_from_binary(project, binary); FIXME !! //gtk_dock_panel_remove_item(dpanel, ditem); for (i = 0; i < project->binaries_count; i++) if (project->binaries[i]->binary == binary) break; if ((i + 1) < project->binaries_count) memmove(&project->binaries[i], &project->binaries[i + 1], (project->binaries_count - i - 1) * sizeof(loaded_binary *)); project->binaries = (loaded_binary **)realloc(project->binaries, --project->binaries_count * sizeof(loaded_binary *)); update_project_area(project); } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à afficher. * * * * Description : Met en place un projet à l'écran. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_study_project_display(const GStudyProject *project) { size_t i; /* Boucle de parcours #1 */ loaded_binary *handled; /* Binaire prise en compte */ size_t j; /* Boucle de parcours #2 */ for (i = 0; i < project->binaries_count; i++) { handled = project->binaries[i]; for (j = 0; j < handled->count; j++) g_panel_item_dock(handled->items[j]); } } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à cacher. * * * * Description : Supprime de l'écran un projet en place. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_study_project_hide(const GStudyProject *project) { size_t i; /* Boucle de parcours #1 */ loaded_binary *handled; /* Binaire prise en compte */ size_t j; /* Boucle de parcours #2 */ for (i = 0; i < project->binaries_count; i++) { handled = project->binaries[i]; for (j = 0; j < handled->count; j++) g_panel_item_undock(handled->items[j]); } } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à afficher. * * count = nombre de binaires pris en compte. [OUT] * * * * Description : Fournit l'ensemble des binaires associés à un projet. * * * * Retour : Liste à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ GLoadedBinary **g_study_project_get_binaries(const GStudyProject *project, size_t *count) { GLoadedBinary **result; /* Tableau à retourner */ size_t i; /* Boucle de parcours */ *count = project->binaries_count; result = (GLoadedBinary **)calloc(*count, sizeof(GLoadedBinary *)); for (i = 0; i < *count; i++) { result[i] = project->binaries[i]->binary; g_object_ref(G_OBJECT(result[i])); } return result; } /* ---------------------------------------------------------------------------------- */ /* VUES ET BASCULEMENT ENTRE LES VUES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : project = zone d'inscription du nouveau panneau. * * binary = fichier binaire dont les vues sont à créer. * * wanted = interface de visualisation demandée. * * panel = interface de visualisation principale. [OUT] * * * * Description : Met en place un ensemble de vues pour un binaire. * * * * Retour : Panneau mis en place et prêt à être inséré. * * * * Remarques : - * * * ******************************************************************************/ GPanelItem *_setup_new_panel_item_for_binary(GStudyProject *project, GLoadedBinary *binary, BinaryView wanted, GtkViewPanel **panel) { GPanelItem *result; /* Nouveau panneau à renvoyer */ size_t k; /* Boucle de parcours #3 */ loaded_binary *handled; /* Dossier de suivi à compléter*/ GtkViewPanel *views[BVW_COUNT]; /* Composants pour l'affichage */ BinaryView i; /* Boucle de parcours #1 */ GtkWidget *view; /* Affichage du binaire */ GtkWidget *scroll; /* Surface d'exposition */ GtkWidget *selected; /* Interface de prédilection */ const char *name; /* Titre associé au binaire */ const char *lname; /* Description du binaire */ BinaryView j; /* Boucle de parcours #2 */ /* Recherche du dossier correspondant */ for (k = 0; k < project->binaries_count; k++) if (project->binaries[k]->binary == binary) break; assert(k < project->binaries_count); handled = project->binaries[k]; /* Créations */ for (i = 0; i < BVW_COUNT; i++) { /* Préparation du support visuel */ switch (i) { case BVW_BLOCK: view = gtk_block_view_new(); break; case BVW_GRAPH: view = gtk_graph_view_new(); break; case BVW_SOURCE: view = gtk_source_view_new(); break; default: /* GCC ! */ break; } gtk_widget_show(view); views[i] = GTK_VIEW_PANEL(view); gtk_view_panel_attach_binary(views[i], binary, i); /* Intégration finale dans un support défilant */ scroll = qck_create_scrolled_window(NULL, NULL); gtk_container_add(GTK_CONTAINER(scroll), view); if (i == wanted) { selected = scroll; *panel = GTK_VIEW_PANEL(view); } } /* Support graphique final */ name = g_loaded_binary_get_name(binary, false); lname = g_loaded_binary_get_name(binary, true); result = g_panel_item_new(PIP_BINARY_VIEW, name, lname, selected, true, "N"); register_panel_item(result, project->ref, get_main_configuration()); handled->items = (GPanelItem **)realloc(handled->items, ++handled->count * sizeof(GPanelItem *)); handled->items[handled->count - 1] = result; /* Etablissement des liens */ for (i = 0; i < BVW_COUNT; i++) for (j = 0; j < BVW_COUNT; j++) { if (j == i) continue; switch (j) { case BVW_BLOCK: g_object_set_data(G_OBJECT(views[i]), "block_alt_view", views[j]); break; case BVW_GRAPH: g_object_set_data(G_OBJECT(views[i]), "graph_alt_view", views[j]); break; case BVW_SOURCE: g_object_set_data(G_OBJECT(views[i]), "source_alt_view", views[j]); break; default: /* GCC ! */ break; } } return result; } /****************************************************************************** * * * Paramètres : project = zone d'inscription du nouveau panneau. * * binary = fichier binaire dont les vues sont à créer. * * wanted = interface de visualisation demandée. * * panel = interface de visualisation principale. [OUT] * * * * Description : Met en place un ensemble de vues pour un binaire. * * * * Retour : Panneau mis en place et prêt à être inséré. * * * * Remarques : - * * * ******************************************************************************/ GPanelItem *setup_new_panel_item_for_binary(GStudyProject *project, GLoadedBinary *binary, BinaryView wanted, GtkViewPanel **panel) { GPanelItem *result; /* Nouveau panneau à renvoyer */ /** * La liste des binaires pris en charge ne doit pas évoluer en cours * de traitement. On place donc le verrou adapté... */ g_mutex_lock(&project->bin_mutex); result = _setup_new_panel_item_for_binary(project, binary, wanted, panel); g_mutex_unlock(&project->bin_mutex); return result; } /****************************************************************************** * * * Paramètres : panel = panneau affichant un contenu binaire. * * * * Description : Fournit la station d'accueil d'un panneau d'affichage. * * * * Retour : Composant GTK fourni sans transfert de propriété. * * * * Remarques : - * * * ******************************************************************************/ GtkDockStation *get_dock_station_for_view_panel(GtkViewPanel *panel) { GtkWidget *result; /* Support trouvé à retourner */ /** * La hiérarchie des composants empilés est la suivante : * * - GtkBlockView / GtkGraphView / GtkSourceView (avec GtkViewport intégré) * - GtkScrolledWindow * - GtkDockStation * */ result = gtk_widget_get_parent(GTK_WIDGET(panel)); /* ScrolledWindow */ result = gtk_widget_get_parent(result); /* DockStation */ return GTK_DOCK_STATION(result); } /****************************************************************************** * * * Paramètres : panel = panneau affichant un contenu binaire. * * * * Description : Fournit le support défilant d'un panneau d'affichage. * * * * Retour : Composant GTK fourni sans transfert de propriété. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *get_scroll_window_for_view_panel(GtkViewPanel *panel) { GtkWidget *result; /* Support trouvé à retourner */ /** * La hiérarchie des composants empilés est la suivante : * * - GtkBlockView / GtkGraphView / GtkSourceView (avec GtkViewport intégré) * - GtkScrolledWindow * - GtkDockStation * */ result = gtk_widget_get_parent(GTK_WIDGET(panel)); /* ScrolledWindow */ return result; } /****************************************************************************** * * * Paramètres : panel = panneau affichant un contenu binaire. * * view = autre vision recherchée. * * * * Description : Fournit une vision alternative d'un panneau d'affichage. * * * * Retour : Composant GTK fourni sans transfert de propriété. * * * * Remarques : - * * * ******************************************************************************/ GtkViewPanel *get_alt_view_for_view_panel(GtkViewPanel *panel, BinaryView view) { GtkViewPanel *result; /* Panneau visé à renvoyer */ switch (view) { case BVW_BLOCK: result = GTK_VIEW_PANEL(g_object_get_data(G_OBJECT(panel), "block_alt_view")); break; case BVW_GRAPH: result = GTK_VIEW_PANEL(g_object_get_data(G_OBJECT(panel), "graph_alt_view")); break; case BVW_SOURCE: result = GTK_VIEW_PANEL(g_object_get_data(G_OBJECT(panel), "source_alt_view")); break; default: assert(false); result = NULL; break; } return result; } /* ---------------------------------------------------------------------------------- */ /* GESTION GLOBALISEE DES PROJETS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : project = éventuel adresse à renvoyer désormais. * * * * Description : Fournit l'adresse du projet courant. * * * * Retour : Adresse du projet ouvert ou NULL si aucun (!). * * * * Remarques : - * * * ******************************************************************************/ GStudyProject *_get_current_study_project(GStudyProject *project) { static GStudyProject *result = NULL; /* Adresse à retourner */ if (project != NULL) { if (result != NULL) { g_study_project_hide(result); g_object_unref(G_OBJECT(result)); } result = project; } return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit le gestionnaire des projets connus. * * * * Retour : Instance de gestion unique. * * * * Remarques : - * * * ******************************************************************************/ GtkRecentManager *get_projects_manager(void) { static GtkRecentManager *result = NULL; /* Singleton à retourner */ if (result == NULL) { result = gtk_recent_manager_get_default(); //gtk_recent_manager_purge_items(result, NULL); } return result; } /****************************************************************************** * * * Paramètres : project = projet à traiter. * * * * Description : Place un projet au sommet de la pile des projets récents. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void push_project_into_recent_list(const GStudyProject *project) { GtkRecentManager *manager; /* Gestionnaire global */ char *qualified; /* Chemin avec 'file://' */ GtkRecentData recent; /* Données complètes */ if (project->filename == NULL) return; /* Constitution de la liste des projets récents */ /* Constitution de la liste des projets récents */ manager = get_projects_manager(); qualified = (char *)calloc(strlen("file://") + strlen(project->filename) + 1, sizeof(char)); strcpy(qualified, "file://"); strcat(qualified, project->filename); memset(&recent, 0, sizeof(GtkRecentData)); recent.mime_type = "application/chrysalide.project"; recent.app_name = "Chrysalide"; recent.app_exec = "chrysalide %f"; gtk_recent_manager_add_full(manager, qualified, &recent); free(qualified); /* Pour la prochaine ouverture du programme... */ g_generic_config_set_value(get_main_configuration(), MPK_LAST_PROJECT, project->filename); } /* ---------------------------------------------------------------------------------- */ /* AMORCE POUR CHARGEMENT DE CONTENUS */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour les tâches de préparations d'étude. */ G_DEFINE_TYPE(GDelayedStudy, g_delayed_study, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des intégrations de binaires à étudier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_class_init(GDelayedStudyClass *klass) { GObjectClass *object; /* Autre version de la classe */ GDelayedWorkClass *work; /* Version en classe parente */ object = G_OBJECT_CLASS(klass); work = G_DELAYED_WORK_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_study_dispose; object->finalize = (GObjectFinalizeFunc)g_delayed_study_finalize; work->run = (run_task_fc)g_delayed_study_process; } /****************************************************************************** * * * Paramètres : dstudy = instance à initialiser. * * * * Description : Initialise une intégration de binaire à étudier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_init(GDelayedStudy *dstudy) { dstudy->only_preload = false; } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_dispose(GDelayedStudy *dstudy) { g_object_unref(G_OBJECT(dstudy->project)); g_object_unref(G_OBJECT(dstudy->content)); G_OBJECT_CLASS(g_delayed_study_parent_class)->dispose(G_OBJECT(dstudy)); } /****************************************************************************** * * * Paramètres : binary = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_finalize(GDelayedStudy *dstudy) { G_OBJECT_CLASS(g_delayed_study_parent_class)->finalize(G_OBJECT(dstudy)); } /****************************************************************************** * * * Paramètres : project = projet dont le contenu est à compléter. * * content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Crée une tâche d'intégration de contenu binaire. * * * * Retour : Tâche créée. * * * * Remarques : L'appelant perd la propriété du contenu. * * * ******************************************************************************/ GDelayedStudy *g_delayed_study_new(GStudyProject *project, GBinContent *content, ProjectContentState state) { GDelayedStudy *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_DELAYED_STUDY, NULL); g_object_ref(G_OBJECT(project)); result->project = project; g_object_ref(G_OBJECT(content)); result->content = content; result->state = state; return result; } /****************************************************************************** * * * Paramètres : dstudy = intégration à mener. * * status = barre de statut à tenir informée. * * * * Description : Prépare une intégration de binaire au projet courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_study_process(GDelayedStudy *dstudy, GtkStatusStack *status) { FormatMatchStatus mstatus; /* Statut d'une reconnaissance */ char *target; /* Sous-traitance requise */ GLoadedBinary *binary; /* Représentation chargée */ mstatus = find_matching_format(dstudy->content, NULL, &target); switch (mstatus) { case FMS_MATCHED: if (dstudy->only_preload) g_study_project_add_binary_content(dstudy->project, dstudy->content, dstudy->state); else { binary = g_loaded_binary_new(dstudy->content); if (binary != NULL) { g_study_project_add_binary_content(dstudy->project, dstudy->content, dstudy->state); g_signal_connect_to_main(binary, "disassembly-done", G_CALLBACK(g_study_project_add_loaded_binary), dstudy->project, g_cclosure_marshal_VOID__VOID); g_loaded_binary_analyse(binary); } } break; case FMS_FORWARDED: /** * L'émetteur de ce type de réponse a pour charge de * reprogrammer lui même l'analyse de nouveaux contenus. */ log_variadic_message(LMT_PROCESS, _("binary '%s' contains other binaries..."), g_binary_content_describe(dstudy->content, true)); if (dstudy->state == PCS_ROOT) g_study_project_add_binary_content(dstudy->project, dstudy->content, PCS_ROOT); break; default: /** * Les jeux sont faits pour le contenu binaire courant. */ log_variadic_message(LMT_PROCESS, _("Unknown binary format for '%s'..."), g_binary_content_describe(dstudy->content, true)); break; } } /****************************************************************************** * * * Paramètres : dstudy = tâche d'analyse de contenu pour projet à mener. * * * * Description : Limite l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_delayed_study_preload_only(GDelayedStudy *dstudy) { dstudy->only_preload = true; } /****************************************************************************** * * * Paramètres : content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Programme l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void qck_study_new_content(GBinContent *content, ProjectContentState state) { GDelayedStudy *dstudy; /* Etude à conduire */ dstudy = g_delayed_study_new(get_current_project(), content, state); study_new_content(dstudy); } /****************************************************************************** * * * Paramètres : content = contenu binaire chargé à analyser. * * state = état du contenu à conserver. * * * * Description : Programme l'étude et l'intégration d'un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void study_new_content(GDelayedStudy *dstudy) { GWorkQueue *queue; /* Gestionnaire de différés */ queue = get_work_queue(); g_work_queue_schedule_work(queue, G_DELAYED_WORK(dstudy), DEFAULT_WORK_GROUP); }