/* Chrysalide - Outil d'analyse de fichiers binaires * gtkstatusstack.c - empilement d'informations de statut * * Copyright (C) 2015 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 "gtkstatusstack.h" #include #include #include #include #include "easygtk.h" #include "../common/extstr.h" /* ------------------------- GESTION EXTERIEURE DE LA BARRE ------------------------- */ /* Navigation au sein d'assemblage */ typedef union _assembly_info assembly_info; /* Abstration d'une gestion de barre de statut (instance) */ struct _GtkStatusStack { GtkBin parent; /* A laisser en premier */ GtkWidget *asm_status; /* Barre de status d'assemblage*/ assembly_info *asm_info; /* Informations courantes */ }; /* Abstration d'une gestion de barre de statut (classe) */ struct _GtkStatusStackClass { GtkBinClass parent; /* A laisser en premier */ }; /* Initialise la classe des barres de statut améliorées. */ static void gtk_status_stack_class_init(GtkStatusStackClass *); /* Initialise une instance de barre de statut améliorée. */ static void gtk_status_stack_init(GtkStatusStack *); /* Supprime toutes les références externes. */ static void gtk_status_stack_dispose(GtkStatusStack *); /* Procède à la libération totale de la mémoire. */ static void gtk_status_stack_finalize(GtkStatusStack *); /* S'assure de l'affichage du niveau de pile attendu. */ static void gtk_status_stack_switch(GtkStatusStack *, GtkWidget *); /* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */ /* Navigation au sein d'assemblage */ union _assembly_info { bool reset; /* Réinitialisation */ struct { mrange_t current; /* Emplacement correspondant */ char *segment; /* Segment d'appartenance */ VMPA_BUFFER(phys); /* Localisation physique */ VMPA_BUFFER(virt); /* Localisation virtuelle */ char *symbol; /* Eventuel symbole concerné */ const char *encoding; /* Encodage de l'instruction */ phys_t size; /* Taille de l'instruction */ }; }; /* Supprime l'empreinte mémoire d'informations d'assemblage. */ static void reset_assembly_info(assembly_info *); /* Construit une barre d'état pour language d'assemblage. */ static GtkWidget *build_assembly_status_stack(GtkStatusStack *); /* Réagit à un redimensionnement de la barre de désassemblage. */ static void on_size_allocate_for_asm_status(GtkWidget *, GdkRectangle *, GObject *); /* Réagit à un clic sur l'icône de zoom. */ static void on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GdkEventButton *, GtkStatusStack *); /* S'assure de l'affichage à jour de la partie "assemblage". */ static void gtk_status_stack_show_current_instruction(GtkStatusStack *); /* ---------------------------------------------------------------------------------- */ /* GESTION EXTERIEURE DE LA BARRE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type de la barre de statut améliorée. */ G_DEFINE_TYPE(GtkStatusStack, gtk_status_stack, GTK_TYPE_BIN) /****************************************************************************** * * * Paramètres : klass = classe GTK à initialiser. * * * * Description : Initialise la classe des barres de statut améliorées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_class_init(GtkStatusStackClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose; object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize; } /****************************************************************************** * * * Paramètres : stack = instance GTK à initialiser. * * * * Description : Initialise une instance de barre de statut améliorée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_init(GtkStatusStack *stack) { stack->asm_status = build_assembly_status_stack(stack); stack->asm_info = (assembly_info *)calloc(1, sizeof(assembly_info)); reset_assembly_info(stack->asm_info); } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_dispose(GtkStatusStack *stack) { g_object_unref(G_OBJECT(stack->asm_status)); G_OBJECT_CLASS(gtk_status_stack_parent_class)->dispose(G_OBJECT(stack)); } /****************************************************************************** * * * Paramètres : view = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_finalize(GtkStatusStack *stack) { reset_assembly_info(stack->asm_info); free(stack->asm_info); G_OBJECT_CLASS(gtk_status_stack_parent_class)->finalize(G_OBJECT(stack)); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée une nouvelle instance de barre de statut. * * * * Retour : Composant GTK mis en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *gtk_status_stack_new(void) { return g_object_new(GTK_TYPE_STATUS_STACK, NULL); } /****************************************************************************** * * * Paramètres : stack = pile de statuts à considérer. * * next = niveau de pile à afficher désormais. * * * * Description : S'assure de l'affichage du niveau de pile attendu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_switch(GtkStatusStack *stack, GtkWidget *next) { GtkWidget *child; /* Support courant */ child = gtk_bin_get_child(GTK_BIN(stack)); if (child != next) { if (child != NULL) gtk_container_remove(GTK_CONTAINER(stack), child); g_object_ref(G_OBJECT(next)); gtk_container_add(GTK_CONTAINER(stack), next); } } /* ---------------------------------------------------------------------------------- */ /* STATUT DES INFORMATIONS DE DESASSEMBLAGE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : info = informations à réinitialiser. * * * * Description : Supprime l'empreinte mémoire d'informations d'assemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void reset_assembly_info(assembly_info *info) { info->reset = true; if (info->segment != NULL) { free(info->segment); info->segment = NULL; } if (info->symbol != NULL) { free(info->symbol); info->symbol = NULL; } } /****************************************************************************** * * * Paramètres : stack = composant global en cours de construction. * * * * Description : Construit une barre d'état pour language d'assemblage. * * * * Retour : Composant GTK mis en place. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *build_assembly_status_stack(GtkStatusStack *stack) { GtkWidget *result; /* Support à retourner */ GObject *ref; /* Espace de référencements */ GtkWidget *hbox; /* Sous-division horizontale */ GtkWidget *label; /* Etiquette pour impression */ GtkWidget *zoom; /* Sélection du zoom courant */ result = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show(result); ref = G_OBJECT(result); g_signal_connect(result, "size-allocate", G_CALLBACK(on_size_allocate_for_asm_status), ref); /* Première partie : navigation */ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 16); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(result), hbox, TRUE, TRUE, 8); label = qck_create_label(ref, "segment", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = qck_create_label(ref, "phys", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = qck_create_label(ref, "virt", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = qck_create_label(ref, "offset", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); /* Seconde partie : architecture */ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); g_object_set_data(ref, "arch_box", hbox); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(result), hbox, FALSE, TRUE, 8); label = qck_create_label(ref, "arch", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = qck_create_label(ref, "size", NULL); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); /* Troisième partie : affichage */ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(result), hbox, FALSE, FALSE, 8); zoom = qck_create_entry(ref, "zoom", "100%"); gtk_entry_set_icon_from_icon_name(GTK_ENTRY(zoom), GTK_ENTRY_ICON_SECONDARY, "go-up-symbolic"); g_signal_connect(zoom, "icon-press", G_CALLBACK(on_zoom_icon_press), stack); gtk_box_pack_start(GTK_BOX(hbox), zoom, FALSE, TRUE, 0); return result; } /****************************************************************************** * * * Paramètres : widget = composant graphique qui vient d'évoluer. * * allocation = espace réservé pour le composant visé. * * ref = espace de référencement global. * * * * Description : Réagit à un redimensionnement de la barre de désassemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_size_allocate_for_asm_status(GtkWidget *widget, GdkRectangle *allocation, GObject *ref) { GtkWidget *hbox; /* Sous-division horizontale */ hbox = GTK_WIDGET(g_object_get_data(ref, "arch_box")); gtk_widget_set_size_request(hbox, (allocation->width * 40) / 100, -1); /** * On intervient après que le containeur soit passer collecter les tailles * de ses enfants lors de son redimensionnement. * * Donc on force un prise en compte des changements. */ gtk_container_check_resize(GTK_CONTAINER(widget)); } /****************************************************************************** * * * Paramètres : entry = zone de texte visée par la procédure. * * icon_pos = position de l'image associée à l'entrée. * * event = informations liées à l'événement. * * stack = composant graphique de gestion des statuts. * * * * Description : Réagit à un clic sur l'icône de zoom. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEventButton *event, GtkStatusStack *stack) { GtkWidget *popup; /* Popup à faire surgir */ GdkRectangle rect; /* Zone précise à cibler */ if (event->button != GDK_BUTTON_PRIMARY) return; popup = gtk_popover_new(GTK_WIDGET(entry)); gtk_entry_get_icon_area(entry, GTK_ENTRY_ICON_SECONDARY, &rect); gtk_popover_set_pointing_to(GTK_POPOVER(popup), &rect); gtk_widget_show(popup); } /****************************************************************************** * * * Paramètres : stack = barre de statut à actualiser. * * binary = binaire chargé rassemblant l'ensemble des infos. * * instr = instruction désassemblée ciblée graphiquement. * * * * Description : Actualise les informations liées une position d'assemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GLoadedBinary *binary, const GArchInstruction *instr) { assembly_info *info; /* Informations à constituer */ GExeFormat *format; /* Format de binaire à traiter */ const mrange_t *range; /* Emplacement d'instruction */ const vmpa2t *addr; /* Localisation de départ */ GPortionLayer *layer; /* Couche première de portions */ GBinPortion *portion; /* Zone mémoire d'appartenance */ const char *text; /* Texte au contenu à copier */ GBinSymbol *symbol; /* Symbole présent à l'adresse */ phys_t diff; /* Décallage de l'adresse */ const char *label; /* Description d'un symbole */ vmpa2t tmp; /* Zone de construction temp. */ VMPA_BUFFER(offset); /* Décalage physique */ info = stack->asm_info; format = g_loaded_binary_get_format(binary); /* Bascule vers une zone courante nouvelle ? */ range = g_arch_instruction_get_range(instr); addr = get_mrange_addr(range); if (cmp_mrange(&info->current, range) == 0) goto gssuci_useless; /* Réinitialisation */ reset_assembly_info(info); copy_mrange(&info->current, range); /* Zone d'appartenance */ layer = g_exe_format_get_main_layer(format); portion = g_portion_layer_find_portion_at_addr(layer, addr, (GdkRectangle []) { }); text = g_binary_portion_get_desc(portion); if (text != NULL) info->segment = strdup(text); else info->segment = strdup(_("Binary")); g_object_unref(G_OBJECT(layer)); /* Adresses de base */ vmpa2_phys_to_string(addr, MDS_UNDEFINED, info->phys, NULL); vmpa2_virt_to_string(addr, MDS_UNDEFINED, info->virt, NULL); info->encoding = g_arch_instruction_get_encoding(instr); info->size = get_mrange_length(range); /* Symbole concerné */ if (g_binary_format_resolve_symbol(G_BIN_FORMAT(format), addr, &symbol, &diff)) { label = g_binary_symbol_get_label(symbol); if (label != NULL) { info->symbol = strdup(label); info->symbol = stradd(info->symbol, "+"); init_vmpa(&tmp, diff, VMPA_NO_VIRTUAL); vmpa2_phys_to_string(&tmp, MDS_UNDEFINED, offset, NULL); info->symbol = stradd(info->symbol, offset); } g_object_unref(G_OBJECT(symbol)); } /* Nettoyage et conclusion */ info->reset = false; gtk_status_stack_show_current_instruction(stack); gssuci_useless: //g_object_unref(G_OBJECT(format)); ; } /****************************************************************************** * * * Paramètres : stack = barre de statut à actualiser. * * * * Description : Réinitialise les informations associées une position. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_status_stack_reset_current_instruction(GtkStatusStack *stack) { assembly_info *info; /* Informations à constituer */ info = stack->asm_info; reset_assembly_info(info); gtk_status_stack_show_current_instruction(stack); } /****************************************************************************** * * * Paramètres : stack = pile de statuts à manipuler. * * * * Description : S'assure de l'affichage à jour de la partie "assemblage". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_status_stack_show_current_instruction(GtkStatusStack *stack) { GObject *ref; /* Espace de référencements */ assembly_info *info; /* Informations à consulter */ GtkLabel *label; /* Etiquette à actualiser */ char raw_pos[6 + VMPA_MAX_LEN + 1]; /* Formatage final en direct */ char *content; /* Contenu dynamique */ gtk_status_stack_switch(stack, stack->asm_status); ref = G_OBJECT(stack->asm_status); info = stack->asm_info; /* Première partie : navigation */ if (info->reset) { label = GTK_LABEL(g_object_get_data(ref, "segment")); gtk_label_set_text(label, NULL); label = GTK_LABEL(g_object_get_data(ref, "phys")); gtk_label_set_text(label, NULL); label = GTK_LABEL(g_object_get_data(ref, "virt")); gtk_label_set_text(label, NULL); label = GTK_LABEL(g_object_get_data(ref, "offset")); gtk_label_set_text(label, NULL); } else { label = GTK_LABEL(g_object_get_data(ref, "segment")); gtk_label_set_text(label, info->segment); snprintf(raw_pos, sizeof(raw_pos), "phys: %s", info->phys); label = GTK_LABEL(g_object_get_data(ref, "phys")); gtk_label_set_text(label, raw_pos); snprintf(raw_pos, sizeof(raw_pos), "virt: %s", info->virt); label = GTK_LABEL(g_object_get_data(ref, "virt")); gtk_label_set_text(label, raw_pos); label = GTK_LABEL(g_object_get_data(ref, "offset")); gtk_label_set_text(label, info->symbol != NULL ? info->symbol : ""); } /* Seconde partie : architecture */ if (info->reset) { label = GTK_LABEL(g_object_get_data(ref, "arch")); gtk_label_set_text(label, NULL); label = GTK_LABEL(g_object_get_data(ref, "size")); gtk_label_set_text(label, NULL); } else { label = GTK_LABEL(g_object_get_data(ref, "arch")); gtk_label_set_text(label, info->encoding); if (info->size > 1) asprintf(&content, "%" PRIu64 " %s", (uint64_t)info->size, _("bytes")); else asprintf(&content, "%" PRIu64 " %s", (uint64_t)info->size, _("byte")); label = GTK_LABEL(g_object_get_data(ref, "size")); gtk_label_set_text(label, content); free(content); } }