From b639c1f4abca32152bf88f8fd47a9cd114da701b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 22 Feb 2015 11:35:09 +0000
Subject: Created a dialog box to select an entry point to display.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@476 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                             |  35 ++++
 plugins/pychrysa/glibext/bufferline.c |   2 +-
 src/arch/instruction.c                |   2 +
 src/arch/vmpa.c                       |  41 ++++
 src/arch/vmpa.h                       |  19 ++
 src/dialogs/Makefile.am               |   1 +
 src/dialogs/gotox.c                   | 367 ++++++++++++++++++++++++++++++++++
 src/dialogs/gotox.h                   |  44 ++++
 src/glibext/gbinportion.c             |  15 +-
 src/glibext/gbufferline.c             |  56 +++++-
 src/glibext/gbufferline.h             |  10 +-
 src/glibext/gbuffersegment.c          |  76 ++++++-
 src/glibext/gbuffersegment.h          |   2 +-
 src/glibext/gcodebuffer.c             |  90 ++++++++-
 src/glibext/gcodebuffer.h             |   2 +-
 src/gui/menus/binary.c                |  57 ++++++
 16 files changed, 790 insertions(+), 29 deletions(-)
 create mode 100644 src/dialogs/gotox.c
 create mode 100644 src/dialogs/gotox.h

diff --git a/ChangeLog b/ChangeLog
index 5949c37..6ebe5de 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+15-02-22  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/glibext/bufferline.c:
+	Update code.
+
+	* src/arch/instruction.c:
+	Mark buffer lines as containing code.
+
+	* src/arch/vmpa.c:
+	* src/arch/vmpa.h:
+	Provide helpers for dealing with GLib. Convert locations into names and offsets.
+
+	* src/dialogs/gotox.c:
+	* src/dialogs/gotox.h:
+	Nen entries: create a dialog box to select an entry point to display.
+
+	* src/dialogs/Makefile.am:
+	Add the 'gotox.[ch]' files to libdialogs_la_SOURCES.
+
+	* src/glibext/gbinportion.c:
+	Update code.
+
+	* src/glibext/gbufferline.c:
+	* src/glibext/gbufferline.h:
+	* src/glibext/gbuffersegment.c:
+	* src/glibext/gbuffersegment.h:
+	Export parts of line content as text using optional markup.
+
+	* src/glibext/gcodebuffer.c:
+	* src/glibext/gcodebuffer.h:
+	Look for the first code lines located at a given address. Update code.
+
+	* src/gui/menus/binary.c:
+	Add a menu entry to select one binary entry.
+
 15-02-18  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/disass/area.c:
diff --git a/plugins/pychrysa/glibext/bufferline.c b/plugins/pychrysa/glibext/bufferline.c
index e4b7216..d5b8b13 100644
--- a/plugins/pychrysa/glibext/bufferline.c
+++ b/plugins/pychrysa/glibext/bufferline.c
@@ -61,7 +61,7 @@ static PyObject *py_buffer_line_get_text(PyObject *self, PyObject *args)
     char *text;                             /* Texte reconstruit à libérer */
 
     line = G_BUFFER_LINE(pygobject_get(self));
