diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-03-08 19:30:52 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-03-08 19:30:52 (GMT) |
commit | 68bb7efaf61e4f5ca2f2cffce84995ffd667c4cc (patch) | |
tree | 9b6a6f63ee20b08d8c2ac35849ee051d61787447 /src | |
parent | dc9e68505c4cc7ad208e63dbc7d0e0e8f582d0d9 (diff) |
Handle cross references as well as entry points.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@482 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src')
28 files changed, 1030 insertions, 104 deletions
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c index de9830c..37e6996 100644 --- a/src/analysis/disass/disassembler.c +++ b/src/analysis/disass/disassembler.c @@ -262,6 +262,43 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta + + + /** + * TODO : établir les couvertures de fonctions, + * pour être en mesure de disposer de résolution de type XXX+yyy lors + * de l'établissement des liens. + */ + + + + + /* Seconde étape */ + + id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true); + + + /** + * + * Lequel choisir ??? + +G_BIN_FORMAT(disass->format) +G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary) + + */ + + + establish_links_between_instructions(*disass->instrs, G_BIN_FORMAT(disass->format), statusbar, id); + + gtk_extended_status_bar_remove(statusbar, id); + + //run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true); + + + + + + /* Septième étape */ //id = gtk_extended_status_bar_push(statusbar, _("Printing disassembled code..."), true); diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c index dc870fc..022ace3 100644 --- a/src/analysis/disass/links.c +++ b/src/analysis/disass/links.c @@ -26,9 +26,150 @@ #include "../../arch/instruction.h" +#include "../../arch/target.h" +/* Complète un désassemblage accompli pour une instruction. */ +static void convert_immediate_into_target(GArchInstruction *, size_t, GBinFormat *); + + + + + + + + +/****************************************************************************** +* * +* Paramètres : instr = instruction désassemblée à traiter. * +* index = indice de l'opérande à traiter. * +* format = accès aux données du binaire d'origine. * +* * +* Description : Complète un désassemblage accompli pour une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void convert_immediate_into_target(GArchInstruction *instr, size_t index, GBinFormat *format) +{ + GArchOperand *op; /* Opérande numérique en place */ + virt_t addr; /* Adresse visée par le saut */ + MemoryDataSize msize; /* Taille de l'opérande */ + GArchOperand *new; /* Instruction de ciblage */ + + op = g_arch_instruction_get_operand(instr, index); + if (!G_IS_IMM_OPERAND(op)) return; + + if (g_imm_operand_to_virt_t(G_IMM_OPERAND(op), &addr)) + { + msize = g_imm_operand_get_size(G_IMM_OPERAND(op)); + + new = g_target_operand_new(msize, addr); + + if (!g_target_operand_resolve(G_TARGET_OPERAND(new), format)) + g_object_unref(G_OBJECT(new)); + else + g_arch_instruction_replace_operand(instr, new, op); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction désassemblée à traiter. * +* list = ensemble d'instructions à relier. * +* format = accès aux données du binaire d'origine. * +* * +* Description : Complète un désassemblage accompli pour une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void establish_links_for_instruction(GArchInstruction *instr, GArchInstruction *list, GBinFormat *format) +{ + size_t count; /* Nombre d'opérandes présents */ + size_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande numérique en place */ + virt_t virt; /* Adresse liée à une cible */ + vmpa2t addr; /* Localisation plus complète */ + GArchInstruction *target; /* Instruction visée au final */ + + count = g_arch_instruction_count_operands(instr); + + for (i = 0; i < count; i++) + { + convert_immediate_into_target(instr, i, format); + + op = g_arch_instruction_get_operand(instr, i); + if (!G_IS_TARGET_OPERAND(op)) continue; + + virt = g_target_operand_get_addr(G_TARGET_OPERAND(op)); + init_vmpa(&addr, VMPA_NO_PHYSICAL, virt); + + target = g_arch_instruction_find_by_address(list, &addr, true); + + if (target != NULL) + g_arch_instruction_link_with(instr, target, ILT_JUMP /* FIXME */); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'instructions à relier. * +* format = accès aux données du binaire d'origine. * +* statusbar = barre de statut avec progression à mettre à jour.* +* id = identifiant du message affiché à l'utilisateur. * +* * +* Description : Etablit les liens entres les différentes lignes de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void establish_links_between_instructions(GArchInstruction *list, GBinFormat *format, GtkExtStatusBar *statusbar, bstatus_id_t id) +{ + GArchInstruction *iter; /* Boucle de parcours */ + + for (iter = list; + iter != NULL; + iter = g_arch_instruction_get_next_iter(list, iter, ~0/* FIXME */)) + { + + + establish_links_for_instruction(iter, list, format); + + + } + +} + + + + + + + + + + + + +#if 0 + /****************************************************************************** * * * Paramètres : list = ensemble d'instructions à relier. * @@ -153,3 +294,9 @@ void establish_links_between_lines(GArchInstruction *list, GBinRoutine **routine } } + + + + +#endif + diff --git a/src/analysis/disass/links.h b/src/analysis/disass/links.h index 2522e74..f4092f9 100644 --- a/src/analysis/disass/links.h +++ b/src/analysis/disass/links.h @@ -25,12 +25,22 @@ #define _ANALYSIS_DISASS_LINKS_H -#include "../routine.h" +//#include "../routine.h" +#include "../../arch/instruction.h" +#include "../../format/format.h" #include "../../gtkext/gtkextstatusbar.h" + + +/* Etablit les liens entres les différentes lignes de code. */ +void establish_links_between_instructions(GArchInstruction *, GBinFormat *, GtkExtStatusBar *, bstatus_id_t); + + + + /* Etablit les liens entres les différentes lignes de code. */ -void establish_links_between_lines(GArchInstruction *, GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t); +//void establish_links_between_lines(GArchInstruction *, GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t); diff --git a/src/arch/immediate.c b/src/arch/immediate.c index 3a3e64c..fc8e40d 100644 --- a/src/arch/immediate.c +++ b/src/arch/immediate.c @@ -858,10 +858,39 @@ static void g_imm_operand_print(const GImmOperand *operand, GBufferLine *line, A { char value[VMPA_MAX_SIZE]; /* Chaîne à imprimer */ size_t len; /* Taille de l'élément inséré */ + GBufferSegment *segment; /* Nouveau segment mis en place*/ len = g_imm_operand_to_string(operand, syntax, value); - g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_IMMEDIATE); + segment = g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_IMMEDIATE); + g_buffer_segment_set_creator(segment, G_OBJECT(operand)); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à traiter. * +* addr = valeur résultante. [OUT] * +* * +* Description : Convertit une valeur immédiate en adresse de type virt_t. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_imm_operand_to_virt_t(const GImmOperand *operand, virt_t *addr) +{ + bool result; /* Bilan à renvoyer */ + + result = !MDS_IS_SIGNED(operand->size); + + if (result) + *addr = operand->raw; + + return result; } diff --git a/src/arch/immediate.h b/src/arch/immediate.h index a0721b2..6d1d62e 100644 --- a/src/arch/immediate.h +++ b/src/arch/immediate.h @@ -108,6 +108,9 @@ bool g_imm_operand_is_negative(const GImmOperand *); /* Indique si une valeur immédiate est nulle ou non. */ bool g_imm_operand_is_null(const GImmOperand *); +/* Convertit une valeur immédiate en adresse de type virt_t. */ +bool g_imm_operand_to_virt_t(const GImmOperand *, virt_t *); + /* Convertit une valeur immédiate en adresse de type vmpa_t. */ bool g_imm_operand_to_vmpa_t(const GImmOperand *, vmpa_t *) __attribute__ ((deprecated)); diff --git a/src/arch/instruction.c b/src/arch/instruction.c index c9811cf..aced77e 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -1011,6 +1011,35 @@ GArchInstruction *g_arch_instruction_get_next_iter(const GArchInstruction *list, /****************************************************************************** * * +* Paramètres : list = liste de lignes à parcourir. * +* range = emplacement mémoire à comparer. * +* * +* Description : Recherche une instruction d'après son emplacement mémoire. * +* * +* Retour : Instruction trouvée à l'adresse donnée, NULL si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchInstruction *g_arch_instruction_find_by_range(GArchInstruction *list, const mrange_t *range) +{ + GArchInstruction *result; /* Trouvaille à retourner */ + + ainstr_list_for_each(result, list) + { + if (cmp_mrange(&result->range, range) == 0) + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : list = liste de lignes à parcourir. * * addr = position en mémoire ou physique à chercher. * * strict = définit la considération à porter à l'adresse. * @@ -1023,16 +1052,19 @@ GArchInstruction *g_arch_instruction_get_next_iter(const GArchInstruction *list, * * ******************************************************************************/ -GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *list, vmpa_t addr, bool strict) +GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *list, const vmpa2t *addr, bool strict) { GArchInstruction *result; /* Trouvaille à retourner */ + bool found; /* Bilan de comparaisons */ ainstr_list_for_each(result, list) { - if (strict && result->offset == addr) break; + if (strict) + found = (cmp_vmpa(get_mrange_addr(&result->range), addr) == 0); + else + found = mrange_contains_addr(&result->range, addr); - else if (!strict && result->offset < addr - && addr < (result->offset + result->length)) break; + if (found) break; } diff --git a/src/arch/instruction.h b/src/arch/instruction.h index f1ce67f..12cfbb9 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -218,8 +218,11 @@ GArchInstruction *g_arch_instruction_get_prev_iter(const GArchInstruction *, con /* Fournit l'élement suivant un autre pour un parcours. */ GArchInstruction *g_arch_instruction_get_next_iter(const GArchInstruction *, const GArchInstruction *, vmpa_t); +/* Recherche une instruction d'après son emplacement mémoire. */ +GArchInstruction *g_arch_instruction_find_by_range(GArchInstruction *, const mrange_t *); + /* Recherche une instruction d'après son adresse. */ -GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *, vmpa_t, bool); +GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *, const vmpa2t *, bool); diff --git a/src/arch/target.c b/src/arch/target.c index 40e9598..7509711 100644 --- a/src/arch/target.c +++ b/src/arch/target.c @@ -212,6 +212,7 @@ GArchOperand *g_target_operand_new(MemoryDataSize size, virt_t addr) static void g_target_operand_print(const GTargetOperand *operand, GBufferLine *line, AsmSyntax syntax) { const char *label; /* Etiquette liée à un symbole */ + GBufferSegment *segment; /* Nouveau segment mis en place*/ vmpa2t tmp; /* Coquille vide pour argument */ VMPA_BUFFER(value); /* Adresse brute à imprimer */ size_t len; /* Taille de l'élément inséré */ @@ -222,16 +223,19 @@ static void g_target_operand_print(const GTargetOperand *operand, GBufferLine *l g_buffer_line_insert_text(line, BLC_MAIN, "<", 1, RTT_LTGT); label = g_binary_symbol_get_label(operand->symbol); - g_buffer_line_insert_text(line, BLC_MAIN, label, strlen(label), RTT_LABEL); + segment = g_buffer_line_insert_text(line, BLC_MAIN, label, strlen(label), RTT_LABEL); + g_buffer_segment_set_creator(segment, G_OBJECT(operand)); if (operand->diff > 0) { - g_buffer_line_insert_text(line, BLC_MAIN, "+", 1, RTT_SIGNS); + segment = g_buffer_line_insert_text(line, BLC_MAIN, "+", 1, RTT_SIGNS); + g_buffer_segment_set_creator(segment, G_OBJECT(operand)); init_vmpa(&tmp, operand->diff, VMPA_NO_VIRTUAL); vmpa2_phys_to_string(&tmp, MDS_4_BITS, value, &len); - g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_LABEL); + segment = g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_LABEL); + g_buffer_segment_set_creator(segment, G_OBJECT(operand)); g_buffer_line_insert_text(line, BLC_MAIN, ">", 1, RTT_LTGT); @@ -243,7 +247,8 @@ static void g_target_operand_print(const GTargetOperand *operand, GBufferLine *l init_vmpa(&tmp, VMPA_NO_PHYSICAL, operand->addr); vmpa2_virt_to_string(&tmp, operand->size, value, &len); - g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_LABEL); + segment = g_buffer_line_insert_text(line, BLC_MAIN, value, len, RTT_LABEL); + g_buffer_segment_set_creator(segment, G_OBJECT(operand)); } diff --git a/src/dialogs/gotox.c b/src/dialogs/gotox.c index 653a969..33664d7 100644 --- a/src/dialogs/gotox.c +++ b/src/dialogs/gotox.c @@ -52,6 +52,8 @@ typedef enum _GotoXColumn } GotoXColumn; +/* Construit la fenêtre de sélection d'adresses. */ +static GtkWidget *create_gotox_dialog(GtkWindow *, GtkTreeStore **); /* Ajoute une nouvelle localisation de destination. */ static void add_new_location_to_list(GtkTreeStore *, GLoadedBinary *, const vmpa2t *, GBinSymbol *); @@ -61,9 +63,9 @@ static void add_new_location_to_list(GtkTreeStore *, GLoadedBinary *, const vmpa /****************************************************************************** * * * Paramètres : parent = fenêtre parente à surpasser. * -* binary = binaire dont les points d'entrée sont à afficher. * +* store = modèle de gestion pour les éléments de liste. [OUT] * * * -* Description : Construit la fenêtre de sélection des sections. * +* Description : Construit la fenêtre de sélection d'adresses. * * * * Retour : Adresse de la fenêtre mise en place. * * * @@ -71,7 +73,7 @@ static void add_new_location_to_list(GtkTreeStore *, GLoadedBinary *, const vmpa * * ******************************************************************************/ -GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary) +static GtkWidget *create_gotox_dialog(GtkWindow *parent, GtkTreeStore **store) { GtkWidget *result; /* Fenêtre à renvoyer */ GtkWidget *dlgvbox; /* Zone principale de la boîte */ @@ -80,15 +82,8 @@ GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary) GtkWidget *treeview; /* Affichage de la liste */ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ GtkTreeViewColumn *column; /* Colonne de la liste */ - GtkTreeStore *store; /* Modèle de gestion */ - GBinFormat *format; /* Format associé au binaire */ - GBinSymbol **symbols; /* Symboles à représenter */ - size_t sym_count; /* Qté de symboles présents */ - size_t i; /* Boucle de parcours */ - vmpa2t addr; /* Localisation de symbole */ result = gtk_dialog_new(); - gtk_window_set_title(GTK_WINDOW(result), _("Binary's entry points")); gtk_window_set_default_size(GTK_WINDOW(result), 600, 350); gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER); gtk_window_set_modal(GTK_WINDOW(result), TRUE); @@ -111,12 +106,12 @@ GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary) gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwnd), GTK_SHADOW_IN); - store = gtk_tree_store_new(GXC_COUNT, - G_TYPE_UINT64, G_TYPE_UINT64, - CAIRO_GOBJECT_TYPE_SURFACE, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + *store = gtk_tree_store_new(GXC_COUNT, + G_TYPE_UINT64, G_TYPE_UINT64, + CAIRO_GOBJECT_TYPE_SURFACE, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(*store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(treeview), TRUE); @@ -167,6 +162,40 @@ GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary) gtk_dialog_add_button(GTK_DIALOG(result), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(result), _("_Go"), GTK_RESPONSE_OK); + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : parent = fenêtre parente à surpasser. * +* binary = binaire dont les points d'entrée sont à afficher. * +* * +* Description : Construit la fenêtre de sélection des points d'entrée. * +* * +* Retour : Adresse de la fenêtre mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *create_gotox_dialog_for_entry_points(GtkWindow *parent, GLoadedBinary *binary) +{ + GtkWidget *result; /* Fenêtre à renvoyer */ + GtkTreeStore *store; /* Modèle de gestion */ + GBinFormat *format; /* Format associé au binaire */ + GBinSymbol **symbols; /* Symboles à représenter */ + size_t sym_count; /* Qté de symboles présents */ + size_t i; /* Boucle de parcours */ + vmpa2t addr; /* Localisation de symbole */ + + /* Mise en place de la boîte de dialogue */ + + result = create_gotox_dialog(parent, &store); + + gtk_window_set_title(GTK_WINDOW(result), _("Binary's entry points")); + /* Affichage de tous les points d'entrées */ format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); @@ -193,6 +222,61 @@ GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary) /****************************************************************************** * * +* Paramètres : parent = fenêtre parente à surpasser. * +* binary = binaire dont les points d'entrée sont à afficher. * +* instr = instruction de référence sur laquelle s'appuyer. * +* back = sens de la récupérations des instructions visées. * +* * +* Description : Construit la fenêtre de sélection des références croisées. * +* * +* Retour : Adresse de la fenêtre mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBinary *binary, const GArchInstruction *instr, bool back) +{ + GtkWidget *result; /* Fenêtre à renvoyer */ + GtkTreeStore *store; /* Modèle de gestion */ + GArchInstruction **list; /* Liste d'instructions */ + size_t count; /* Nombre d'éléments présents */ + size_t i; /* Boucle de parcours */ + const vmpa2t *addr; /* Adresse à considérer */ + + /* Mise en place de la boîte de dialogue */ + + result = create_gotox_dialog(parent, &store); + + if (back) + gtk_window_set_title(GTK_WINDOW(result), _("List of backward cross references")); + else + gtk_window_set_title(GTK_WINDOW(result), _("List of forward cross references")); + + /* Affichage de toutes les instructions référencées */ + + if (back) + count = g_arch_instruction_get_sources(instr, &list, NULL); + else + count = g_arch_instruction_get_destinations(instr, &list, NULL, NULL); + + for (i = 0; i < count; i++) + { + addr = get_mrange_addr(g_arch_instruction_get_range(list[i])); + + add_new_location_to_list(store, binary, addr, NULL); + + } + + g_object_unref(G_OBJECT(store)); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : store = modèle de gestionnaire pour la liste affichée. * * binary = représentation du binaire chargé en mémoire. * * addr = localisation à venir ajouter à la liste. * @@ -266,17 +350,21 @@ static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary, /* Image de représentation */ - switch (g_binary_symbol_get_target_type(symbol)) - { - case STP_ENTRY_POINT: - filename = find_pixmap_file("entrypoint.png"); - break; + if (symbol == NULL) + filename = NULL; - default: - filename = NULL; - break; + else + switch (g_binary_symbol_get_target_type(symbol)) + { + case STP_ENTRY_POINT: + filename = find_pixmap_file("entrypoint.png"); + break; - } + default: + filename = NULL; + break; + + } if (filename != NULL) { diff --git a/src/dialogs/gotox.h b/src/dialogs/gotox.h index 1153478..88d1fc9 100644 --- a/src/dialogs/gotox.h +++ b/src/dialogs/gotox.h @@ -33,8 +33,11 @@ -/* Construit la fenêtre de saut à une adresse. */ -GtkWidget *create_gotox_dialog(GtkWindow *, GLoadedBinary *); +/* Construit la fenêtre de sélection des points d'entrée. */ +GtkWidget *create_gotox_dialog_for_entry_points(GtkWindow *, GLoadedBinary *); + +/* Construit la fenêtre de sélection des références croisées. */ +GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *, GLoadedBinary *, const GArchInstruction *, bool); /* Fournit l'adresse obtenue par la saisie de l'utilisateur. */ vmpa2t *get_address_from_gotox_dialog(GtkWidget *); diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c index ac838b8..0422af5 100644 --- a/src/glibext/gbufferline.c +++ b/src/glibext/gbufferline.c @@ -1010,15 +1010,15 @@ GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *line, GSLis * * * Description : Ajoute du texte à formater dans une ligne donnée. * * * -* Retour : - * +* Retour : Portion de texte mis en place, voire NULL. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type) +GBufferSegment *g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type) { - GBufferSegment *segment; /* Portion de texte à ajouter */ + GBufferSegment *result; /* Portion de texte à renvoyer */ if (length == 0) return; @@ -1031,8 +1031,10 @@ void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const else line->last_used = column; - segment = g_buffer_segment_new(type, text, length); - g_buffer_line_add_segment(line, column, segment); + result = g_buffer_segment_new(type, text, length); + g_buffer_line_add_segment(line, column, result); + + return result; } diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h index bf703ab..3a00ce0 100644 --- a/src/glibext/gbufferline.h +++ b/src/glibext/gbufferline.h @@ -122,7 +122,7 @@ GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegm GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *, GSList *, const GBufferSegment *); /* Ajoute du texte à formater dans une ligne donnée. */ -void g_buffer_line_insert_text(GBufferLine *, BufferLineColumn, const char *, size_t, RenderingTagType); +GBufferSegment *g_buffer_line_insert_text(GBufferLine *, BufferLineColumn, const char *, size_t, RenderingTagType); /* Donne le texte représenté par une ligne de tampon. */ char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineColumn, bool); diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c index 27891a8..d25d728 100644 --- a/src/glibext/gbuffersegment.c +++ b/src/glibext/gbuffersegment.c @@ -98,6 +98,8 @@ struct _GBufferSegment { GObject parent; /* A laisser en premier */ + GObject *creator; /* Objet à l'origine du segment*/ + char *text; /* Texte brut conservé */ fnv64_t hash; /* Empreinte pour comparaisons */ @@ -131,6 +133,12 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *); /* Procède à l'initialisation d'un fragment de texte. */ static void g_buffer_segment_init(GBufferSegment *); +/* Supprime toutes les références externes. */ +static void g_buffer_segment_dispose(GBufferSegment *); + +/* Procède à la libération totale de la mémoire. */ +static void g_buffer_segment_finalize(GBufferSegment *); + /* Définit les dernières propriétés de rendu restantes. */ static void g_buffer_segment_prepare(GBufferSegment *, size_t); @@ -154,6 +162,7 @@ G_DEFINE_TYPE(GBufferSegment, g_buffer_segment, G_TYPE_OBJECT); static void g_buffer_segment_class_init(GBufferSegmentClass *class) { + GObjectClass *object; /* Autre version de la classe */ GtkStyleContext *context; /* Contexte pour les styles */ GtkWidgetPath *path; /* Chemin d'accès aux thèmes */ gchar *filename; /* Accès à une image 1x1 */ @@ -164,6 +173,11 @@ static void g_buffer_segment_class_init(GBufferSegmentClass *class) cairo_text_extents_t extents; /* Couverture des caractères */ RenderingTagType i; /* Boucle de parcours */ + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_segment_dispose; + object->finalize = (GObjectFinalizeFunc)g_buffer_segment_finalize; + /* Création d'un contexte d'accès */ path = gtk_widget_path_new(); @@ -285,6 +299,47 @@ static void g_buffer_segment_init(GBufferSegment *segment) /****************************************************************************** * * +* Paramètres : segment = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_segment_dispose(GBufferSegment *segment) +{ + if (segment->creator != NULL) + g_object_unref(segment->creator); + + G_OBJECT_CLASS(g_buffer_segment_parent_class)->dispose(G_OBJECT(segment)); + +} + + +/****************************************************************************** +* * +* Paramètres : segment = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_segment_finalize(GBufferSegment *segment) +{ + G_OBJECT_CLASS(g_buffer_segment_parent_class)->finalize(G_OBJECT(segment)); + +} + + +/****************************************************************************** +* * * Paramètres : type = propriétés de la zone de texte. * * text = chaîne de caractères à traiter. * * length = quantité de ces caractères. * @@ -359,6 +414,52 @@ static void g_buffer_segment_prepare(GBufferSegment *segment, size_t length) /****************************************************************************** * * +* Paramètres : segment = instance de segment à compléter. * +* obj = instance GLib quelconque à mémoriser. * +* * +* Description : Associe à un segment un objet GLib identifié comme créateur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_segment_set_creator(GBufferSegment *segment, GObject *obj) +{ + if (segment->creator != NULL) + g_object_unref(segment->creator); + + segment->creator = obj; + g_object_ref(obj); + +} + + +/****************************************************************************** +* * +* Paramètres : segment = instance de segment à compléter. * +* * +* Description : Renvoie vers un éventuel objet lié en tant que créateur. * +* * +* Retour : Instance GLib quelconque ou NULL si aucune référencée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_segment_get_creator(const GBufferSegment *segment) +{ + if (segment->creator != NULL) + g_object_ref(segment->creator); + + return segment->creator; + +} + + +/****************************************************************************** +* * * Paramètres : segment = fragment de texte à consulter. * * ref = segment de référence servant à la comparaison. * * * diff --git a/src/glibext/gbuffersegment.h b/src/glibext/gbuffersegment.h index ace4e42..51bfb2a 100644 --- a/src/glibext/gbuffersegment.h +++ b/src/glibext/gbuffersegment.h @@ -106,6 +106,12 @@ GType g_buffer_segment_get_type(void); /* Crée un nouveau fragment de texte avec des propriétés. */ GBufferSegment *g_buffer_segment_new(RenderingTagType, const char *, size_t); +/* Associe à un segment un objet GLib identifié comme créateur. */ +void g_buffer_segment_set_creator(GBufferSegment *, GObject *); + +/* Renvoie vers un éventuel objet lié en tant que créateur. */ +GObject *g_buffer_segment_get_creator(const GBufferSegment *); + /* Indique si les textes de deux segments sont identiques. */ bool g_buffer_segment_compare(const GBufferSegment *, const GBufferSegment *); diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c index 4b5378d..ac6e807 100644 --- a/src/glibext/gcodebuffer.c +++ b/src/glibext/gcodebuffer.c @@ -145,6 +145,7 @@ struct _GBufferView GCodeBuffer *buffer; /* Tampon de code visualisé */ vmpa_t start; /* Première ligne intégrée */ vmpa_t end; /* Dernière ligne intégrée */ + size_t first_index; /* Indice de la première ligne */ gint line_height; /* Hauteur maximale des lignes */ gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ @@ -813,6 +814,8 @@ static void g_buffer_view_class_init(GBufferViewClass *class) static void g_buffer_view_init(GBufferView *buffer) { + buffer->first_index = 0; + g_buffer_view_reset_required_height(buffer); g_buffer_view_reset_required_widths(buffer); @@ -1156,6 +1159,112 @@ gint g_buffer_view_get_height(const GBufferView *view) /****************************************************************************** * * +* Paramètres : view = visualisation à consulter. * +* x = abscisse comprise dans le segment recherché. [OUT] * +* y = ordonnée comprise dans la ligne recherchée. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* display = règles d'affichage des colonnes modulables. * +* segment = portion de texte recherchée ou NULL. [OUT] * +* * +* Description : Fournit la ligne et son segment présents à une position. * +* * +* Retour : Ligne retrouvée ou NULL si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice attendu */ + + /* Recherche d'une ligne correspondante */ + + lheight = g_buffer_view_get_line_height(view); + index = view->first_index + y / lheight; + + if (idx != NULL) + *idx = index; + + result = (index < view->buffer->used ? view->buffer->lines[index] : NULL); + + /* Recherche du segment visé éventuel */ + + if (result != NULL && segment != NULL) + { + if (*x < view->left_text) + *segment = NULL; + + else + *segment = g_buffer_line_get_segment_at(result, view->max_widths, display, x, GDK_SCROLL_LEFT, true); + + } + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* caret = position du curseur à construire. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : Adresse si une a pu être déterminée, NULL sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret) +{ + gint remaining; /* Copie de travail modifiable */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + GBufferSegment *segment; /* Segment présent sur la place*/ + + remaining = x; + + line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment); + + if (line == NULL) return NULL; + if (segment == NULL) printf(" -- no segment\n"); + if (segment == NULL) return NULL; + + + + + + printf("\n[BASE] tronc = %d reste = %d dernier = %d largeur = %d\n", + x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining), + g_buffer_segment_get_width(segment)); + + printf(" '%s'\n", g_buffer_segment_get_text(segment, false)); + + + + + caret->x = (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining); + + caret->y = (index - view->first_index) * view->line_height; + + caret->width = 2; + caret->height = view->line_height; + + return get_mrange_addr(g_buffer_line_get_range(line)); + +} + + +/****************************************************************************** +* * * Paramètres : view = vue de tampon à mettre à jour. * * line = ligne correspondant à la position. * * index = indice de cette même ligne dans le tampon. * @@ -1171,7 +1280,7 @@ gint g_buffer_view_get_height(const GBufferView *view) * * ******************************************************************************/ -const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) +const vmpa2t *g_buffer_view_compute_caret_old(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) { gint tmp_x; /* Copie de travail modifiable */ GBufferSegment *segment; /* Segment visé par le pointeur*/ @@ -1428,7 +1537,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b if (index > first) { line = view->buffer->lines[index - 1]; - result = g_buffer_view_compute_caret(view, line, index - 1, caret->x, display, caret); + result = g_buffer_view_compute_caret_old(view, line, index - 1, caret->x, display, caret); } break; @@ -1438,7 +1547,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b if (index < last) { line = view->buffer->lines[index + 1]; - result = g_buffer_view_compute_caret(view, line, index + 1, caret->x, display, caret); + result = g_buffer_view_compute_caret_old(view, line, index + 1, caret->x, display, caret); } break; @@ -1453,7 +1562,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b if (!moved && index > first) { line = view->buffer->lines[index - 1]; - result = g_buffer_view_compute_caret(view, line, index - 1, INT_MAX, display, caret); + result = g_buffer_view_compute_caret_old(view, line, index - 1, INT_MAX, display, caret); } break; @@ -1468,7 +1577,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b if (!moved && index < last) { line = view->buffer->lines[index + 1]; - result = g_buffer_view_compute_caret(view, line, index + 1, left_pos, display, caret); + result = g_buffer_view_compute_caret_old(view, line, index + 1, left_pos, display, caret); } break; @@ -1486,7 +1595,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b /* if (result && !computed) - result = g_buffer_view_compute_caret(view, caret->x, caret->y, caret, display, NULL); + result = g_buffer_view_compute_caret_old(view, caret->x, caret->y, caret, display, NULL); */ return result; diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h index 5fd4e7b..e607b9c 100644 --- a/src/glibext/gcodebuffer.h +++ b/src/glibext/gcodebuffer.h @@ -128,8 +128,14 @@ gint g_buffer_view_get_width(GBufferView *, const bool *); /* Fournit la hauteur requise par une visualisation. */ gint g_buffer_view_get_height(const GBufferView *); +/* Fournit la ligne et son segment présents à une position. */ +GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint, size_t *, const bool *, GBufferSegment **); + +/* Calcule la position idéale de curseur pour un point donné. */ +const vmpa2t *g_buffer_view_compute_caret(GBufferView *, gint, gint, const bool *, GdkRectangle *); + /* Calcule la position idéale de curseur pour un point donné. */ -const vmpa2t *g_buffer_view_compute_caret(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *); +const vmpa2t *g_buffer_view_compute_caret_old(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *) __attribute__ ((deprecated)); /* Déplace le curseur au sein d'une vue de tampon. */ const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkScrollDirection, const bool *); @@ -147,7 +153,7 @@ void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_ void g_buffer_view_export(const GBufferView *, buffer_export_context *, BufferExportType, const bool *); /* Fournit la ligne présente à une ordonnée donnée. */ -GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); +GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *) __attribute__ ((deprecated)); /* Indique la position d'affichage d'une adresse donnée. */ bool g_buffer_view_get_address_coordinates(GBufferView *, const vmpa2t *, gint *, gint *, bool); diff --git a/src/gtkext/gtkbufferview-int.h b/src/gtkext/gtkbufferview-int.h index 4f82757..a6d937b 100644 --- a/src/gtkext/gtkbufferview-int.h +++ b/src/gtkext/gtkbufferview-int.h @@ -45,7 +45,7 @@ struct _GtkBufferView gint left_text; /* Début d'impression du code */ GdkRectangle caret; /* Emplacement du curseur */ - const vmpa2t *caret_addr; /* Position mémoire du curseur */ + const vmpa2t *caret_addr; /* Position mémoire du curseur */ /* FIXME : REMME */ guint caret_timer; /* Identifiant du chronomètre */ bool show_caret; /* Bascule entre les affichages*/ diff --git a/src/gtkext/gtkbufferview.c b/src/gtkext/gtkbufferview.c index 30cf075..c7c0267 100644 --- a/src/gtkext/gtkbufferview.c +++ b/src/gtkext/gtkbufferview.c @@ -61,6 +61,9 @@ static void gtk_buffer_view_compute_scroll_inc(GtkBufferView *, gint, GtkOrienta /* Indique la position d'affichage d'une adresse donnée. */ static bool gtk_buffer_view_get_address_coordinates(const GtkBufferView *, const vmpa2t *, gint *, gint *, ScrollPositionTweak); +/* Fournit des éléments liés à la position courante dans la vue. */ +static bool gtk_buffer_view_get_position(const GtkBufferView *, GBufferLine **, GBufferSegment **); + /* Place en cache un rendu destiné à l'aperçu graphique rapide. */ static void gtk_buffer_view_cache_glance(GtkBufferView *, cairo_t *, const GtkAllocation *, double); @@ -117,6 +120,7 @@ static void gtk_buffer_view_class_init(GtkBufferViewClass *class) panel_class->compute_size = (compute_requested_size)gtk_buffer_view_compute_requested_size; panel_class->compute_inc = (compute_scroll_inc)gtk_buffer_view_compute_scroll_inc; panel_class->get_coordinates = (get_addr_coordinates_fc)gtk_buffer_view_get_address_coordinates; + panel_class->get_position = (get_view_position_fc)gtk_buffer_view_get_position; g_signal_new("caret-moved", GTK_TYPE_BUFFER_VIEW, @@ -255,7 +259,8 @@ static gboolean gtk_buffer_view_button_press(GtkWidget *widget, GdkEventButton * } else { - addr = g_buffer_view_compute_caret(view->buffer_view, line, index, real_x, pview->display, &new); + //addr = g_buffer_view_compute_caret_old(view->buffer_view, line, index, real_x, pview->display, &new); + addr = g_buffer_view_compute_caret(view->buffer_view, real_x, real_y, pview->display, &new); gtk_buffer_view_relocate_caret(view, &new, addr); } @@ -608,6 +613,40 @@ static bool gtk_buffer_view_get_address_coordinates(const GtkBufferView *view, c /****************************************************************************** * * +* Paramètres : view = composant GTK à consulter. * +* line = ligne de tampon où se trouve le curseur. [OUT] * +* segment = eventuel segment de ligne actif. [OUT] * +* * +* Description : Fournit des éléments liés à la position courante dans la vue.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool gtk_buffer_view_get_position(const GtkBufferView *view, GBufferLine **line, GBufferSegment **segment) +{ + GBufferSegment *seg; /* Segment à récupérer */ + + /* Si aucune position n'est définie... */ + if (view->caret_addr == NULL) + return false; + + *line = g_buffer_view_find_line_and_segment_at(view->buffer_view, + (gint []){ view->caret.x }, view->caret.y, NULL, + GTK_VIEW_PANEL(view)->display, &seg); + + if (segment != NULL) + *segment = seg; + + return (line != NULL); + +} + + +/****************************************************************************** +* * * Paramètres : view = composant GTK à manipuler. * * cairo = assistant pour la création de rendus. * * area = taille de la surface réduite à disposition. * diff --git a/src/gtkext/gtkviewpanel-int.h b/src/gtkext/gtkviewpanel-int.h index 90bd141..220b253 100644 --- a/src/gtkext/gtkviewpanel-int.h +++ b/src/gtkext/gtkviewpanel-int.h @@ -51,6 +51,9 @@ typedef void (* prepare_resize_fc) (GtkViewPanel *); /* Indique la position d'affichage d'une adresse donnée. */ typedef bool (* get_addr_coordinates_fc) (const GtkViewPanel *, const vmpa2t *, gint *, gint *, ScrollPositionTweak); +/* Fournit des éléments liés à la position courante dans la vue. */ +typedef bool (* get_view_position_fc) (const GtkViewPanel *, GBufferLine **, GBufferSegment **); + /* Place en cache un rendu destiné à l'aperçu graphique rapide. */ typedef void (* cache_glance_fc) (GtkViewPanel *, cairo_t *, const GtkAllocation *, double); @@ -87,6 +90,7 @@ struct _GtkViewPanelClass compute_requested_size compute_size; /* Calcul de la taille requise */ compute_scroll_inc compute_inc; /* Calcul des bonds */ get_addr_coordinates_fc get_coordinates;/* Conversion adresse <-> pos. */ + get_view_position_fc get_position; /* Indications sur la position */ }; diff --git a/src/gtkext/gtkviewpanel.c b/src/gtkext/gtkviewpanel.c index 40ae038..d434f1e 100644 --- a/src/gtkext/gtkviewpanel.c +++ b/src/gtkext/gtkviewpanel.c @@ -822,6 +822,43 @@ void gtk_view_panel_scroll_to_address(GtkViewPanel *panel, const vmpa2t *addr, S /****************************************************************************** * * +* Paramètres : panel = composant GTK à consulter. * +* line = ligne de tampon où se trouve le curseur. [OUT] * +* segment = eventuel segment de ligne actif. [OUT] * +* * +* Description : Fournit des éléments liés à la position courante dans la vue.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool gtk_view_panel_get_position(const GtkViewPanel *panel, GBufferLine **line, GBufferSegment **segment) +{ + bool result; /* Bilan de l'opération */ + + if (GTK_VIEW_PANEL_GET_CLASS(panel)->get_position == NULL) + return false; + + result = GTK_VIEW_PANEL_GET_CLASS(panel)->get_position(panel, line, segment); + + if (result) + { + g_object_ref(G_OBJECT(*line)); + + if (segment != NULL && *segment != NULL) + g_object_ref(G_OBJECT(*segment)); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : panel = composant GTK à manipuler. * * cairo = assistant pour la création de rendus. * * area = taille de la surface réduite à disposition. * diff --git a/src/gtkext/gtkviewpanel.h b/src/gtkext/gtkviewpanel.h index c733314..080ad97 100644 --- a/src/gtkext/gtkviewpanel.h +++ b/src/gtkext/gtkviewpanel.h @@ -84,6 +84,9 @@ typedef enum _ScrollPositionTweak /* S'assure qu'une adresse donnée est visible à l'écran. */ void gtk_view_panel_scroll_to_address(GtkViewPanel *, const vmpa2t *, ScrollPositionTweak); +/* Fournit des éléments liés à la position courante dans la vue. */ +bool gtk_view_panel_get_position(const GtkViewPanel *, GBufferLine **, GBufferSegment **); + /* Place en cache un rendu destiné à l'aperçu graphique rapide. */ void gtk_view_panel_cache_glance(GtkViewPanel *, cairo_t *, const GtkAllocation *, double); diff --git a/src/gui/editem-int.h b/src/gui/editem-int.h index 7dc3ad4..b76769f 100644 --- a/src/gui/editem-int.h +++ b/src/gui/editem-int.h @@ -40,6 +40,9 @@ typedef void (* update_item_binary_fc) (GEditorItem *, GLoadedBinary *); /* Réagit à un changement d'affichage principal de contenu. */ +typedef void (* manage_item_view_fc) (GEditorItem *, GtkViewPanel *, bool); + +/* Réagit à un changement d'affichage principal de contenu. */ typedef void (* update_item_view_fc) (GEditorItem *, GtkViewPanel *); /* Concentre l'attention de l'ensemble sur une adresse donnée. */ @@ -70,6 +73,7 @@ struct _GEditorItemClass GObjectClass parent; /* A laisser en premier */ update_item_binary_fc update_binary; /* Changement de binaire */ + manage_item_view_fc manage_view; /* Gestion des vues manipulées */ update_item_view_fc update_view; /* Rechargement dû à une vue */ update_item_view_fc update_content; /* Rechargement dû à un contenu*/ focus_addr_fc focus_addr; /* Prête attention à une addr. */ diff --git a/src/gui/editem.c b/src/gui/editem.c index cde5d7f..e4c74a9 100644 --- a/src/gui/editem.c +++ b/src/gui/editem.c @@ -229,6 +229,37 @@ void change_editor_items_current_binary(GObject *ref, GLoadedBinary *binary) /****************************************************************************** * * +* Paramètres : view = nouveau panneau d'affichage nouveau. * +* created = fait état d'une création ou d'une destruction. * +* * +* Description : Lance une actualisation liée à une modification du cheptel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void manage_editor_items_view(GtkViewPanel *view, bool created) +{ + GEditorItem *iter; /* Boucle de parcours */ + GEditorItemClass *klass; /* Classe correspondante */ + + editem_list_for_each(iter, _editem_list) + { + klass = G_EDITOR_ITEM_GET_CLASS(iter); + + if (klass->manage_view != NULL) + klass->manage_view(iter, view, created); + + + } + +} + + +/****************************************************************************** +* * * Paramètres : ref = espace de référencement global. * * view = nouveau panneau d'affichage actif. * * * diff --git a/src/gui/editem.h b/src/gui/editem.h index d1b91a5..827c752 100644 --- a/src/gui/editem.h +++ b/src/gui/editem.h @@ -79,6 +79,9 @@ void register_editor_item(GEditorItem *); /* Lance une actualisation du fait d'un changement de binaire. */ void change_editor_items_current_binary(GObject *, GLoadedBinary *); +/* Lance une actualisation liée à une modification du cheptel. */ +void manage_editor_items_view(GtkViewPanel *, bool); + /* Lance une actualisation du fait d'un changement de vue. */ void change_editor_items_current_view(GObject *, GtkViewPanel *); diff --git a/src/gui/menus/binary.c b/src/gui/menus/binary.c index 50a9143..c93ad57 100644 --- a/src/gui/menus/binary.c +++ b/src/gui/menus/binary.c @@ -121,7 +121,7 @@ static void mcb_binary_entry_points(GtkMenuItem *menuitem, GMenuBar *bar) ref = g_editor_item_get_global_ref(item); binary = g_editor_item_get_current_binary(item); - dialog = create_gotox_dialog(GTK_WINDOW(ref), binary); + dialog = create_gotox_dialog_for_entry_points(GTK_WINDOW(ref), binary); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { diff --git a/src/gui/menus/edition.c b/src/gui/menus/edition.c index 8893ce9..3c1d6ac 100644 --- a/src/gui/menus/edition.c +++ b/src/gui/menus/edition.c @@ -28,19 +28,27 @@ #include <i18n.h> +#include "../../arch/target.h" #include "../../dialogs/bookmark.h" #include "../../dialogs/goto.h" +#include "../../dialogs/gotox.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkbufferview.h" -/* Réagit avec le menu "Edition -> Signets -> Basculer...". */ -static void mcb_edition_bookmarks_toggle(GtkMenuItem *, GMenuBar *); - /* Réagit avec le menu "Edition -> Aller à l'adresse...". */ static void mcb_edition_goto(GtkMenuItem *, GMenuBar *); +/* Réagit avec le menu "Edition -> Suivre la référence". */ +static void mcb_edition_follow_ref(GtkMenuItem *, GMenuBar *); + +/* Réagit avec le menu "Edition -> Lister toutes les réfs...". */ +static void mcb_edition_list_xrefs(GtkMenuItem *, GMenuBar *); + +/* Réagit avec le menu "Edition -> Signets -> Basculer...". */ +static void mcb_edition_bookmarks_toggle(GtkMenuItem *, GMenuBar *); + /****************************************************************************** @@ -71,6 +79,27 @@ GtkWidget *build_menu_edition(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b menubar = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(result), menubar); + submenuitem = qck_create_menu_item(NULL, NULL, _("Go to address..."), + G_CALLBACK(mcb_edition_goto), bar); + add_accelerator_to_menu_item(submenuitem, "<Ctrl>G", accgroup); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + + submenuitem = qck_create_menu_separator(); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + + submenuitem = qck_create_menu_item(ref, "mnu_edit_follow_ref", _("Follow the reference"), + G_CALLBACK(mcb_edition_follow_ref), bar); + add_accelerator_to_menu_item(submenuitem, "Return", accgroup); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + + submenuitem = qck_create_menu_item(ref, "mnu_edit_list_xrefs", _("List all references leading to..."), + G_CALLBACK(mcb_edition_list_xrefs), bar); + add_accelerator_to_menu_item(submenuitem, "X", accgroup); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + + submenuitem = qck_create_menu_separator(); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + submenuitem = qck_create_menu_item(NULL, NULL, _("Bookmarks"), NULL, NULL); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); @@ -82,13 +111,6 @@ GtkWidget *build_menu_edition(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b add_accelerator_to_menu_item(deepmenuitem, "<Ctrl>D", accgroup); gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); - submenuitem = qck_create_menu_separator(); - gtk_container_add(GTK_CONTAINER(menubar), submenuitem); - - submenuitem = qck_create_menu_item(NULL, NULL, _("Go to address..."), - G_CALLBACK(mcb_edition_goto), bar); - add_accelerator_to_menu_item(submenuitem, "<Ctrl>G", accgroup); - gtk_container_add(GTK_CONTAINER(menubar), submenuitem); return result; @@ -100,6 +122,171 @@ GtkWidget *build_menu_edition(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b * Paramètres : menuitem = élément de menu sélectionné. * * bar = barre de menu parente. * * * +* Description : Réagit avec le menu "Edition -> Aller à l'adresse...". * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mcb_edition_goto(GtkMenuItem *menuitem, GMenuBar *bar) +{ + GObject *ref; /* Espace de référencements */ + GtkWidget *dialog; /* Boîte de dialogue à montrer */ + vmpa2t *addr; /* Adresse de destination */ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ + + ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar)); + dialog = create_goto_dialog(GTK_WINDOW(ref)); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) + { + addr = get_address_from_goto_dialog(dialog); + + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); + gtk_view_panel_scroll_to_address(vpanel, addr, SPT_CENTER); + + delete_vmpa(addr); + + } + + gtk_widget_destroy(dialog); + +} + + +/****************************************************************************** +* * +* Paramètres : menuitem = élément de menu sélectionné. * +* bar = barre de menu parente. * +* * +* Description : Réagit avec le menu "Edition -> Suivre la référence". * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mcb_edition_follow_ref(GtkMenuItem *menuitem, GMenuBar *bar) +{ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ + GBufferLine *line; /* Ligne de position courante */ + 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 */ + + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); + + if (gtk_view_panel_get_position(vpanel, &line, &segment)) + { + if (segment != NULL) + creator = g_buffer_segment_get_creator(segment); + else + creator = NULL; + + if (creator != NULL) + { + /** + * 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) + { + init_vmpa(&addr, VMPA_NO_PHYSICAL, virt); + gtk_view_panel_scroll_to_address(vpanel, &addr, SPT_CENTER); + } + + g_object_unref(creator); + + } + + if (segment != NULL) g_object_unref(G_OBJECT(segment)); + g_object_unref(G_OBJECT(line)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : menuitem = élément de menu sélectionné. * +* bar = barre de menu parente. * +* * +* Description : Réagit avec le menu "Edition -> Lister toutes les réfs...". * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mcb_edition_list_xrefs(GtkMenuItem *menuitem, GMenuBar *bar) +{ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ + GBufferLine *line; /* Ligne de position courante */ + const mrange_t *range; /* Couverture en mémoire */ + GLoadedBinary *binary; /* Représentation binaire */ + GArchInstruction *list; /* Ensemble des instructions */ + GArchInstruction *instr; /* Point de croisements */ + GObject *ref; /* Espace de référencements */ + GtkWidget *dialog; /* Boîte de dialogue à montrer */ + vmpa2t *addr; /* Adresse de destination */ + + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); + + if (gtk_view_panel_get_position(vpanel, &line, NULL)) + { + range = g_buffer_line_get_range(line); + + binary = g_editor_item_get_current_binary(G_EDITOR_ITEM(bar)); + list = g_loaded_binary_get_instructions(binary); + + instr = g_arch_instruction_find_by_range(list, range); + + ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar)); + + dialog = create_gotox_dialog_for_cross_references(GTK_WINDOW(ref), binary, instr, true); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) + { + addr = get_address_from_gotox_dialog(dialog); + + gtk_view_panel_scroll_to_address(vpanel, addr, SPT_CENTER); + + delete_vmpa(addr); + + } + + gtk_widget_destroy(dialog); + + g_object_unref(G_OBJECT(line)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : menuitem = élément de menu sélectionné. * +* bar = barre de menu parente. * +* * * Description : Réagit avec le menu "Edition -> Signets -> Basculer...". * * * * Retour : - * @@ -192,42 +379,3 @@ static void mcb_edition_bookmarks_toggle(GtkMenuItem *menuitem, GMenuBar *bar) g_object_unref(G_OBJECT(collec)); } - - -/****************************************************************************** -* * -* Paramètres : menuitem = élément de menu sélectionné. * -* bar = barre de menu parente. * -* * -* Description : Réagit avec le menu "Edition -> Aller à l'adresse...". * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void mcb_edition_goto(GtkMenuItem *menuitem, GMenuBar *bar) -{ - GObject *ref; /* Espace de référencements */ - GtkWidget *dialog; /* Boîte de dialogue à montrer */ - vmpa2t *addr; /* Adresse de destination */ - GtkViewPanel *vpanel; /* Afficheur effectif de code */ - - ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar)); - dialog = create_goto_dialog(GTK_WINDOW(ref)); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) - { - addr = get_address_from_goto_dialog(dialog); - - vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); - gtk_view_panel_scroll_to_address(vpanel, addr, SPT_CENTER); - - delete_vmpa(addr); - - } - - gtk_widget_destroy(dialog); - -} diff --git a/src/gui/menus/menubar.c b/src/gui/menus/menubar.c index 77ff7cd..cc69e0d 100644 --- a/src/gui/menus/menubar.c +++ b/src/gui/menus/menubar.c @@ -72,6 +72,9 @@ static void g_menu_bar_dispose(GMenuBar *); /* Procède à la libération totale de la mémoire. */ static void g_menu_bar_finalize(GMenuBar *); +/* Lance une actualisation liée à une modification du cheptel. */ +static void manage_view_in_menu_bar(GMenuBar *, GtkViewPanel *, bool); + /* Lance une actualisation du fait d'un changement de vue. */ static void update_menu_bar_for_view(GMenuBar *, GtkViewPanel *); @@ -108,6 +111,7 @@ static void g_menu_bar_class_init(GMenuBarClass *klass) editem = G_EDITOR_ITEM_CLASS(klass); + editem->manage_view = (manage_item_view_fc)manage_view_in_menu_bar; editem->update_view = (update_item_view_fc)update_menu_bar_for_view; editem->update_project = (update_project_fc)update_menu_bar_for_project; @@ -247,6 +251,73 @@ GEditorItem *g_menu_bar_new(GObject *ref, GtkAccelGroup *accgroup) /****************************************************************************** * * +* Paramètres : bar = barre de menus à actualiser. * +* view = nouveau panneau d'affichage nouveau. * +* created = fait état d'une création ou d'une destruction. * +* * +* Description : Lance une actualisation liée à une modification du cheptel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void manage_view_in_menu_bar(GMenuBar *bar, GtkViewPanel *view, bool created) +{ + + gboolean view_got_focus(GtkWidget *widget, GtkDirectionType dir, GObject *ref) + { + GtkWidget *item; + + item = GTK_WIDGET(g_object_get_data(ref, "mnu_edit_follow_ref")); + + gtk_widget_set_sensitive(item, TRUE); + + item = GTK_WIDGET(g_object_get_data(ref, "mnu_edit_list_xrefs")); + + gtk_widget_set_sensitive(item, TRUE); + + return FALSE; + + } + + gboolean view_lost_focus(GtkWidget *widget, GtkDirectionType dir, GObject *ref) + { + GtkWidget *item; + + item = GTK_WIDGET(g_object_get_data(ref, "mnu_edit_follow_ref")); + + gtk_widget_set_sensitive(item, FALSE); + + item = GTK_WIDGET(g_object_get_data(ref, "mnu_edit_list_xrefs")); + + gtk_widget_set_sensitive(item, FALSE); + + return FALSE; + + } + + + if (created) + { + g_signal_connect(view, "focus-in-event", G_CALLBACK(view_got_focus), G_EDITOR_ITEM(bar)->ref); + g_signal_connect(view, "focus-out-event", G_CALLBACK(view_lost_focus), G_EDITOR_ITEM(bar)->ref); + } + else + { + g_signal_handlers_disconnect_by_func(view, G_CALLBACK(view_got_focus), G_EDITOR_ITEM(bar)->ref); + g_signal_handlers_disconnect_by_func(view, G_CALLBACK(view_lost_focus), G_EDITOR_ITEM(bar)->ref); + } + + + // update_menu_view_for_view(bar->view, view, bar); + +} + + +/****************************************************************************** +* * * Paramètres : bar = barre de menus à actualiser. * * view = nouveau panneau d'affichage actif. * * * diff --git a/src/project.c b/src/project.c index c8d23f7..5786532 100644 --- a/src/project.c +++ b/src/project.c @@ -403,6 +403,8 @@ size_t g_study_project_attach_binary(GStudyProject *project, GLoadedBinary *bina break; } + manage_editor_items_view(GTK_VIEW_PANEL(view), true); + gtk_widget_show(view); loaded->views[i] = GTK_VIEW_PANEL(view); @@ -470,6 +472,9 @@ void g_study_project_detach_binary(GStudyProject *project, GLoadedBinary *binary //gtk_dock_panel_remove_item(dpanel, ditem); + + //manage_editor_items_view(GObject *ref, GtkViewPanel *view, bool created) + for (i = 0; i < project->binaries_count; i++) if (project->binaries[i]->binary == binary) break; |