From 0846c211ca24bc4e88bbc517362e1e08deb837b5 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 31 Dec 2018 18:03:56 +0100
Subject: Remembered the target locations used in the Goto dialog box.

---
 src/analysis/binary.c     | 281 +++++++++++++++++++++++++++++++++++++++++++++-
 src/analysis/binary.h     |   8 ++
 src/analysis/loaded-int.h |   2 +-
 src/analysis/loaded.c     |   2 +-
 src/analysis/loaded.h     |   2 +-
 src/gui/dialogs/goto.c    |  42 ++++++-
 src/gui/menus/edition.c   |   6 +
 7 files changed, 332 insertions(+), 11 deletions(-)

diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 4d6c8ba..c38a725 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -88,6 +88,10 @@ struct _GLoadedBinary
 
     GDisplayOptions *options[BVW_COUNT];    /* Options d'affichage         */
 
+    vmpa2t *old_gotos;                      /* Conservation de destinations*/
+    size_t goto_count;                      /* Taille de cette liste       */
+    GMutex goto_access;                     /* Encadrement des accès       */
+
 };
 
 /* Description de fichier binaire (classe) */
@@ -138,6 +142,17 @@ static bool g_loaded_binary_connect_remote(GLoadedBinary *);
 
 
 
+/* -------------------- SAUVEGARDE ET RESTAURATION DE PARAMETRES -------------------- */
+
+
+/* Charge en mémoire les anciennes destinations visitées. */
+static bool g_loaded_binary_load_old_gotos(GLoadedBinary *, xmlXPathContext *, const char *);
+
+/* Ecrit les anciennes destinations visitées dans du XML. */
+static bool g_loaded_binary_save_old_gotos(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *);
+
+
+
 /* ---------------------- GESTION SOUS FORME DE CONTENU CHARGE ---------------------- */
 
 
@@ -145,7 +160,7 @@ static bool g_loaded_binary_connect_remote(GLoadedBinary *);
 static bool g_loaded_binary_restore(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Ecrit une sauvegarde du binaire dans un fichier XML. */
-static bool g_loaded_binary_save(const GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *);
+static bool g_loaded_binary_save(GLoadedBinary *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Fournit le contenu représenté de l'élément chargé. */
 static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *);
@@ -253,6 +268,8 @@ static void g_loaded_binary_init(GLoadedBinary *binary)
     g_display_options_add(binary->options[BVW_GRAPH], _("Virtual address"), false);
     g_display_options_add(binary->options[BVW_GRAPH], _("Binary code"), false);
 
+    g_mutex_init(&binary->goto_access);
+
 }
 
 
@@ -319,6 +336,8 @@ static void g_loaded_binary_dispose(GLoadedBinary *binary)
     for (i = 0; i < BVW_COUNT; i++)
         g_clear_object(&binary->options[i]);
 
+    g_mutex_clear(&binary->goto_access);
+
     G_OBJECT_CLASS(g_loaded_binary_parent_class)->dispose(G_OBJECT(binary));
 
 }
