diff options
Diffstat (limited to 'plugins/elf/loading.c')
-rw-r--r-- | plugins/elf/loading.c | 453 |
1 files changed, 410 insertions, 43 deletions
diff --git a/plugins/elf/loading.c b/plugins/elf/loading.c index 377eb14..5d82fcc 100644 --- a/plugins/elf/loading.c +++ b/plugins/elf/loading.c @@ -24,13 +24,19 @@ #include "loading.h" +#include <assert.h> +#include <string.h> + + #include <i18n.h> +#include <common/extstr.h> +#include <common/sort.h> #include <core/logs.h> +#include <core/params.h> #include <glibext/delayed-int.h> #include "elf-int.h" -#include "section.h" @@ -41,24 +47,58 @@ struct _GElfLoading GElfFormat *format; /* Format à faire évoluer */ + phys_t str_start; /* Chaînes à disposition */ + union { struct { - const elf_shdr *section; /* Section à éplucher */ bool use_virt; /* Représentatio par défaut */ - elf_shdr strtab; /* Section .strtab trouvée */ - bool has_strtab; /* Présence de cette section */ + }; + + struct + { + elf_rel *relocs_to_fill; /* Tableau à remplir */ + + }; + + struct + { + elf_rel *relocs; /* Relocalisations présentes */ + size_t rel_count; /* Qté de ces relocalisations */ + + phys_t sym_start; /* Début de zone des symboles */ + uint32_t sym_count; /* Nombre de symboles présents */ }; + }; - elf_loading_cb callback; /* Routine de traitement finale*/ - phys_t first; /* Position du premier élément */ - phys_t begin; /* Point de départ du parcours */ - phys_t end; /* Point d'arrivée exclu */ + union + { + struct + { + phys_t begin; /* Point de départ du parcours */ + phys_t end; /* Point d'arrivée exclu */ + + elf_loading_cb callback_0; /* Routine de traitement #0 */ + + }; + + struct + { + sym_iter_t *iter; /* Symboles à parcourir */ + + elf_applying_cb callback_1; /* Routine de traitement #1 */ + + }; + + }; + + unsigned int kind; /* Type de traitements */ + bool status; /* Bilan des traitements */ activity_id_t id; /* Identifiant pour messages */ @@ -136,6 +176,7 @@ static void g_elf_loading_class_init(GElfLoadingClass *klass) static void g_elf_loading_init(GElfLoading *loading) { + loading->status = false; } @@ -180,12 +221,61 @@ static void g_elf_loading_finalize(GElfLoading *loading) /****************************************************************************** * * -* Paramètres : format = = ensemble d'instructions désassemblées. * -* section = prototypes existants à insérer. * -* use_virt = quantité de ces prototypes. * -* first = position du premier élément. * +* Paramètres : format = ensemble d'instructions désassemblées. * +* str_start = début des chaînes de caractères à consulter. * +* first = position du premier élément. * +* begin = point de départ du parcours de liste. * +* end = point d'arrivée exclu du parcours. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* * +* Description : Crée une tâche de chargement pour ELF différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GElfLoading *g_elf_loading_new_for_symbols(GElfFormat *format, phys_t str_start, phys_t first, phys_t begin, phys_t end, activity_id_t id, elf_loading_cb callback) +{ + GElfLoading *result; /* Tâche à retourner */ +#ifndef NDEBUG + bool status; /* Etat d'une consultation */ +#endif + + result = g_object_new(G_TYPE_ELF_LOADING, NULL); + + result->format = format; + + result->str_start = str_start; + +#ifndef NDEBUG + status = g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &result->use_virt); + assert(status); +#else + g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &result->use_virt); +#endif + + result->begin = begin; + result->end = end; + result->callback_0 = callback; + + result->kind = 0; + + result->id = id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = ensemble d'instructions désassemblées. * * begin = point de départ du parcours de liste. * * end = point d'arrivée exclu du parcours. * +* relocs = table des relocalisations à remplir. * * id = identifiant du message affiché à l'utilisateur. * * callback = routine de traitements particuliers. * * * @@ -197,7 +287,7 @@ static void g_elf_loading_finalize(GElfLoading *loading) * * ******************************************************************************/ -GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool use_virt, phys_t first, phys_t begin, phys_t end, activity_id_t id, elf_loading_cb callback) +GElfLoading *g_elf_loading_new_for_relocations(GElfFormat *format, phys_t begin, phys_t end, elf_rel *relocs, activity_id_t id, elf_loading_cb callback) { GElfLoading *result; /* Tâche à retourner */ @@ -205,17 +295,15 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool result->format = format; - result->section = section; - result->use_virt = use_virt; + result->str_start = VMPA_NO_PHYSICAL; - result->has_strtab = find_elf_section_by_index(format, - ELF_SHDR(format, *section, sh_link), - &result->strtab); + result->relocs_to_fill = relocs; - result->callback = callback; - result->first = first; result->begin = begin; result->end = end; + result->callback_0 = callback; + + result->kind = 0; result->id = id; @@ -226,8 +314,55 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool /****************************************************************************** * * -* Paramètres : study = étude de routines à mener. * -* status = barre de statut à tenir informée. * +* Paramètres : format = ensemble d'instructions désassemblées. * +* iter = itérateur sur les symboles à parcourir. * +* str_start = début de la zone contenant les descriptions. * +* relocs = table des relocalisations chargées. * +* rel_count = nombre de ces éléments à interpréter. * +* sym_start = localisation du début de la zone de symboles. * +* sym_count = nombre de descriptions de symbole attendues. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* * +* Description : Crée une tâche de chargement pour ELF différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GElfLoading *g_elf_loading_new_for_applying(GElfFormat *format, sym_iter_t *iter, phys_t str_start, elf_rel *relocs, size_t rel_count, phys_t sym_start, uint32_t sym_count, activity_id_t id, elf_applying_cb callback) +{ + GElfLoading *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_ELF_LOADING, NULL); + + result->format = format; + + result->str_start = str_start; + + result->relocs = relocs; + result->rel_count = rel_count; + result->sym_start = sym_start; + result->sym_count = sym_count; + + result->iter = iter; + result->callback_1 = callback; + + result->kind = 1; + + result->id = id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = traitements différés à mener. * +* status = barre de statut à tenir informée. * * * * Description : Assure le chargement pour un format ELF en différé. * * * @@ -239,22 +374,66 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) { + GElfFormat *format; /* Format plus accessible */ phys_t iter; /* Boucle de parcours */ phys_t old; /* Sauvegarde du point d'avant */ bool ret; /* Bilan d'un appel */ + size_t processed; /* Nombre de symboles traités */ + GBinSymbol *symbol; /* Symbole analysé */ + + format = loading->format; - for (iter = loading->begin; iter < loading->end; ) + switch (loading->kind) { - old = iter; - ret = loading->callback(loading, loading->format, &iter); + case 0: - if (!ret) - { - log_variadic_message(LMT_ERROR, _("Error while loading ELF data @ 0x%08x!"), old); + for (iter = loading->begin; iter < loading->end; ) + { + old = iter; + ret = loading->callback_0(loading, format, &iter); + + if (!ret) + { + log_variadic_message(LMT_ERROR, _("Error while loading ELF data @ 0x%08x!"), old); + break; + } + + gtk_status_stack_update_activity_value(status, loading->id, 1); + + } + + loading->status = (iter == loading->end); break; - } - gtk_status_stack_update_activity_value(status, loading->id, 1); + case 1: + + ret = true; + + processed = 0; + + for (symbol = get_symbol_iterator_next(loading->iter); + symbol != NULL && ret; + symbol = get_symbol_iterator_next(loading->iter)) + { + ret = loading->callback_1(loading, format, symbol); + + if (!ret) + { + log_variadic_message(LMT_ERROR, _("Error while applying ELF relocation %zu!"), processed); + break; + } + + processed++; + + gtk_status_stack_update_activity_value(status, loading->id, 1); + + if (processed == loading->rel_count) + break; + + } + + loading->status = (processed == loading->rel_count); + break; } @@ -263,14 +442,95 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) /****************************************************************************** * * -* Paramètres : loading = chargement pour ELF à mener. * -* section = prototypes existants à insérer. [OUT] * -* use_virt = quantité de ces prototypes. [OUT] * -* strtab = informations quant à la table des chaînes. [OUT]* -* has_strtab = validité du champ précédemment renseigné. [OUT] * -* first = position du premier élément. [OUT] * +* Paramètres : loading = procédure de chargements écoulés à consulter. * +* * +* Description : Fournit le bilan des traitements différés. * +* * +* Retour : true si tout s'est bien déroulé. * * * -* Description : Fournit les infos utiles au chargement de symbols internes. * +* Remarques : - * +* * +******************************************************************************/ + +bool g_elf_loading_get_status(const GElfLoading *loading) +{ + return loading->status; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à mener. * +* name = indice de la désignation du symbole concerné. * +* virt = adresse virtuelle du symbole en mémoire. * +* prefix = préfixe d'une désignation par défaut. * +* alt = zone de constitution d'un nom alternatif. [OUT] * +* addr = localisation compléte à associer au symbole. [OUT] * +* * +* Description : Construit la désignation adaptée à un symbole. * +* * +* Retour : Pointeur vers une étiquette constituée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_elf_loading_build_name(const GElfLoading *loading, uint32_t name, virt_t virt, const char *prefix, char *alt, vmpa2t *addr) +{ + const char *result; /* Désignation à retourner */ + GElfFormat *format; /* Format plus accessible */ + vmpa2t pos; /* Position de lecture */ + const GBinContent *content; /* Contenu binaire à lire */ + size_t plen; /* Taille du préfixe */ + + result = NULL; + + format = loading->format; + + if (g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, addr)) + { + init_vmpa(&pos, loading->str_start + name, VMPA_NO_VIRTUAL); + + content = G_BIN_FORMAT(format)->content; + + result = (const char *)g_binary_content_get_raw_access(content, &pos, 1); + + if (result != NULL && result[0] == '\0') + result = NULL; + + if (result == NULL) + { + /** + * Charge à l'appelant de s'assurer que la zone tampon est assez grande ! + */ + + strcpy(alt, prefix); + plen = strlen(prefix); + + if (loading->use_virt) + vmpa2_virt_to_string(addr, MDS_UNDEFINED, alt + plen, NULL); + else + vmpa2_phys_to_string(addr, MDS_UNDEFINED, alt + plen, NULL); + + result = alt; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à compléter. * +* iter = tête de lecture courante. * +* reloc = relocalisation à conserver en mémoire. * +* * +* Description : Intègre dans la liste adaptée une relocalisation chargée. * * * * Retour : - * * * @@ -278,14 +538,121 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) * * ******************************************************************************/ -void g_elf_loading_get_internal_info(GElfLoading *loading, const elf_shdr **section, bool *use_virt, const elf_shdr **strtab, bool *has_strtab, phys_t *first) +void g_elf_loading_store_relocation(const GElfLoading *loading, const phys_t *iter, const elf_rel *reloc) +{ + GElfFormat *format; /* Format plus accessible */ + size_t index; /* Indice de l'élément */ + + format = loading->format; + + index = (*iter - loading->begin); + + assert(index % sizeof(ELF_SIZEOF_REL(format)) == 0); + + index /= sizeof(ELF_SIZEOF_REL(format)); + + /* La tête de lecture a consommé un élément ! */ + index--; + + memcpy(&loading->relocs_to_fill[index], reloc, sizeof(elf_rel)); + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à consulter. * +* offset = décalage à retrouver idéalement. * +* reloc = informations quant à la relocalisation. [OUT] * +* * +* Description : Recherche une relocalisation par son décalage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_elf_loading_search_for_relocation(const GElfLoading *loading, const uint64_t *offset, elf_rel **reloc) { - *section = loading->section; - *use_virt = loading->use_virt; + bool result; /* Validité à faire remonter */ + void *found; /* Eventuel élément trouvé */ + + int compare_relocations(const uint64_t *off, const elf_rel *rel) + { + return sort_uint64_t(*off, ELF_REL(loading->format, *rel, r_offset)); + } - *strtab = &loading->strtab; - *has_strtab = loading->has_strtab; + found = bsearch(offset, loading->relocs, loading->rel_count, + sizeof(elf_rel), (__compar_fn_t)compare_relocations); - *first = loading->first; + result = (found != NULL); + + if (result) + *reloc = (elf_rel *)found; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à poursuivre. * +* index = indice du symbole concerné. * +* * +* Description : Construit la désignation adaptée à un symbole importé. * +* * +* Retour : Nouvelle étiquette constituée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_elf_loading_build_plt_name(const GElfLoading *loading, uint64_t index) +{ + char *result; /* Désignation à retourner */ + GElfFormat *format; /* Format plus accessible */ + phys_t offset; /* Tête de lecture brute */ + elf_sym sym; /* Symbole aux infos visées */ + bool status; /* Bilan de récupération */ + uint32_t name; /* Indice du nom du symbole */ + vmpa2t pos; /* Position de lecture */ + const GBinContent *content; /* Contenu binaire à lire */ + const char *prefix; /* Première partie de nom */ + + format = loading->format; + + offset = loading->sym_start + index * ELF_SIZEOF_SYM(format); + + status = read_elf_symbol(format, &offset, &sym); + + if (!status) + result = NULL; + + else + { + name = ELF_SYM(format, sym, st_name); + + offset = loading->str_start + name; + + init_vmpa(&pos, offset, VMPA_NO_VIRTUAL); + + content = G_BIN_FORMAT(format)->content; + + prefix = (const char *)g_binary_content_get_raw_access(content, &pos, 1); + + if (prefix != NULL && prefix[0] == '\0') + result = NULL; + + else + { + result = strdup(prefix); + result = stradd(result, "@plt"); + } + + } + + return result; } |