-    text = g_buffer_line_get_text(line);
+    text = "";//g_buffer_line_get_text(line);
 
     result = PyString_FromString(text);
 
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index 67fd184..c9811cf 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -792,6 +792,8 @@ static GBufferLine *_g_arch_instruction_print(const GArchInstruction *instr, GCo
 
     result = g_code_buffer_append_new_line(buffer, &instr->range);
 
+    g_buffer_line_add_flag(result, BLF_HAS_CODE);
+
     g_buffer_line_fill_for_instr(result, msize/* TODO ! */, msize,
                                  content, get_mrange_length(&instr->range), true);
 
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index c479319..67be9a9 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -641,6 +641,47 @@ bool prepare_vmpa_db_statement(const vmpa2t *addr, bool create, bound_value **va
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                          AIDES FONCTIONNELLES AUXILIAIRES                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : label  = désignation humaine d'unn symbole de base.          *
+*                offset = décalage déterminé à faie apparaître au besoin.     *
+*                                                                             *
+*  Description : Construit une désignation de symbole avec décalage.          *
+*                                                                             *
+*  Retour      : Chaîne de caractères constituée à libérer après usage.       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *make_symbol_offset(const char *label, phys_t offset)
+{
+    char *result;                           /* Construction à retourner    */
+    size_t length;                          /* Taille de désignation créée */
+
+    if (offset == 0)
+        result = strdup(label);
+
+    else
+    {
+        length = strlen(label) + 1 + VMPA_MAX_LEN + 1;
+        result = (char *)calloc(length, sizeof(char));
+
+        snprintf(result, length, "%s+0x%llx", label, (unsigned long long)offset);
+
+    }
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                          DEFINITION D'UNE ZONE EN MEMOIRE                          */
 /* ---------------------------------------------------------------------------------- */
 
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index ec356c8..675d5cb 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -52,6 +52,17 @@
 #define phys_t off_t
 #define virt_t uint64_t
 
+/* Equivalents pour GLib */
+#define G_TYPE_PHYS uint64_t
+#define G_TYPE_VIRT uint64_t
+#define G_TYPE_PHYS_T G_TYPE_UINT64
+#define G_TYPE_VIRT_T G_TYPE_UINT64
+
+
+#define PHYS_CAST(v) ((uint64_t)v)
+#define VIRT_CAST(v) ((uint64_t)v)
+
+
 #define VMPA_NO_PHYSICAL ((phys_t)-1)
 #define VMPA_NO_VIRTUAL ((virt_t)-2)
 
@@ -137,6 +148,14 @@ bool prepare_vmpa_db_statement(const vmpa2t *, bool, bound_value **, size_t *);
 
 
 
+/* ------------------------ AIDES FONCTIONNELLES AUXILIAIRES ------------------------ */
+
+
+/* Construit une désignation de symbole avec décalage. */
+char *make_symbol_offset(const char *, phys_t);
+
+
+
 /* ------------------------ DEFINITION D'UNE ZONE EN MEMOIRE ------------------------ */
 
 
diff --git a/src/dialogs/Makefile.am b/src/dialogs/Makefile.am
index 54b6fa2..1fe821a 100644
--- a/src/dialogs/Makefile.am
+++ b/src/dialogs/Makefile.am
@@ -6,6 +6,7 @@ libdialogs_la_SOURCES =					\
 	bookmark.h bookmark.c				\
 	export.h export.c					\
 	goto.h goto.c						\
+	gotox.h gotox.c						\
 	plugins.h plugins.c					\
 	shellcode.h shellcode.c				\
 	storage.h storage.c
diff --git a/src/dialogs/gotox.c b/src/dialogs/gotox.c
new file mode 100644
index 0000000..653a969
--- /dev/null
+++ b/src/dialogs/gotox.c
@@ -0,0 +1,367 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * goto.c - boîte de dialogue pour les sauts à une adresse donnée
+ *
+ * Copyright (C) 2012-2014 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gotox.h"
+
+
+#include <cairo-gobject.h>
+#include <malloc.h>
+
+
+#include <i18n.h>
+
+
+#include "../gtkext/easygtk.h"
+#include "../gtkext/support.h"
+
+
+
+/* Colonnes de la liste des symboles */
+typedef enum _GotoXColumn
+{
+    GXC_PHYSICAL,                           /* Correspondance physique     */
+    GXC_VIRTUAL,                            /* Correspondance virtuelle    */
+
+    GXC_PICTURE,                            /* Image de représentation     */
+    GXC_ADDRESS,                            /* Adresse mémoire du symbole  */
+    GXC_NAME,                               /* Désignation humaine         */
+    GXC_CONTENT,                            /* Contenu de la ligne visée   */
+
+    GXC_COUNT                               /* Nombre de colonnes          */
+
+} GotoXColumn;
+
+
+
+/* Ajoute une nouvelle localisation de destination. */
+static void add_new_location_to_list(GtkTreeStore *, GLoadedBinary *, const vmpa2t *, GBinSymbol *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  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 sections.              *
+*                                                                             *
+*  Retour      : Adresse de la fenêtre mise en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *create_gotox_dialog(GtkWindow *parent, GLoadedBinary *binary)
+{
+    GtkWidget *result;                      /* Fenêtre à renvoyer          */
+    GtkWidget *dlgvbox;                     /* Zone principale de la boîte */
+    GtkWidget *vbox;                        /* Support à construire #1     */
+    GtkWidget *scrollwnd;                   /* Support défilant            */
+    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);
+    gtk_window_set_type_hint(GTK_WINDOW(result), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+    dlgvbox = gtk_dialog_get_content_area(GTK_DIALOG(result));
+    gtk_widget_show(dlgvbox);
+
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
+    gtk_widget_show(vbox);
+    gtk_box_pack_start(GTK_BOX(dlgvbox), vbox, TRUE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
+
+    /* Liste arborescente ou linéaire */
+
+    scrollwnd = gtk_scrolled_window_new(NULL, NULL);
+    gtk_widget_show(scrollwnd);
+    gtk_box_pack_start(GTK_BOX(vbox), scrollwnd, TRUE, TRUE, 0);
+
+    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);
+
+    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);
+
+    g_object_set_data(G_OBJECT(result), "treeview", treeview);
+
+    gtk_widget_show(treeview);
+    gtk_container_add(GTK_CONTAINER(scrollwnd), treeview);
+
+    /* Cellules d'affichage */
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(_("Address"), renderer,
+                                                      "markup", GXC_ADDRESS,
+                                                      NULL);
+    gtk_tree_view_column_set_sort_column_id(column, GXC_ADDRESS);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    column = gtk_tree_view_column_new();
+
+    gtk_tree_view_column_set_title(column, _("Name"));
+
+    renderer = gtk_cell_renderer_pixbuf_new();
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_set_attributes(column, renderer,
+                                        "surface", GXC_PICTURE,
+                                        NULL);
+
+    g_object_set(G_OBJECT(renderer), "xpad", 4, NULL);
+
+    renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_set_attributes(column, renderer,
+                                        "text", GXC_NAME,
+                                        NULL);
+
+    gtk_tree_view_column_set_sort_column_id(column, GXC_NAME);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(_("Content"), renderer,
+                                                      "markup", GXC_CONTENT,
+                                                      NULL);
+    gtk_tree_view_column_set_sort_column_id(column, GXC_CONTENT);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+    /* Zone de validation */
+
+    gtk_dialog_add_button(GTK_DIALOG(result), _("_Cancel"), GTK_RESPONSE_CANCEL);
+    gtk_dialog_add_button(GTK_DIALOG(result), _("_Go"), GTK_RESPONSE_OK);
+
+    /* Affichage de tous les points d'entrées */
+
+    format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+    symbols = g_binary_format_get_symbols(format, &sym_count);
+
+    for (i = 0; i < sym_count; i++)
+    {
+        if (g_binary_symbol_get_target_type(symbols[i]) != STP_ENTRY_POINT)
+            continue;
+
+        copy_vmpa(&addr, get_mrange_addr(g_binary_symbol_get_range(symbols[i])));
+
+        add_new_location_to_list(store, binary, &addr, symbols[i]);
+
+    }
+
+    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.            *
+*                hint   = éventuel symbole à venir retrouver à l'adresse.     *
+*                                                                             *
+*  Description : Ajoute une nouvelle localisation de destination.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary, const vmpa2t *addr, GBinSymbol *hint)
+{
+    GCodeBuffer *buffer;                    /* Tampon de désassemblage     */
+    GBufferLine *line;                      /* Ligne présente à l'adresse  */
+    char *virtual;                          /* Transcription d'adresse     */
+    const char *label;                      /* Etiquette de symbole trouvé */
+    GBinFormat *format;                     /* Format associé au binaire   */
+    GBinSymbol *symbol;                     /* Symbole associé à l'adresse */
+    phys_t diff;                            /* Décalage vis à vis du début */
+    char *name;                             /* Désignation humaine         */
+    gchar *filename;                        /* Chemin d'accès à utiliser   */
+    cairo_surface_t *icon;                  /* Image pour les symboles     */
+    char *content;                          /* Contenu de la ligne visée   */
+    GtkTreeIter iter;                       /* Point d'insertion           */
+
+    /* Adresse en mémoire virtuelle */
+
+    buffer = g_loaded_binary_get_disassembled_buffer(binary);
+    line = g_code_buffer_find_line_by_addr(buffer, addr);
+
+    if (line != NULL)
+        virtual = g_buffer_line_get_text(line, BLC_VIRTUAL, BLC_VIRTUAL + 1, true);
+    else
+        virtual = strdup(_("<line address not found>"));
+
+    /* Désignation humaine de l'adresse */
+
+    if (hint != NULL)
+    {
+        symbol = hint;
+        g_object_ref(G_OBJECT(symbol));
+
+        label = g_binary_symbol_get_label(hint);
+
+        name = make_symbol_offset(label, 0);
+
+    }
+    else
+    {
+        format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+        if (g_binary_format_resolve_symbol(format, addr, &symbol, &diff))
+        {
+            label = g_binary_symbol_get_label(symbol);
+
+            name = make_symbol_offset(label, diff);
+
+        }
+        else
+        {
+            symbol = NULL;
+
+            name = strdup(_("<no symbol found>"));
+
+        }
+
+    }
+
+    /* Image de représentation */
+
+    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)
+    {
+        icon = cairo_image_surface_create_from_png(filename);
+        g_free(filename);
+    }
+    else
+        icon = NULL;
+
+    /* Contenu d'assemblage */
+
+    if (line != NULL)
+        content = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true);
+    else
+        content = strdup(_("<assembly line not found>"));
+
+    /* Insertion finale */
+
+    gtk_tree_store_append(store, &iter, NULL);
+
+    gtk_tree_store_set(store, &iter,
+                       GXC_PHYSICAL, PHYS_CAST(get_phy_addr(addr)),
+                       GXC_VIRTUAL, VIRT_CAST(get_virt_addr(addr)),
+                       GXC_PICTURE, icon,
+                       GXC_ADDRESS, virtual,
+                       GXC_NAME, name,
+                       GXC_CONTENT, content,
+                       -1);
+
+    if (symbol != NULL)
+        g_object_unref(G_OBJECT(symbol));
+
+    if (virtual != NULL) free(virtual);
+    if (icon != NULL) cairo_surface_destroy(icon);
+    free(name);
+    if (content != NULL) free(content);
+
+    if (line != NULL)
+        g_object_unref(G_OBJECT(line));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dialog = boîte de dialogue ayant reçu une validation.        *
+*                                                                             *
+*  Description : Fournit l'adresse obtenue par la saisie de l'utilisateur.    *
+*                                                                             *
+*  Retour      : Adresse reccueillie par la boîte de dialogue ou NULL si rien.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+vmpa2t *get_address_from_gotox_dialog(GtkWidget *dialog)
+{
+    vmpa2t *result;                         /* Adresse à retourner         */
+    GtkTreeView *treeview;                  /* Liste d'adresses à lire     */
+    GtkTreeSelection *selection;            /* Sélection courante          */
+    GtkTreeModel *model;                    /* Modèle de gestionnaire      */
+    GList *selected;                        /* Liste des sélections        */
+    GtkTreeIter iter;                       /* Tête de lecture             */
+    G_TYPE_PHYS phys;                       /* Position physique           */
+    G_TYPE_VIRT virt;                       /* Adresse virtuelle           */
+
+    treeview = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(dialog), "treeview"));
+
+    selection = gtk_tree_view_get_selection(treeview);
+
+    selected = gtk_tree_selection_get_selected_rows(selection, &model);
+    if (selected == NULL) return NULL;
+
+    if (!gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)selected->data))
+        return NULL;
+
+    gtk_tree_model_get(model, &iter,
+                       GXC_PHYSICAL, &phys,
+                       GXC_VIRTUAL, &virt,
+                       -1);
+
+    result = make_vmpa(phys, virt);
+
+    g_list_free_full(selected, (GDestroyNotify)gtk_tree_path_free);
+
+    return result;
+
+}
diff --git a/src/dialogs/gotox.h b/src/dialogs/gotox.h
new file mode 100644
index 0000000..1153478
--- /dev/null
+++ b/src/dialogs/gotox.h
@@ -0,0 +1,44 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * goto.h - prototypes pour la boîte de dialogue pour les sauts à une adresse donnée
+ *
+ * Copyright (C) 2012 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DIALOGS_GOTOX_H
+#define _DIALOGS_GOTOX_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../analysis/binary.h"
+#include "../arch/vmpa.h"
+
+
+
+/* Construit la fenêtre de saut à une adresse. */
+GtkWidget *create_gotox_dialog(GtkWindow *, GLoadedBinary *);
+
+/* Fournit l'adresse obtenue par la saisie de l'utilisateur. */
+vmpa2t *get_address_from_gotox_dialog(GtkWidget *);
+
+
+
+#endif  /* _DIALOGS_GOTOX_H */
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 1fbb460..16f4814 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -699,18 +699,21 @@ bool g_binary_portion_get_pos_from_addr(GBinPortion *portion, const vmpa2t *addr
 
 void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, MemoryDataSize msize)
 {
+    mrange_t range;                         /* Couverture à fournir        */
     GBufferLine *line;                      /* Nouvelle ligne à éditer     */
     char rights[64];                        /* Traduction en texte         */
 
     /* On ne traite pas les portions anonymes ! */
     if (portion->desc == NULL) return;
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    init_mrange(&range, get_mrange_addr(&portion->range), 0);
+
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
     /* Séparation */
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
     g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
@@ -719,7 +722,7 @@ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, Mem
 
     /* Retour à la ligne */
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
     g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
@@ -727,7 +730,7 @@ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, Mem
 
     /* Description */
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
     g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
@@ -746,13 +749,13 @@ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, Mem
 
     /* Retour à la ligne */
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
     g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
     g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
 
-    line = g_code_buffer_append_new_line(buffer, &portion->range);
+    line = g_code_buffer_append_new_line(buffer, &range);
     g_buffer_line_fill_mrange(line, msize, msize);
 
 }
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 824578d..ff64604 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -24,6 +24,7 @@
 #include "gbufferline.h"
 
 
