/* OpenIDA - Outil d'analyse de fichiers binaires * gcodebuffer.h - prototypes pour l'affichage d'un fragment de code d'assemblage * * Copyright (C) 2010-2012 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 "gcodebuffer.h" #include #include #include "chrysamarshal.h" #include "delayed-int.h" /* -------------------------- PARCOURS DU CODE D'UN TAMPON -------------------------- */ #define G_TYPE_BUFFER_SCAN g_buffer_scan_get_type() #define G_BUFFER_SCAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_buffer_scan_get_type(), GDelayedExport)) #define G_IS_BUFFER_SCAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_buffer_scan_get_type())) #define G_BUFFER_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_SCAN, GDelayedExportClass)) #define G_IS_BUFFER_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_SCAN)) #define G_BUFFER_SCAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_SCAN, GDelayedExportClass)) /* Ensembles binaires à désassembler (instance) */ typedef struct _GBufferScan { GDelayedWork parent; /* A laisser en premier */ GCodeBuffer *buffer; /* Tampon à manipuler */ vmpa_t start; /* Début du parcours ou 0 */ vmpa_t end; /* Fin du parcours ou VMPA_MAX */ char *message; /* Message de progression */ process_line_fc process; /* Fonction de traitement réel */ void *user_data; /* Données à faire suivre */ } GBufferScan; /* Ensembles binaires à désassembler (classe) */ typedef struct _GBufferScanClass { GDelayedWorkClass parent; /* A laisser en premier */ } GBufferScanClass; /* Indique le type défini pour les tâches d'exportation différée. */ static GType g_buffer_scan_get_type(void); /* Initialise la classe des tâches d'exportation différée. */ static void g_buffer_scan_class_init(GBufferScanClass *); /* Initialise une tâche d'exportation différée. */ static void g_buffer_scan_init(GBufferScan *); /* Crée une tâche d'exportation différée. */ static GBufferScan *g_buffer_scan_new(GCodeBuffer *, vmpa_t, vmpa_t, const char *, process_line_fc, void *); /* Assure l'exportation en différé. */ static void g_buffer_scan_process(GBufferScan *, GtkExtStatusBar *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ /* Tampon pour code désassemblé (instance) */ struct _GCodeBuffer { GObject parent; /* A laisser en premier */ GBufferLine **lines; /* Liste des lignes intégrées */ size_t count; /* Quantité en cache */ size_t used; /* Quantité utilisée */ size_t indent; /* Indentation des lignes */ }; /* Tampon pour code désassemblé (classe) */ struct _GCodeBufferClass { GObjectClass parent; /* A laisser en premier */ }; /* Taille des allocations de masse */ #define LINE_ALLOC_BULK 20 /* Procède à l'initialisation d'une classe de tampon de code. */ static void g_code_buffer_class_init(GCodeBufferClass *); /* Procède à l'initialisation d'un tampon pour code désassemblé. */ static void g_code_buffer_init(GCodeBuffer *); /* Convertit une adresse en indice de ligne. */ static size_t _g_code_buffer_get_index_from_address(GCodeBuffer *, vmpa_t); /* Convertit une adresse en indice de ligne. */ static size_t g_code_buffer_get_index_from_address(GCodeBuffer *, vmpa_t); /* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */ /* Vue d'un tampon pour code désassemblé (instance) */ struct _GBufferView { GObject parent; /* A laisser en premier */ GCodeBuffer *buffer; /* Tampon de code visualisé */ vmpa_t start; /* Première ligne intégrée */ vmpa_t end; /* Dernière ligne intégrée */ GFontCache *fcache; /* Cache pour les polices */ gint line_height; /* Hauteur maximale des lignes */ gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ gint left_margin; /* Marge gauche + espace */ gint left_text; /* Début d'impression du code */ gint last_width; /* Plus grande col. de fusion */ BufferLineColumn last_merge; /* Colonne de fusion extrême */ buffer_line_draw_fc drawing_extra; /* Fonction d'accompagnement */ void *drawing_data; /* Donnée utilisateur */ GSList *highlighted; /* Segments mis en évidence */ }; /* Vue d'un tampon pour code désassemblé (classe) */ struct _GBufferViewClass { GObjectClass parent; /* A laisser en premier */ /* Signaux */ void (* need_redraw) (GBufferView *); }; #define HEIGHT_CACHED(view) ((view)->line_height != -1) #define WIDTHS_CACHED(view) ((view)->max_widths[0] != -1) /* Procède à l'initialisation d'une classe de vue de tampon. */ static void g_buffer_view_class_init(GBufferViewClass *); /* Procède à l'initialisation d'une vue d'un tampon pour code. */ static void g_buffer_view_init(GBufferView *); /* Réinitialise le cache de la hauteur des lignes. */ static void g_buffer_view_reset_required_height(GBufferView *); /* Réinitialise le cache des largeurs de colonne calculées. */ static void g_buffer_view_reset_required_widths(GBufferView *); /* Calcule les largeurs requises par une visualisation. */ static void g_buffer_view_compute_required_widths(GBufferView *, bool, bool); /* ---------------------------------------------------------------------------------- */ /* PARCOURS DU CODE D'UN TAMPON */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour les tâches d'exportation différée. */ G_DEFINE_TYPE(GBufferScan, g_buffer_scan, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des tâches d'exportation différée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_scan_class_init(GBufferScanClass *klass) { } /****************************************************************************** * * * Paramètres : disass = instance à initialiser. * * * * Description : Initialise une tâche d'exportation différée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_scan_init(GBufferScan *disass) { G_DELAYED_WORK(disass)->run = (run_task_fc)g_buffer_scan_process; } /****************************************************************************** * * * Paramètres : buffer = tampon à manipuler. * * start = première adresse visée ou 0. * * end = dernière adresse visée ou VMPA_MAX. * * message = message à afficher lors de la progression. * * process = fonction assurant le traitement effectif. * * data = données utilisateur à faire suivre. * * * * Description : Crée une tâche d'exportation différée. * * * * Retour : Tâche créée. * * * * Remarques : - * * * ******************************************************************************/ static GBufferScan *g_buffer_scan_new(GCodeBuffer *buffer, vmpa_t start, vmpa_t end, const char *message, process_line_fc process, void *data) { GBufferScan *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_BUFFER_SCAN, NULL); result->buffer = buffer; g_object_ref(G_OBJECT(buffer)); result->start = start; result->end = end; result->message = strdup(message); result->process = process; result->user_data = data; return result; } /****************************************************************************** * * * Paramètres : scan = parcours à mener. * * statusbar = barre de statut à tenir informée. * * * * Description : Assure l'exportation en différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar) { size_t first; /* Première ligne visée */ size_t last; /* Dernière ligne visée + 1 */ GBufferLine **lines; /* Liste des lignes à traiter */ guint id; /* Identifiant de statut */ size_t i; /* Boucle de parcours */ /* TODO : lock scan->buffer->lines */ first = g_code_buffer_get_index_from_address(scan->buffer, scan->start); last = g_code_buffer_get_index_from_address(scan->buffer, scan->end); lines = scan->buffer->lines; id = gtk_extended_status_bar_push(statusbar, scan->message, true); if (scan->buffer->used > 0) for (i = first; i <= last; i++) { if (!scan->process(scan->buffer, lines[i], scan->user_data)) break; gtk_extended_status_bar_update_activity(statusbar, id, (i - first) * 1.0 / (last - first)); } /* TODO : unlock scan->buffer->lines */ gtk_extended_status_bar_remove(statusbar, id); /* Avertit le commanditaire... */ scan->process(scan->buffer, NULL, scan->user_data); } /* ---------------------------------------------------------------------------------- */ /* TAMPON POUR CODE DESASSEMBLE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type du composant de tampon pour code désassemblé. */ G_DEFINE_TYPE(GCodeBuffer, g_code_buffer, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe de composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une classe de tampon de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_code_buffer_class_init(GCodeBufferClass *class) { } /****************************************************************************** * * * Paramètres : buffer = composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'un tampon pour code désassemblé.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_code_buffer_init(GCodeBuffer *buffer) { } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau composant de tampon pour code désassemblé. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GCodeBuffer *g_code_buffer_new(void) { GCodeBuffer *result; /* Composant à retourner */ result = g_object_new(G_TYPE_CODE_BUFFER, NULL); return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où va se situer la ligne. * * * * Description : Convertit une adresse en indice de ligne. * * * * Retour : Indice de l'adresse trouvée, ou 0 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static size_t _g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t addr) { size_t result; /* Indice à retourner */ if (addr == VMPA_MAX) return (buffer->used > 0 ? buffer->used - 1 : 0); /* TODO : coder un parcours plus optimal ! */ for (result = 0; result < buffer->used; result++) if (g_buffer_line_get_address(buffer->lines[result]) == addr) break; return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où va se situer la ligne. * * * * Description : Convertit une adresse en indice de ligne. * * * * Retour : Indice de l'adresse trouvée, ou 0 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static size_t g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t addr) { size_t result; /* Indice à retourner */ result = _g_code_buffer_get_index_from_address(buffer, addr); /** * Par commodités, on évite certaines instructions en cas d'échec dans les * fonctions d'appels : la condition des boucles utilisant l'indice retourné (0) * fait son office directement ! */ if (result == buffer->used) result = 0; return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où va se situer la ligne. * * * * Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. * * * * Retour : Nouvelle ligne vierge à écrire. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer, vmpa_t addr) { GBufferLine *result; /* Instance à retourner */ size_t i; /* Boucle de parcours */ if (buffer->used == buffer->count) { buffer->count += LINE_ALLOC_BULK; buffer->lines = (GBufferLine **)realloc(buffer->lines, buffer->count * sizeof(GBufferLine *)); } result = g_buffer_line_new(addr); buffer->lines[buffer->used++] = result; for (i = 0; i < buffer->indent; i++) g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 4, RTT_RAW); return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où va se situer la ligne. * * before = emplacement de l'insertion. * * * * Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. * * * * Retour : Nouvelle ligne vierge à écrire. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_code_buffer_insert_at(GCodeBuffer *buffer, vmpa_t addr, bool before) { GBufferLine *result; /* Instance à retourner */ size_t index; /* Indice de la ligne visée */ index = _g_code_buffer_get_index_from_address(buffer, addr); if (index == buffer->used) return NULL; if (buffer->used == buffer->count) { buffer->count += LINE_ALLOC_BULK; buffer->lines = (GBufferLine **)realloc(buffer->lines, buffer->count * sizeof(GBufferLine *)); } if (before) { memmove(&buffer->lines[index + 1], &buffer->lines[index], sizeof(GBufferLine *) * (buffer->used - index)); buffer->used++; result = g_buffer_line_new(addr); buffer->lines[index] = result; } else /* FIXME */ ; return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * line = point d'insertion. * * * * Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. * * * * Retour : Nouvelle ligne vierge à écrire. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_code_buffer_insert_after(GCodeBuffer *buffer, GBufferLine *line) { /* FIXME */ return NULL; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où retrouver la ligne recherchée. * * * * Description : Retrouve une ligne au sein d'un tampon avec une adresse. * * * * Retour : Line retrouvée ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, vmpa_t addr) { GBufferLine *result; /* Instance à retourner */ size_t index; /* Indice de la ligne visée */ index = _g_code_buffer_get_index_from_address(buffer, addr); if (index == buffer->used) result = NULL; else result = buffer->lines[index]; return result; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * * * Description : Augmente l'indentation des prochaines lignes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_code_buffer_inc_indentation(GCodeBuffer *buffer) { buffer->indent++; } /****************************************************************************** * * * Paramètres : buffer = composant GTK à mettre à jour. * * * * Description : Diminue l'indentation des prochaines lignes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_code_buffer_dec_indentation(GCodeBuffer *buffer) { /* BUG_ON(buffer->indent == 0) */ buffer->indent--; } /****************************************************************************** * * * Paramètres : buffer = tampon de données à utiliser. * * start = première adresse visée ou 0. * * end = dernière adresse visée ou VMPA_MAX. * * message = message à afficher lors de la progression. * * process = fonction assurant le traitement effectif. * * data = données utilisateur à faire suivre. * * * * Description : Lance un parcours des différentes lignes du tampon de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_code_scan(GCodeBuffer *buffer, vmpa_t start, vmpa_t end, const char *message, process_line_fc process, void *data) { GBufferScan *scan; /* Procédure de parcours */ GWorkQueue *queue; /* Gestionnaire de différés */ scan = g_buffer_scan_new(buffer, start, end, message, process, data); queue = get_work_queue(); g_work_queue_schedule_work(queue, G_DELAYED_WORK(scan)); } /* ---------------------------------------------------------------------------------- */ /* VUE PARTICULIERE D'UN TAMPON DE CODE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type de la vue d'un tampon pour code désassemblé. */ G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe de composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une classe de vue de tampon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_class_init(GBufferViewClass *class) { g_signal_new("need-redraw", G_TYPE_BUFFER_VIEW, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GBufferViewClass, need_redraw), NULL, NULL, g_cclosure_user_marshal_VOID__OBJECT, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : buffer = composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une vue d'un tampon pour code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_init(GBufferView *buffer) { buffer->fcache = g_font_cache_new(); g_buffer_view_reset_required_height(buffer); g_buffer_view_reset_required_widths(buffer); } /****************************************************************************** * * * Paramètres : buffer = tampon à représenter à l'écran. * * widget = composant GTK de destination pour le rendu. * * * * Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GBufferView *g_buffer_view_new(GCodeBuffer *buffer) { GBufferView *result; /* Composant à retourner */ result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); g_object_ref(G_OBJECT(buffer)); result->buffer = buffer; result->start = 0; result->end = VMPA_MAX; return result; } /****************************************************************************** * * * Paramètres : view = visualisateur à mettre à jour. * * first = première ligne à imprimer. * * last = première ligne hors cadre. * * * * Description : Restreint le champ d'application de l'affichage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_restrict(GBufferView *view, vmpa_t start, vmpa_t end) { view->start = start; view->end = end; } /****************************************************************************** * * * Paramètres : view = visualisateur à mettre à jour. * * first = première ligne à imprimer ou NULL. [OUT] * * last = première ligne hors cadre ou NULL. [OUT] * * * * Description : Indique le champ d'application de l'affichage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_get_restrictions(GBufferView *view, vmpa_t *start, vmpa_t *end) { if (start != NULL) *start = view->start; if (end != NULL) *end = view->end; } /****************************************************************************** * * * Paramètres : view = visualisateur à consulter. * * * * Description : Fournit le tampon de code lié à un visualisateur donné. * * * * Retour : Tampon de code associé au gestionnaire d'affichage. * * * * Remarques : - * * * ******************************************************************************/ GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view) { return view->buffer; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * * * Description : Réinitialise le cache de la hauteur des lignes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_reset_required_height(GBufferView *view) { view->line_height = -1; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * * * Description : Réinitialise le cache des largeurs de colonne calculées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_reset_required_widths(GBufferView *view) { unsigned int i; /* Boucle de parcours */ for (i = 0; i < BLC_COUNT; i++) view->max_widths[i] = -1; } /****************************************************************************** * * * Paramètres : view = visualisation à mettre à jour. * * * * Description : Calcule la hauteur requise par une visualisation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_compute_required_height(GBufferView *view) { view->line_height = 17; } /****************************************************************************** * * * Paramètres : view = visualisation à mettre à jour. * * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * * * Description : Calcule les largeurs requises par une visualisation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_buffer_view_compute_required_widths(GBufferView *view, bool addr, bool code) { GBufferLine **lines; /* Liste des lignes à traiter */ size_t first; /* Première ligne intégrée */ size_t last; /* Dernière ligne intégrée */ size_t i; /* Boucle de parcours #1 */ unsigned int j; /* Boucle de parcours #2 */ gint width; /* Largeur d'une colonne */ BufferLineColumn merge; /* Début de fusion de colonnes */ if (!HEIGHT_CACHED(view)) g_buffer_view_compute_required_height(view); lines = view->buffer->lines; first = g_code_buffer_get_index_from_address(view->buffer, view->start); last = g_code_buffer_get_index_from_address(view->buffer, view->end); view->left_margin = 2 * view->line_height; view->left_text = 2.5 * view->line_height; view->last_width = 0; view->last_merge = BLC_INVALID; if (view->buffer->used > 0) for (i = first; i <= last; i++) { for (j = 0; j < BLC_COUNT; j++) { width = g_buffer_line_get_column_width(lines[i], j); view->max_widths[j] = MAX(view->max_widths[j], width); } width = g_buffer_line_get_merge_width(lines[i], &merge, addr, code); view->last_width = MAX(view->last_width, width); if (merge != BLC_COUNT) { if (view->last_merge == BLC_INVALID) view->last_merge = merge; else view->last_merge = MAX(view->last_merge, merge); } } if (view->last_merge == BLC_INVALID) view->last_merge = BLC_COUNT; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * * * Description : Fournit la hauteur d'impression d'une ligne visualisée. * * * * Retour : Hauteur de ligne en pixel. * * * * Remarques : - * * * ******************************************************************************/ gint g_buffer_view_get_line_height(GBufferView *view) { if (!HEIGHT_CACHED(view)) g_buffer_view_compute_required_height(view); return view->line_height; } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * width = largeur requise pour une pleine visualisation. [OUT]* * height = hauteur requise pour une pleine visualisation. [OUT]* * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * * * Description : Fournit les dimensions requises par une visualisation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_get_size(GBufferView *view, gint *width, gint *height, bool addr, bool code) { gint col_width; /* Calcul selon les colonnes */ gint full_width; /* Calcul selon les fusions */ BufferLineColumn i; /* Boucle de parcours */ size_t first; /* Première ligne intégrée */ size_t last; /* Dernière ligne intégrée */ if (!WIDTHS_CACHED(view)) g_buffer_view_compute_required_widths(view, addr, code); *width = view->left_text; *height = view->line_height; col_width = 0; full_width = 0; /* Première méthode */ for (i = 0; i < BLC_COUNT; i++) { if (i == BLC_ADDRESS && !addr) continue; if (i == BLC_BINARY && !code) continue; col_width += view->max_widths[i]; if ((i + 1) < BLC_COUNT) col_width += COL_MARGIN; } /* Seconde méthode */ for (i = 0; i < view->last_merge; i++) { if (i == BLC_ADDRESS && !addr) continue; if (i == BLC_BINARY && !code) continue; full_width += view->max_widths[i]; if ((i + 1) < view->last_merge) full_width += COL_MARGIN; } full_width += view->last_width + COL_MARGIN; /* Mise en concurrence et poursuite... */ *width += + MAX(col_width, full_width); first = g_code_buffer_get_index_from_address(view->buffer, view->start); last = g_code_buffer_get_index_from_address(view->buffer, view->end); *height *= (last - first + 1); } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * * * Description : Supprime toute mise en évidence de segments. * * * * Retour : true si un besoin d'actualisation d'affichage se fait sentir.* * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_unhighlight_segments(GBufferView *view) { GSList *iter; /* Boucle de parcours */ GBufferSegment *segment; /* Segment visé par le pointeur*/ if (g_slist_length(view->highlighted) == 0) return false; for (iter = view->highlighted; iter != NULL; iter = view->highlighted) { segment = G_BUFFER_SEGMENT(iter->data); g_buffer_segment_set_style(segment, SRS_CLASSIC); g_object_unref(G_OBJECT(segment)); view->highlighted = g_slist_remove_link(view->highlighted, iter); } return true; } /****************************************************************************** * * * Paramètres : view = vue de tampon à mettre à jour. * * x = abscisse de la zone principale à traiter. * * y = ordonnée de la zone principale à traiter. * * * * Description : Surligne tous les segments similaires à celui sous la souris.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y) { GBufferLine *line; /* Ligne sous le pointeur */ GBufferSegment *segment; /* Segment visé par le pointeur*/ bool need_redraw; /* Besoin d'actualisation ? */ size_t first; /* Première ligne intégrée */ size_t last; /* Dernière ligne intégrée */ size_t i; /* Boucle de parcours */ line = g_buffer_view_find_line_at(view, y); if (line == NULL) return; do { vmpa_t addr; addr = g_buffer_line_get_address(line); printf(" ... x2 clic at 0x%08lx\n", addr); } while (0); x -= view->left_text; if (x < 0) return; segment = g_buffer_line_get_segment_at(line, view->max_widths, x); printf(" ... seg @%d ? %p\n", x, segment); if (segment == NULL) return; printf("text :: '%s'\n", g_buffer_segment_get_text(segment)); if (view->highlighted != NULL) need_redraw = g_buffer_view_unhighlight_segments(view); else need_redraw = false; first = g_code_buffer_get_index_from_address(view->buffer, view->start); last = g_code_buffer_get_index_from_address(view->buffer, view->end); for (i = first; i < last; i++) view->highlighted = g_buffer_line_highlight_all_same_segments(view->buffer->lines[i], view->highlighted, segment); if (g_slist_length(view->highlighted) > 0) need_redraw = true; if (need_redraw) g_signal_emit_by_name(view, "need-redraw"); } /****************************************************************************** * * * Paramètres : view = visualisation à mettre à jour. * * method = procédure à appeler à chaque dessin de ligne. * * data = donnée utilisateur à passer lors des appels. * * * * Description : Définit à une procédure à appeler lors des dessins de ligne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_define_extra_drawing(GBufferView *view, buffer_line_draw_fc method, void *data) { view->drawing_extra = method; view->drawing_data = data; } /****************************************************************************** * * * Paramètres : view = visualisation à représenter. * * event = informations liées à l'événement. * * gc = contexte graphique à utiliser pour les pinceaux. * * fake_x = abscisse réelle du point 0 à l'écran. * * fake_y = ordonnée réelle du point 0 à l'écran. * * addr = indique si les positions doivent être affichées. * * code = indique si le code binaire doit être affiché. * * * * Description : Imprime la visualisation du tampon de code désassemblé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_buffer_view_draw(const GBufferView *view, const GdkEventExpose *event, GdkGC *gc, gint fake_x, gint fake_y, bool addr, bool code) { cairo_t *cairo; /* Gestionnaire de rendu */ gint real_x; /* Abscisse réelle pour tampon */ gint real_y; /* Ordonnée réelle pour tampon */ size_t first; /* Première ligne visée */ size_t end; /* Dernière ligne avant limite */ size_t last; /* Dernière ligne visée + 1 */ gint y; /* Point de départ + décallage */ GBufferLine **lines; /* Liste des lignes à traiter */ size_t i; /* Boucle de parcours */ cairo = gdk_cairo_create(event->window); gdk_cairo_region(cairo, event->region); real_x = fake_x + view->left_text; real_y = fake_y + event->area.y; first = g_code_buffer_get_index_from_address(view->buffer, view->start); first += (real_y / view->line_height); last = first + (event->area.height / view->line_height); if (event->area.height % view->line_height > 0) last++; end = g_code_buffer_get_index_from_address(view->buffer, view->end); last = MIN(last, end); y = event->area.y - (real_y % view->line_height); lines = view->buffer->lines; if (view->buffer->used > 0) for (i = first; i <= last; i++) { /* TODO : skip if... */ /* if (view->drawing_extra != NULL) view->drawing_extra(lines[i], drawable, gc, fake_x, y, view->drawing_data); */ g_buffer_line_draw(lines[i], cairo, view->fcache, view->max_widths, real_x, y, addr, code); y += view->line_height; } cairo_destroy(cairo); } /****************************************************************************** * * * Paramètres : view = visualisation à consulter. * * y = ordonnée comprise dans la ligne recherchée. * * * * Description : Fournit la ligne présente à une ordonnée donnée. * * * * Retour : Ligne retrouvée ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y) { gint lheight; /* Hauteur d'une ligne */ size_t index; /* Indice attendu */ lheight = g_buffer_view_get_line_height(view); index = y / lheight; return (index < view->buffer->used ? view->buffer->lines[index] : NULL); } /****************************************************************************** * * * Paramètres : view = composant GTK à consulter. * * addr = adresse à présenter à l'écran. * * x = position horizontale au sein du composant. [OUT] * * y = position verticale au sein du composant. [OUT] * * * * Description : Indique la position d'affichage d'une adresse donnée. * * * * Retour : true si l'adresse fait partie du composant, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_buffer_view_get_address_coordinates(GBufferView *view, vmpa_t addr, gint *x, gint *y) { gint lheight; /* Hauteur d'une ligne */ vmpa_t current; /* Adresse parcourue */ size_t first; /* Première ligne intégrée */ size_t last; /* Dernière ligne intégrée */ size_t i; /* Boucle de parcours */ *x = 0; *y = 0; lheight = g_buffer_view_get_line_height(view); current = VMPA_MAX; first = g_code_buffer_get_index_from_address(view->buffer, view->start); last = g_code_buffer_get_index_from_address(view->buffer, view->end); if (view->buffer->used > 0) for (i = first; i <= last; i++) { current = g_buffer_line_get_address(view->buffer->lines[i]); if (current == addr) break; if (current > addr) return false; *y += lheight; } return (current == addr); }