diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2013-01-31 21:29:49 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2013-01-31 21:29:49 (GMT) |
commit | 0936f64aac6a4fa9ebc08962bc9cac663f210c00 (patch) | |
tree | e888b4d7b547680bb26082913216bc637073e734 /src/decomp/instr | |
parent | b6341581220e92114b0838a15a1c1cec1078efc2 (diff) |
Saved the first steps of switch instructions decompilation.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@335 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/decomp/instr')
-rw-r--r-- | src/decomp/instr/Makefile.am | 3 | ||||
-rw-r--r-- | src/decomp/instr/ite.c | 46 | ||||
-rw-r--r-- | src/decomp/instr/ite.h | 16 | ||||
-rw-r--r-- | src/decomp/instr/switch.c | 379 | ||||
-rw-r--r-- | src/decomp/instr/switch.h | 66 |
5 files changed, 478 insertions, 32 deletions
diff --git a/src/decomp/instr/Makefile.am b/src/decomp/instr/Makefile.am index b4e16eb..6120cac 100644 --- a/src/decomp/instr/Makefile.am +++ b/src/decomp/instr/Makefile.am @@ -2,7 +2,8 @@ noinst_LTLIBRARIES = libdecompinstr.la libdecompinstr_la_SOURCES = \ - ite.h ite.c + ite.h ite.c \ + switch.h switch.c libdecompinstr_la_LDFLAGS = diff --git a/src/decomp/instr/ite.c b/src/decomp/instr/ite.c index d78bb31..60627a6 100644 --- a/src/decomp/instr/ite.c +++ b/src/decomp/instr/ite.c @@ -1,8 +1,8 @@ /* OpenIDA - Outil d'analyse de fichiers binaires - * cond.c - représentation des conditions + * ite.c - représentation des branchements conditionnels * - * Copyright (C) 2010 Cyrille Bagard + * Copyright (C) 2010-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -107,7 +107,7 @@ static void g_ite_instruction_class_init(GITEInstructionClass *klass) /****************************************************************************** * * -* Paramètres : expr = instance à initialiser. * +* Paramètres : instr = instance à initialiser. * * * * Description : Initialise une instance d'aiguillage du flux d'exécution. * * * @@ -117,15 +117,15 @@ static void g_ite_instruction_class_init(GITEInstructionClass *klass) * * ******************************************************************************/ -static void g_ite_instruction_init(GITEInstruction *expr) +static void g_ite_instruction_init(GITEInstruction *instr) { - GDecInstruction *instr; /* Autre version de l'objet */ + GDecInstruction *base; /* Autre version de l'objet */ - instr = G_DEC_INSTRUCTION(expr); + base = G_DEC_INSTRUCTION(instr); - instr->visit = (dec_instr_visit_fc)g_ite_instruction_visit; - instr->replace = (dec_instr_replace_fc)g_ite_instruction_replace; - instr->print = (dec_instr_print_fc)g_ite_instruction_print; + base->visit = (dec_instr_visit_fc)g_ite_instruction_visit; + base->replace = (dec_instr_replace_fc)g_ite_instruction_replace; + base->print = (dec_instr_print_fc)g_ite_instruction_print; } @@ -226,7 +226,7 @@ static bool g_ite_instruction_replace(GITEInstruction *instr, GDecInstruction *o /****************************************************************************** * * -* Paramètres : expr = instruction à transcrire en version humaine. * +* Paramètres : instr = instruction à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * * output = langage de programmation de sortie. * @@ -239,24 +239,24 @@ static bool g_ite_instruction_replace(GITEInstruction *instr, GDecInstruction *o * * ******************************************************************************/ -static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output) +static GBufferLine *g_ite_instruction_print(const GITEInstruction *instr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output) { GBufferLine *result; /* Ligne à retourner */ g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "if ", 3, RTT_KEY_WORD); - if (expr->inverse) + if (instr->inverse) g_buffer_line_insert_text(line /* FIXME */, BLC_ASSEMBLY_HEAD, "!", 1, RTT_KEY_WORD); - result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->cond), + result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->cond), buffer, line, output); - result = g_dec_instruction_print(expr->true_branch, buffer, result, output); + result = g_dec_instruction_print(instr->true_branch, buffer, result, output); - if (expr->false_branch != NULL) + if (instr->false_branch != NULL) { g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "else", 4, RTT_KEY_WORD); - result = g_dec_instruction_print(expr->false_branch, buffer, result, output); + result = g_dec_instruction_print(instr->false_branch, buffer, result, output); } return result; @@ -266,7 +266,7 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu /****************************************************************************** * * -* Paramètres : cond = expression fixant le choix de l'aiguillage. * +* Paramètres : instr = expression fixant le choix de l'aiguillage. * * true_branch = instructions si la condition est vérifiée. * * false_branch = instructions si la cond. n'est pas vérifiée. * * * @@ -278,21 +278,21 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu * * ******************************************************************************/ -void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch) +void g_ite_instruction_set_branches(GITEInstruction *instr, GDecInstruction *true_branch, GDecInstruction *false_branch) { if (true_branch == NULL) { - expr->inverse = true; + instr->inverse = true; - expr->true_branch = false_branch; - expr->false_branch = true_branch; + instr->true_branch = false_branch; + instr->false_branch = true_branch; } else { - expr->true_branch = true_branch; - expr->false_branch = false_branch; + instr->true_branch = true_branch; + instr->false_branch = false_branch; } } diff --git a/src/decomp/instr/ite.h b/src/decomp/instr/ite.h index e53abe8..7137452 100644 --- a/src/decomp/instr/ite.h +++ b/src/decomp/instr/ite.h @@ -1,8 +1,8 @@ /* OpenIDA - Outil d'analyse de fichiers binaires - * ite.h - prototypes pour la représentation des conditions + * ite.h - prototypes pour la représentation des branchements conditionnels * - * Copyright (C) 2010 Cyrille Bagard + * Copyright (C) 2010-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -21,8 +21,8 @@ */ -#ifndef _DECOMP_EXPR_ITE_H -#define _DECOMP_EXPR_ITE_H +#ifndef _DECOMP_INSTR_ITE_H +#define _DECOMP_INSTR_ITE_H #include <glib-object.h> @@ -52,12 +52,12 @@ typedef struct _GITEInstructionClass GITEInstructionClass; /* Indique le type défini pour un aiguillage du flux d'exécution. */ GType g_ite_instruction_get_type(void); -/* Détermine le corps des différentes branches possibles. */ -void g_ite_instruction_set_branches(GITEInstruction *, GDecInstruction *, GDecInstruction *); - /* Exprime un aiguillage du flux en fonction d'une condition. */ GDecInstruction *g_ite_instruction_new(GDecExpression *, vmpa_t, vmpa_t); +/* Détermine le corps des différentes branches possibles. */ +void g_ite_instruction_set_branches(GITEInstruction *, GDecInstruction *, GDecInstruction *); + -#endif /* _DECOMP_EXPR_ITE_H */ +#endif /* _DECOMP_INSTR_ITE_H */ diff --git a/src/decomp/instr/switch.c b/src/decomp/instr/switch.c new file mode 100644 index 0000000..3c204a0 --- /dev/null +++ b/src/decomp/instr/switch.c @@ -0,0 +1,379 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * switch.c - décodage des aiguillages multiples du flot d'exécution + * + * Copyright (C) 2013 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "switch.h" + + +#include <malloc.h> +#include <stdlib.h> + + +#include "../instruction-int.h" + + +/* Détails d'un cas */ +typedef struct _case_info +{ + vmpa_t addr; /* Adresse des blocs associés */ + + GDecExpression **values; /* Valeur d'embranchement */ + size_t values_count; /* Quantité de cas rassemblés */ + + GDecInstruction *instrs; /* Instructions du cas */ + +} case_info; + + +/* Définition d'un aiguillage multiple du flux d'exécution (instance) */ +struct _GSwitchInstruction +{ + GDecInstruction parent; /* A laisser en premier */ + + GDecExpression *value; /* Valeur décidant du flot */ + + case_info *cases; /* Embranchements présents */ + size_t cases_count; /* Nombre de cas de sélection */ + + GDecInstruction *def_case; /* Instructions par défaut */ + +}; + + +/* Définition d'un aiguillage multiple du flux d'exécution (classe) */ +struct _GSwitchInstructionClass +{ + GDecInstructionClass parent; /* A laisser en premier */ + +}; + + + +/* Initialise la classe des aiguillages de flux d'exécution. */ +static void g_switch_instruction_class_init(GSwitchInstructionClass *); + +/* Initialise une instance d'aiguillage du flux d'exécution. */ +static void g_switch_instruction_init(GSwitchInstruction *); + +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_switch_instruction_visit(GSwitchInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_switch_instruction_replace(GSwitchInstruction *, GDecInstruction *, GDecInstruction *); + +/* Imprime pour l'écran un version humaine d'une instruction. */ +static GBufferLine *g_switch_instruction_print(const GSwitchInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *); + + + +/* Indique le type défini pour un aiguillage du flux d'exécution. */ +G_DEFINE_TYPE(GSwitchInstruction, g_switch_instruction, G_TYPE_DEC_INSTRUCTION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des aiguillages de flux d'exécution. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switch_instruction_class_init(GSwitchInstructionClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instance à initialiser. * +* * +* Description : Initialise une instance d'aiguillage du flux d'exécution. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switch_instruction_init(GSwitchInstruction *instr) +{ + GDecInstruction *base; /* Autre version de l'objet */ + + base = G_DEC_INSTRUCTION(instr); + + base->visit = (dec_instr_visit_fc)g_switch_instruction_visit; + base->replace = (dec_instr_replace_fc)g_switch_instruction_replace; + base->print = (dec_instr_print_fc)g_switch_instruction_print; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur déterminant la voie à suivre. * +* * +* Description : Exprime un aiguillage multiple du flux selon une valeur. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDecInstruction *g_switch_instruction_new(GDecExpression *value) +{ + GSwitchInstruction *result; /* Expression à retourner */ + + result = g_object_new(G_TYPE_SWITCH_INSTRUCTION, NULL); + + result->value = value; + + return G_DEC_INSTRUCTION(result); + +} + + +/****************************************************************************** +* * +* Paramètres : instr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_switch_instruction_visit(GSwitchInstruction *instr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + return true; + for (i = 0; i < instr->cases_count && result; i++) + result = _g_dec_instruction_visit(instr->cases[i].instrs, G_DEC_INSTRUCTION(instr), + callback, flags, data); + + if (result && instr->def_case != NULL) + result = _g_dec_instruction_visit(instr->def_case, G_DEC_INSTRUCTION(instr), + callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_switch_instruction_replace(GSwitchInstruction *instr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = false; + return false; + for (i = 0; i < instr->cases_count; i++) + result |= g_dec_instruction_replace(instr->cases[i].instrs, old, new); + + if (instr->def_case != NULL) + result |= g_dec_instruction_replace(instr->def_case, old, new); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à transcrire en version humaine. * +* buffer = tampon où doit se réaliser l'insertion. * +* line = ligne d'impression prête à emploi ou NULL. * +* output = langage de programmation de sortie. * +* * +* Description : Imprime pour l'écran un version humaine d'une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GBufferLine *g_switch_instruction_print(const GSwitchInstruction *instr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output) +{ + GBufferLine *result; /* Ligne à retourner */ + size_t i; /* Boucle de parcours #1 */ + size_t j; /* Boucle de parcours #2 */ + + g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "switch", 9, RTT_KEY_WORD); + + g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW); + g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "(", 1, RTT_PUNCT); + + result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->value), buffer, line, output); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ")", 1, RTT_PUNCT); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW); + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "{", 1, RTT_HOOK); + + g_code_buffer_inc_indentation(buffer); + + /* Cas d'aiguillage définis */ + + for (i = 0; i < instr->cases_count; i++) + { + for (j = 0; j < instr->cases[i].values_count; j++) + { + result = g_code_buffer_append_new_line_fixme(buffer); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "case", 4, RTT_KEY_WORD); + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW); + + result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->cases[i].values[j]) + , buffer, result, output); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT); + + } + + result = g_dec_instruction_print(instr->cases[i].instrs, buffer, result, output); + + } + + /* Cas par défaut */ + + if (instr->def_case != NULL) + { + result = g_code_buffer_append_new_line_fixme(buffer); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "default", 7, RTT_KEY_WORD); + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT); + + result = g_dec_instruction_print(instr->def_case, buffer, result, output); + + } + + /* Clôture */ + + g_code_buffer_dec_indentation(buffer); + + result = g_code_buffer_append_new_line_fixme(buffer); + + g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "}", 1, RTT_HOOK); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à compléter avec un nouveau cas. * +* value = valeur validant l'exécution des instructions. * +* instrs = instructions associées au cas présenté. * +* addr = adresse du bloc d'instructions. * +* * +* Description : Ajoute un cas d'exécution à l'aiguillage multiple. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_switch_instruction_add_case(GSwitchInstruction *instr, GDecExpression *value, GDecInstruction *instrs, vmpa_t addr) +{ + case_info *found; /* Cas similaires déjà intégrés*/ + + found = (case_info *)bsearch(&addr, instr->cases, instr->cases_count, sizeof(case_info), + (__compar_fn_t)compare_vmpa); + + if (found != NULL) + { + found->values = (GDecExpression **)realloc(found->values, + found->values_count++ * sizeof(GDecExpression *)); + + found->values[found->values_count - 1] = value; + + } + else + { + instr->cases = (case_info *)realloc(instr->cases, + ++instr->cases_count * sizeof(case_info)); + + instr->cases[instr->cases_count - 1].addr = addr; + instr->cases[instr->cases_count - 1].values = (GDecExpression **)malloc(sizeof(GDecExpression *)); + instr->cases[instr->cases_count - 1].values_count = 1; + instr->cases[instr->cases_count - 1].instrs = instrs; + + instr->cases[instr->cases_count - 1].values[0] = value; + + qsort(instr->cases, instr->cases_count, sizeof(case_info), (__compar_fn_t)compare_vmpa); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à compléter avec un nouveau cas. * +* instrs = instructions associées au cas présenté. * +* * +* Description : Ajoute un cas d'exécution par défaut à l'aiguillage multiple.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_switch_instruction_set_default_case(GSwitchInstruction *instr, GDecInstruction *instrs) +{ + if (instr->def_case != NULL) + g_object_unref(G_OBJECT(instr->def_case)); + + instr->def_case = instrs; + +} diff --git a/src/decomp/instr/switch.h b/src/decomp/instr/switch.h new file mode 100644 index 0000000..fa00c3e --- /dev/null +++ b/src/decomp/instr/switch.h @@ -0,0 +1,66 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * switch.h - prototypes pour les aiguillages multiples du flot d'exécution + * + * Copyright (C) 2013 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _DECOMP_INSTR_SWITCH_H +#define _DECOMP_INSTR_SWITCH_H + + +#include <glib-object.h> + + +#include "../expression.h" +#include "../instruction.h" + + + +#define G_TYPE_SWITCH_INSTRUCTION g_switch_instruction_get_type() +#define G_SWITCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_switch_instruction_get_type(), GSwitchInstruction)) +#define G_IS_SWITCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_switch_instruction_get_type())) +#define G_SWITCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SWITCH_INSTRUCTION, GSwitchInstructionClass)) +#define G_IS_SWITCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SWITCH_INSTRUCTION)) +#define G_SWITCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SWITCH_INSTRUCTION, GSwitchInstructionClass)) + + + +/* Définition d'un aiguillage multiple du flux d'exécution (instance) */ +typedef struct _GSwitchInstruction GSwitchInstruction; + +/* Définition d'un aiguillage multiple du flux d'exécution (classe) */ +typedef struct _GSwitchInstructionClass GSwitchInstructionClass; + + +/* Indique le type défini pour un multiple aiguillage du flux d'exécution. */ +GType g_switch_instruction_get_type(void); + +/* Exprime un aiguillage multiple du flux selon une valeur. */ +GDecInstruction *g_switch_instruction_new(GDecExpression *); + +/* Ajoute un cas d'exécution à l'aiguillage multiple. */ +void g_switch_instruction_add_case(GSwitchInstruction *, GDecExpression *, GDecInstruction *, vmpa_t); + +/* Ajoute un cas d'exécution par défaut à l'aiguillage multiple. */ +void g_switch_instruction_set_default_case(GSwitchInstruction *, GDecInstruction *); + + + +#endif /* _DECOMP_INSTR_SWITCH_H */ |