From 3a9fe39c6a8923f45e7c96d80b0bfe52b8686ff9 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 18 Jul 2009 15:41:02 +0000
Subject: Computed the end of routines with no limit.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@98 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                  |  22 ++++++++
 src/analysis/binary.c      | 130 +++++++++++++++++++++++++++++++++++++++++++++
 src/analysis/line.c        |  45 ++++++++++++++++
 src/analysis/line.h        |   3 ++
 src/analysis/prototype.c   |  53 ++++++++++++++++++
 src/analysis/prototype.h   |   6 +++
 src/arch/instruction-int.h |   4 ++
 src/arch/instruction.c     |  19 +++++++
 src/arch/instruction.h     |   4 ++
 src/arch/x86/instruction.c |  22 ++++++++
 src/format/elf/symbol.c    |   9 +---
 11 files changed, 309 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 67b76b1..01a22cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+09-07-18  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/binary.c:
+	Compute the end of routines with no limit.
+
+	* src/analysis/line.c:
+	* src/analysis/line.h:
+	Look for a code line in a list of lines.
+
+	* src/analysis/prototype.c:
+	* src/analysis/prototype.h:
+	Compare routines for qsort().
+
+	* src/arch/instruction.c:
+	* src/arch/instruction.h:
+	* src/arch/instruction-int.h:
+	* src/arch/x86/instruction.c:
+	Add a function which tells if an instruction is a return from a call.
+
+	* src/format/elf/symbol.c:
+	Clean the code. Only match with real functions when loading symbols.
+
 09-07-16  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gtkext/gtkgraphview.c:
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 09b7212..396dbe0 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -91,6 +91,12 @@ void disassemble_openida_binary(openida_binary *);
 /* Etablit les liens entres les différentes lignes de code. */
 void establish_links_in_openida_binary(const openida_binary *);
 
