From b7347c96930027fc11b9c5038157f972d58a41bf Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 24 Mar 2017 08:38:31 +0100 Subject: Built routine digest for tooltip hints. --- ChangeLog | 22 ++++ src/analysis/routine.c | 252 +++++++++++++++++++++++++++++++++++++++++++ src/analysis/routine.h | 8 ++ src/arch/processor.c | 4 +- src/format/symbol.c | 4 + src/glibext/gbufferview.c | 64 +++++++++++ src/glibext/gbufferview.h | 4 + src/gtkext/gtkbinarystrip.c | 4 +- src/gtkext/gtkblockdisplay.c | 113 ++++++++++++++++++- 9 files changed, 470 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f41802b..d24904f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +17-03-24 Cyrille Bagard + + * src/analysis/routine.c: + * src/analysis/routine.h: + Build routine digest for tooltip hints. + + * src/arch/processor.c: + Add an assertion on provided instructions. + + * src/format/symbol.c: + Add some extra 'TODO' marks. + + * src/glibext/gbufferview.c: + * src/glibext/gbufferview.h: + Provide the GObject creator at a given location. + + * src/gtkext/gtkbinarystrip.c: + Cosmetic. + + * src/gtkext/gtkblockdisplay.c: + Show hints as tooltips. + 17-03-22 Cyrille Bagard * src/arch/post.c: diff --git a/src/analysis/routine.c b/src/analysis/routine.c index 8322acf..089d287 100644 --- a/src/analysis/routine.c +++ b/src/analysis/routine.c @@ -26,9 +26,14 @@ #include #include +#include #include +#include + + +#include "../arch/raw.h" #include "../common/extstr.h" @@ -1130,3 +1135,250 @@ void g_binary_routine_print_code(const GBinRoutine *routine, GLangOutput *lang, } #endif + + + + + +/****************************************************************************** +* * +* Paramètres : routine = routine à mettre à jour. * +* binary = informations relatives au binaire chargé. * +* * +* Description : Construit un petit résumé concis de la routine. * +* * +* Retour : Chaîne de caractères à libérer après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_binary_routine_build_tooltip(const GBinRoutine *routine, const GLoadedBinary *binary) +{ + char *result; /* Description à retourner */ + unsigned int ins_count; /* Quantité d'instructions */ + unsigned int call_count; /* Quantité d'appels */ + char *call_info; /* Détails des appels */ + unsigned int string_count; /* Quantité de chaînes */ + char *string_info; /* Détails des chaînes */ + GArchProcessor *proc; /* Architecture utilisée */ + GBufferCache *cache; /* Tampon de désassemblage */ + instr_iter_t *iter; /* Parcours local d'adresses */ + GArchInstruction *instr; /* Instruction correspondante */ + instr_link_t *dests; /* Instr. visées par une autre */ + size_t dcount; /* Nombre de liens de dest. */ + size_t i; /* Boucle de parcours */ + const mrange_t *irange; /* Emplacement d'instruction */ + size_t index; /* Indice de ligne à traiter */ + GBufferLine *line; /* Ligne présente à l'adresse */ + char *info; /* Ligne d'information créée */ + size_t blk_count; /* Nombre de blocs basiques */ + + result = NULL; + + ins_count = 0; + + call_count = 0; + call_info = NULL; + + string_count = 0; + string_info = NULL; + + proc = g_loaded_binary_get_processor(binary); + cache = g_loaded_binary_get_disassembled_cache(binary); + + /* Parcours des instructions */ + + iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(&routine->range)); + if (iter == NULL) goto gbrbt_no_iter; + + restrict_instruction_iterator(iter, &routine->range); + + for (instr = get_instruction_iterator_current(iter); + instr != NULL; + instr = get_instruction_iterator_next(iter)) + { + ins_count ++; + + /* Appels ? */ + + g_arch_instruction_rlock_dest(instr); + dcount = g_arch_instruction_get_destinations(instr, &dests); + + for (i = 0; i < dcount; i++) + switch (dests[i].type) + { + case ILT_CALL: + + call_count++; + + if (call_count > 6) + continue; + + if (call_count == 6) + { + call_info = stradd(call_info, "\n ..."); + continue; + } + + irange = g_arch_instruction_get_range(instr); + + index = g_buffer_cache_find_index_by_addr(cache, get_mrange_addr(irange), true); + + index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); + + line = g_buffer_cache_find_line_by_index(cache, index); + + if (line != NULL) + { + info = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true); + g_object_unref(G_OBJECT(line)); + } + + else + info = NULL; + + if (call_info != NULL) + call_info = stradd(call_info, "\n"); + + if (info != NULL) + { + call_info = stradd(call_info, " - "); + call_info = stradd(call_info, info); + free(info); + } + + else + call_info = stradd(call_info, " - ???"); + + break; + + case ILT_REF: + + if (!G_IS_RAW_INSTRUCTION(dests[i].linked)) + continue; + + if (!g_raw_instruction_is_string(G_RAW_INSTRUCTION(dests[i].linked))) + continue; + + string_count++; + + if (string_count > 6) + continue; + + if (string_count == 6) + { + string_info = stradd(string_info, "\n ..."); + continue; + } + + irange = g_arch_instruction_get_range(dests[i].linked); + + index = g_buffer_cache_find_index_by_addr(cache, get_mrange_addr(irange), true); + + index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); + + line = g_buffer_cache_find_line_by_index(cache, index); + + if (line != NULL) + { + info = g_buffer_line_get_text(line, BLC_ASSEMBLY, BLC_COUNT, true); + g_object_unref(G_OBJECT(line)); + } + + else + info = NULL; + + if (string_info != NULL) + string_info = stradd(string_info, "\n"); + + if (info != NULL) + { + string_info = stradd(string_info, " - "); + string_info = stradd(string_info, info); + free(info); + } + + else + string_info = stradd(string_info, " - ???"); + + break; + + default: + break; + + } + + g_arch_instruction_runlock_dest(instr); + + g_object_unref(G_OBJECT(instr)); + + } + + delete_instruction_iterator(iter); + + /* Construction du résumé */ + + if (ins_count > 1) + asprintf(&result, "%u %s, ", ins_count, _("instructions")); + else + asprintf(&result, "%u %s, ", ins_count, _("instruction")); + + blk_count = g_block_list_count_blocks(routine->blocks); + + if (blk_count > 1) + asprintf(&info, "%zu %s", blk_count, _("basic blocks")); + else + asprintf(&info, "%zu %s", blk_count, _("basic block")); + + result = stradd(result, info); + free(info); + + result = stradd(result, "\n"); + + if (call_count > 1) + asprintf(&info, "%u %s, ", call_count, _("calls")); + else + asprintf(&info, "%u %s, ", call_count, _("call")); + + result = stradd(result, info); + free(info); + + if (string_count > 1) + asprintf(&info, "%u %s", string_count, _("strings")); + else + asprintf(&info, "%u %s", string_count, _("string")); + + result = stradd(result, info); + free(info); + + if (call_count > 0) + { + result = stradd(result, "\n\n"); + result = stradd(result, call_count > 1 ? _("Calls:") : _("Call:")); + result = stradd(result, "\n"); + + result = stradd(result, call_info); + free(call_info); + + } + + if (string_count > 0) + { + result = stradd(result, "\n\n"); + result = stradd(result, string_count > 1 ? _("Strings:") : _("String:")); + result = stradd(result, "\n"); + + result = stradd(result, string_info); + free(string_info); + + } + + gbrbt_no_iter: + + g_object_unref(G_OBJECT(cache)); + g_object_unref(G_OBJECT(proc)); + + return result; + +} diff --git a/src/analysis/routine.h b/src/analysis/routine.h index aab0818..e880118 100644 --- a/src/analysis/routine.h +++ b/src/analysis/routine.h @@ -30,8 +30,10 @@ #include +#include "binary.h" #include "variable.h" #include "disass/block.h" +#include "../arch/processor.h" //#include "../arch/instruction.h" @@ -187,4 +189,10 @@ char *_g_binary_routine_to_string(const GBinRoutine *, Routine2StringOptions); + +/* Construit un petit résumé concis de la routine. */ +char *g_binary_routine_build_tooltip(const GBinRoutine *, const GLoadedBinary *); + + + #endif /* _ANALYSIS_ROUTINE_H */ diff --git a/src/arch/processor.c b/src/arch/processor.c index ba46e73..3a049b1 100644 --- a/src/arch/processor.c +++ b/src/arch/processor.c @@ -485,9 +485,9 @@ GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *proc, s assert(index < proc->instr_count); result = proc->instructions[index]; + assert(result != NULL); - if (result != NULL) - g_object_ref(G_OBJECT(result)); + g_object_ref(G_OBJECT(result)); } diff --git a/src/format/symbol.c b/src/format/symbol.c index 898ce9a..789dd86 100644 --- a/src/format/symbol.c +++ b/src/format/symbol.c @@ -645,6 +645,8 @@ GBinRoutine *g_binary_symbol_get_routine(const GBinSymbol *symbol) { /* TODO : rajouter des assert() sur le type de symbole */ + /* TODO : ref() */ + return symbol->extra.routine; } @@ -666,6 +668,8 @@ GArchInstruction *g_binary_symbol_get_instruction(const GBinSymbol *symbol) { /* TODO : rajouter des assert() sur le type de symbole */ + /* TODO : ref() */ + return symbol->extra.instr; } diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c index 6a5b6d4..e134118 100644 --- a/src/glibext/gbufferview.c +++ b/src/glibext/gbufferview.c @@ -893,6 +893,70 @@ bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection d +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse de la zone principale à traiter. * +* y = ordonnée de la zone principale à traiter. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Trouve le créateur à l'origine d'un emplacement donné. * +* * +* Retour : Créateur trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const bool *display) +{ + GObject *result; /* Trouvaille à faire remonter */ + gint text_pos; /* Abscisse de départ du texte */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + line_width_summary summary; /* Résumé concis des largeurs */ + + result = NULL; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvfc_done; + + /* Détermination de la ligne concernée */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvfc_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Recherche d'un segment et de son empreinte */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + result = g_buffer_line_get_creator_at(line, &summary, display, (gint []) { 0 }, &x, GDK_SCROLL_LEFT, false); + + g_object_unref(G_OBJECT(line)); + + gbvfc_done: + + return result; + +} + + diff --git a/src/glibext/gbufferview.h b/src/glibext/gbufferview.h index 82995d1..6336fb4 100644 --- a/src/glibext/gbufferview.h +++ b/src/glibext/gbufferview.h @@ -85,6 +85,10 @@ bool g_buffer_view_move_caret(GBufferView *, bool, GdkScrollDirection, const boo +/* Trouve le créateur à l'origine d'un emplacement donné. */ +GObject *g_buffer_view_find_creator(GBufferView *, gint, gint, const bool *); + + /* Supprime toute mise en évidence de segments. */ bool g_buffer_view_unhighlight_segments(GBufferView *); diff --git a/src/gtkext/gtkbinarystrip.c b/src/gtkext/gtkbinarystrip.c index d18a6ab..bc5a6ec 100644 --- a/src/gtkext/gtkbinarystrip.c +++ b/src/gtkext/gtkbinarystrip.c @@ -418,7 +418,9 @@ static gboolean gtk_binary_strip_query_tooltip(GtkWidget *widget, gint x, gint y g_object_unref(G_OBJECT(format)); } - else result = FALSE; + + else + result = FALSE; return result; diff --git a/src/gtkext/gtkblockdisplay.c b/src/gtkext/gtkblockdisplay.c index 26dbada..9698ee5 100644 --- a/src/gtkext/gtkblockdisplay.c +++ b/src/gtkext/gtkblockdisplay.c @@ -25,6 +25,7 @@ #include "gtkbufferdisplay-int.h" +#include "../arch/target.h" @@ -62,6 +63,9 @@ static void gtk_block_display_finalize(GtkBlockDisplay *); /* Assure la gestion des clics de souris sur le composant. */ static gboolean gtk_block_display_button_press(GtkWidget *, GdkEventButton *); +/* Prépare l'affichage d'une astuce. */ +static gboolean gtk_block_display_query_tooltip(GtkWidget *, gint, gint, gboolean, GtkTooltip *); + /* Redessine l'affichage suite à un changement visuel. */ static gboolean gtk_block_display_need_redraw(GtkBlockDisplay *, GBufferView *); @@ -104,6 +108,7 @@ static void gtk_block_display_class_init(GtkBlockDisplayClass *class) widget_class = GTK_WIDGET_CLASS(class); widget_class->button_press_event = gtk_block_display_button_press; + widget_class->query_tooltip = gtk_block_display_query_tooltip; panel_class = GTK_DISPLAY_PANEL_CLASS(class); @@ -128,7 +133,7 @@ static void gtk_block_display_class_init(GtkBlockDisplayClass *class) /****************************************************************************** * * -* Paramètres : view = composant GTK à initialiser. * +* Paramètres : display = composant GTK à initialiser. * * * * Description : Procède à l'initialisation de l'afficheur de bloc assembleur.* * * @@ -138,8 +143,13 @@ static void gtk_block_display_class_init(GtkBlockDisplayClass *class) * * ******************************************************************************/ -static void gtk_block_display_init(GtkBlockDisplay *view) +static void gtk_block_display_init(GtkBlockDisplay *display) { + GObject *object; /* Autre version de l'instance */ + + object = G_OBJECT(display); + + g_object_set(object, "has-tooltip", TRUE, NULL); } @@ -255,6 +265,105 @@ static gboolean gtk_block_display_button_press(GtkWidget *widget, GdkEventButton /****************************************************************************** * * +* 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_block_display_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard, GtkTooltip *tooltip) +{ + gboolean result; /* Bilan à retourner */ + GtkBlockDisplay *display; /* Autre version du composant */ + GtkDisplayPanel *panel; /* Version racine du composant */ + gint real_x; /* Abscisse absolue réelle */ + gint real_y; /* Ordonnée absolue réelle */ + GObject *creator; /* Origine du segment pointé */ + GBinSymbol *symbol; /* Eventuel symbole survolé */ + GTargetOperand *operand; /* Operande associé */ + phys_t diff; /* Différence avec la base */ + SymbolType stype; /* Type de symbole identifié */ + GBinRoutine *routine; /* Routine à manipuler */ + char *info; /* Information à faire paraître*/ + + if (keyboard) return FALSE; + + result = FALSE; + + display = GTK_BLOCK_DISPLAY(widget); + panel = GTK_DISPLAY_PANEL(display); + + real_x = x; + real_y = y; + gtk_display_panel_compute_real_coord(panel, &real_x, &real_y); + + creator = g_buffer_view_find_creator(GTK_BUFFER_DISPLAY(display)->view, real_x, real_y, panel->display); + + if (creator != NULL) + { + symbol = NULL; + + if (!G_IS_TARGET_OPERAND(creator)) + goto gbdqt_done; + + operand = G_TARGET_OPERAND(creator); + + symbol = g_target_operand_get_symbol(operand, &diff); + + if (symbol == NULL || diff != 0) + goto gbdqt_done; + + stype = g_binary_symbol_get_target_type(symbol); + + switch (stype) + { + case STP_ROUTINE: + case STP_ENTRY_POINT: + + routine = g_binary_symbol_get_routine(symbol); + + info = g_binary_routine_build_tooltip(routine, panel->binary); + + //g_object_unref(G_OBJECT(routine)); + + result = (info != NULL); + break; + + default: + break; + + } + + if (result) + { + gtk_tooltip_set_markup(tooltip, info); + free(info); + } + + gbdqt_done: + + if (symbol != NULL) + g_object_unref(G_OBJECT(symbol)); + + g_object_unref(creator); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : display = composant GTK d'affichage. * * view = composant GLib interne. * * * -- cgit v0.11.2-87-g4458