summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2020-01-27 18:48:58 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2020-01-27 18:48:58 (GMT)
commitc1ca03be00a4e975f89d30edfb72b57fb5612282 (patch)
tree4884513252458a261eb1290c93748b2bbbd98ff8
parent1b3887c5609831bc2aee2f00f6a4d31d7406a225 (diff)
Created a huge optimization for the Dex format loading.
-rw-r--r--plugins/dex/class.c143
-rw-r--r--plugins/dex/class.h4
-rw-r--r--plugins/dex/pool.c45
-rw-r--r--src/common/sort.c35
-rw-r--r--src/common/sort.h3
-rw-r--r--src/format/format.c107
-rw-r--r--src/format/format.h3
7 files changed, 282 insertions, 58 deletions
diff --git a/plugins/dex/class.c b/plugins/dex/class.c
index dafa984..d549014 100644
--- a/plugins/dex/class.c
+++ b/plugins/dex/class.c
@@ -222,11 +222,7 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
uleb128_t index; /* Conservation du dernier id */
uleb128_t i; /* Boucle de parcours */
GDexField *field; /* Champ chargé */
- GDexPool *pool; /* Table de ressources */
- GDataType *ctype; /* Type créé par la classe */
- GBinFormat *base; /* Autre version du format */
GDexMethod *method; /* Méthode chargée */
- GBinRoutine *routine; /* Version interne de méthode */
result = g_object_new(G_TYPE_DEX_CLASS, NULL);
@@ -292,16 +288,6 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
* Chargement des méthodes de classe.
*/
- pool = g_dex_format_get_pool(format);
-
- ctype = g_dex_pool_get_type_(pool, def->class_idx);
-
- g_object_unref(G_OBJECT(pool));
-
- if (ctype == NULL) goto gdcn_unknown_type;
-
- base = G_BIN_FORMAT(format);
-
index = 0;
result->dmethods_count = data.direct_methods_size;
@@ -314,18 +300,6 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
result->direct_methods[i] = method;
- /* Ajout à la liste des symboles */
- if (g_dex_method_has_dex_body(method))
- {
- routine = g_dex_method_get_routine(method);
-
- g_object_ref(G_OBJECT(ctype));
- g_binary_routine_set_namespace(routine, ctype, strdup("."));
-
- g_binary_format_add_symbol(base, G_BIN_SYMBOL(routine));
-
- }
-
}
index = 0;
@@ -340,32 +314,14 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
result->virtual_methods[i] = method;
- /* Ajout à la liste des symboles */
- if (g_dex_method_has_dex_body(method))
- {
- routine = g_dex_method_get_routine(method);
-
- g_object_ref(G_OBJECT(ctype));
- g_binary_routine_set_namespace(routine, ctype, strdup("."));
-
- g_binary_format_add_symbol(base, G_BIN_SYMBOL(routine));
-
- }
-
}
- g_object_unref(G_OBJECT(ctype));
-
gdcn_done:
return result;
gdcn_bad_method:
- g_object_unref(G_OBJECT(ctype));
-
- gdcn_unknown_type:
-
gdcn_bad_field:
gdcn_bad_item:
@@ -379,7 +335,7 @@ GDexClass *g_dex_class_new(GDexFormat *format, const class_def_item *def)
/******************************************************************************
* *
-* Paramètres : class = informations chargées à consulter. *
+* Paramètres : class = informations chargées à consulter. *
* *
* Description : Fournit la définition brute d'une classe. *
* *
@@ -398,7 +354,7 @@ const class_def_item *g_dex_class_get_definition(const GDexClass *class)
/******************************************************************************
* *
-* Paramètres : class = informations chargées à consulter. *
+* Paramètres : class = informations chargées à consulter. *
* *
* Description : Fournit la définition brute des données d'une classe. *
* *
@@ -660,6 +616,101 @@ GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t
/******************************************************************************
* *
+* Paramètres : class = informations chargées à consulter. *
+* symbols = liste de symboles complétée. [OUT] *
+* count = taille de cette liste. [OUT] *
+* *
+* Description : Etablit une liste de tous les symboles d'une classe. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_dex_class_get_collect_symbols(const GDexClass *class, GBinSymbol ***symbols, size_t *count)
+{
+ bool result; /* Bilan à retourner */
+ GDexPool *pool; /* Table de ressources */
+ GDataType *ctype; /* Type créé par la classe */
+ size_t slots_used; /* Compteur d'utilisations */
+ size_t i; /* Boucle de parcours */
+ GDexMethod *method; /* Méthode chargée */
+ GBinRoutine *routine; /* Version interne de méthode */
+
+ result = false;
+
+ /* Contexte des méthodes */
+
+ pool = g_dex_format_get_pool(class->format);
+
+ ctype = g_dex_pool_get_type_(pool, class->definition.class_idx);
+
+ g_object_unref(G_OBJECT(pool));
+
+ if (ctype == NULL) goto unknown_type;
+
+ /* Intégration des méthodes */
+
+ *symbols = realloc(*symbols, (*count + class->dmethods_count + class->vmethods_count) * sizeof(GBinSymbol *));
+
+ result = true;
+
+ slots_used = 0;
+
+ for (i = 0; i < class->dmethods_count; i++)
+ {
+ method = class->direct_methods[i];
+
+ if (g_dex_method_has_dex_body(method))
+ {
+ routine = g_dex_method_get_routine(method);
+
+ g_object_ref(G_OBJECT(ctype));
+ g_binary_routine_set_namespace(routine, ctype, strdup("."));
+
+ (*symbols)[*count + slots_used] = G_BIN_SYMBOL(routine);
+ slots_used++;
+
+ }
+
+ }
+
+ *count += slots_used;
+
+ slots_used = 0;
+
+ for (i = 0; i < class->vmethods_count; i++)
+ {
+ method = class->virtual_methods[i];
+
+ if (g_dex_method_has_dex_body(method))
+ {
+ routine = g_dex_method_get_routine(method);
+
+ g_object_ref(G_OBJECT(ctype));
+ g_binary_routine_set_namespace(routine, ctype, strdup("."));
+
+ (*symbols)[*count + slots_used] = G_BIN_SYMBOL(routine);
+ slots_used++;
+
+ }
+
+ }
+
+ *count += slots_used;
+
+ g_object_unref(G_OBJECT(ctype));
+
+ unknown_type:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : class = informations chargées à consulter. *
* format = format permettant d'obtenir une adresse complète. *
* *
diff --git a/plugins/dex/class.h b/plugins/dex/class.h
index cae4a5a..a7874a7 100644
--- a/plugins/dex/class.h
+++ b/plugins/dex/class.h
@@ -50,7 +50,6 @@ typedef struct _GDexClass GDexClass;
typedef struct _GDexClassClass GDexClassClass;
-
/* Détermine le type d'une classe issue du code source. */
GType g_dex_class_get_type(void);
@@ -84,6 +83,9 @@ size_t g_dex_class_count_methods(const GDexClass *, bool);
/* Fournit une méthode chargée correspondant à un type donné. */
GDexMethod *g_dex_class_get_method(const GDexClass *, bool, size_t);
+/* Etablit une liste de tous les symboles d'une classe. */
+bool g_dex_class_get_collect_symbols(const GDexClass *, GBinSymbol ***, size_t *);
+
/* Intègre la méthode en tant que portion de code. */
void g_dex_class_include_as_portion(const GDexClass *, GExeFormat *);
diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c
index c24617a..d800e8f 100644
--- a/plugins/dex/pool.c
+++ b/plugins/dex/pool.c
@@ -251,6 +251,11 @@ bool g_dex_pool_load_all_string_symbols(GDexPool *pool, wgroup_id_t gid, GtkStat
gtk_status_stack_remove_activity(status, msg);
+ /* Insertion en tant que symboles */
+
+ if (result)
+ result = g_binary_format_add_symbols(G_BIN_FORMAT(pool->format), pool->strings, count);
+
return result;
}
@@ -367,7 +372,6 @@ GBinSymbol *g_dex_pool_get_string_symbol(GDexPool *pool, uint32_t index)
const char *string; /* Chaîne de caractères liée */
GBinFormat *base; /* Autre version du format */
GBinSymbol *new; /* Nouveau symbol créé */
- bool inserted; /* Bilan d'une insertion */
result = NULL;
@@ -385,16 +389,10 @@ GBinSymbol *g_dex_pool_get_string_symbol(GDexPool *pool, uint32_t index)
new = g_string_symbol_new_read_only(base, &range, SET_MUTF_8);
- g_string_symbol_build_label(G_STR_SYMBOL(new), base);
-
- g_object_ref(G_OBJECT(new));
- inserted = g_binary_format_add_symbol(base, new);
-
- if (inserted)
- pool->strings[index] = new;
+ if (new != NULL)
+ g_string_symbol_build_label(G_STR_SYMBOL(new), base);
- else
- g_object_unref(G_OBJECT(new));
+ pool->strings[index] = new;
}
@@ -1175,10 +1173,14 @@ bool g_dex_pool_load_all_classes(GDexPool *pool, wgroup_id_t gid, GtkStatusStack
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 */
+ guint i; /* Boucle de parcours #1 */
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*/
+ GBinSymbol **symbols; /* Symboles présents à injecter*/
+ size_t scount; /* Quantité de ces symboles */
+ uint32_t j; /* Boucle de parcours #2 */
+ size_t k; /* Boucle de parcours #3 */
result = true;
@@ -1216,6 +1218,27 @@ bool g_dex_pool_load_all_classes(GDexPool *pool, wgroup_id_t gid, GtkStatusStack
gtk_status_stack_remove_activity(status, msg);
+ /* Insertion en tant que symboles */
+
+ if (result)
+ {
+ symbols = NULL;
+ scount = 0;
+
+ for (j = 0; j < count && result; j++)
+ result = g_dex_class_get_collect_symbols(pool->classes[j], &symbols, &scount);
+
+ if (result)
+ result = g_binary_format_add_symbols(G_BIN_FORMAT(pool->format), symbols, count);
+
+ for (k = 0; k < scount; k++)
+ g_object_unref(symbols[k]);
+
+ if (symbols != NULL)
+ free(symbols);
+
+ }
+
return result;
}
diff --git a/src/common/sort.c b/src/common/sort.c
index e34d995..a905440 100644
--- a/src/common/sort.c
+++ b/src/common/sort.c
@@ -267,6 +267,41 @@ void *_qinsert(void *base, size_t *nmemb, size_t size, void *new, size_t index)
/******************************************************************************
* *
+* Paramètres : base = adresse du tableau à parcourir. *
+* nmemb = nombre d'éléments présents au total. [OUT] *
+* size = taille de chaque élément du tableau. *
+* new = nouveaux éléments à insérer. *
+* count = quantité de ces nouveaux éléments. *
+* index = indice du point d'insertion. *
+* *
+* Description : Ajoute à l'endroit indiqué des éléments dans un tableau. *
+* *
+* Retour : Nouvel emplacement du tableau agrandi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void *_qinsert_batch(void *base, size_t *nmemb, size_t size, void *new, size_t count, size_t index)
+{
+ void *result; /* Tableau trié à retourner */
+
+ result = realloc(base, (*nmemb + count) * size);
+
+ if (index < *nmemb)
+ memmove((char *)result + (index + count) * size, (char *)result + index * size, (*nmemb - index) * size);
+
+ (*nmemb) += count;
+
+ memcpy((char *)result + index * size, new, count * size);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : base = adresse du tableau à parcourir. *
* nmemb = nombre d'éléments présents au total. [OUT] *
* size = taille de chaque élément du tableau. *
diff --git a/src/common/sort.h b/src/common/sort.h
index eb86ccb..7362f64 100644
--- a/src/common/sort.h
+++ b/src/common/sort.h
@@ -49,6 +49,9 @@ bool bsearch_index(const void *, const void *, size_t, size_t, __compar_fn_t, si
/* Ajoute à l'endroit indiqué un élément dans un tableau. */
void *_qinsert(void *, size_t *, size_t, void *, size_t);
+/* Ajoute à l'endroit indiqué des éléments dans un tableau. */
+void *_qinsert_batch(void *, size_t *, size_t, void *, size_t, size_t);
+
/* Ajoute au bon endroit un élément dans un tableau trié. */
void *qinsert(void *, size_t *, size_t, __compar_fn_t, void *);
diff --git a/src/format/format.c b/src/format/format.c
index ab4864f..f6a4bd0 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -871,6 +871,113 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol)
/******************************************************************************
* *
+* Paramètres : format = informations chargées à compléter. *
+* symbols = ensemble de symboles à ajouter à la liste. *
+* count = taille de cet ensemble. *
+* *
+* Description : Ajoute plusieurs symboles à la collection du format binaire. *
+* *
+* Retour : true si les symboles dûment localisés ont été insérés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_t count)
+{
+ bool result; /* Statut d'ajout à retourner */
+#ifndef NDEBUG
+ phys_t last; /* Dernière position rencontrée*/
+#endif
+ size_t i; /* Boucle de parcours */
+#ifndef NDEBUG
+ const mrange_t *range; /* Couverture du symbole */
+ const vmpa2t *addr; /* Emplacement du symbole */
+#endif
+ size_t index; /* Indice du point d'insertion */
+
+ /**
+ * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol()
+ * fassent bien leur office, il faut que les symboles soient triés.
+ *
+ * Cependant, les localisations à satisfaire lors d'une recherche recontrent
+ * un problème si les positions physiques ne sont pas renseignées. En effet
+ * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas
+ * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le
+ * même ordre que les segments du binaire).
+ *
+ * Comme les comparaisons entre localisations se réalisent sur les éléments
+ * renseignés communs, à commencer par la position physique si c'est possible,
+ * une localisation s'appuyant uniquement sur une adresse virtuelle va être
+ * analysée suivant une liste non triée d'adresses virtuelles.
+ *
+ * On corrige donc le tir si besoin est en forçant la comparaison via les
+ * positions physiques.
+ */
+
+#ifndef NDEBUG
+ last = VMPA_NO_PHYSICAL;
+
+ for (i = 0; i < count; i++)
+ {
+ range = g_binary_symbol_get_range(symbols[i]);
+ addr = get_mrange_addr(range);
+
+ assert(has_phys_addr(addr)
+ || g_binary_symbol_get_status(symbols[i]) == SSS_IMPORTED
+ || g_binary_symbol_get_status(symbols[i]) == SSS_DYNAMIC);
+
+
+ if (has_phys_addr(addr))
+ {
+ assert(last == VMPA_NO_PHYSICAL || last <= get_phy_addr(addr));
+ last = get_phy_addr(addr);
+ }
+
+ }
+#endif
+
+ g_binary_format_lock_unlock_symbols_wr(format, true);
+
+ /**
+ * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution
+ * amènent à la création d'un même symbole.
+ *
+ * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps)
+ * pour faire une vérification avant construction puis ajout, on préfère limiter
+ * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la
+ * construction du symbole dans les cas peu fréquents où le symbole était déjà en place.
+ */
+
+ result = bsearch_index(symbols[0], format->symbols, format->sym_count,
+ sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index);
+
+ if (!result)
+ {
+ for (i = 0; i < count; i++)
+ g_object_ref(G_OBJECT(symbols[i]));
+
+ format->symbols = _qinsert_batch(format->symbols, &format->sym_count,
+ sizeof(GBinSymbol *), symbols, count, index);
+
+ format->sym_stamp++;
+ result = true;
+
+ }
+
+ g_binary_format_lock_unlock_symbols_wr(format, false);
+
+ if (result)
+ for (i = 0; i < count; i++)
+ g_signal_emit_by_name(format, "symbol-added", symbols[i]);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : format = informations chargées à compléter. *
* index = indice du symbole à retirer de la liste. *
* *
diff --git a/src/format/format.h b/src/format/format.h
index 748fd54..b001a15 100644
--- a/src/format/format.h
+++ b/src/format/format.h
@@ -129,6 +129,9 @@ GBinSymbol *g_binary_format_get_symbol(const GBinFormat *, size_t);
/* Ajoute un symbole à la collection du format binaire. */
bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *);
+/* Ajoute plusieurs symboles à la collection du format binaire. */
+bool g_binary_format_add_symbols(GBinFormat *, GBinSymbol **, size_t);
+
/* Retire un symbole de la collection du format binaire. */
void g_binary_format_remove_symbol(GBinFormat *, GBinSymbol *);