+/* S'assure que toutes les routines ont une taille définie. */
+void limit_all_routines_in_openida_binary(const openida_binary *);
+
+/* Cherche l'adresse de fin d'une routine. */
+vmpa_t find_best_ending_address_for_routine(GRenderingLine *, size_t, const vmpa_t *, const off_t *, size_t);
+
 
 
 /******************************************************************************
@@ -629,6 +635,7 @@ void disassemble_openida_binary(openida_binary *binary)
     }
 
     establish_links_in_openida_binary(binary);
+    limit_all_routines_in_openida_binary(binary);
 
     line = g_rendering_line_find_by_address(binary->lines, NULL, get_exe_entry_point(binary->format));
     if (line != NULL) g_rendering_line_add_flag(line, RLF_ENTRY_POINT);
@@ -733,3 +740,126 @@ void establish_links_in_openida_binary(const openida_binary *binary)
     }
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = binaire dont le contenu est à lier.                 *
+*                                                                             *
+*  Description : S'assure que toutes les routines ont une taille définie.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void limit_all_routines_in_openida_binary(const openida_binary *binary)
+{
+    GBinRoutine **routines;                 /* Liste des routines trouvées */
+    size_t routines_count;                  /* Nombre de ces routines      */
+    size_t i;                               /* Boucle de parcours          */
+    vmpa_t *starts;                         /* Adresses de départ          */
+    off_t *lengths;                         /* Tailles des routines        */
+    GRenderingLine *line;                   /* Ligne de départ / d'arrivée */
+    vmpa_t start;                           /* Adresse de début de routine */
+    vmpa_t last;                            /* Meilleur dernière adresse   */
+    GArchInstruction *instr;                /* Instruction à ausculter     */
+    off_t length;                           /* Taille du code              */
+
+    routines = get_all_exe_routines(binary->format, &routines_count);
+    if (routines_count == 0) return;
+
+    qsort(routines, routines_count, sizeof(GBinRoutine *), g_binary_routine_rcompare);
+
+    starts = (vmpa_t *)calloc(routines_count, sizeof(vmpa_t));
+    lengths = (off_t *)calloc(routines_count, sizeof(off_t));
+
+    for (i = 0; i < routines_count; i++)
+    {
+        starts[i] = g_binary_routine_get_address(routines[i]);
+        lengths[i] = g_binary_routine_get_size(routines[i]);
+    }
+
+    for (i = 0; i < routines_count; i++)
+    {
+        if (lengths[i] > 0) continue;
+
+        start = g_binary_routine_get_address(routines[i]);
+        line = g_rendering_line_find_by_address(binary->lines, NULL, start);
+
+        last = find_best_ending_address_for_routine(line, i, starts, lengths, routines_count);
+
+        line = g_rendering_line_find_by_address(binary->lines, NULL, last);
+        line = g_rendering_line_loop_for_code(line, NULL);
+
+        instr = g_code_line_get_instruction(G_CODE_LINE(line));
+        g_arch_instruction_get_location(instr, NULL, &length, NULL);
+
+        lengths[i] = last - start + length;
+        g_binary_routine_set_size(routines[i], lengths[i]);
+
+    }
+
+    free(starts);
+    free(lengths);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line    = ligne de départ du parcours.                       *
+*                index   = indice de la routine traitée dans la liste.        *
+*                starts  = adresse de départ des autres routines.             *
+*                lengths = taille des différentes routines, valides ou nulles.*
+*                count   = quantité de routines présentes.                    *
+*                                                                             *
+*  Description : Cherche l'adresse de fin d'une routine.                      *
+*                                                                             *
+*  Retour      : Plus grande adresse de dernière instruction de routine.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+vmpa_t find_best_ending_address_for_routine(GRenderingLine *line, size_t index, const vmpa_t *starts, const off_t *lengths, size_t count)
+{
+    vmpa_t result;                          /* Haute adresse à remonter    */
+    GRenderingLine *iter;                   /* Boucle de parcours #1       */
+    vmpa_t candidate;                       /* Candidat potentiel          */
+    size_t i;                               /* Boucle de parcours #2       */
+    GArchInstruction *instr;                /* Instruction à ausculter     */
+
+    result = starts[index];
+
+    for (iter = line; iter != NULL; iter = g_rendering_line_get_next_iter(line, iter, NULL))
+    {
+        if (!G_IS_CODE_LINE(iter)) continue;
+
+        candidate = get_rendering_line_address(iter);
+
+        /* Regarde si on n'empiète pas sur une autre routine */
+
+        for (i = 0; i < count; i++)
+        {
+            if (i == index) continue;
+
+            if (starts[i] <= candidate && candidate < (starts[i] + lengths[i]))
+                break;
+
+        }
+
+        if (i != count) break;
+        else result = candidate;
+
+        /* Retour de fonction ? */
+
+        instr = g_code_line_get_instruction(G_CODE_LINE(iter));
+        if (g_arch_instruction_is_return(instr)) break;
+
+    }
+
+    return result;
+
+}
diff --git a/src/analysis/line.c b/src/analysis/line.c
index 740673a..cd54db0 100644
--- a/src/analysis/line.c
+++ b/src/analysis/line.c
@@ -34,6 +34,7 @@
 #include <sys/param.h>
 
 
+#include "line_code.h"
 #include "../common/dllist.h"
 
 
