summaryrefslogtreecommitdiff
path: root/plugins/elf/loading.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-01-29 20:56:31 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-01-29 21:04:47 (GMT)
commit6c51b9eed427fd55ce1457834853386cc8d543cd (patch)
tree47b8106bdb086278386d05c838178a06cc00f805 /plugins/elf/loading.c
parent8a7d7b3303dee1a381893391c04acab35dec6942 (diff)
Handled properly imported/exported ELF symbols, as well as all other symbols.
Diffstat (limited to 'plugins/elf/loading.c')
-rw-r--r--plugins/elf/loading.c453
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;
}