+#include <assert.h>
 #include <string.h>
 #include <gtk/gtk.h>    /* Récupération du langage par défaut ; FIXME ? */
 
@@ -834,7 +835,7 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
     if (result == NULL)
         printf(" -- get segment at -- found nothing...\n");
     else
-        printf(" -- get segment at -- found %p '%s'...\n", result, g_buffer_segment_get_text(result));
+        printf(" -- get segment at -- found %p '%s'...\n", result, g_buffer_segment_get_text(result, false));
 
 
 
@@ -1025,7 +1026,10 @@ void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line = ligne à venir consulter.                              *
+*  Paramètres  : line   = ligne à venir consulter.                            *
+*                first  = première colonne à parcourir.                       *
+*                end    = colonne de fin de parcours.                         *
+*                markup = indique si le texte doit être décoré ou non.        *
 *                                                                             *
 *  Description : Donne le texte représenté par une ligne de tampon.           *
 *                                                                             *
@@ -1035,23 +1039,38 @@ void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const
 *                                                                             *
 ******************************************************************************/
 
-char *g_buffer_line_get_text(const GBufferLine *line)
+char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end, bool markup)
 {
     char *result;                           /* Construction à retourner    */
     BufferLineColumn i;                     /* Boucle de parcours #1       */
     size_t j;                               /* Boucle de parcours #2       */
+    char *extra;                            /* Contenu à intégrer au texte */
 
     result = NULL;
 
-    for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++)
+    assert(first < end);
+
+    for (i = first; i < end; i++)
+    {
+        if (i > first && result != NULL)
+            result = stradd(result, " ");
+
         for (j = 0; j < line->columns[i].count; j++)
+        {
+            extra = g_buffer_segment_get_text(line->columns[i].segments[j], markup);
+
             if (result == NULL)
+                result = extra;
+
+            else
             {
-                result = strdup(g_buffer_segment_get_text(line->columns[i].segments[j]));
-                result = stradd(result, " ");
+                result = stradd(result, extra);
+                free(extra);
             }
-            else
-                result = stradd(result, g_buffer_segment_get_text(line->columns[i].segments[j]));
+
+        }
+
+    }
 
     return result;
 
