summaryrefslogtreecommitdiff
path: root/plugins/elf/symbols.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/elf/symbols.c')
-rw-r--r--plugins/elf/symbols.c1020
1 files changed, 723 insertions, 297 deletions
diff --git a/plugins/elf/symbols.c b/plugins/elf/symbols.c
index 7bf68f5..4854d7b 100644
--- a/plugins/elf/symbols.c
+++ b/plugins/elf/symbols.c
@@ -26,15 +26,17 @@
#include <assert.h>
#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
#include <i18n.h>
#include <arch/raw.h>
#include <common/extstr.h>
+#include <common/sort.h>
#include <core/global.h>
#include <core/logs.h>
-#include <core/params.h>
+#include <format/symiter.h>
#include <format/mangling/demangler.h>
@@ -47,11 +49,7 @@
-
-
-
-
-
+/* ------------------------- CHARGEMENT GLOBAL DES SYMBOLES ------------------------- */
/* Enregistre un point d'entrée au sein d'un binaire ELF. */
@@ -60,44 +58,59 @@ static void register_elf_entry_point(GElfFormat *, virt_t, phys_t, GBinRoutine *
/* Enumère tous les points d'entrée principaux d'un binaire ELF. */
static bool load_all_elf_basic_entry_points(GElfFormat *);
+/* Assure le chargement des symboles internes ELF en différé. */
+static bool do_elf_symbol_loading(GElfLoading *, GElfFormat *, bool, phys_t *, GBinSymbol **);
+/* Charge tous les symboles possibles. */
+static void add_all_elf_symbols(GElfFormat *, phys_t, size_t, phys_t, GWorkQueue *, wgroup_id_t, elf_loading_cb, GtkStatusStack *, activity_id_t);
+/* --------------------------- DETAIL DES SYMBOLES LOCAUX --------------------------- */
-
-
-/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */
-
-
-/* Assure le chargement des symboles internes ELF en différé. */
-static bool do_elf_internal_symbol_loading(GElfLoading *, GElfFormat *, phys_t *);
+/* Assure le chargement des symboles locaux ELF en différé. */
+static bool do_elf_local_symbol_loading(GElfLoading *, GElfFormat *, phys_t *);
/* Charge tous les symboles internes possibles. */
-static bool load_elf_internal_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *);
+static bool load_elf_local_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *);
+
+/* --------------------------- DETAIL DE SYMBOLES GLOBAUX --------------------------- */
-/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */
+/* Assure le chargement des symboles globaux ELF en différé. */
+static bool do_elf_global_symbol_loading(GElfLoading *, GElfFormat *, phys_t *);
-/* Retrouve un élément donné dans la section dynamique. */
-static bool find_elf_dynamic_item(const GElfFormat *, const elf_shdr *, int32_t, elf_dyn *);
+/* Dénombre le nombre de symboles en lien avec l'extérieur. */
+static bool count_elf_global_symbols(GElfFormat *, GExeFormat *, uint32_t *);
/* Charge tous les éléments dynamiques externes possibles. */
-static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);
+static bool load_elf_global_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *);
+/* ----------------------- PRISE EN COMPTE DE RELOCALISATIONS ----------------------- */
+/* Assure le chargement des relocalisations ELF en différé. */
+static bool do_elf_relocation_loading(GElfLoading *, GElfFormat *, phys_t *);
+/* Charge en mémoire toutes les relocalisations présentes. */
+static bool load_elf_relocations(GElfFormat *, const elf_phdr *, elf_rel **, size_t *, GtkStatusStack *);
+/* Assure l'intégration d'un symbole issu des relocalisations. */
+static bool do_elf_relocation_renaming(GElfLoading *, GElfFormat *, GBinSymbol *);
+/* Applique les étiquettes issues des relocalisations. */
+static bool apply_elf_relocations(GElfFormat *, elf_rel *, size_t, sym_iter_t *, GtkStatusStack *);
+/* ---------------------------------------------------------------------------------- */
+/* CHARGEMENT GLOBAL DES SYMBOLES */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -118,46 +131,31 @@ bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status)
bool result; /* Bilan à retourner */
wgroup_id_t gid; /* Identifiant pour les tâches */
- elf_shdr *sections; /* Groupe de sections trouvées */
- size_t count; /* Quantité de données */
-
result = true;
gid = g_work_queue_define_work_group(get_work_queue());
/* Symboles internes */
- result &= load_elf_internal_symbols(format, gid, status);
-
-
-
+ result &= load_elf_local_symbols(format, gid, status);
- /* Symboles externes */
+ /* Symboles importés et/ou exportés */
- if (find_elf_sections_by_type(format, SHT_DYNAMIC, &sections, &count))
+ if (find_elf_dynamic_program_header(format, (elf_phdr []) { 0 }))
{
log_variadic_message(LMT_INFO, _("Binary is dynamically linked"));
- result &= load_elf_external_symbols(format, &sections[0]);
-
- free(sections);
+ result &= load_elf_global_symbols(format, gid, status);
}
else log_variadic_message(LMT_INFO, _("Binary is statically linked"));
-
-
-
/* Symboles d'entrée, si encore besoin */
/**
* Le tri en préalable
*/
-
-
-
-
result &= load_all_elf_basic_entry_points(format);
return result;
@@ -165,9 +163,6 @@ bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status)
}
-
-
-
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
@@ -429,68 +424,293 @@ static bool load_all_elf_basic_entry_points(GElfFormat *format)
}
+/******************************************************************************
+* *
+* Paramètres : loading = chargement de symboles en cours. *
+* format = format ELF à compléter. *
+* local = s'apprête-t-on à constuire un symbole interne ? *
+* iter = tête de lecture évoluant avec le temps. [OUT] *
+* new = éventuel renseignement du nouveau symbole. [OUT] *
+* *
+* Description : Assure le chargement des symboles internes ELF en différé. *
+* *
+* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool do_elf_symbol_loading(GElfLoading *loading, GElfFormat *format, bool local, phys_t *iter, GBinSymbol **new)
+{
+ bool result; /* Bilan à retourner */
+ elf_sym sym; /* Symbole aux infos visées */
+ virt_t virt; /* Adresse virtuelle */
+ SymbolStatus status; /* Visibilité du symbole */
+ GBinFormat *base; /* Version basique du format */
+ uint32_t index; /* Indice du nom du symbole */
+ const char *name; /* Nom du symbole trouvé */
+ GBinSymbol *symbol; /* Nouveau symbole construit */
+ char alt_name[6 + VMPA_MAX_LEN]; /* Nom abstrait de substitution*/
+ virt_t original_virt; /* Adresse virtuelle retenue */
+ vmpa2t addr; /* Localisation d'un symbole */
+ mrange_t range; /* Couverture mémoire associée */
+ GBinRoutine *routine; /* Nouvelle routine trouvée */
+
+ if (new != NULL)
+ *new = NULL;
+
+ result = read_elf_symbol(format, iter, &sym);
+ if (!result) goto desl_done;
+
+ /**
+ * Si l'adresse virtuelle est nulle, on ne peut ratacher le symbole à aucune position...
+ *
+ * On ne réalise donc aucune opération ici, quitte à laisser une seconde passe
+ * s'occuper des symboles importés par exemple.
+ */
+
+ virt = ELF_SYM(format, sym, st_value);
+ if (virt == 0) goto desl_done;
+
+ /**
+ * En ce qui concerne la nature de la visibilité, on distingue les deux situations suivantes :
+ * - zone DYNSYM : uniquement les importations / exportations.
+ * - zone SYMTAB : tous les symboles.
+ *
+ * La première zone doit donc être traitée en amont, et la seconde complète les traitements
+ * avec à priori uniquement des symboles locaux.
+ */
+
+ if (local)
+ status = SSS_INTERNAL;
+
+ else
+ status = ELF_SYM(format, sym, st_shndx) == 0 ? SSS_IMPORTED : SSS_EXPORTED;
+
+ /* Traitements particuliers */
+
+ base = G_BIN_FORMAT(format);
+
+ index = ELF_SYM(format, sym, st_name);
+ switch (ELF_ST_TYPE(format, sym))
+ {
+ case STT_OBJECT:
+
+ name = g_elf_loading_build_name(loading, index, virt, "obj_", alt_name, &addr);
+ if (name == NULL) break;
+
+ init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
+
+ symbol = g_binary_symbol_new(&range, STP_OBJECT);
+
+ g_binary_symbol_set_alt_label(symbol, name);
+
+ break;
+
+ case STT_FUNC:
+
+ original_virt = virt;
+
+ /* Ajustement de la position */
+
+ if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
+ virt &= ~0x1;
+
+ /* Constitution d'une routine */
+
+ name = g_elf_loading_build_name(loading, index, virt, "func_", alt_name, &addr);
+ if (name == NULL) break;
+
+ routine = try_to_demangle_routine(name);
+ symbol = G_BIN_SYMBOL(routine);
+
+ init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
+
+ g_binary_symbol_set_range(symbol, &range);
+
+ /* Comptabilisation pour le désassemblage brut */
+
+ g_binary_format_register_code_point(base, original_virt, false);
+
+ break;
+
+ default:
+ symbol = NULL;
+ break;
+
+ }
+
+ if (symbol != NULL)
+ {
+ g_binary_symbol_set_status(symbol, status);
+
+ if (new != NULL)
+ {
+ g_object_ref(G_OBJECT(symbol));
+ *new = symbol;
+ }
+
+ g_binary_format_add_symbol(base, symbol);
+ }
+ desl_done:
+ return result;
+}
/******************************************************************************
* *
-* Paramètres : format = description de l'exécutable à consulter. *
-* sym = section comprenant les symboles à venir lire. *
-* index = indice de l'entrée à venir lire. *
-* symbol = ensemble d'informations lues. [OUT] *
+* Paramètres : format = description de l'exécutable à compléter. *
+* sym_start = localisation du début de la zone de symboles. *
+* count = nombre de descriptions de symbole attendues. *
+* str_start = début de la zone contenant les descriptions. *
+* wq = espace de travail dédié. *
+* gid = groupe de travail impliqué. *
+* callback = routine de traitements particuliers. *
+* status = barre de statut à tenir informée. *
+* msg = identifiant du message de progression. *
* *
-* Description : Récupère la définition complète d'un symbole donné. *
+* Description : Charge tous les symboles possibles. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool get_elf_symbol_by_index(GElfFormat *format, const elf_shdr *sym, off_t index, elf_sym *symbol)
+static void add_all_elf_symbols(GElfFormat *format, phys_t sym_start, size_t count, phys_t str_start, GWorkQueue *wq, wgroup_id_t gid, elf_loading_cb callback, GtkStatusStack *status, activity_id_t msg)
{
- phys_t sym_start; /* Début de section */
- phys_t sym_size; /* Taille de section */
- phys_t offset; /* Emplacement à venir lire */
+ phys_t sym_size; /* Taille de chaque symbole lu */
+ guint runs_count; /* Qté d'exécutions parallèles */
+ phys_t run_size; /* Volume réparti par exécution*/
+ guint i; /* Boucle de parcours */
+ phys_t begin; /* Début de zone de traitement */
+ phys_t end; /* Fin d'un zone de traitement */
+ GElfLoading *loading; /* Tâche de chargement à lancer*/
+
+ sym_size = ELF_SIZEOF_SYM(format);
+
+ runs_count = g_get_num_processors();
- get_elf_section_content(format, sym, &sym_start, &sym_size, NULL);
+ run_size = count / runs_count;
- offset = sym_start + index * ELF_SIZEOF_SYM(format);
- if ((offset + ELF_SIZEOF_SYM(format)) > (sym_start + sym_size)) return NULL;
+ gtk_status_stack_extend_activity(status, msg, count);
- return read_elf_symbol(format, &offset, symbol);
+ for (i = 0; i < runs_count; i++)
+ {
+ begin = sym_start + i * run_size * sym_size;
+
+ if ((i + 1) == runs_count)
+ end = sym_start + count * sym_size;
+ else
+ end = begin + run_size * sym_size;
+
+ loading = g_elf_loading_new_for_symbols(format, str_start, sym_start, begin, end, msg, callback);
+
+ g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid);
+
+ }
}
+
+/* ---------------------------------------------------------------------------------- */
+/* DETAIL DES SYMBOLES LOCAUX */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : format = description de l'exécutable à consulter. *
-* sym = section comprenant les symboles à venir lire. *
-* str = section de chaînes de caractères pour les noms. *
-* index = indice de l'entrée à venir lire. *
+* Paramètres : loading = chargement de symboles externes en cours. *
+* format = format ELF à compléter. *
+* iter = tête de lecture évoluant avec le temps. [OUT] *
* *
-* Description : Récupère la désignation d'un symbole donné. *
+* Description : Assure le chargement des symboles locaux ELF en différé. *
* *
-* Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. *
+* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. *
* *
* Remarques : - *
* *
******************************************************************************/
-const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const elf_shdr *str, off_t index)
+static bool do_elf_local_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
{
- const char *result; /* Résultat à retourner */
- elf_sym symbol; /* Symbole aux infos visées */
+ bool result; /* Bilan à retourner */
+
+ result = do_elf_symbol_loading(loading, format, true, iter, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à compléter. *
+* gid = groupe de travail impliqué. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Charge tous les symboles internes possibles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool load_elf_local_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+{
+ bool result; /* Bilan à retourner */
+ activity_id_t msg; /* Message de progression */
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ size_t size; /* Taille de chaque symbole lu */
+ elf_shdr *symtabs; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+ size_t i; /* Boucle de parcours */
+ phys_t sym_start; /* Début de la zone à traiter */
+ phys_t sym_size; /* Taille de cette même zone */
+ size_t sym_count; /* Nombre de symboles déduits */
+ elf_shdr strtab; /* Section dédiées aux chaînes */
+ phys_t str_start; /* Début de cette section */
+
+ result = true;
+
+ msg = gtk_status_stack_add_activity(status, _("Loading local symbols..."), 0);
+
+ queue = get_work_queue();
+
+ size = ELF_SIZEOF_SYM(format);
+
+ if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtabs, &count))
+ for (i = 0; i < count; i++)
+ {
+ get_elf_section_content(format, &symtabs[i], &sym_start, &sym_size, NULL);
+
+ if (sym_size % size != 0)
+ continue;
+
+ sym_count = sym_size / size;
- result = NULL;
+ if (!find_elf_section_by_index(format, ELF_SHDR(format, symtabs[i], sh_link), &strtab))
+ continue;
- if (get_elf_symbol_by_index(format, sym, index, &symbol))
- result = extract_name_from_elf_string_section(format, str, ELF_SYM(format, symbol, st_name));
+ get_elf_section_content(format, &strtab, &str_start, NULL, NULL);
+
+ add_all_elf_symbols(format, sym_start, sym_count, str_start,
+ queue, gid, do_elf_local_symbol_loading, status, msg);
+
+ }
+
+ g_work_queue_wait_for_completion(queue, gid);
+
+ gtk_status_stack_remove_activity(status, msg);
+
+ if (symtabs != NULL) free(symtabs);
return result;
@@ -499,181 +719,193 @@ const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const e
/* ---------------------------------------------------------------------------------- */
-/* DETAIL DES SYMBOLES INTERNES */
+/* DETAIL DE SYMBOLES GLOBAUX */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : loading = chargement de symboles internes en cours. *
+* Paramètres : loading = chargement de symboles externes en cours. *
* format = format ELF à compléter. *
* iter = tête de lecture évoluant avec le temps. [OUT] *
* *
-* Description : Assure le chargement des symboles internes ELF en différé. *
+* Description : Assure le chargement des symboles globaux ELF en différé. *
* *
-* Retour : - *
+* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
+static bool do_elf_global_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
{
bool result; /* Bilan à retourner */
- elf_sym sym; /* Symbole aux infos visées */
- SymbolStatus status; /* Visibilité du symbole */
- vmpa2t addr; /* Localisation d'un symbole */
- virt_t virt; /* Adresse virtuelle */
- const elf_shdr *section; /* Groupe de sections trouvées */
- bool use_virt; /* Choix de construction de nom*/
- const elf_shdr *strtab; /* Section .strtab trouvée */
- bool has_strtab; /* Présence de cette section */
- phys_t first; /* Position du premier élément */
- const char *name; /* Nom du symbole trouvé */
- GBinFormat *base; /* Version basique du format */
- GBinSymbol *symbol; /* Nouveau symbole construit */
- char alt_name[6 + VMPA_MAX_LEN]; /* Nom abstrait de substitution*/
- virt_t final_virt; /* Adresse virtuelle retenue */
- mrange_t range; /* Couverture mémoire associée */
- GBinRoutine *routine; /* Nouvelle routine trouvée */
-
- result = read_elf_symbol(format, iter, &sym);
- if (!result) goto geslp_done;
+ GBinSymbol *symbol; /* Nouveau symbole en place */
- /* Nature de la visibilité et adresse associée */
+ result = do_elf_symbol_loading(loading, format, false, iter, &symbol);
- if (ELF_SYM(format, sym, st_shndx) == 0)
- {
- status = SSS_IMPORTED;
- init_vmpa(&addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
-
- }
+ return result;
- else
- {
- status = SSS_EXPORTED;
+}
- virt = ELF_SYM(format, sym, st_value);
- if (virt == 0) goto geslp_done;
- }
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* exec = autre vision de ce format. *
+* count = nombre de symboles présents. [OUT] *
+* *
+* Description : Dénombre le nombre de symboles en lien avec l'extérieur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /* Première ébauche de nom */
+static bool count_elf_global_symbols(GElfFormat *format, GExeFormat *exec, uint32_t *count)
+{
+ bool result; /* Bilan à retourner */
+ elf_dyn hash; /* Table de type DT_HASH */
+ bool found; /* Détection validée */
+ vmpa2t addr; /* Position de départ brute */
- g_elf_loading_get_internal_info(loading, &section, &use_virt, &strtab, &has_strtab, &first);
+ result = false;
- if (!has_strtab)
- name = NULL;
+ /**
+ * Cf. l'astuce indiquée par :
+ *
+ * - http://www.gabriel.urdhr.fr/2015/09/28/elf-file-format/#symbol-tables
+ * - http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash
+ *
+ */
- else
- name = get_elf_symbol_name(format, section, strtab,
- ((*iter - first) / ELF_SIZEOF_SYM(format)) - 1);
+ found = find_elf_dynamic_item(format, DT_HASH, &hash);
+ if (!found) goto cegs_exit;
- /* Traitements particuliers */
+ exec = G_EXE_FORMAT(format);
- base = G_BIN_FORMAT(format);
+ result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, hash, d_un.d_ptr), &addr);
+ if (!result) goto cegs_exit;
- switch (ELF_ST_TYPE(format, sym))
- {
- case STT_OBJECT:
+ advance_vmpa(&addr, 4);
- /* Ajustement de la position */
+ result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, count);
+ if (!result) goto cegs_exit;
- if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, &addr))
- {
- symbol = NULL;
- break;
- }
+ cegs_exit:
- /* Création d'un nom unique ? */
+ return result;
- if (name == NULL)
- {
- strcpy(alt_name, "obj_");
+}
- if (use_virt)
- vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
- else
- vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
- name = alt_name;
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à compléter. *
+* gid = groupe de travail impliqué. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Charge tous les éléments dynamiques externes possibles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- }
+static bool load_elf_global_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+{
+ bool result; /* Bilan à retourner */
+ GExeFormat *exec; /* Autre vision du format */
+ elf_dyn strtab; /* Table de type DT_STRTAB */
+ phys_t str_start; /* Début de zone des chaînes */
+ elf_dyn symtab; /* Table de type DT_SYMTAB */
+ phys_t sym_start; /* Début de zone des symboles */
+ uint32_t count; /* Nombre de symboles présents */
+ activity_id_t msg; /* Message de progression */
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ result = true;
- /* TODO */
+ /**
+ * Les spécifications ne sont pas très claires sur le nombre de tables
+ * possible... On y parle de LA table des symboles, ce qui laisse penser
+ * qu'il ne peut y en avoir qu'une.
+ */
- symbol = NULL;
+ exec = G_EXE_FORMAT(format);
+ /* Récupération du début des chaînes de description */
- break;
+ result = find_elf_dynamic_item(format, DT_STRTAB, &strtab);
+ if (!result) goto lees_exit;
- case STT_FUNC:
+ result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, strtab, d_un.d_ptr), &str_start);
+ if (!result) goto lees_exit;
- /* Ajustement de la position */
+ /* Récupération du début des définitions de symboles */
- if (status == SSS_IMPORTED)
- init_mrange(&range, &addr, 0);
+ result = find_elf_dynamic_item(format, DT_SYMTAB, &symtab);
+ if (!result) goto lees_exit;
- else
- {
- if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
- final_virt = virt & ~0x1;
- else
- final_virt = virt;
+ result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, symtab, d_un.d_ptr), &sym_start);
+ if (!result) goto lees_exit;
- if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr))
- {
- symbol = NULL;
- break;
- }
+ /* Détermination du nombre d'éléments */
- init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
+ result = count_elf_global_symbols(format, exec, &count);
+ if (!result) goto lees_exit;
- }
+ /* Chargement des symboles */
- /* Création d'un nom unique ? */
+ msg = gtk_status_stack_add_activity(status, _("Loading global symbols..."), 0);
- if (name == NULL)
- {
- strcpy(alt_name, "func_");
+ queue = get_work_queue();
- if (use_virt)
- vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
- else
- vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
+ add_all_elf_symbols(format, sym_start, count, str_start,
+ queue, gid, do_elf_global_symbol_loading, status, msg);
- name = alt_name;
+ g_work_queue_wait_for_completion(queue, gid);
- }
+ gtk_status_stack_remove_activity(status, msg);
- /* Routine */
+ lees_exit:
- routine = try_to_demangle_routine(name);
- symbol = G_BIN_SYMBOL(routine);
+ return result;
- /* Comptabilisation pour le désassemblage brut */
+}
- g_binary_format_register_code_point(G_BIN_FORMAT(format), virt, false);
- break;
- default:
- symbol = NULL;
- break;
+/* ---------------------------------------------------------------------------------- */
+/* PRISE EN COMPTE DE RELOCALISATIONS */
+/* ---------------------------------------------------------------------------------- */
- }
- if (symbol != NULL)
- {
- g_binary_symbol_set_range(symbol, &range);
- g_binary_symbol_set_status(symbol, status);
+/******************************************************************************
+* *
+* Paramètres : loading = chargement de relocalisations en cours. *
+* format = format ELF à compléter. *
+* iter = tête de lecture évoluant avec le temps. [OUT] *
+* *
+* Description : Assure le chargement des relocalisations ELF en différé. *
+* *
+* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- g_binary_format_add_symbol(base, symbol);
+static bool do_elf_relocation_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
+{
+ bool result; /* Bilan à retourner */
+ elf_rel reloc; /* Relocalisation constituée */
- }
+ result = read_elf_relocation(format, iter, &reloc);
- geslp_done:
+ if (result)
+ g_elf_loading_store_relocation(loading, iter, &reloc);
return result;
@@ -682,11 +914,13 @@ static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *for
/******************************************************************************
* *
-* Paramètres : format = description de l'exécutable à compléter. *
-* gid = groupe de travail impliqué. *
- status = barre de statut à tenir informée. *
+* Paramètres : format = informations chargées à consulter. *
+* dynamic = en-tête de programme de type DYNAMIC. *
+* relocs = liste des relocalisations triées à charger. [OUT] *
+* count = taille de cette liste. [OUT] *
+* status = barre de statut à tenir informée. *
* *
-* Description : Charge tous les symboles internes possibles. *
+* Description : Charge en mémoire toutes les relocalisations présentes. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -694,101 +928,158 @@ static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *for
* *
******************************************************************************/
-static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+static bool load_elf_relocations(GElfFormat *format, const elf_phdr *dynamic, elf_rel **relocs, size_t *count, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
- bool no_name; /* Choix de construction de nom*/
+ GExeFormat *exec; /* Autre vision du format */
+ elf_dyn jmprel; /* Table des relocalisations */
+ vmpa2t start; /* Position de départ brute */
+ elf_dyn pltrelsz; /* Taille de table en octets */
+ uint64_t length; /* Nombre total des éléments */
+ mrange_t shr_range; /* Emplacement des relocs. #1 */
+ mrange_t phr_range; /* Emplacement des relocs. #2 */
+ phys_t rel_size; /* Taille de chaque élément lu */
+ bool ret; /* Bilan d'un appel */
activity_id_t msg; /* Message de progression */
GWorkQueue *queue; /* Gestionnaire de différés */
- elf_shdr *dynsym_sections; /* Groupe de sections trouvées */
- size_t count; /* Quantité de données */
- elf_shdr *symtab_sections; /* Groupe de sections trouvées */
- size_t i; /* Boucle de parcours */
+ wgroup_id_t gid; /* Identifiant pour les tâches */
+ guint runs_count; /* Qté d'exécutions parallèles */
+ phys_t run_size; /* Volume réparti par exécution*/
+ GElfLoading **loadings; /* Tâches de chargement */
+ guint i; /* Boucle de parcours */
+ phys_t begin; /* Début de zone de traitement */
+ phys_t end; /* Fin d'un zone de traitement */
result = true;
- /* Charge tous les symboles définis dans une section */
- void add_all_symbols_from_section(const elf_shdr *section, bool use_virt, GWorkQueue *wq, activity_id_t id)
- {
- phys_t start; /* Début de la zone à traiter */
- phys_t size; /* Taille de cette même zone */
- phys_t sym_size; /* Taille de chaque symbole lu */
- guint runs_count; /* Qté d'exécutions parallèles */
- phys_t run_size; /* Volume réparti par exécution*/
- guint i; /* Boucle de parcours */
- phys_t begin; /* Début de zone de traitement */
- phys_t end; /* Fin d'un zone de traitement */
- GElfLoading *loading; /* Tâche de chargement à lancer*/
+ *relocs = NULL;
+ *count = 0;
- get_elf_section_content(format, section, &start, &size, NULL);
+ exec = G_EXE_FORMAT(format);
- sym_size = ELF_SIZEOF_SYM(format);
+ /* Collecte des informations */
- runs_count = g_get_num_processors();
+ if (!find_elf_dynamic_item_from_pheader(format, dynamic, DT_JMPREL, &jmprel))
+ goto ler_exit;
- run_size = size / (sym_size * runs_count);
+ result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, jmprel, d_un.d_ptr), &start);
- gtk_status_stack_extend_activity(status, id, size / sym_size);
+ if (!result)
+ goto ler_exit;
- for (i = 0; i < runs_count; i++)
- {
- begin = start + i * run_size * sym_size;
+ if (!find_elf_dynamic_item_from_pheader(format, dynamic, DT_PLTRELSZ, &pltrelsz))
+ goto ler_exit;
- if ((i + 1) == runs_count)
- end = start + size;
- else
- end = begin + run_size * sym_size;
+ length = ELF_DYN(format, pltrelsz, d_un.d_val);
- loading = g_elf_loading_new(format, section, use_virt, start, begin, end,
- id, do_elf_internal_symbol_loading);
+ /* Corrélation des informations */
- g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid);
+ ret = find_elf_section_range_by_name(format, ".rel.plt", &shr_range);
- }
+ if (ret)
+ {
+ init_mrange(&phr_range, &start, length);
+
+ if (cmp_mrange(&phr_range, &shr_range) != 0)
+ log_simple_message(LMT_BAD_BINARY,
+ _("The linker PLT and the PLT section differ by their area definition."));
}
- if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name))
- return false;
+ /* Détermination du nombre d'éléments */
- msg = gtk_status_stack_add_activity(status, _("Loading internal symbols..."), 0);
+ rel_size = ELF_SIZEOF_REL(format);
+
+ if (length % rel_size != 0)
+ {
+ result = false;
+ goto ler_exit;
+ }
+
+ length /= rel_size;
+
+ /* Chargement en mémoire des relocalisations */
+
+ if (length == 0)
+ goto ler_exit;
+
+ *relocs = (elf_rel *)malloc(length * sizeof(elf_rel));
+ *count = length;
+
+ msg = gtk_status_stack_add_activity(status, _("Loading relocations..."), length);
queue = get_work_queue();
+ gid = g_work_queue_define_work_group(queue);
- if (find_elf_sections_by_type(format, SHT_DYNSYM, &dynsym_sections, &count))
- for (i = 0; i < count; i++)
- add_all_symbols_from_section(&dynsym_sections[i], no_name, queue, msg);
+ runs_count = g_get_num_processors();
- if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtab_sections, &count))
- for (i = 0; i < count; i++)
- add_all_symbols_from_section(&symtab_sections[i], no_name, queue, msg);
+ run_size = length / runs_count;
+
+ loadings = (GElfLoading **)malloc(runs_count * sizeof(GElfLoading *));
+
+ for (i = 0; i < runs_count; i++)
+ {
+ begin = get_phy_addr(&start) + i * run_size * rel_size;
+
+ if ((i + 1) == runs_count)
+ end = get_phy_addr(&start) + length * rel_size;
+ else
+ end = begin + run_size * rel_size;
+
+ loadings[i] = g_elf_loading_new_for_relocations(format, begin, end,
+ (*relocs) + i * run_size,
+ msg, do_elf_relocation_loading);
+
+ g_object_ref(G_OBJECT(loadings[i]));
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(loadings[i]), gid);
+
+ }
g_work_queue_wait_for_completion(queue, gid);
gtk_status_stack_remove_activity(status, msg);
- if (dynsym_sections != NULL) free(dynsym_sections);
- if (symtab_sections != NULL) free(symtab_sections);
+ /* Vérifications du bon déroulement */
- return result;
+ for (i = 0; i < runs_count; i++)
+ {
+ result &= g_elf_loading_get_status(loadings[i]);
-}
+ g_object_ref(G_OBJECT(loadings[i]));
+ }
+ free(loadings);
-/* ---------------------------------------------------------------------------------- */
-/* DETAIL DES SYMBOLES EXTERNES */
-/* ---------------------------------------------------------------------------------- */
+ if (!result)
+ {
+ free(*relocs);
+ goto ler_exit;
+ }
+
+ /* Tri de la liste obtenue */
+
+ int compare_relocations(const elf_rel *a, const elf_rel *b)
+ {
+ return sort_uint64_t(ELF_REL(format, *a, r_offset), ELF_REL(format, *b, r_offset));
+ }
+
+ qsort(*relocs, *count, sizeof(elf_rel), (__compar_fn_t)compare_relocations);
+
+ ler_exit:
+
+ return result;
+
+}
/******************************************************************************
* *
-* Paramètres : format = informations chargées à consulter. *
-* dynamic = section de type SHT_DYNAMIC. *
-* type = sorte d'élément recherché. *
-* item = élément retrouvé dans la section. [OUT] *
+* Paramètres : format = informations chargées à consulter. *
+* status = barre de statut à tenir informée. *
* *
-* Description : Retrouve un élément donné dans la section dynamique. *
+* Description : Actualise la désignation des fonctions externes à reloger. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -796,55 +1087,71 @@ static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkSt
* *
******************************************************************************/
-static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *section, int32_t type, elf_dyn *item)
+bool refresh_elf_relocations(GElfFormat *format, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
- const GBinContent *content; /* Contenu binaire à lire */
- phys_t pos; /* Position de lecture */
- vmpa2t tmp; /* Position écrasable */
- int32_t tag32; /* Type de l'entrée (32 bits) */
- int64_t tag64; /* Type de l'entrée (64 bits) */
+ elf_phdr dynamic; /* En-tête de programme DYNAMIC*/
+ elf_rel *relocs; /* Relocalisations présentes */
+ size_t rel_count; /* Qté de ces relocalisations */
+ virt_t plt_virt; /* Adresse de la PLT */
+ GExeFormat *exec; /* Autre vision du format */
+ vmpa2t plt_addr; /* Localisation complète */
+ GBinFormat *base; /* Autre vision du format */
+ size_t first; /* Indice du premier symbole */
+ sym_iter_t *iter; /* Boucle de parcours */
result = true;
- content = G_BIN_FORMAT(format)->content;
+ if (!find_elf_dynamic_program_header(format, &dynamic))
+ goto rer_quick_exit;
- for (pos = ELF_SHDR(format, *section, sh_offset);
- result;
- pos += ELF_SIZEOF_DYN(format))
- {
- init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL);
+ /* Chargement des relocalisations */
- if (format->is_32b)
- {
- result = g_binary_content_read_s32(content, &tmp, format->endian, &tag32);
- if (tag32 == type) break;
- }
- else
- {
- result = g_binary_content_read_s64(content, &tmp, format->endian, &tag64);
- if (tag64 == type) break;
- }
+ if (!load_elf_relocations(format, &dynamic, &relocs, &rel_count, status))
+ goto rer_quick_exit;
- }
+ /* Localisation du code de la PLT */
+
+ if (!resolve_plt_using_got(format, &plt_virt))
+ goto rer_exit;
+
+ exec = G_EXE_FORMAT(format);
+
+ if (!g_exe_format_translate_address_into_vmpa(exec, plt_virt, &plt_addr))
+ goto rer_exit;
+
+ /* Parcours des symboles */
+
+ base = G_BIN_FORMAT(format);
+
+ /**
+ * Il existe normalement un symbole "plt_entry" créé au chargement des symboles...
+ */
+
+ g_binary_format_lock_symbols_rd(base);
+
+ result = g_binary_format_find_symbol_index_at(base, &plt_addr, &first);
+
+ if (result)
+ iter = create_symbol_iterator(base, first);
+
+ g_binary_format_unlock_symbols_rd(base);
if (result)
{
- init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL);
+ result = apply_elf_relocations(format, relocs, rel_count, iter, status);
- if (format->is_32b)
- {
- result = g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_tag);
- result &= g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_un.d_val);
- }
- else
- {
- result = g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_tag);
- result &= g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_un.d_val);
- }
+ delete_symbol_iterator(iter);
}
+ rer_exit:
+
+ if (relocs != NULL)
+ free(relocs);
+
+ rer_quick_exit:
+
return result;
}
@@ -852,52 +1159,171 @@ static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *sect
/******************************************************************************
* *
-* Paramètres : format = informations chargées à consulter. *
-* dynamic = section de type SHT_DYNAMIC. *
+* Paramètres : loading = chargement de relocalisations en cours. *
+* format = format ELF à compléter. *
+* symbol = symbole courant issu de la liste à analyser. *
* *
-* Description : Charge tous les éléments dynamiques externes possibles. *
+* Description : Assure l'intégration d'un symbole issu des relocalisations. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool load_elf_external_symbols(GElfFormat *format, const elf_shdr *section)
+static bool do_elf_relocation_renaming(GElfLoading *loading, GElfFormat *format, GBinSymbol *symbol)
{
bool result; /* Bilan à retourner */
- elf_dyn item; /* Elément dynamique */
- elf_shdr relxxx; /* Section .rel.xxx trouvée */
- elf_shdr dynsym; /* Section .dynsym trouvée */
- elf_shdr dynstr; /* Section .dynstr trouvée */
+ const mrange_t *range; /* Espace occupé par le symbole*/
+ SymbolType stype; /* Type de symbole présenté */
+ uint64_t offset; /* Décalage à retrouver */
+ elf_rel *reloc; /* Infos de relocalisation */
+ uint64_t index; /* Indice du symbole concerné */
+ char *name; /* Nouvelle désignation */
+#ifndef NDEBUG
+ const char *label; /* Etiquette courante */
+#endif
- result = true;
+ result = false;
+
+ range = g_binary_symbol_get_range(symbol);
+
+ stype = g_binary_symbol_get_target_type(symbol);
- /* Section .rel.plt */
- if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
+ if (stype != STP_ROUTINE && stype != STP_CODE_LABEL && stype != STP_ENTRY_POINT)
{
- result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);
+ g_binary_format_add_error(G_BIN_FORMAT(format), BFE_SPECIFICATION, get_mrange_addr(range),
+ _("The PLT seems to contains more than routines"));
- if (result)
- result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_link), &dynsym);
+ goto derr_exit;
- if (result)
- result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);
+ }
- if (result)
- switch (ELF_HDR(format, format->header, e_machine))
- {
- case EM_ARM:
- result = load_elf_arm_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
- break;
+ /* Assurance du port du type adapté */
- default:
- break;
+ g_binary_symbol_set_status(symbol, SSS_IMPORTED);
- }
+ /* Détermination de la relocalisation associée */
+
+ if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
+ result = retrieve_arm_linkage_offset(format, range, &offset);
+ else
+ result = false;
+ if (!result) goto derr_exit;
+
+ result = g_elf_loading_search_for_relocation(loading, &offset, &reloc);
+ if (!result) goto derr_exit;
+
+ /* Récupération des données du symbole visé */
+
+ index = ELF_REL_SYM(format, *reloc);
+
+ name = g_elf_loading_build_plt_name(loading, index);
+
+#ifndef NDEBUG
+
+ label = g_binary_symbol_get_label(symbol);
+
+ if (strncmp(label, "sub_", 4) != 0 && strncmp(label, "loc_", 4) != 0)
+ {
+ if (strncmp(name, label, strlen(label)) != 0)
+ g_binary_format_add_error(G_BIN_FORMAT(format), BFE_SPECIFICATION, get_mrange_addr(range),
+ _("Mismatch detected in the ELF symbol address"));
}
+#endif
+
+ g_binary_symbol_set_alt_label(symbol, name);
+
+ free(name);
+
+ derr_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = format ELF à compléter. *
+* relocs = table des relocalisations chargées. *
+* rel_count = nombre de ces éléments à interpréter. *
+* iter = itérateur sur les symboles à parcourir. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Applique les étiquettes issues des relocalisations. *
+* *
+* Retour : Bilan des traitements. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool apply_elf_relocations(GElfFormat *format, elf_rel *relocs, size_t rel_count, sym_iter_t *iter, GtkStatusStack *status)
+{
+ bool result; /* Bilan à retourner */
+ GExeFormat *exec; /* Autre vision du format */
+ elf_dyn strtab; /* Table de type DT_STRTAB */
+ phys_t str_start; /* Début de zone des chaînes */
+ elf_dyn symtab; /* Table de type DT_SYMTAB */
+ phys_t sym_start; /* Début de zone des symboles */
+ uint32_t sym_count; /* Nombre de symboles présents */
+ activity_id_t msg; /* Message de progression */
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ wgroup_id_t gid; /* Identifiant pour les tâches */
+ GElfLoading *loading; /* Tâche de chargement */
+
+ exec = G_EXE_FORMAT(format);
+
+ /* Récupération du début des chaînes de description */
+
+ result = find_elf_dynamic_item(format, DT_STRTAB, &strtab);
+ if (!result) goto aer_exit;
+
+ result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, strtab, d_un.d_ptr), &str_start);
+ if (!result) goto aer_exit;
+
+ /* Récupération du début des définitions de symboles */
+
+ result = find_elf_dynamic_item(format, DT_SYMTAB, &symtab);
+ if (!result) goto aer_exit;
+
+ result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, symtab, d_un.d_ptr), &sym_start);
+ if (!result) goto aer_exit;
+
+ /* Détermination du nombre d'éléments */
+
+ result = count_elf_global_symbols(format, exec, &sym_count);
+ if (!result) goto aer_exit;
+
+ /* Mise en application des références externes */
+
+ msg = gtk_status_stack_add_activity(status, _("Applying relocations..."), rel_count);
+
+ queue = get_work_queue();
+ gid = g_work_queue_define_work_group(queue);
+
+ loading = g_elf_loading_new_for_applying(format, iter, str_start, relocs, rel_count,
+ sym_start, sym_count, msg, do_elf_relocation_renaming);
+
+ g_object_ref(G_OBJECT(loading));
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid);
+
+ g_work_queue_wait_for_completion(queue, gid);
+
+ gtk_status_stack_remove_activity(status, msg);
+
+ /* Vérification du bon déroulement */
+
+ result = g_elf_loading_get_status(loading);
+
+ g_object_unref(G_OBJECT(loading));
+
+ aer_exit:
+
return result;
}