@@ -732,3 +733,47 @@ GRenderingLine *g_rendering_line_find_by_address(GRenderingLine *lines, const GR
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : start = première ligne de l'ensemble à parcourir.            *
+*                last  = dernière élément imposé du parcours ou NULL.         *
+*                                                                             *
+*  Description : Donne la première ligne de code correspondant à une adresse. *
+*                                                                             *
+*  Retour      : Ligne de code pour l'adresse donnée, NULL si aucune trouvée. *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GRenderingLine *g_rendering_line_loop_for_code(GRenderingLine *start, const GRenderingLine *last)
+{
+    GRenderingLine *result;                 /* Trouvaille à retourner      */
+    vmpa_t reference;                       /* Adresse à conserver         */
+
+    result = start;
+    reference = start->offset;
+
+    lines_list_for_each(result, start)
+    {
+        if (G_IS_CODE_LINE(result)) break;
+
+        if (result->offset != reference)
+        {
+            result = NULL;
+            break;
+        }
+
+        if (result == last)
+        {
+            result = NULL;
+            break;
+        }
+
+    }
+
+    return result;
+
+}
diff --git a/src/analysis/line.h b/src/analysis/line.h
index 5f22db2..621ab60 100644
--- a/src/analysis/line.h
+++ b/src/analysis/line.h
@@ -131,6 +131,9 @@ GRenderingLine *g_rendering_line_find_by_y(GRenderingLine *, const GRenderingLin
 /* Recherche une ligne d'après sa position en mémoire/physique. */
 GRenderingLine *g_rendering_line_find_by_address(GRenderingLine *, const GRenderingLine *, vmpa_t);
 
+/* Donne la première ligne de code correspondant à une adresse. */
+GRenderingLine *g_rendering_line_loop_for_code(GRenderingLine *, const GRenderingLine *);
+
 
 
 #endif  /* _ANALYSIS_LINE_H */
diff --git a/src/analysis/prototype.c b/src/analysis/prototype.c
index d68a485..72ee809 100644
--- a/src/analysis/prototype.c
+++ b/src/analysis/prototype.c
@@ -161,6 +161,59 @@ void g_binary_routine_finalize(GBinRoutine *routine)
 }
 #endif
 
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = premières informations à consulter.                      *
+*                b = secondes informations à consulter.                       *
+*                                                                             *
+*  Description : Etablit la comparaison ascendante entre deux routines.       *
+*                                                                             *
+*  Retour      : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b).                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int g_binary_routine_compare(const GBinRoutine **a, const GBinRoutine **b)
+{
+    int result;                             /* Bilan à renvoyer            */
+
+    if ((*a)->addr < (*b)->addr) result = -1;
+    else if((*a)->addr > (*b)->addr) result = 1;
+    else result = 0;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = premières informations à consulter.                      *
+*                b = secondes informations à consulter.                       *
+*                                                                             *
+*  Description : Etablit la comparaison descendante entre deux routines.      *
+*                                                                             *
+*  Retour      : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b).                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int g_binary_routine_rcompare(const GBinRoutine **a, const GBinRoutine **b)
+{
+    int result;                             /* Bilan à renvoyer            */
+
+    if ((*a)->addr > (*b)->addr) result = -1;
+    else if((*a)->addr < (*b)->addr) result = 1;
+    else result = 0;
+
+    return result;
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : routine = routine à mettre à jour.                           *
diff --git a/src/analysis/prototype.h b/src/analysis/prototype.h
index fe6d0a4..2a9439e 100644
--- a/src/analysis/prototype.h
+++ b/src/analysis/prototype.h
@@ -64,6 +64,12 @@ GType g_bin_routine_get_type(void);
 /* Crée une représentation de routine. */
 GBinRoutine *g_binary_routine_new(void);
 
+/* Etablit la comparaison ascendante entre deux routines. */
+int g_binary_routine_compare(const GBinRoutine **, const GBinRoutine **);
+
+/* Etablit la comparaison descendante entre deux routines. */
+int g_binary_routine_rcompare(const GBinRoutine **, const GBinRoutine **);
+
 /* Définit la position physique / en mémoire d'une routine. */
 void g_binary_routine_set_address(GBinRoutine *, vmpa_t);
 
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h
index 6ae0597..db6a3bf 100644
--- a/src/arch/instruction-int.h
+++ b/src/arch/instruction-int.h
@@ -36,6 +36,9 @@ typedef const char * (* get_instruction_text_fc) (const GArchInstruction *, cons
 /* Informe sur une éventuelle référence à une autre instruction. */
 typedef InstructionLinkType (* get_instruction_link_fc) (const GArchInstruction *, vmpa_t *);
 
+/* Indique si l'instruction correspond à un retour de fonction. */
+typedef bool (* is_instruction_return_fc) (const GArchInstruction *);
+
 
 /* Définition générique d'une instruction d'architecture (instance) */
 struct _GArchInstruction
@@ -52,6 +55,7 @@ struct _GArchInstruction
 
     get_instruction_text_fc get_text;       /* Texte humain équivalent     */
     get_instruction_link_fc get_link;       /* Référence à une instruction */
+    is_instruction_return_fc is_return;     /* Retour de fonction ou pas ? */
 
 };
 
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index 69644dc..e0cea9f 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -321,3 +321,22 @@ InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *instr, v
     return instr->get_link(instr, addr);
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction à consulter.                             *
+*                                                                             *
+*  Description : Indique si l'instruction correspond à un retour de fonction. *
+*                                                                             *
+*  Retour      : true si l'instruction est un 'return' quelconque ou false.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_instruction_is_return(const GArchInstruction *instr)
+{
+    return instr->is_return(instr);
+
+}
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index b8be830..c0cb9f6 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -25,6 +25,7 @@
 #define _ARCH_INSTRUCTION_H
 
 
+#include <stdbool.h>
 #include <glib-object.h>
 #include <sys/types.h>
 
@@ -90,6 +91,9 @@ char *g_arch_instruction_get_text(const GArchInstruction *, const exe_format *,
 /* Informe sur une éventuelle référence à une autre instruction. */
 InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *, vmpa_t *);
 
+/* Indique si l'instruction correspond à un retour de fonction. */
+bool g_arch_instruction_is_return(const GArchInstruction *instr);
+
 
 
 #endif  /* _ARCH_INSTRUCTION_H */
diff --git a/src/arch/x86/instruction.c b/src/arch/x86/instruction.c
index 0321e88..0af29c1 100644
--- a/src/arch/x86/instruction.c
+++ b/src/arch/x86/instruction.c
@@ -326,6 +326,8 @@ static const char *x86_get_instruction_text(const GX86Instruction *, const exe_f
 /* Informe sur une éventuelle référence à une autre instruction. */
 static InstructionLinkType x86_get_instruction_link(const GX86Instruction *, vmpa_t *);
 
+/* Indique si l'instruction correspond à un retour de fonction. */
+static bool x86_instruction_is_return(const GX86Instruction *);
 
 
 
@@ -372,6 +374,7 @@ static void g_x86_instruction_init(GX86Instruction *instr)
 
     parent->get_text = (get_instruction_text_fc)x86_get_instruction_text;
     parent->get_link = (get_instruction_link_fc)x86_get_instruction_link;
+    parent->is_return = (is_instruction_return_fc)x86_instruction_is_return;
 
 }
 
@@ -622,3 +625,22 @@ static InstructionLinkType x86_get_instruction_link(const GX86Instruction *instr
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction à consulter.                             *
+*                                                                             *
+*  Description : Indique si l'instruction correspond à un retour de fonction. *
+*                                                                             *
+*  Retour      : true si l'instruction est un 'return' quelconque ou false.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool x86_instruction_is_return(const GX86Instruction *instr)
+{
+    return (instr->type == XOP_RET);
+
+}
diff --git a/src/format/elf/symbol.c b/src/format/elf/symbol.c
index 4fd56fe..35943e9 100644
--- a/src/format/elf/symbol.c
+++ b/src/format/elf/symbol.c
@@ -30,11 +30,6 @@
 #include <string.h>
 
 
-#include "../../arch/processor.h" /* FIXME : remove me ! */
-#include "../../arch/instruction.h" /* FIXME : remove me ! */
-#include "../../arch/instruction-int.h" /* FIXME : remove me ! */
-
-
 #include "elf-int.h"
 #include "helper_mips.h"
 #include "section.h"
@@ -254,9 +249,7 @@ bool load_elf_symbol_table_32(elf_format *format, const off_t *sym_start, const
     {
         memcpy(&symbol, &EXE_FORMAT(format)->content[iter], sizeof(Elf32_Sym));
 
-        if (!(ELF32_ST_TYPE(symbol.st_info) == STT_FUNC
-              || (ELF32_ST_TYPE(symbol.st_info) == STT_NOTYPE
-                  && ELF32_ST_BIND(symbol.st_info) == STB_GLOBAL))) continue;
+        if (!(ELF32_ST_TYPE(symbol.st_info) == STT_FUNC)) continue;
 
         if (symbol.st_value == 0) continue;
 
-- 
cgit v0.11.2-87-g4458