@@ -1160,6 +1179,25 @@ void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : line = ligne à venir consulter.                              *
+*                                                                             *
+*  Description : Renseigne sur les propriétés particulières liées à une ligne.*
+*                                                                             *
+*  Retour      : Propriétés intégrées.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line)
+{
+    return line->flags;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : line = ligne à venir compléter.                              *
 *                flag = propriété à supprimer.                                *
 *                                                                             *
@@ -1201,7 +1239,7 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths
     gint x;                                 /* Point de départ d'impression*/
     BufferLineColumn i;                     /* Boucle de parcours          */
 
-    if (line->flags != BLF_NONE)
+    if (line->flags != BLF_NONE && line->flags != BLF_HAS_CODE)
     {
         class = G_BUFFER_LINE_GET_CLASS(line);
 
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index 6984c37..bf703ab 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -87,8 +87,9 @@ typedef enum _BufferLineColumn
 typedef enum _BufferLineFlags
 {
     BLF_NONE        = 0 << 0,               /* Aucune                      */
-    BLF_ENTRYPOINT  = 1 << 0,               /* Représentation d'une entrée */
-    BLF_BOOKMARK    = 1 << 1                /* Signet associé              */
+    BLF_HAS_CODE    = 1 << 0,               /* La ligne contient du code   */
+    BLF_ENTRYPOINT  = 1 << 1,               /* Représentation d'une entrée */
+    BLF_BOOKMARK    = 1 << 2                /* Signet associé              */
 
 } BufferLineFlags;
 
@@ -124,7 +125,7 @@ GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *, GSList *,
 void 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 *);
+char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineColumn, bool);
 
 /* Fournit la largeur requise pour une colonne de ligne donnée. */
 gint g_buffer_line_get_column_width(GBufferLine *, BufferLineColumn);
