From 53213051036151645ae287436ad94dff92c7fa20 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 23 Jul 2018 09:45:44 +0200
Subject: Changed the way Dex methods are loaded and displayed.

---
 plugins/dalvik/operands/pool.c |   6 +-
 plugins/dex/dex-int.h          |   1 +
 plugins/dex/format.c           |   3 +
 plugins/dex/method.c           |  18 ++++++
 plugins/dex/pool.c             | 122 ++++++++++++++++++++++++++++++++++-------
 plugins/dex/pool.h             |   3 +
 6 files changed, 129 insertions(+), 24 deletions(-)

diff --git a/plugins/dalvik/operands/pool.c b/plugins/dalvik/operands/pool.c
index 6e4229b..f4fe1fa 100644
--- a/plugins/dalvik/operands/pool.c
+++ b/plugins/dalvik/operands/pool.c
@@ -377,12 +377,10 @@ static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *operand, GBuff
 
             if (routine != NULL)
             {
-                tmp = g_binary_routine_to_string(routine, true);
+                tmp = g_binary_symbol_get_label(G_BIN_SYMBOL(routine));
                 g_object_unref(G_OBJECT(routine));
 
-                g_buffer_line_append_text(line, BLC_ASSEMBLY, "<", 1, RTT_HOOK, NULL);
-                g_buffer_line_append_text(line, BLC_ASSEMBLY, tmp, strlen(tmp), RTT_VAR_NAME, G_OBJECT(operand));
-                g_buffer_line_append_text(line, BLC_ASSEMBLY, ">", 1, RTT_HOOK, NULL);
+                g_buffer_line_append_text(line, BLC_ASSEMBLY, tmp, strlen(tmp), RTT_LABEL, G_OBJECT(operand));
 
             }
             else
diff --git a/plugins/dex/dex-int.h b/plugins/dex/dex-int.h
index 5180b58..48a920c 100644
--- a/plugins/dex/dex-int.h
+++ b/plugins/dex/dex-int.h
@@ -44,6 +44,7 @@ struct _GDexFormat
     GBinSymbol **strings;                   /* Symboles pour les chaînes   */
     GDataType **types;                      /* Types partagés pour Dalvik  */
     GBinVariable **fields;                  /* Champs de données partagés  */
+    GDexMethod **methods;                   /* Méthodes déclarées          */
     GDexClass **classes;                    /* Classes retrouvées          */
 
 };
