From 7972f2da7d0e363fe918992cb5661b17ee3577d7 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 26 Sep 2016 20:24:23 +0200
Subject: Defined a proper cache for routine names with their packages.

---
 ChangeLog              |  15 ++++-
 src/analysis/routine.c | 179 +++++++++++++++++++++++++++++++++++++------------
 src/analysis/routine.h |  10 +--
 src/analysis/type.c    |  16 +++--
 src/format/dex/class.c |  18 ++++-
 src/format/symbol.c    |   2 +-
 6 files changed, 183 insertions(+), 57 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7b657fe..7fb2826 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,20 @@
 16-09-26  Cyrille Bagard <nocbos@gmail.com>
 
+	* src/analysis/routine.c:
+	* src/analysis/routine.h:
+	Define a proper cache for routine names with their packages. Clean the code.
+
+	* src/analysis/type.c:
+	Build a namespace from types recursively.
+
+	* src/format/dex/class.c:
+	* src/format/symbol.c:
+	Update code.
+
+16-09-26  Cyrille Bagard <nocbos@gmail.com>
+
 	* src/analysis/disass/disassembler.c:
-	Delete code sorting routines as they are already sorted.
+	Delete code sorting routines as they are already sorted. Clean the code.
 
 16-09-25  Cyrille Bagard <nocbos@gmail.com>
 
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index 559b9bf..7483bf0 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -45,13 +45,16 @@ struct _GBinRoutine
     GDataType *ret_type;                    /* Type retourné               */
 
     GDataType *namespace;                   /* Espace de noms / classe     */
+    const char *ns_sep;                     /* Séparateur d'éléments       */
     char *name;                             /* Désignation humaine         */
     GDataType *full_name;                   /* Désignation très complète   */
-    char *long_name;                        /* Désignation très complète ??*/
 
     GBinVariable **args;                    /* Arguments de la routines    */
     size_t args_count;                      /* Nombre d'arguments          */
 
+    char *cached_decl;                      /* Cache pour désignation #1   */
+    char *cached_full_decl;                 /* Cache pour désignation #2   */
+
     GBinVariable **locals;                  /* Variables locales du code   */
     size_t locals_count;                    /* Nombre de variables locales */
 
@@ -76,6 +79,9 @@ static void g_bin_routine_class_init(GBinRoutineClass *);
 /* Initialise une instance représentation de routine. */
 static void g_bin_routine_init(GBinRoutine *);
 
+/* Vide le cache des descriptions humaines. */
+static void g_binary_routine_reset_declarator(GBinRoutine *, bool);
+
 
 
 /* Indique le type définit pour une représentation de routine. */
@@ -102,7 +108,7 @@ static void g_bin_routine_class_init(GBinRoutineClass *klass)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line = instance à initialiser.                               *
+*  Paramètres  : routine = instance à initialiser.                            *
 *                                                                             *
 *  Description : Initialise une instance représentation de routine.           *
 *                                                                             *
@@ -112,7 +118,7 @@ static void g_bin_routine_class_init(GBinRoutineClass *klass)
 *                                                                             *
 ******************************************************************************/
 
-static void g_bin_routine_init(GBinRoutine *line)
+static void g_bin_routine_init(GBinRoutine *routine)
 {
 
 }
@@ -301,6 +307,7 @@ void g_binary_routine_set_type(GBinRoutine *routine, RoutineType type)
 *                                                                             *
 *  Paramètres  : routine   = routine à mettre à jour.                         *
 *                namespace = instance d'appartenance.                         *
+*                sep       = séparateur à utiliser entre les éléments.        *
 *                                                                             *
 *  Description : Définit le groupe d'appartenance d'une routine donnée.       *
 *                                                                             *
@@ -310,9 +317,12 @@ void g_binary_routine_set_type(GBinRoutine *routine, RoutineType type)
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_routine_set_namespace(GBinRoutine *routine, GDataType *namespace)
+void g_binary_routine_set_namespace(GBinRoutine *routine, GDataType *namespace, const char *sep)
 {
     routine->namespace = namespace;
+    routine->ns_sep = sep;
+
+    g_binary_routine_reset_declarator(routine, false);
 
 }
 
@@ -356,6 +366,8 @@ void g_binary_routine_set_name(GBinRoutine *routine, char *name)
 
     routine->name = name;
 
+    g_binary_routine_reset_declarator(routine, true);
+
 }
 
 
@@ -371,11 +383,8 @@ void g_binary_routine_set_name(GBinRoutine *routine, char *name)
 *                                                                             *
 ******************************************************************************/
 
-const char *g_binary_routine_get_name(GBinRoutine *routine)
+const char *g_binary_routine_get_name(const GBinRoutine *routine)
 {
-    if (routine->name == NULL && routine->full_name != NULL)
-        g_binary_routine_set_name(routine, g_data_type_to_string(routine->full_name));
-
     return routine->name;
 
 }