@@ -138,6 +139,9 @@ void g_buffer_line_start_merge_at(GBufferLine *, BufferLineColumn);
 /* Ajoute une propriété particulière à une ligne donnée. */
 void g_buffer_line_add_flag(GBufferLine *, BufferLineFlags);
 
+/* Renseigne sur les propriétés particulières liées à une ligne. */
+BufferLineFlags g_buffer_line_get_flags(const GBufferLine *);
+
 /* Retire une propriété particulière à une ligne donnée. */
 void g_buffer_line_remove_flag(GBufferLine *, BufferLineFlags);
 
diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c
index 1ebb543..27891a8 100644
--- a/src/glibext/gbuffersegment.c
+++ b/src/glibext/gbuffersegment.c
@@ -29,6 +29,7 @@
 #include <string.h>
 
 
+#include "../common/extstr.h"
 #include "../common/fnv1a.h"
 #include "../gtkext/gtkblockview.h"
 #include "../gtkext/support.h"
@@ -385,6 +386,7 @@ bool g_buffer_segment_compare(const GBufferSegment *segment, const GBufferSegmen
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : segment = fragment de texte à consulter.                     *
+*                markup  = indique si le texte doit être décoré ou non.       *
 *                                                                             *
 *  Description : Fournit le texte brut conservé dans le segment.              *
 *                                                                             *
@@ -394,9 +396,79 @@ bool g_buffer_segment_compare(const GBufferSegment *segment, const GBufferSegmen
 *                                                                             *
 ******************************************************************************/
 
-const char *g_buffer_segment_get_text(const GBufferSegment *segment)
+char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 {
-    return segment->text;
+    char *result;                           /* Description à renvoyer      */
+    char color[7];                          /* Couleur hexadécimale        */
+
+    /* Résolution du cas simple */
+    if (!markup)
+        return strdup(segment->text);
+
+    result = strdup("<span ");
+
+    /* Couleur */
+
+    result = stradd(result, "foreground=\"#");
+
+    snprintf(color, sizeof(color), "%02hhx%02hhx%02hhx",
+             (unsigned char)(segment->pattern->foreground.color.red * 255),
+             (unsigned char)(segment->pattern->foreground.color.green * 255),
+             (unsigned char)(segment->pattern->foreground.color.blue * 255));
+
+    result = stradd(result, color);
+
+    result = stradd(result, "\"");
+
+    /* Style */
+
+    result = stradd(result, "style=\"");
+
+    switch (segment->pattern->slant)
+    {
+        case CAIRO_FONT_SLANT_NORMAL:
+            result = stradd(result, "normal");
+            break;
+
+        case CAIRO_FONT_SLANT_ITALIC:
+            result = stradd(result, "italic");
+            break;
+
+        case CAIRO_FONT_SLANT_OBLIQUE:
+            result = stradd(result, "oblique");
+            break;
+
+    }
+
+    result = stradd(result, "\"");
+
+    /* Epaisseur */
+
+    result = stradd(result, "weight=\"");
+
+    switch (segment->pattern->weight)
+    {
+        case CAIRO_FONT_WEIGHT_NORMAL:
+            result = stradd(result, "normal");
+            break;
+
+        case CAIRO_FONT_WEIGHT_BOLD:
+            result = stradd(result, "bold");
+            break;
+
+    }
+
+    result = stradd(result, "\"");
+
+    /* Conclusion */
+
+    result = stradd(result, ">");
+
+    result = stradd(result, segment->text);
+
+    result = stradd(result, "</span>");
+
+    return result;
 
 }
 
diff --git a/src/glibext/gbuffersegment.h b/src/glibext/gbuffersegment.h
index 10ae374..ace4e42 100644
--- a/src/glibext/gbuffersegment.h
+++ b/src/glibext/gbuffersegment.h
@@ -110,7 +110,7 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType, const char *, size_t);
 bool g_buffer_segment_compare(const GBufferSegment *, const GBufferSegment *);
 
 /* Fournit le texte brut conservé dans le segment. */
-const char *g_buffer_segment_get_text(const GBufferSegment *);
+char *g_buffer_segment_get_text(const GBufferSegment *, bool);
 
 /* Fournit la quantité de pixels requise pour l'impression. */
 gint g_buffer_segment_get_width(const GBufferSegment *);
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index d13c9d6..afad0f4 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -127,6 +127,9 @@ static void g_code_buffer_init(GCodeBuffer *);
 static size_t _g_code_buffer_get_index_from_address(const GCodeBuffer *, const vmpa2t *, bool);
 
 /* Convertit une adresse en indice de ligne. */
+static size_t _g_code_buffer_get_index_from_address_new(const GCodeBuffer *, const vmpa2t *, bool);
+
+/* Convertit une adresse en indice de ligne. */
 static size_t g_code_buffer_get_index_from_address(GCodeBuffer *, const vmpa2t *, bool);
 
 
@@ -419,6 +422,66 @@ static size_t _g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, c
 
     return (first ? 0 : buffer->used - 1);
 
+#if 0
+
+    for (result = 0; result < buffer->used; result++)
+        if (g_buffer_line_get_address(buffer->lines[result]) == addr)
+            break;
+
+    if (!first)
+        for (; result < (buffer->used - 1); result++)
+            if (g_buffer_line_get_address(buffer->lines[result + 1]) != addr)
+                break;
+
+#endif
+
+    return result;
+
+}
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
+*                addr   = adresse où va se situer la ligne.                   *
+*                first  = indique si on l'arrête à la première ou la dernière.*
+*                                                                             *
+*  Description : Convertit une adresse en indice de ligne.                    *
+*                                                                             *
+*  Retour      : Indice de l'adresse trouvée, ou 0 en cas d'échec.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t _g_code_buffer_get_index_from_address_new(const GCodeBuffer *buffer, const vmpa2t *addr, bool first)
+{
+    size_t result;                          /* Indice à retourner          */
+    const mrange_t *range;                  /* Couverture d'une ligne      */
+
+
+    for (result = 0; result < buffer->used; result++)
+    {
+        range = g_buffer_line_get_range(buffer->lines[result]);
+
+        if (mrange_contains_addr(range, addr))
+        {
+            printf(":: STOP :: %x + %u  //  %x\n",
+                   range->addr.virtual, range->length, addr->virtual);
+            break;
+        }
+
+    }
+
+#if 0
+
+    size_t result;                          /* Indice à retourner          */
+
+    if (addr == VMPA_MAX)
+        return (buffer->used > 0 ? buffer->used - 1 : 0);
+
+    /* TODO : coder un parcours plus optimal ! */
+
+    return (first ? 0 : buffer->used - 1);
 
 #if 0
 
@@ -433,6 +496,8 @@ static size_t _g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, c
 
 #endif
 
+#endif
+
     return result;
 
 }