diff --git a/plugins/dex/format.c b/plugins/dex/format.c
index af005e6..d354ad0 100644
--- a/plugins/dex/format.c
+++ b/plugins/dex/format.c
@@ -405,6 +405,9 @@ static bool g_dex_format_analyze(GDexFormat *format, wgroup_id_t gid, GtkStatusS
     if (!load_all_dex_fields(format, gid, status))
         goto gdfa_error;
 
+    if (!load_all_dex_methods(format, gid, status))
+        goto gdfa_error;
+
     if (!load_all_dex_classes(format, gid, status))
         goto gdfa_error;
 
diff --git a/plugins/dex/method.c b/plugins/dex/method.c
index 5b7b30e..e5f6273 100644
--- a/plugins/dex/method.c
+++ b/plugins/dex/method.c
@@ -49,6 +49,10 @@ struct _GDexMethod
      * en place à partir du constructeur g_dex_method_new_defined().
      */
 
+#ifndef NDEBUG
+    bool already_defined;                   /* Vérofication d'unicité      */
+#endif
+
     encoded_method info;                    /* Propriétés de la méthode    */
     bool has_body;                          /* Indication de présence      */
     code_item body;                         /* Corps de la méthode         */
@@ -120,6 +124,9 @@ static void g_dex_method_class_init(GDexMethodClass *class)
 
 static void g_dex_method_init(GDexMethod *method)
 {
+#ifndef NDEBUG
+    method->already_defined = false;
+#endif
 
 }
 
@@ -197,6 +204,11 @@ GDexMethod *g_dex_method_new_defined(GDexFormat *format, const encoded_method *s
     if (result == NULL)
         return NULL;
 
+#ifndef NDEBUG
+    assert(!result->already_defined);
+    result->already_defined = true;
+#endif
+
     result->info = *seed;
 
     result->has_body = (seed->code_off > 0);
@@ -253,17 +265,23 @@ GDexMethod *g_dex_method_new_defined(GDexFormat *format, const encoded_method *s
 GDexMethod *g_dex_method_new_callable(GDexFormat *format, const method_id_item *method_id)
 {
     GDexMethod *result;                     /* Composant à retourner       */
+    GDataType *ns;                          /* Espace d'appartenance       */
     const char *name;                       /* Nom de la routine finale    */
     GBinRoutine *routine;                   /* Routine représentée         */
 
     result = NULL;
 
+    ns = get_type_from_dex_pool(format, method_id->class_idx);
+
     name = get_string_from_dex_pool(format, method_id->name_idx, NULL);
     if (name == NULL) goto gdmne_exit;
 
     routine = get_prototype_from_dex_pool(format, method_id->proto_idx);
     if (routine == NULL) goto gdmne_exit;
 
+    if (ns != NULL)
+        g_binary_routine_set_namespace(routine, ns, strdup("."));
+
     g_binary_routine_set_name(routine, strdup(name));
 
     result = g_object_new(G_TYPE_DEX_METHOD, NULL);
diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c
index 8a421b2..75841df 100644
--- a/plugins/dex/pool.c
+++ b/plugins/dex/pool.c
@@ -711,6 +711,93 @@ GBinRoutine *get_prototype_from_dex_pool(GDexFormat *format, uint32_t index)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : format = représentation interne du format DEX à compléter.   *
+*                gid    = groupe de travail impliqué.                         *
+                 status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Charge toutes les classes listées dans le contenu binaire.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool load_all_dex_methods(GDexFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+{
+    bool result;                            /* Bilan à retourner           */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    uint32_t run_size;                      /* Volume réparti par exécution*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    activity_id_t msg;                      /* Message de progression      */
+    guint i;                                /* Boucle de parcours          */
+    uint32_t begin;                         /* Début de bloc de traitement */
+    uint32_t end;                           /* Fin d'un bloc de traitement */
+    GDexLoading *loading;                   /* Tâche de chargement à lancer*/
+
+    /**
+     * Il existe deux voies pour récupérer une méthode :
+     *
+     *    - depuis 'method_id_item', qui précise classe d'appartenance, prototype
+     *      et nom.
+     *
+     *    - depuis 'encoded_method', qui contient une définition 'method_id_item',
+     *      ainsi que des attributs propres à la méthode visée.
+     *
+     * Techniquement, il peut donc y avoir plusieurs variations d'un même
+     * 'method_id_item' selon différents 'encoded_method'.
+     *
+     * Dans la pratique, c'est hautement improbable : une méthode ne peut pas
+     * être privée et publique  par exemple, ou renvoyer vers différents code.
+     *
+     * Donc on se permet d'associer une unique méthode par 'method_id_item',
+     * et de précharger le tout.
+     */
+
+    result = true;
+
+    /* Préparation du réceptacle */
+
+    format->methods = (GDexMethod **)calloc(format->header.method_ids_size, sizeof(GDexMethod *));
+
+    /* Lancement des chargements */
+
+    runs_count = get_max_online_threads();
+
+    run_size = format->header.method_ids_size / runs_count;
+
+    queue = get_work_queue();
+
+    msg = gtk_status_stack_add_activity(status, _("Loading all methods from the Dex pool..."),
+                                        format->header.method_ids_size);
+
+    for (i = 0; i < runs_count; i++)
+    {
+        begin = i * run_size;
+
+        if ((i + 1) == runs_count)
+            end = format->header.method_ids_size;
+        else
+            end = begin + run_size;
+
+        loading = g_dex_loading_new(format, begin, end, msg,
+                                    (dex_loading_cb)get_method_from_dex_pool, &result);
+
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid);
+
+    }
+
+    g_work_queue_wait_for_completion(queue, gid);
+
+    gtk_status_stack_remove_activity(status, msg);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : format = représentation interne du format DEX à consulter.   *
 *                                                                             *
 *  Description : Compte le nombre de méthodes dans une table DEX.             *
@@ -735,7 +822,7 @@ uint32_t count_methods_in_dex_pool(const GDexFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = représentation interne du format DEX à consulter.   *
-*                index  = index de la classe recherchée.                      *
+*                index  = index de la méthode recherchée.                     *
 *                                                                             *
 *  Description : Extrait une représentation de méthode d'une table DEX.       *
 *                                                                             *
@@ -748,36 +835,31 @@ uint32_t count_methods_in_dex_pool(const GDexFormat *format)
 GDexMethod *get_method_from_dex_pool(GDexFormat *format, uint32_t index)
 {
     GDexMethod *result;                     /* Instance à retourner        */
-    uint32_t count;                         /* Nombre d'éléments présents  */
     phys_t pos;                             /* Tête de lecture             */
     vmpa2t addr;                            /* Tête de lecture générique   */
     method_id_item method_id;               /* Définition de la méthode    */
 
     result = NULL;
 
-    count = count_methods_in_dex_pool(format);
-
-    if (index >= count)
+    if (index >= format->header.method_ids_size)
         goto gmfdp_error;
 
-    /**
-     * On charge ici une méthode à partir de la définition de 'method_id_item'.
-     *
-     * C'est l'élément 'encoded_method' qui référence cette cette définition et qui
-     * applique ensuite les attributs finaux de la méthode. La classe parente est
-     * précisée en outre bien en amont.
-     *
-     * Comme une même définition peut donc servir à plusieurs instances,
-     * on ne peut pas conserver un tableau d'allocations communes.
-     */
+    if (format->methods[index] == NULL)
+    {
+        pos = format->header.method_ids_off + index * sizeof(method_id_item);
+        init_vmpa(&addr, pos, VMPA_NO_VIRTUAL);
 
-    pos = format->header.method_ids_off + index * sizeof(method_id_item);
-    init_vmpa(&addr, pos, VMPA_NO_VIRTUAL);
+        if (!read_dex_method_id_item(format, &addr, &method_id))
+            goto gmfdp_error;
 
-    if (!read_dex_method_id_item(format, &addr, &method_id))
-        goto gmfdp_error;
+        format->methods[index] = g_dex_method_new_callable(format, &method_id);
 
-    result = g_dex_method_new_callable(format, &method_id);
+    }
+
+    result = format->methods[index];
+
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
  gmfdp_error:
 
diff --git a/plugins/dex/pool.h b/plugins/dex/pool.h
index ac7db60..dd27f94 100644
--- a/plugins/dex/pool.h
+++ b/plugins/dex/pool.h
@@ -71,6 +71,9 @@ uint32_t count_prototypes_in_dex_pool(const GDexFormat *);
 /* Extrait une représentation de routine d'une table DEX. */
 GBinRoutine *get_prototype_from_dex_pool(GDexFormat *, uint32_t);
 
+/* Charge toutes les classes listées dans le contenu binaire. */
+bool load_all_dex_methods(GDexFormat *, wgroup_id_t, GtkStatusStack *);
+
 /* Compte le nombre de méthodes dans une table DEX. */
 uint32_t count_methods_in_dex_pool(const GDexFormat *);
 
-- 
cgit v0.11.2-87-g4458