From d76e89e102aacfe945b44eb3150cb9f4bbf7b613 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 6 May 2015 00:07:18 +0000 Subject: Displayed a tooltip for strings or code symbols in buffer views. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@530 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 25 ++++++ plugins/pychrysa/glibext/codebuffer.c | 2 +- src/analysis/binary.c | 2 +- src/arch/vmpa.c | 43 ++++++++++ src/arch/vmpa.h | 3 + src/dialogs/gotox.c | 2 +- src/format/format.c | 46 +++++++++++ src/format/format.h | 3 + src/glibext/gcodebuffer.c | 109 +++++++++++++++++++++--- src/glibext/gcodebuffer.h | 8 +- src/gtkext/gtkbufferview.c | 150 ++++++++++++++++++++++++++++++++++ 11 files changed, 379 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7fa5720..9137274 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +15-05-06 Cyrille Bagard + + * plugins/pychrysa/glibext/codebuffer.c: + * src/analysis/binary.c: + Update code. + + * src/arch/vmpa.c: + * src/arch/vmpa.h: + Tell if a range contains memory up to and including a given address. + + * src/dialogs/gotox.c: + Update code. + + * src/format/format.c: + * src/format/format.h: + Provide the next symbol following a given address. + + * src/glibext/gcodebuffer.c: + * src/glibext/gcodebuffer.h: + Respect the MVC design pattern a little bit more when looking for lines. + Allow to get lines by indexes. + + * src/gtkext/gtkbufferview.c: + Display a tooltip for strings or code symbols in buffer views. + 15-05-05 Cyrille Bagard * src/gtkext/gtkgraphview.c: diff --git a/plugins/pychrysa/glibext/codebuffer.c b/plugins/pychrysa/glibext/codebuffer.c index ddead68..6368ee7 100644 --- a/plugins/pychrysa/glibext/codebuffer.c +++ b/plugins/pychrysa/glibext/codebuffer.c @@ -66,7 +66,7 @@ static PyObject *py_code_buffer_find_line_by_addr(PyObject *self, PyObject *args ret = PyArg_ParseTuple(args, "K", &addr); if (!ret) Py_RETURN_NONE; - line = g_code_buffer_find_line_by_addr(buffer, addr); + line = g_code_buffer_find_line_by_addr(buffer, addr, 0, NULL); if (line == NULL) Py_RETURN_NONE; result = pygobject_new(G_OBJECT(line)); diff --git a/src/analysis/binary.c b/src/analysis/binary.c index cf01e16..b0712fd 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -850,7 +850,7 @@ static void on_binary_bookmarks_change(GDbCollection *collec, DBAction action, G addr = g_db_bookmark_get_address(bookmark); - line = g_code_buffer_find_line_by_addr(binary->disass_buffer, addr); + line = g_code_buffer_find_line_by_addr(binary->disass_buffer, addr, BLF_HAS_CODE, NULL); if (line != NULL) { diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index 67be9a9..ad4c078 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -842,6 +842,49 @@ bool mrange_contains_addr(const mrange_t *range, const vmpa2t *addr) /****************************************************************************** * * * Paramètres : range = zone mémoire à consulter. * +* addr = localisation mémoire à analyser. * +* * +* Description : Indique si une localisation est incluse dans une zone ou non.* +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mrange_contains_addr_inclusive(const mrange_t *range, const vmpa2t *addr) +{ + bool result; /* Bilan à retourner */ + int ret; /* Bilan d'une comparaison */ + phys_t diff; /* Espace entre deux adresses */ + + ret = cmp_vmpa(&range->addr, addr); + + if (ret <= -1) + { + diff = compute_vmpa_diff(&range->addr, addr); + + if (diff != VMPA_NO_PHYSICAL) + result = (diff <= range->length); + else + result = false; + + } + + else if (ret == 0) + result = true; + + else + result = false; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : range = zone mémoire à consulter. * * addr = localisation mémoire à déterminer. * * * * Description : Calcule la position extérieure final d'une couverture. * diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 675d5cb..3e0d35c 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -187,6 +187,9 @@ bool mrange_contains_mrange(const mrange_t *, const mrange_t *); /* Indique si une localisation est incluse dans une zone ou non. */ bool mrange_contains_addr(const mrange_t *, const vmpa2t *); +/* Indique si une localisation est incluse dans une zone ou non. */ +bool mrange_contains_addr_inclusive(const mrange_t *, const vmpa2t *); + /* Calcule la position extérieure final d'une couverture. */ void compute_mrange_end_addr(const mrange_t *, vmpa2t *); diff --git a/src/dialogs/gotox.c b/src/dialogs/gotox.c index fdf5e2a..00c4fd0 100644 --- a/src/dialogs/gotox.c +++ b/src/dialogs/gotox.c @@ -344,7 +344,7 @@ static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary, /* Adresse en mémoire virtuelle */ buffer = g_loaded_binary_get_disassembled_buffer(binary); - line = g_code_buffer_find_line_by_addr(buffer, addr); + line = g_code_buffer_find_line_by_addr(buffer, addr, BLF_HAS_CODE, NULL); if (line != NULL) virtual = g_buffer_line_get_text(line, BLC_VIRTUAL, BLC_VIRTUAL + 1, true); diff --git a/src/format/format.c b/src/format/format.c index 2256160..c1877d2 100644 --- a/src/format/format.c +++ b/src/format/format.c @@ -482,6 +482,8 @@ bool g_binary_format_find_symbol_at(const GBinFormat *format, const vmpa2t *addr result = false; + *symbol = NULL; /* TODO : vérifier les doublons côtés appelants */ + for (i = 0; i < format->symbols_count && !result; i++) { range = g_binary_symbol_get_range(format->symbols[i]); @@ -507,6 +509,50 @@ bool g_binary_format_find_symbol_at(const GBinFormat *format, const vmpa2t *addr * Paramètres : format = informations chargées à consulter. * * addr = adresse à cibler lors des recherches. * * symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole suivant celui lié à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_next_symbol_at(const GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + const mrange_t *range; /* Espace mémoire parcouru */ + + result = false; + + *symbol = NULL; + + for (i = 0; i < format->symbols_count && !result; i++) + { + range = g_binary_symbol_get_range(format->symbols[i]); + + if (cmp_vmpa(get_mrange_addr(range), addr) == 0 && (i + 1) < format->symbols_count) + { + *symbol = format->symbols[i + 1]; + g_object_ref(G_OBJECT(*symbol)); + + result = true; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * * diff = décallage entre l'adresse et le symbole. [OUT] * * * * Description : Recherche le symbole correspondant à une adresse. * diff --git a/src/format/format.h b/src/format/format.h index 66f014b..807e328 100644 --- a/src/format/format.h +++ b/src/format/format.h @@ -82,6 +82,9 @@ bool g_binary_format_find_symbol_by_label(const GBinFormat *, const char *, GBin /* Recherche le symbole correspondant à une adresse. */ bool g_binary_format_find_symbol_at(const GBinFormat *, const vmpa2t *, GBinSymbol **); +/* Recherche le symbole suivant celui lié à une adresse. */ +bool g_binary_format_find_next_symbol_at(const GBinFormat *, const vmpa2t *, GBinSymbol **); + /* Recherche le symbole correspondant à une adresse. */ bool g_binary_format_resolve_symbol(const GBinFormat *, const vmpa2t *, GBinSymbol **, phys_t *); diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c index 8633461..c9abf4e 100644 --- a/src/glibext/gcodebuffer.c +++ b/src/glibext/gcodebuffer.c @@ -145,8 +145,8 @@ struct _GBufferView GCodeBuffer *buffer; /* Tampon de code visualisé */ vmpa2t *start; /* Première ligne intégrée */ vmpa2t *end; /* Dernière ligne intégrée */ - size_t first_index; /* Indice de la première ligne */ - size_t last_index; /* Indice de la dernière ligne */ + size_t first_index; /* Indice de la première ligne */ /* FIXME : utiliser partout ? */ + size_t last_index; /* Indice de la dernière ligne */ /* FIXME : idem */ gint line_height; /* Hauteur maximale des lignes */ gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ @@ -744,6 +744,8 @@ GBufferLine *g_code_buffer_insert_after(GCodeBuffer *buffer, GBufferLine *line) * * * Paramètres : buffer = composant GTK à mettre à jour. * * addr = adresse où retrouver la ligne recherchée. * +* flags = propriétés à vérifier en tout ou partie. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * * * * Description : Retrouve une ligne au sein d'un tampon avec une adresse. * * * @@ -753,7 +755,7 @@ GBufferLine *g_code_buffer_insert_after(GCodeBuffer *buffer, GBufferLine *line) * * ******************************************************************************/ -GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vmpa2t *addr) +GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) { GBufferLine *result; /* Instance à retourner */ size_t index; /* Indice de la ligne visée */ @@ -765,18 +767,24 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vm else { + if (idx != NULL) + *idx = index; + result = buffer->lines[index]; - while ((g_buffer_line_get_flags(result) & BLF_HAS_CODE) == 0) - { - if ((index + 1) == buffer->used) break; + if (flags != BLF_NONE) + while ((g_buffer_line_get_flags(result) & flags) == 0) + { + if ((index + 1) == buffer->used) break; - /* FIXME : vérifier que l'adresse est toujours celle recherchée ! */ - /* TODO : passer la recherche de code en option via argument ? */ + /* FIXME : vérifier que l'adresse est toujours celle recherchée ! */ - result = buffer->lines[++index]; + if (idx != NULL) + (*idx)++; - } + result = buffer->lines[++index]; + + } g_object_ref(G_OBJECT(result)); @@ -1943,6 +1951,87 @@ void g_buffer_view_export(const GBufferView *view, buffer_export_context *ctx, B /****************************************************************************** * * +* Paramètres : view = visualisation à consulter. * +* addr = adresse où retrouver la ligne recherchée. * +* flags = propriétés à vérifier en tout ou partie. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* * +* 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_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + phys_t length; /* Taille de la vue */ + mrange_t vrange; /* Couverture de la vue */ + bool allowed; /* Rechercher validée ? */ + + /* Vérification des bornes */ + + if (view->start != NULL/* && view->end != NULL*/) + { + length = compute_vmpa_diff(view->start, view->end); + + init_mrange(&vrange, view->start, length); + + allowed = mrange_contains_addr_inclusive(&vrange, addr); + + } + else allowed = true; + + /* Lancement des recherches ? */ + + if (allowed) + result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* index = indice de la ligne recherchée. * +* * +* Description : Retrouve une ligne au sein d'un tampon avec un indice. * +* * +* Retour : Line retrouvée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + bool allowed; /* Rechercher validée ? */ + + /* Vérification des bornes */ + + allowed = (view->first_index <= index && index < view->last_index); + + /* Lancement des recherches ? */ + + if (allowed) + result = view->buffer->lines[index]; + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : view = visualisation à consulter. * * y = ordonnée comprise dans la ligne recherchée. * * idx = indice de la ligne trouvée ou NULL. [OUT] * diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h index a248df3..652ea23 100644 --- a/src/glibext/gcodebuffer.h +++ b/src/glibext/gcodebuffer.h @@ -70,7 +70,7 @@ GBufferLine *g_code_buffer_insert_at(GCodeBuffer *, vmpa_t, bool); GBufferLine *g_code_buffer_insert_after(GCodeBuffer *, GBufferLine *); /* Retrouve une ligne au sein d'un tampon avec une adresse. */ -GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t *); +GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t *, BufferLineFlags, size_t *); /* Augmente l'indentation des prochaines lignes. */ void g_code_buffer_inc_indentation(GCodeBuffer *); @@ -152,6 +152,12 @@ void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_ /* Exporte le contenu du tampon de code désassemblé. */ void g_buffer_view_export(const GBufferView *, buffer_export_context *, BufferExportType, const bool *); +/* Retrouve une ligne au sein d'un tampon avec une adresse. */ +GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *, const vmpa2t *, BufferLineFlags, size_t *); + +/* Retrouve une ligne au sein d'un tampon avec un indice. */ +GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *, size_t ); + /* Fournit la ligne présente à une ordonnée donnée. */ GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *) __attribute__ ((deprecated)); diff --git a/src/gtkext/gtkbufferview.c b/src/gtkext/gtkbufferview.c index 86a738a..8e4ffd4 100644 --- a/src/gtkext/gtkbufferview.c +++ b/src/gtkext/gtkbufferview.c @@ -27,6 +27,8 @@ #include +#include "../arch/target.h" +#include "../common/extstr.h" #include "../core/params.h" #include "../glibext/chrysamarshal.h" @@ -59,6 +61,9 @@ static gboolean gtk_buffer_view_draw(GtkWidget *, cairo_t *); /* Prend en compte une frappe de touche sur le composant. */ static gboolean gtk_buffer_view_key_press(GtkWidget *, GdkEventKey *); +/* Prépare l'affichage d'une astuce. */ +static gboolean gtk_buffer_view_query_tooltip(GtkWidget *, gint, gint, gboolean, GtkTooltip *); + /* Indique les dimensions de travail du composant d'affichage. */ static void gtk_buffer_view_compute_requested_size(GtkBufferView *, gint *, gint *); @@ -135,6 +140,7 @@ static void gtk_buffer_view_class_init(GtkBufferViewClass *class) widget_class->button_press_event = gtk_buffer_view_button_press; widget_class->draw = gtk_buffer_view_draw; widget_class->key_press_event = gtk_buffer_view_key_press; + widget_class->query_tooltip = gtk_buffer_view_query_tooltip; panel_class->compute_size = (compute_requested_size_fc)gtk_buffer_view_compute_requested_size; panel_class->compute_inc = (compute_scroll_inc_fc)gtk_buffer_view_compute_scroll_inc; @@ -176,6 +182,12 @@ static void gtk_buffer_view_class_init(GtkBufferViewClass *class) static void gtk_buffer_view_init(GtkBufferView *view) { + GObject *object; /* Autre version de l'instance */ + + object = G_OBJECT(view); + + g_object_set(object, "has-tooltip", TRUE, NULL); + view->caret.x = 10; view->caret.y = 10; view->caret.width = 100; @@ -484,7 +496,145 @@ static gboolean gtk_buffer_view_key_press(GtkWidget *widget, GdkEventKey *event) } +/****************************************************************************** +* * +* Paramètres : widget = composant GTK visé par l'opération. * +* x = abscisse de la position du message. * +* y = ordonnée de la position du message. * +* keyboard = indique une demande suite à obtiention du focus. * +* tooltip = astuce à compléter. [OUT] * +* * +* Description : Prépare l'affichage d'une astuce. * +* * +* Retour : TRUE pour un affichage validé, FALSE sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean gtk_buffer_view_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard, GtkTooltip *tooltip) +{ + GtkBufferView *view; /* Autre version du composant */ + gint real_x; /* Abscisse absolue réelle */ + gint real_y; /* Ordonnée absolue réelle */ + GBufferLine *line; /* Ligne en cours de survol */ + GBufferSegment *segment; /* Segment actif s'il existe */ + GObject *creator; /* Créateur à l'orgine du seg. */ + virt_t virt; /* Adresse virtuelle */ + vmpa2t addr; /* Adresse de destination */ + GBinFormat *format; /* Format du fichier binaire */ + GBinSymbol *target_sym; /* Symbole présent à l'adresse */ + GBinSymbol *next_sym; /* Symbole suivant l'adresse */ + const vmpa2t *stop_addr; /* Adresse associée, pour fin */ + const mrange_t *lrange; /* Couverture d'une ligne */ + size_t count; /* Nbre de lignes max à traiter*/ + char *markup; /* Description à construire */ + size_t i; /* Boucle de parcours */ + size_t index; /* Indice d'une ligne imprimée */ + char *text; /* Contenu à ajouter */ + + if (keyboard) return FALSE; + + view = GTK_BUFFER_VIEW(widget); + + /* Récupération de la destination pointée */ + + real_x = x; + real_y = y; + gtk_view_panel_compute_real_coord(GTK_VIEW_PANEL(view), &real_x, &real_y); + + + line = g_buffer_view_find_line_and_segment_at(view->buffer_view, + &real_x, real_y, NULL, + GTK_VIEW_PANEL(view)->display, &segment); + + if (line == NULL || segment == NULL) goto no_tooltip; + + creator = g_buffer_segment_get_creator(segment); + if (creator == NULL) goto no_tooltip; + + /** + * On fait le pari de reposer uniquement sur des adresses virtuelles ! + * A changer dans un futur ? + */ + + virt = VMPA_NO_VIRTUAL; + + if (G_IS_TARGET_OPERAND(creator)) + virt = g_target_operand_get_addr(G_TARGET_OPERAND(creator)); + + else if (G_IS_IMM_OPERAND(creator)) + { + if (!g_imm_operand_to_virt_t(G_IMM_OPERAND(creator), &virt)) + virt = VMPA_NO_VIRTUAL; + } + + if (virt == VMPA_NO_VIRTUAL) goto no_tooltip; + + init_vmpa(&addr, VMPA_NO_PHYSICAL, virt); + + /* Construction du contenu textuel */ + + format = G_BIN_FORMAT(g_loaded_binary_get_format(GTK_VIEW_PANEL(view)->binary)); + + if (!g_binary_format_find_symbol_at(format, &addr, &target_sym)) + goto no_tooltip; + + g_object_unref(G_OBJECT(target_sym)); + + /* Construction du contenu textuel */ + + if (g_binary_format_find_next_symbol_at(format, &addr, &next_sym)) + stop_addr = get_mrange_addr(g_binary_symbol_get_range(next_sym)); + + count = 4; + + markup = NULL; + + for (i = 0, line = g_buffer_view_find_line_by_addr(view->buffer_view, &addr, BLF_NONE, &index); + i < count && line != NULL; + i++, line = g_buffer_view_find_line_by_index(view->buffer_view, index + i)) + { + + /* Si on commence à marcher sur les plates-bandes du symbole suivant... */ + if (next_sym != NULL) + { + lrange = g_buffer_line_get_range(line); + + if (mrange_contains_addr(lrange, stop_addr)) + break; + + } + + text = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true); + + if (markup != NULL) + markup = stradd(markup, "\n"); + + if (text != NULL) + markup = stradd(markup, text); + + free(text); + + } + + if (next_sym != NULL) + g_object_unref(G_OBJECT(next_sym)); + + if (markup == NULL) goto no_tooltip; + /* Impression finale */ + + gtk_tooltip_set_markup(tooltip, markup); + free(markup); + + return TRUE; + + no_tooltip: + + return FALSE; + +} /****************************************************************************** -- cgit v0.11.2-87-g4458