@@ -596,18 +661,31 @@ GBufferLine *g_code_buffer_insert_after(GCodeBuffer *buffer, GBufferLine *line)
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, vmpa_t addr)
+GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vmpa2t *addr)
 {
     GBufferLine *result;                    /* Instance à retourner        */
     size_t index;                           /* Indice de la ligne visée    */
 
-    index = _g_code_buffer_get_index_from_address(buffer, addr, true);
+    index = _g_code_buffer_get_index_from_address_new(buffer, addr, true);
 
     if (index == buffer->used)
         result = NULL;
     else
+    {
         result = buffer->lines[index];
 
+        while ((g_buffer_line_get_flags(result) & BLF_HAS_CODE) == 0)
+        {
+            if ((index + 1) == buffer->used) break;
+
+            result = buffer->lines[++index];
+
+        }
+
+        g_object_ref(G_OBJECT(result));
+
+    }
+
     return result;
 
 }
@@ -1109,7 +1187,7 @@ const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, GBufferLine *line,
            x - tmp_x, tmp_x, g_buffer_segment_get_caret_position(segment, tmp_x),
            g_buffer_segment_get_width(segment));
 
-    printf("        '%s'\n", g_buffer_segment_get_text(segment));
+    printf("        '%s'\n", g_buffer_segment_get_text(segment, false));
 
     caret->x = (x - tmp_x) + g_buffer_segment_get_caret_position(segment, tmp_x);
 
