diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/sort.c | 35 | ||||
-rw-r--r-- | src/common/sort.h | 3 | ||||
-rw-r--r-- | src/format/format.c | 107 | ||||
-rw-r--r-- | src/format/format.h | 3 |
4 files changed, 148 insertions, 0 deletions
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 *); |