@@ -1288,6 +1307,258 @@ GBufferCache *g_loaded_binary_get_disassembled_cache(const GLoadedBinary *binary
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                      SAUVEGARDE ET RESTAURATION DE PARAMETRES                      */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary  = élément binaire à traiter.                         *
+*                context = contexte pour les recherches XPath.                *
+*                path    = chemin d'accès au noeud XML à lire.                *
+*                                                                             *
+*  Description : Charge en mémoire les anciennes destinations visitées.       *
+*                                                                             *
+*  Retour      : true si l'opération a bien tourné, false sinon.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_loaded_binary_load_old_gotos(GLoadedBinary *binary, xmlXPathContext *context, const char *path)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    char *top_access;                       /* Chemin d'accès principal    */
+    xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
+    size_t count;                           /* Nombre de contenus premiers */
+    size_t i;                               /* Boucle de parcours          */
+    char *access;                           /* Chemin d'accès à un élément */
+    char *value;                            /* Valeur lue à partie du XML  */
+    bool is_virt;                           /* Détermination de l'utile    */
+    vmpa2t *new;                            /* Nouvelle destination        */
+
+    result = true;
+
+    asprintf(&top_access, "%s/OldGotos/Target", path);
+
+    xobject = get_node_xpath_object(context, top_access);
+
+    count = XPATH_OBJ_NODES_COUNT(xobject);
+
+    for (i = 0; i < count; i++)
+    {
+        asprintf(&access, "%s/OldGotos/Target[position()=%zu]", path, i + 1);
+
+        /* Type de destination */
+
+        value = get_node_prop_value(context, access, "type");
+        if (value == NULL)
+        {
+            result = false;
+            break;
+        }
+
+        is_virt = (strcmp(value, "virt") == 0);
+
+        free(value);
+
+        /* Adresse de destination */
+
+        value = get_node_prop_value(context, access, "location");
+        if (value == NULL)
+        {
+            result = false;
+            break;
+        }
+
+        if (is_virt)
+            new = string_to_vmpa_virt(value);
+        else
+            new = string_to_vmpa_phy(value);
+
+        free(value);
+
+        /* Intégration */
+
+        binary->old_gotos = realloc(binary->old_gotos, ++binary->goto_count * sizeof(vmpa2t));
+
+        copy_vmpa(&binary->old_gotos[binary->goto_count - 1], new);
+
+        delete_vmpa(new);
+
+        free(access);
+
+    }
+
+    if(xobject != NULL)
+        xmlXPathFreeObject(xobject);
+
+    free(top_access);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary  = élément binaire à traiter.                         *
+*                xdoc    = structure XML en cours d'édition.                  *
+*                context = contexte à utiliser pour les recherches.           *
+*                path    = chemin d'accès réservé au binaire.                 *
+*                                                                             *
+*  Description : Ecrit les anciennes destinations visitées dans du XML.       *
+*                                                                             *
+*  Retour      : true si l'opération a bien tourné, false sinon.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_loaded_binary_save_old_gotos(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    size_t i;                               /* Boucle de parcours          */
+    char *access;                           /* Chemin d'accès à un élément */
+    const vmpa2t *addr;                     /* Adresse de destination      */
+    bool is_virt;                           /* Détermination de l'utile    */
+    VMPA_BUFFER(loc);                       /* Version humaintement lisible*/
+
+    result = true;
+
+    g_mutex_lock(&binary->goto_access);
+
+    for (i = 0; i < binary->goto_count && result; i++)
+    {
+        asprintf(&access, "%s/OldGotos/Target[position()=%zu]", path, i + 1);
+
+        result = (ensure_node_exist(xdoc, context, access) != NULL);
+
+        addr = &binary->old_gotos[i];
+
+        is_virt = has_virt_addr(addr);
+
+        if (result)
+            result = add_string_attribute_to_node(xdoc, context, access, "type", is_virt ? "virt" : "phys");
+
+        if (result)
+        {
+            if (is_virt)
+                vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);
+            else
+                vmpa2_phys_to_string(addr, MDS_UNDEFINED, loc, NULL);
+
+            result = add_string_attribute_to_node(xdoc, context, access, "location", loc);
+
+        }
+
+        free(access);
+
+    }
+
+    g_mutex_unlock(&binary->goto_access);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = élément binaire à consulter.                        *
+*                new    = nouvelle destination à conserver en mémoire.        *
+*                                                                             *
+*  Description : Complète la liste des destinations déjà visitées.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_loaded_binary_remember_new_goto(GLoadedBinary *binary, const vmpa2t *new)
+{
+    size_t previous_count;                  /* Sauvegarde de la taille     */
+    size_t i;                               /* Boucle de parcours          */
+
+    g_mutex_lock(&binary->goto_access);
+
+    /* Mise en avant de la nouvelle ancienne destination */
+
+    binary->old_gotos = realloc(binary->old_gotos, ++binary->goto_count * sizeof(vmpa2t));
+
+    if (binary->goto_count > 1)
+        memmove(&binary->old_gotos[1], &binary->old_gotos[0], (binary->goto_count - 1) * sizeof(vmpa2t));
+
+    copy_vmpa(&binary->old_gotos[0], new);
+
+    /* Suppression de la même destination à une autre position */
+
+    previous_count = binary->goto_count;
+
+    for (i = 1; i < binary->goto_count; i++)
+        if (cmp_vmpa(&binary->old_gotos[i], new) == 0)
+        {
+            if ((i + 1) < binary->goto_count)
+                memmove(&binary->old_gotos[i], &binary->old_gotos[i + 1],
+                        (binary->goto_count - i - 1) * sizeof(vmpa2t));
+
+            binary->goto_count--;
+            i--;
+
+        }
+
+    if (previous_count != binary->goto_count)
+        binary->old_gotos = realloc(binary->old_gotos, binary->goto_count * sizeof(vmpa2t));
+
+    g_mutex_unlock(&binary->goto_access);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = élément binaire à consulter.                        *
+*                count  = nombre d'éléments dans la liste renvoyée.           *
+*                                                                             *
+*  Description : Fournit la liste des anciennes destinations déjà visitées.   *
+*                                                                             *
+*  Retour      : Liste de destinations à libérer de la mémoire ou NULL.       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+vmpa2t *g_loaded_binary_get_old_gotos(GLoadedBinary *binary, size_t *count)
+{
+    vmpa2t *result;                         /* Liste à renvoyer            */
+    size_t i;                               /* Boucle de parcours          */
+
+    g_mutex_lock(&binary->goto_access);
+
+    *count = binary->goto_count;
+
+    if (*count == 0)
+        result = NULL;
+
+    else
+    {
+        result = malloc(*count * sizeof(vmpa2t));
+
+        for (i = 0; i < *count; i++)
+            copy_vmpa(&result[i], &binary->old_gotos[i]);
+
+    }
+
+    g_mutex_unlock(&binary->goto_access);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                        GESTION SOUS FORME DE CONTENU CHARGE                        */
 /* ---------------------------------------------------------------------------------- */
 
@@ -1315,6 +1586,9 @@ static bool g_loaded_binary_restore(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPat
 
     result = g_loaded_binary_load_storage(binary, context, path);
 
+    if (result)
+        result = g_loaded_binary_load_old_gotos(binary, context, path);
+
     return result;
 
 }
@@ -1335,7 +1609,7 @@ static bool g_loaded_binary_restore(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPat
 *                                                                             *
 ******************************************************************************/
 
-static bool g_loaded_binary_save(const GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path)
+static bool g_loaded_binary_save(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathContext *context, const char *path)
 {
     bool result;                            /* Bilan à faire remonter      */
 
@@ -1348,6 +1622,9 @@ static bool g_loaded_binary_save(const GLoadedBinary *binary, xmlDoc *xdoc, xmlX
     if (result)
         result = g_loaded_binary_save_storage(binary, xdoc, context, path);
 
+    if (result)
+        result = g_loaded_binary_save_old_gotos(binary, xdoc, context, path);
+
     /* Sauvegarde côté serveur */
 
     if (result)
diff --git a/src/analysis/binary.h b/src/analysis/binary.h
index 831cade..ad4f568 100644
--- a/src/analysis/binary.h
+++ b/src/analysis/binary.h
@@ -153,6 +153,14 @@ GArchProcessor *g_loaded_binary_get_processor(const GLoadedBinary *);
 GBufferCache *g_loaded_binary_get_disassembled_cache(const GLoadedBinary *);
 
 
+/* -------------------- SAUVEGARDE ET RESTAURATION DE PARAMETRES -------------------- */
+
+
+/* Complète la liste des destinations déjà visitées. */
+void g_loaded_binary_remember_new_goto(GLoadedBinary *, const vmpa2t *);
+
+/* Fournit la liste des anciennes destinations déjà visitées. */
+vmpa2t *g_loaded_binary_get_old_gotos(GLoadedBinary *, size_t *);
 
 
 
diff --git a/src/analysis/loaded-int.h b/src/analysis/loaded-int.h
index ed7d84a..face2bb 100644
--- a/src/analysis/loaded-int.h
+++ b/src/analysis/loaded-int.h
@@ -34,7 +34,7 @@
 typedef bool (* restore_content_fc) (GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Ecrit une sauvegarde de l'élément dans un fichier XML. */
-typedef bool (* save_content_fc) (const GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
+typedef bool (* save_content_fc) (GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Fournit le contenu représenté de l'élément chargé. */
 typedef GBinContent * (* get_content_fc) (const GLoadedContent *);
diff --git a/src/analysis/loaded.c b/src/analysis/loaded.c
index d148366..2343992 100644
--- a/src/analysis/loaded.c
+++ b/src/analysis/loaded.c
@@ -187,7 +187,7 @@ bool g_loaded_content_restore(GLoadedContent *content, xmlDocPtr xdoc, xmlXPathC
 *                                                                             *
 ******************************************************************************/
 
-bool g_loaded_content_save(const GLoadedContent *content, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path)
+bool g_loaded_content_save(GLoadedContent *content, xmlDocPtr xdoc, xmlXPathContextPtr context, const char *path)
 {
     bool result;                            /* Bilan à faire remonter      */
     GLoadedContentIface *iface;             /* Interface utilisée          */
diff --git a/src/analysis/loaded.h b/src/analysis/loaded.h
index 60d1fce..284efae 100644
--- a/src/analysis/loaded.h
+++ b/src/analysis/loaded.h
@@ -62,7 +62,7 @@ GType g_loaded_content_get_type(void) G_GNUC_CONST;
 bool g_loaded_content_restore(GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Ecrit une sauvegarde de l'élément dans un fichier XML. */
-bool g_loaded_content_save(const GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
+bool g_loaded_content_save(GLoadedContent *, xmlDoc *, xmlXPathContext *, const char *);
 
 /* Fournit le contenu représenté de l'élément chargé. */
 GBinContent *g_loaded_content_get_content(const GLoadedContent *);
diff --git a/src/gui/dialogs/goto.c b/src/gui/dialogs/goto.c
index 1fe2bbd..1cb365f 100644
--- a/src/gui/dialogs/goto.c
+++ b/src/gui/dialogs/goto.c
@@ -30,6 +30,8 @@
 #include <i18n.h>
 
 
+#include "../core/global.h"
+#include "../../analysis/binary.h"
 #include "../../gtkext/easygtk.h"
 
 
@@ -150,6 +152,12 @@ GtkWidget *create_goto_dialog(GtkWindow *parent)
     GtkWidget *entry;                       /* Zone de saisie principale   */
     GtkWidget *hbox;                        /* Support à construire #2     */
     GtkWidget *radio;                       /* Définition de localisation  */
+    GLoadedBinary *binary;                  /* Binaire en cours d'édition  */
+    vmpa2t *old_gotos;                      /* Liste de destinations       */
+    size_t count;                           /* Taille de cette liste       */
+    size_t i;                               /* Boucle de parcours          */
+    bool is_virt;                           /* Détermination de l'utile    */
+    VMPA_BUFFER(loc);                       /* Version humaintement lisible*/
 
     result = gtk_dialog_new();
     gtk_window_set_title(GTK_WINDOW(result), _("Go to address"));
@@ -181,11 +189,6 @@ GtkWidget *create_goto_dialog(GtkWindow *parent)
     g_signal_connect(G_OBJECT(entry), "activate",
                      G_CALLBACK(validate_addresses), GTK_DIALOG(result));
 
-
-    /* TODO */
-    //gtk_combo_box_append_text(combobox, "test");
-
-
     /* Propriétés de la localisation */
 
     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
@@ -207,9 +210,36 @@ GtkWidget *create_goto_dialog(GtkWindow *parent)
     gtk_dialog_add_button(GTK_DIALOG(result), _("_Ok"), GTK_RESPONSE_OK);
 
     gtk_entry_set_text(GTK_ENTRY(entry), "0x");
-    gtk_widget_grab_focus (entry);
+    gtk_widget_grab_focus(entry);
     gtk_editable_set_position(GTK_EDITABLE(entry), -1);
 
+    /* Restaurationd d'anciennes destinations */
+
+    binary = G_LOADED_BINARY(get_current_content());
+    old_gotos = g_loaded_binary_get_old_gotos(binary, &count);
+    g_object_unref(G_OBJECT(binary));
+
+    if (old_gotos != NULL)
+    {
+        for (i = 0; i < count; i++)
+        {
+            is_virt = has_virt_addr(&old_gotos[i]);
+
+            if (is_virt)
+                vmpa2_virt_to_string(&old_gotos[i], MDS_UNDEFINED, loc, NULL);
+            else
+                vmpa2_phys_to_string(&old_gotos[i], MDS_UNDEFINED, loc, NULL);
+
+            gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combobox), loc);
+
+        }
+
+        free(old_gotos);
+
+        gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
+
+    }
+
     return result;
 
 }
diff --git a/src/gui/menus/edition.c b/src/gui/menus/edition.c
index b1ac0ad..be045b5 100644
--- a/src/gui/menus/edition.c
+++ b/src/gui/menus/edition.c
@@ -36,6 +36,7 @@
 #include "../dialogs/bookmark.h"
 #include "../dialogs/goto.h"
 #include "../dialogs/gotox.h"
+#include "../../analysis/binary.h"
 #include "../../analysis/db/items/switcher.h"
 #include "../../arch/targetableop.h"
 #include "../../glibext/gbinarycursor.h"
@@ -422,6 +423,7 @@ static void mcb_edition_goto(GtkMenuItem *menuitem, GMenuBar *bar)
     GtkWidget *dialog;                      /* Boîte de dialogue à montrer */
     vmpa2t *addr;                           /* Adresse de destination      */
     GLoadedPanel *panel;                    /* Afficheur effectif de code  */
+    GLoadedBinary *binary;                  /* Binaire en cours d'édition  */
 
     ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar));
     dialog = create_goto_dialog(GTK_WINDOW(ref));
@@ -433,6 +435,10 @@ static void mcb_edition_goto(GtkMenuItem *menuitem, GMenuBar *bar)
         panel = get_current_view();
         assert(GTK_IS_BLOCK_DISPLAY(panel) || GTK_IS_GRAPH_DISPLAY(panel));
 
+        binary = G_LOADED_BINARY(g_loaded_panel_get_content(panel));
+        g_loaded_binary_remember_new_goto(binary, addr);
+        g_object_unref(G_OBJECT(binary));
+
         gtk_display_panel_request_move(GTK_DISPLAY_PANEL(panel), addr);
 
         g_object_unref(G_OBJECT(panel));
-- 
cgit v0.11.2-87-g4458