@@ -384,40 +393,6 @@ const char *g_binary_routine_get_name(GBinRoutine *routine)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : routine = routine à mettre à jour.                           *
-*                                                                             *
-*  Description : Fournit le nom long et humain d'une routine.                 *
-*                                                                             *
-*  Retour      : Désignation humainement lisible ou NULL si non définie.      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-const char *g_binary_routine_get_long_name(GBinRoutine *routine)
-{
-    if (routine->long_name == NULL)
-    {
-        if (routine->namespace != NULL)
-        {
-            routine->long_name = strdup("");
-            routine->long_name = g_data_type_to_string(routine->namespace);
-            routine->long_name = stradd(routine->long_name, "." /* FIXME */);
-        }
-        else
-            routine->long_name = strdup("");
-
-        routine->long_name = stradd(routine->long_name, g_binary_routine_get_name(routine));
-
-    }
-
-    return routine->long_name;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : routine = routine à mettre à jour.                           *
 *                type    = désignation complète du nom de la routine.         *
 *                                                                             *
 *  Description : Définit de façon indirecte le nom humain d'une routine.      *
@@ -435,6 +410,8 @@ void g_binary_routine_set_name_from_type(GBinRoutine *routine, GDataType *type)
 
     routine->full_name = type;
 
+    g_binary_routine_reset_declarator(routine, true);
+
 }
 
 
