summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2017-03-24 07:38:31 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2017-03-24 07:38:31 (GMT)
commitb7347c96930027fc11b9c5038157f972d58a41bf (patch)
tree182ddabae529e89b28db93acb3404cd7424086ed
parent518ce6e1594ba80be4286bd3e561b0b7f73ce4b0 (diff)
Built routine digest for tooltip hints.
-rw-r--r--ChangeLog22
-rw-r--r--src/analysis/routine.c252
-rw-r--r--src/analysis/routine.h8
-rw-r--r--src/arch/processor.c4
-rw-r--r--src/format/symbol.c4
-rw-r--r--src/glibext/gbufferview.c64
-rw-r--r--src/glibext/gbufferview.h4
-rw-r--r--src/gtkext/gtkbinarystrip.c4
-rw-r--r--src/gtkext/gtkblockdisplay.c113
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 <nocbos@gmail.com>
+
+ * 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 <nocbos@gmail.com>
* 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 <malloc.h>
#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <i18n.h>
+
+
+#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 <sys/types.h>
+#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. *
* *