@@ -1167,7 +1245,7 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
     if (segment == NULL) return false;
 
 
-    printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment));
+    printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false));
 
 
 
@@ -1190,7 +1268,7 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
         segment = g_buffer_line_find_near_segment(line, segment, view->max_widths, display, dir, &offset);
 
 
-        printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment) : NULL);
+        printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL);
 
         if (segment != NULL)
         {
@@ -1484,7 +1562,7 @@ void g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y)
     if (segment == NULL) return;
 
 
-    printf("text :: '%s'\n", g_buffer_segment_get_text(segment));
+    printf("text :: '%s'\n", g_buffer_segment_get_text(segment, false));
 
 
     if (view->highlighted != NULL)
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index 62b725c..ddd45db 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -70,7 +70,7 @@ GBufferLine *g_code_buffer_insert_at(GCodeBuffer *, vmpa_t, bool);
 GBufferLine *g_code_buffer_insert_after(GCodeBuffer *, GBufferLine *);
 
 /* Retrouve une ligne au sein d'un tampon avec une adresse. */
-GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, vmpa_t);
+GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t *);
 
 /* Augmente l'indentation des prochaines lignes. */
 void g_code_buffer_inc_indentation(GCodeBuffer *);
diff --git a/src/gui/menus/binary.c b/src/gui/menus/binary.c
index 9643663..c7c0347 100644
--- a/src/gui/menus/binary.c
+++ b/src/gui/menus/binary.c
@@ -30,11 +30,15 @@
 
 #include "../editem-int.h"
 #include "../../dialogs/export.h"