@@ -599,6 +576,124 @@ void g_binary_routine_remove_arg(GBinRoutine *routine, size_t index)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : routine = routine à mettre à jour.                           *
+*                full    = indique la portée de la réinitialisation.          *
+*                                                                             *
+*  Description : Vide le cache des descriptions humaines.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_binary_routine_reset_declarator(GBinRoutine *routine, bool full)
+{
+    if (full && routine->cached_decl != NULL)
+    {
+        free(routine->cached_decl);
+        routine->cached_decl = NULL;
+    }
+
+    if (routine->cached_full_decl != NULL)
+    {
+        free(routine->cached_full_decl);
+        routine->cached_full_decl = NULL;
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : routine = routine à mettre à jour.                           *
+*                full    = indique si la liste des arguments est à ajouter.   *
+*                                                                             *
+*  Description : Fournit le nom humain d'une routine.                         *
+*                                                                             *
+*  Retour      : Désignation humainement lisible ou NULL si non définie.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char *g_binary_routine_get_declarator(GBinRoutine *routine, bool full)
+{
+    char *new;                              /* Nouvelle description        */
+    char *namespace;                        /* Groupe d'appartenance       */
+    size_t i;                               /* Boucle de parcours          */
+    char *typestr;                          /* Stockage de nom temporaire  */
+
+    if (routine->cached_decl == NULL)
+    {
+        if (routine->full_name != NULL)
+            new = _g_data_type_to_string(routine->full_name, false);
+        else
+            new = routine->name;
+
+        if (routine->namespace != NULL)
+        {
+            namespace = _g_data_type_to_string(routine->namespace, false);
+
+            new = strprep(new, routine->ns_sep);
+            new = strprep(new, namespace);
+
+            free(namespace);
+
+        }
+
+        /* Mémorisation finale */
+
+        routine->cached_decl = new;
+
+    }
+
+    if (full && routine->cached_full_decl == NULL)
+    {
+        /* Type de retour */
+
+        if (routine->ret_type == NULL)
+            new = strdup("??? ");
+        else
+        {
+            new = _g_data_type_to_string(routine->ret_type, true);
+            if (!g_data_type_is_pointer(routine->ret_type, true))
+                new = stradd(new, " ");
+        }
+
+        /* Nom de la routine */
+
+        new = stradd(new, routine->cached_decl);
+
+        /* Liste des arguments */
+
+        new = stradd(new, "(");
+
+        for (i = 0; i < routine->args_count; i++)
+        {
+            if (i > 0) new = stradd(new, ", ");
+
+            typestr = g_binary_variable_to_string(routine->args[i], true);
+            new = stradd(new, typestr);
+            free(typestr);
+
+        }
+
+        new = stradd(new, ")");
+
+        /* Mémorisation finale */
+
+        routine->cached_full_decl = new;
+
+    }
+
+    return (full ? routine->cached_full_decl : routine->cached_decl);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : routine = routine à mettre à jour.                           *
 *                offset  = position abstraite à retrouver.                    *
 *                local   = indique le type de variable à manipuler.           *
 *                                                                             *
diff --git a/src/analysis/routine.h b/src/analysis/routine.h
index 9ee2c2f..38e7b32 100644
--- a/src/analysis/routine.h
+++ b/src/analysis/routine.h
@@ -113,7 +113,7 @@ void g_binary_routine_set_size(GBinRoutine *, off_t);
 void g_binary_routine_set_type(GBinRoutine *, RoutineType);
 
 /* Définit le groupe d'appartenance d'une routine donnée. */
-void g_binary_routine_set_namespace(GBinRoutine *, GDataType *);
+void g_binary_routine_set_namespace(GBinRoutine *, GDataType *, const char *);
 
 /* Fournit le groupe d'appartenance d'une routine donnée. */
 GDataType *g_binary_routine_get_namespace(const GBinRoutine *);
@@ -122,10 +122,7 @@ GDataType *g_binary_routine_get_namespace(const GBinRoutine *);
 void g_binary_routine_set_name(GBinRoutine *, char *);
 
 /* Désignation humainement lisible ou NULL si non définie. */
-const char *g_binary_routine_get_name(GBinRoutine *);
-
-/* Fournit le nom long et humain d'une routine. */
-const char *g_binary_routine_get_long_name(GBinRoutine *);
+const char *g_binary_routine_get_name(const GBinRoutine *);
 
 /* Définit de façon indirecte le nom humain d'une routine. */
 void g_binary_routine_set_name_from_type(GBinRoutine *, GDataType *);
@@ -151,6 +148,9 @@ GBinVariable *g_binary_routine_get_arg(GBinRoutine *, size_t);
 /* Retire un argument d'une routine. */
 void g_binary_routine_remove_arg(GBinRoutine *, size_t);
 
+/* Fournit le nom humain d'une routine. */
+const char *g_binary_routine_get_declarator(GBinRoutine *, bool);
+
 /* S'assure qu'une variable est bien associée à une routine. */
 void g_binary_routine_register_if_needed(GBinRoutine *, size_t, bool);
 
diff --git a/src/analysis/type.c b/src/analysis/type.c
index 37ad5a1..23ecc2a 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -174,20 +174,22 @@ void g_data_type_set_namespace(GDataType *type, GDataType *namespace)
 char *_g_data_type_to_string(const GDataType *type, bool simple)
 {
     char *result;                           /* Chaîne à retourner          */
+    const GDataType *parent;                /* Espace supérieur            */
     char *namespace;                        /* Groupe d'appartenance       */
 
     result = type->to_string(type);
 
-    if (!simple && type->namespace != NULL)
-    {
-        namespace = g_data_type_to_string(type->namespace);
+    if (!simple)
+        for (parent = type->namespace; parent != NULL; parent = parent->namespace)
+        {
+            namespace = g_data_type_to_string(parent);
 
-        result = strprep(result, "." /* FIXME */);
-        result = strprep(result, namespace);
+            result = strprep(result, "." /* FIXME */);
+            result = strprep(result, namespace);
 
-        free(namespace);
+            free(namespace);
 
-    }
+        }
 
     if (type->qualifiers & TQF_RESTRICT)
         result = strprep(result, "restrict ");
diff --git a/src/format/dex/class.c b/src/format/dex/class.c
index a88f3f2..454cc40 100644
--- a/src/format/dex/class.c
+++ b/src/format/dex/class.c
@@ -24,6 +24,7 @@
 #include "class.h"
 
 
+#include <assert.h>
 #include <malloc.h>
 
 
@@ -194,6 +195,7 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
     GDexClass *result;                      /* Composant à retourner       */
     vmpa2t addr;                            /* Tête de lecture générique   */
     class_data_item data;                   /* Contenu de la classe        */
+    GDataType *ctype;                       /* Type créé par la classe     */
     uleb128_t index;                        /* Conservation du dernier id  */
     uleb128_t i;                            /* Boucle de parcours          */
     GDexMethod *method;                     /* Méthode chargée             */
@@ -230,6 +232,9 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
      */
     if (def->access_flags & ACC_ANNOTATION) goto gdcn_done;
 
+    ctype = get_type_from_dex_pool(format, def->class_idx);
+    assert(ctype != NULL);
+
     index = 0;
 
     result->dmethods_count = data.direct_methods_size;
@@ -246,6 +251,9 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
 
         routine = g_dex_method_get_routine(method);
 
+        g_object_ref(G_OBJECT(ctype));
+        g_binary_routine_set_namespace(routine, ctype, ".");
+
         symbol = g_binary_symbol_new(STP_ROUTINE);
         g_binary_symbol_attach_routine(symbol, routine);
 
@@ -269,6 +277,9 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
 
         routine = g_dex_method_get_routine(method);
 
+        g_object_ref(G_OBJECT(ctype));
+        g_binary_routine_set_namespace(routine, ctype, ".");
+
         symbol = g_binary_symbol_new(STP_ROUTINE);
         g_binary_symbol_attach_routine(symbol, routine);
 
@@ -276,13 +287,18 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
 
     }
 
+    g_object_unref(G_OBJECT(ctype));
+
  gdcn_done:
 
     return result;
 
- gdcn_bad_item:
  gdcn_bad_method:
 
+    g_object_unref(G_OBJECT(ctype));
+
+ gdcn_bad_item:
+
     g_object_unref(G_OBJECT(result));
 
     return NULL;
diff --git a/src/format/symbol.c b/src/format/symbol.c
index 2c2e5ad..965487d 100644
--- a/src/format/symbol.c
+++ b/src/format/symbol.c
@@ -329,7 +329,7 @@ const char *g_binary_symbol_get_label(const GBinSymbol *symbol)
         case STP_ROUTINE:
         case STP_ENTRY_POINT:
         case STP_CODE_LABEL:
-            result = g_binary_routine_get_name(symbol->extra.routine);
+            result = g_binary_routine_get_declarator(symbol->extra.routine, false);
             break;
 
         default:
-- 
cgit v0.11.2-87-g4458