summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch/vmpa.c42
-rw-r--r--src/arch/vmpa.h3
-rw-r--r--src/format/elf/elf.c150
-rw-r--r--src/glibext/gbinportion.c57
4 files changed, 231 insertions, 21 deletions
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index a2430b5..e2da876 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -990,6 +990,48 @@ bool mrange_contains_addr_inclusive(const mrange_t *range, const vmpa2t *addr)
/******************************************************************************
* *
* Paramètres : range = zone mémoire à consulter. *
+* other = autre zone mémoire à manipuler. *
+* *
+* Description : Détermine si deux zones mémoire se chevauchent ou non. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool mrange_intersects_mrange(const mrange_t *range, const mrange_t *other)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t end; /* Fin d'une zone mémoire */
+
+ result = false;
+
+ result |= mrange_contains_addr(range, &other->addr);
+ result |= mrange_contains_addr(other, &range->addr);
+
+ if (get_mrange_length(other) > 0)
+ {
+ compute_mrange_end_addr(other, &end);
+ deminish_vmpa(&end, 1);
+ result |= mrange_contains_addr(range, &end);
+ }
+
+ if (get_mrange_length(range) > 0)
+ {
+ compute_mrange_end_addr(range, &end);
+ deminish_vmpa(&end, 1);
+ result |= mrange_contains_addr(other, &end);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = zone mémoire à consulter. *
* addr = localisation mémoire à déterminer. *
* *
* Description : Calcule la position extérieure finale d'une couverture. *
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 4470676..eb63324 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -198,6 +198,9 @@ bool mrange_contains_addr(const mrange_t *, const vmpa2t *);
/* Indique si une localisation est incluse dans une zone ou non. */
bool mrange_contains_addr_inclusive(const mrange_t *, const vmpa2t *);
+/* Détermine si deux zones mémoire se chevauchent ou non. */
+bool mrange_intersects_mrange(const mrange_t *, const mrange_t *);
+
/* Calcule la position extérieure finale d'une couverture. */
void compute_mrange_end_addr(const mrange_t *, vmpa2t *);
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index 3491c71..a48e3b3 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -365,9 +365,11 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format)
static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer *main)
{
GPortionLayer *layer; /* Couche à mettre en place */
+ uint16_t max; /* Décompte d'éléments traités */
+ elf_phdr *sorted_phdrs; /* Liste de segments triée */
uint16_t i; /* Boucle de parcours */
off_t offset; /* Début de part de programme */
- elf_phdr phdr; /* En-tête de programme ELF */
+ elf_phdr *phdr; /* En-tête de programme ELF */
uint32_t p_flags; /* Droits associés à une partie*/
const char *background; /* Fond signigicatif */
GBinPortion *new; /* Nouvelle portion définie */
@@ -376,25 +378,87 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
PortionAccessRights rights; /* Droits d'une portion */
elf_shdr strings; /* Section des descriptions */
bool has_strings; /* Section trouvée ? */
- elf_shdr section; /* En-tête de section ELF */
+ elf_shdr *sorted_shdrs; /* Liste de sections triée */
+ elf_shdr *section; /* En-tête de section ELF */
uint64_t sh_flags; /* Droits associés à une partie*/
const char *name; /* Nom trouvé ou NULL */
- /* Côté segments basiques */
+ /**
+ * La copie des différents en-têtes cherche à reproduire l'inclusion native
+ * du format :
+ *
+ * EXIDX 0x001178 0x00009178 0x00009178 0x00008 0x00008 R 0x4
+ * PHDR 0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4
+ * INTERP 0x000154 0x00008154 0x00008154 0x00019 0x00019 R 0x1
+ * LOAD 0x000000 0x00008000 0x00008000 0x01184 0x01184 R E 0x8000
+ *
+ */
+
+ /**
+ * Côté segments basiques.
+ */
layer = g_portion_layer_new(NO_LENGTH_YET, _("Segment"));
g_portion_layer_attach_sub(main, layer);
- for (i = 0; i < ELF_HDR(format, format->header, e_phnum); i++)
+ /* Constitution d'une liste de travail */
+
+ max = ELF_HDR(format, format->header, e_phnum);
+
+ sorted_phdrs = (elf_phdr *)calloc(max, sizeof(elf_phdr));
+
+ for (i = 0; i < max; i++)
{
offset = ELF_HDR(format, format->header, e_phoff)
+ ELF_HDR(format, format->header, e_phentsize) * i;
- if (!read_elf_program_header(format, offset, &phdr))
+ if (!read_elf_program_header(format, offset, &sorted_phdrs[i]))
+ {
+ if (format->is_32b)
+ sorted_phdrs[i].phdr32.p_type = PT_NULL;
+ else
+ sorted_phdrs[i].phdr64.p_type = PT_NULL;
+ }
+
+ }
+
+ /* Tri de cette liste */
+
+ int sort_phdr(elf_phdr *a, elf_phdr *b)
+ {
+ uint64_t filesz_a; /* Taille de l'en-tête 'a' */
+ uint64_t filesz_b; /* Taille de l'en-tête 'b' */
+ int status; /* Bilan d'une comparaison */
+
+ filesz_a = ELF_PHDR(format, *a, p_filesz);
+ filesz_b = ELF_PHDR(format, *b, p_filesz);
+
+ if (filesz_a < filesz_b)
+ status = 1;
+
+ else if (filesz_a > filesz_b)
+ status = -1;
+
+ else
+ status = 0;
+
+ return status;
+
+ }
+
+ qsort(sorted_phdrs, max, sizeof(elf_phdr), (__compar_fn_t)sort_phdr);
+
+ /* Inclusion de ces en-têtes */
+
+ for (i = 0; i < max; i++)
+ {
+ phdr = &sorted_phdrs[i];
+
+ if (ELF_PHDR(format, *phdr, p_type) == PT_NULL)
continue;
- p_flags = ELF_PHDR(format, phdr, p_flags);
+ p_flags = ELF_PHDR(format, *phdr, p_flags);
if (p_flags & PF_X) background = BPC_CODE;
else if (p_flags & PF_W) background = BPC_DATA;
@@ -404,12 +468,12 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
snprintf(desc, MAX_PORTION_DESC, "%s \"%s\"",
_("Segment"),
- get_elf_program_type_desc(ELF_PHDR(format, phdr, p_type)));
+ get_elf_program_type_desc(ELF_PHDR(format, *phdr, p_type)));
g_binary_portion_set_desc(new, desc);
- init_vmpa(&addr, ELF_PHDR(format, phdr, p_offset), ELF_PHDR(format, phdr, p_vaddr));
- g_binary_portion_set_values(new, &addr, ELF_PHDR(format, phdr, p_filesz));
+ init_vmpa(&addr, ELF_PHDR(format, *phdr, p_offset), ELF_PHDR(format, *phdr, p_vaddr));
+ g_binary_portion_set_values(new, &addr, ELF_PHDR(format, *phdr, p_filesz));
rights = PAC_NONE;
if (p_flags & PF_R) rights |= PAC_READ;
@@ -422,7 +486,11 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
}
- /* Inclusion des sections, si possible... */
+ free(sorted_phdrs);
+
+ /**
+ * Inclusion des sections, si possible...
+ */
has_strings = find_elf_section_by_index(format,
ELF_HDR(format, format->header, e_shstrndx),
@@ -432,12 +500,60 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
g_portion_layer_attach_sub(main, layer);
- for (i = 0; i < ELF_HDR(format, format->header, e_shnum); i++)
+ /* Constitution d'une liste de travail */
+
+ max = ELF_HDR(format, format->header, e_shnum);
+
+ sorted_shdrs = (elf_shdr *)calloc(max, sizeof(elf_shdr));
+
+ for (i = 0; i < max; i++)
+ {
+ if (!find_elf_section_by_index(format, i, &sorted_shdrs[i]))
+ {
+ if (format->is_32b)
+ sorted_shdrs[i].shdr32.sh_offset = 0;
+ else
+ sorted_shdrs[i].shdr64.sh_offset = 0;
+ }
+
+ }
+
+ /* Tri de cette liste */
+
+ int sort_shdr(elf_shdr *a, elf_shdr *b)
+ {
+ uint64_t size_a; /* Taille de l'en-tête 'a' */
+ uint64_t size_b; /* Taille de l'en-tête 'b' */
+ int status; /* Bilan d'une comparaison */
+
+ size_a = ELF_SHDR(format, *a, sh_size);
+ size_b = ELF_SHDR(format, *b, sh_size);
+
+ if (size_a < size_b)
+ status = 1;
+
+ else if (size_a > size_b)
+ status = -1;
+
+ else
+ status = 0;
+
+ return status;
+
+ }
+
+ qsort(sorted_shdrs, max, sizeof(elf_shdr), (__compar_fn_t)sort_shdr);
+
+ /* Inclusion de ces en-têtes */
+
+ for (i = 0; i < max; i++)
{
- if (!find_elf_section_by_index(format, i, &section))
+ section = &sorted_shdrs[i];
+
+ if (ELF_SHDR(format, *section, sh_offset) == 0)
continue;
- sh_flags = ELF_SHDR(format, section, sh_flags);
+ sh_flags = ELF_SHDR(format, *section, sh_flags);
if ((sh_flags & SHF_ALLOC) == 0)
continue;
@@ -450,7 +566,7 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
if (has_strings)
name = extract_name_from_elf_string_section(format, &strings,
- ELF_SHDR(format, section, sh_name));
+ ELF_SHDR(format, *section, sh_name));
else name = NULL;
if (name != NULL)
@@ -460,8 +576,8 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
g_binary_portion_set_desc(new, desc);
- init_vmpa(&addr, ELF_SHDR(format, section, sh_offset), ELF_SHDR(format, section, sh_addr));
- g_binary_portion_set_values(new, &addr, ELF_SHDR(format, section, sh_size));
+ init_vmpa(&addr, ELF_SHDR(format, *section, sh_offset), ELF_SHDR(format, *section, sh_addr));
+ g_binary_portion_set_values(new, &addr, ELF_SHDR(format, *section, sh_size));
rights = PAC_NONE;
if (sh_flags & SHF_ALLOC) rights |= PAC_READ;
@@ -474,6 +590,8 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
}
+ free(sorted_shdrs);
+
}
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 790614a..abdec60 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -898,14 +898,61 @@ void g_portion_layer_attach_sub(GPortionLayer *layer, GPortionLayer *sub)
void g_portion_layer_include(GPortionLayer *layer, GBinPortion *portion)
{
- layer->portions = (GBinPortion **)realloc(layer->portions,
- ++layer->count * sizeof(GBinPortion *));
+ GPortionLayer *sub; /* Sous couche indispensable */
+ bool conflict; /* Conflit dû aux débordements */
+ const mrange_t *range; /* Emplacement de la portion */
+ size_t i; /* Boucle de parcours */
+ const mrange_t *other; /* Emplacements déjà occupés */
+
+ /**
+ * On prend ici en compte le genre de situations suivantes :
+ *
+ * [21] .bss NOBITS 00088240 07823c 0018c8 00 WA 0 0 8
+ * [22] __libc_freeres_ptrs NOBITS 00089b08 07823c 000018 00 WA 0 0 4
+ * [23] .comment PROGBITS 00000000 07823c 000022 01 MS 0 0 1
+ *
+ * Pendant le désassemblage, la procédure n'aime pas trop les intersections
+ * de zones mémoire.
+ */
+
+ conflict = false;
+
+ range = g_binary_portion_get_range(portion);
+
+ for (i = 0; i < layer->count && !conflict; i++)
+ {
+ other = g_binary_portion_get_range(layer->portions[i]);
- layer->portions[layer->count - 1] = portion;
+ conflict = mrange_intersects_mrange(range, other);
- g_binary_portion_set_level(portion, &layer->level);
+ }
+
+ /* La portion recouvre-t-elle une portion déjà existante ? */
+ if (conflict)
+ {
+ if (layer->sub_layer == NULL)
+ {
+ sub = g_portion_layer_new(layer->length, layer->name);
+ g_portion_layer_attach_sub(layer, sub);
+ }
- qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
+ g_portion_layer_include(layer->sub_layer, portion);
+
+ }
+
+ /* Sinon on l'intègre dans la couche courante */
+ else
+ {
+ layer->portions = (GBinPortion **)realloc(layer->portions,
+ ++layer->count * sizeof(GBinPortion *));
+
+ layer->portions[layer->count - 1] = portion;
+
+ g_binary_portion_set_level(portion, &layer->level);
+
+ qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
+
+ }
}