+#include "../../dialogs/gotox.h"
 #include "../../dialogs/storage.h"
 #include "../../gtkext/easygtk.h"
 
 
 
+/* Réagit au menu "Binaire -> Points d'entrée". */
+static void mcb_binary_entry_points(GtkMenuItem *, GMenuBar *);
+
 /* Réagit au menu "Binaire -> Enregistrements...". */
 static void mcb_binary_storage(GtkMenuItem *, GMenuBar *);
 
@@ -69,6 +73,14 @@ GtkWidget *build_menu_binary(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *ba
     menubar = gtk_menu_new();
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(result), menubar);
 
+    submenuitem = qck_create_menu_item(NULL, NULL, _("Entry points"),
+                                       G_CALLBACK(mcb_binary_entry_points), bar);
+    add_accelerator_to_menu_item(submenuitem, "<Ctrl>E", 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_binary_storage", _("Storage..."),
                                        G_CALLBACK(mcb_binary_storage), bar);
     gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
@@ -87,6 +99,51 @@ GtkWidget *build_menu_binary(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *ba
 *  Paramètres  : menuitem = élément de menu sélectionné.                      *
 *                bar      = barre de menu parente.                            *
 *                                                                             *
+*  Description : Réagit au menu "Binaire -> Points d'entrée".                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void mcb_binary_entry_points(GtkMenuItem *menuitem, GMenuBar *bar)
+{
+    GEditorItem *item;                      /* Elément d'éditeur graphique */
+    GObject *ref;                           /* Espace de référencements    */
+    GLoadedBinary *binary;                  /* Binaire présenté à l'écran  */
+    GtkWidget *dialog;                      /* Boîte de dialogue à montrer */
+    vmpa2t *addr;                           /* Adresse de destination      */
+    GtkViewPanel *vpanel;                   /* Afficheur effectif de code  */
+
+    item = G_EDITOR_ITEM(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);
+
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
+    {
+        addr = get_address_from_gotox_dialog(dialog);
+
+        vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar));
+        gtk_view_panel_scroll_to_address(vpanel, addr);
+
+        delete_vmpa(addr);
+
+    }
+
+    gtk_widget_destroy(dialog);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : menuitem = élément de menu sélectionné.                      *
+*                bar      = barre de menu parente.                            *
+*                                                                             *
 *  Description : Réagit au menu "Binaire -> Enregistrements...".              *
 *                                                                             *
 *  Retour      : -                                                            *
-- 
cgit v0.11.2-87-g4458