diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2014-10-07 22:07:27 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2014-10-07 22:07:27 (GMT) |
commit | a5e162d47a574f334b172dfee3128a40e8d52fb3 (patch) | |
tree | 5816a46365d196f40ac39fed884a9ee20fb44194 /tools | |
parent | 1d5f7f28f92251dc4d3bff8d87b3e3052ab9cab2 (diff) |
Created a compiler for architecture instruction definitions.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@410 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 25 | ||||
-rw-r--r-- | tools/coder.c | 1878 | ||||
-rw-r--r-- | tools/coder.h | 158 | ||||
-rw-r--r-- | tools/d2c.mk | 22 | ||||
-rw-r--r-- | tools/d2c_gram.y | 329 | ||||
-rw-r--r-- | tools/d2c_tok.l | 165 |
6 files changed, 2577 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..9a91f9d --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,25 @@ + +BUILT_SOURCES = d2c-d2c_gram.h + +AM_YFLAGS = -d + +bin_PROGRAMS = d2c + + +d2c_SOURCES = \ + coder.h coder.c \ + d2c_gram.y \ + d2c_tok.l + +d2c_YFLAGS = -d -p d2c_ -o y.tab.c + +d2c_LFLAGS = -P d2c_ -o lex.yy.c + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) + + +# Automake fait les choses à moitié +CLEANFILES = d2c_gram.h d2c_gram.c d2c-d2c_tok.c diff --git a/tools/coder.c b/tools/coder.c new file mode 100644 index 0000000..3606bea --- /dev/null +++ b/tools/coder.c @@ -0,0 +1,1878 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * coder.c - lecture automatisée des spécifications d'architecture + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * 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 "coder.h" + + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <inttypes.h> +#include <malloc.h> +#include <regex.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + + + +/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ + + +/* Conversion des chaînes en chaînes */ +typedef struct _string_exch +{ + const char *src; /* Chaîne à trouver */ + const char *dest; /* Chaîne de remplacement */ + +} string_exch; + + +struct _encoding_spec; + + +/* Suivi des constructions */ +struct _rented_coder +{ + const char *outdir; /* Lieu d'enregistrement */ + const char *arch; /* Architecture à traiter */ + const char *header; /* En-tête pour les en-têtes */ + + string_exch *macros; /* Remplacements de chaînes */ + size_t macros_count; /* Nombre de ces remplacements */ + + string_exch *encodings; /* Traductions d'encodages */ + size_t encodings_count; /* Nombre de ces traductions */ + + char *copyright; /* Récupération des droits */ + char *ins; /* Désignation humaine */ + char *details; /* Eventuels compléments */ + + struct _encoding_spec *specs; /* Définitions déjà en place */ + size_t specs_count; /* Nombre de ces définitions */ + struct _encoding_spec *cur_spec; /* Définition courante */ + +}; + + +/* Recherche l'existence d'une macro pour un remplacement. */ +static const char *find_macro_in_coder(const rented_coder *, const char *); + + + +/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ + + +struct _dec_bitfield; +struct _syntax_item; +struct _conv_func; +struct _extra_rule; + + +/* Mémorisation d'un encodage complet */ +typedef struct _encoding_spec +{ + char *prefix; /* Distinction principale */ + unsigned int index; /* Distinction secondaire */ + + struct _dec_bitfield *bitfields; /* Champs de bits détectés */ + size_t bf_count; /* Nombre de ces champs */ + uint64_t bits; /* Bits invariables */ + uint64_t mask; /* Emplacement de ces bits */ + unsigned int curpos; /* Position pendant l'analyse */ + + struct _syntax_item *items; /* Eléments de la syntaxe */ + size_t items_count; /* Nombre de ces éléments */ + + struct _conv_func *conversions; /* Conversions des données */ + size_t conv_count; /* Nombre de ces conversions */ + + struct _extra_rule *rules; /* Régles supplémentaires */ + size_t rules_count; /* Nombre de ces règles */ + +} encoding_spec; + + +/* Libère de la mémoire une spécification d'encodage. */ +static void free_encoding_spec(encoding_spec *); + + + +/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */ + + +/* Propriétés particulières pour les opérandes */ +typedef enum _SyntaxItemFlags +{ + SIF_NONE = (0 << 0), /* Aucune propriété */ + SIF_DECIMAL = (1 << 0) /* Affichage en décimal */ + +} SyntaxItemFlags; + +/* Elément défini dans une syntaxe */ +typedef struct _syntax_item +{ + char *name; /* Désignation humaine */ + bool internal; /* Enregistrement générique ? */ + SyntaxItemFlags flags; /* Propriétés supplémentaires */ + +} syntax_item; + + +/* Libère de la mémoire tous les éléments de syntaxe. */ +static void free_all_syntax_items_in_spec(encoding_spec *); + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Elément d'un mot décodé */ +typedef struct _dec_bitfield +{ + char *name; /* Désignation humaine */ + unsigned int start; /* Position de départ */ + unsigned int length; /* Taille du champ */ + +} dec_bitfield; + + + + +/* Recherche un champ donné dans une définition. */ +static const dec_bitfield *find_named_field_in_spec(const encoding_spec *, const char *); + +/* Libère de la mémoire toutes les champs de bits définis. */ +static void free_all_bitfields_in_spec(encoding_spec *); + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Fonction de conversion */ +typedef struct _conv_func +{ + char *dest; /* Variable de destination */ + char *func; /* Fonction de conversion */ + char *arg; /* Argument de cette fonction */ + +} conv_func; + + +/* Libère de la mémoire toutes les conversions enregistrées. */ +static void free_all_conversion_in_spec(encoding_spec *); + +/* Recherche une fonction converrtissant une donnée brute. */ +static const conv_func *find_conversion_in_coder_spec(const encoding_spec *, const char *); + + + +/* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */ + + +/* Expression d'une condition */ +struct _cond_expr +{ + bool is_simple; /* Sélection de champ */ + + union + { + struct + { + char *variable; /* Variable manipulée */ + CondCompType comp; /* Type de comparaison */ + char *bvalue; /* Valeur binaire comparée */ + + } simple; + + struct + { + cond_expr *a; /* Première sous-expression */ + CondOpType operator; /* Relation entre expressions */ + cond_expr *b; /* Seconde sous-expression */ + + } composed; + + }; + +}; + +/* Règles particulières */ +typedef struct _extra_rule +{ + cond_expr *expr; /* Expression de déclenchement */ + CondActionType action; /* Conséquence d'une validation*/ + char *details; /* Eventuel complément d'info. */ + +} extra_rule; + + +/* Libère de la mémoire une expression conditionnelle. */ +static void free_cond_expr(cond_expr *); + +/* Traduit en code une expression de condition. */ +static bool write_cond_expr(const encoding_spec *, int, const cond_expr *); + +/* Libère de la mémoire des règles. */ +static void free_all_coder_spec_rules(encoding_spec *); + +/* Traduit en code les éventuelles règles présentes. */ +static bool write_coder_spec_rules(const rented_coder *, int, const encoding_spec *, bool *); + + + +/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ + + +/* Ouvre un fichier en écriture pour y placer du code. */ +static int create_code_file(const rented_coder *, const char *, const char *, const char *, char, bool *); + +/* Ecrit une partie des fonctions issues des spécifications. */ +static bool dump_all_matching_specs_in_coder(const rented_coder *, const string_exch *, int, int); + +/* Traduit en code une sous-fonction de désassemblage. */ +static bool write_coder_spec_disass(const rented_coder *, int, const encoding_spec *, const char *, unsigned int); + + + +/* ---------------------------- MANIPULATIONS DE CHAINES ---------------------------- */ + + +/* Bascule toute une chaîne de caractères en (min|maj)uscules. */ +static char *_make_string_xxx(char *, int (* fn) (int)); + +#define make_string_lower(str) _make_string_xxx(str, tolower) +#define make_string_upper(str) _make_string_xxx(str, toupper) + +/* Traduit une chaîne en élément de fonction C. */ +static char *make_callable(const char *raw, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* CONSTRUCTION SELON COMMANDES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Débute la définition d'une fonction de désassemblage. * +* * +* Retour : Gestionnaire mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +rented_coder *create_coder(void) +{ + rented_coder *result; /* Structure à renvoyer */ + + result = (rented_coder *)calloc(1, sizeof(rented_coder)); + + result->cur_spec = (encoding_spec *)calloc(1, sizeof(encoding_spec)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Supprime le codeur de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_coder(rented_coder *coder) +{ + size_t i; /* Boucle de parcours */ + + if (coder->macros != NULL) + free(coder->macros); + + if (coder->encodings != NULL) + free(coder->encodings); + + if (coder->ins != NULL) + free(coder->ins); + + if (coder->details != NULL) + free(coder->details); + + for (i = 0; i < coder->specs_count; i++) + free_encoding_spec(&coder->specs[i]); + + if (coder->specs != NULL) + free(coder->specs); + + free_encoding_spec(coder->cur_spec); + + free(coder->cur_spec); + + free(coder); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Détermine si les propriétés de base d'un codeur sont là. * +* * +* Retour : Bilan de l'état opérationnel. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool do_basic_checks_with_coder(const rented_coder *coder) +{ + return (coder->outdir != NULL && coder->arch != NULL && coder->header != NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* outdir = répertoire de génération des fichiers. * +* * +* Description : Spécifie le répertoire de base pour les sorties de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_coder_output_directory(rented_coder *coder, const char *outdir) +{ + coder->outdir = outdir; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* arch = désignation pour le code de l'architecture lue. * +* * +* Description : Détermine l'architecture visée par les traitements. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_coder_arch(rented_coder *coder, const char *arch) +{ + coder->arch = arch; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* header = base des définitions de protection d'en-têtes. * +* * +* Description : Définit la base des protections des fichiers d'en-tête. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_coder_header_base(rented_coder *coder, const char *header) +{ + coder->header = header; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* src = chaîne à remplacer dans les définitions. * +* dest = chaîne de remplacement. * +* * +* Description : Enregistre une correspondance en matière d'encodage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_encoding_in_coder(rented_coder *coder, const char *src, const char *dest) +{ + string_exch *encoding; /* Traduction à conserver */ + + coder->encodings = (string_exch *)realloc(coder->encodings, ++coder->encodings_count * sizeof(string_exch)); + + encoding = &coder->encodings[coder->encodings_count - 1]; + + encoding->src = src; + encoding->dest = dest; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* src = chaîne à remplacer dans les définitions. * +* dest = chaîne de remplacement. * +* * +* Description : Constitue la matière d'un système de macros. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void define_macro_for_coder(rented_coder *coder, const char *src, const char *dest) +{ + string_exch *macro; /* Nouvelle macro à constituer */ + + coder->macros = (string_exch *)realloc(coder->macros, ++coder->macros_count * sizeof(string_exch)); + + macro = &coder->macros[coder->macros_count - 1]; + + macro->src = src; + macro->dest = dest; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* src = chaîne à remplacer dans les définitions. * +* * +* Description : Recherche l'existence d'une macro pour un remplacement. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const char *find_macro_in_coder(const rented_coder *coder, const char *src) +{ + const char *result; /* Trouvaille à renvoyer */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < coder->macros_count && result == NULL; i++) + if (strcmp(coder->macros[i].src, src) == 0) + result = coder->macros[i].dest; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain.* +* copy = droits de copie en anglais. * +* ins = désignation humaine de l'instruction. * +* details = compléments d'informations éventuels ou NULL. * +* * +* Description : Enregistre les contours d'une instruction d'assemblage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, const char *details) +{ + coder->copyright = copy; + coder->ins = make_string_lower(ins); + coder->details = (details != NULL ? make_callable(details, true) : strdup("")); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* REPRESENTATION D'ENCODAGES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* prefix = distinction principale entre les définitions. * +* index = distinction secondaire entre les définitions. * +* * +* Description : Enregistre une définition supplémentaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) +{ + encoding_spec *spec; /* Définition à compléter */ + + spec = coder->cur_spec; + + spec->prefix = prefix; + spec->index = index; + + coder->specs = (encoding_spec *)realloc(coder->specs, ++coder->specs_count * sizeof(encoding_spec)); + + coder->specs[coder->specs_count - 1] = *spec; + + memset(spec, 0, sizeof(encoding_spec)); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage en cours de libération. * +* * +* Description : Libère de la mémoire une spécification d'encodage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_encoding_spec(encoding_spec *spec) +{ + free_all_syntax_items_in_spec(spec); + + free_all_bitfields_in_spec(spec); + + free_all_conversion_in_spec(spec); + + free_all_coder_spec_rules(spec); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* GESTION DES CHAMPS DE BITS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* name = désignation humaine du champ remarqué. * +* length = taille du champ à mémoriser. * +* * +* Description : Note la présence d'un champ remarquable dans une définition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_named_field_in_coder(rented_coder *coder, char *name, unsigned int length) +{ + encoding_spec *spec; /* Définition à compléter */ + dec_bitfield *field; /* Nouveau champ à constituer */ + + spec = coder->cur_spec; + + assert((spec->curpos + length) < 64); + + spec->bitfields = (dec_bitfield *)realloc(spec->bitfields, + ++spec->bf_count * sizeof(dec_bitfield)); + + field = &spec->bitfields[spec->bf_count - 1]; + + field->name = make_string_lower(name); + field->start = spec->curpos; + field->length = length; + + spec->curpos += length; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à parcourir. * +* name = désignation humaine du champ à retrouver. * +* * +* Description : Recherche un champ donné dans une définition. * +* * +* Retour : Structure associée au champ trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const dec_bitfield *find_named_field_in_spec(const encoding_spec *spec, const char *name) +{ + dec_bitfield *result; /* Champ de bits à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < spec->bf_count && result == NULL; i++) + if (strcmp(spec->bitfields[i].name, name) == 0) + result = &spec->bitfields[i]; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* val = valeur du bit à prendre en compte. * +* * +* Description : Note la présence d'un bit invariable dans une définition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_bit_in_coder(rented_coder *coder, int val) +{ + encoding_spec *spec; /* Définition à compléter */ + + spec = coder->cur_spec; + + assert(spec->curpos < 64); + + spec->bits |= (val ? 1 : 0) << spec->curpos; + spec->mask |= 1 << spec->curpos; + + spec->curpos++; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage en cours de libération. * +* * +* Description : Libère de la mémoire toutes les champs de bits définis. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_all_bitfields_in_spec(encoding_spec *spec) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < spec->bf_count; i++) + free(spec->bitfields[i].name); + + if (spec->bitfields != NULL) + { + free(spec->bitfields); + spec->bitfields = NULL; + } + + spec->bf_count = 0; + + spec->bits = 0; + spec->mask = 0; + + spec->curpos = 0; + +} + + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Indique le nombre de bits traités. * +* * +* Retour : Quantité, positive ou nulle. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int count_coder_bits(const rented_coder *coder) +{ + return coder->cur_spec->curpos; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* SYNTAXE DES INSTRUCTIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement d'humain. * +* name = désignation de l'opérande dans la spécification. * +* internal = précise si l'opérand est non générique ou non. * +* * +* Description : Enregistre la présence d'un nouvel opérande. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_syntax_item_in_coder(rented_coder *coder, char *name, bool internal) +{ + encoding_spec *spec; /* Définition à compléter */ + syntax_item *item; /* Nouvelle prise en compte */ + size_t len; /* Taille du nom fourni */ + + spec = coder->cur_spec; + + spec->items = (syntax_item *)realloc(spec->items, ++spec->items_count * sizeof(syntax_item)); + + item = &spec->items[spec->items_count - 1]; + + /* Récupération des drapeaux */ + + item->flags = SIF_NONE; + + for (len = strlen(name); len > 0; len--) + switch (name[0]) + { + case '#': + item->flags |= SIF_DECIMAL; + memmove(name, name + 1, len); + break; + + default: + len = 1; + break; + + } + + item->name = make_string_lower(name); + item->internal = internal; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage en cours de libération. * +* * +* Description : Libère de la mémoire tous les éléments de syntaxe. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_all_syntax_items_in_spec(encoding_spec *spec) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < spec->items_count; i++) + free(spec->items[i].name); + + if (spec->items != NULL) + { + free(spec->items); + spec->items = NULL; + } + + spec->items_count = 0; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONVERSION DES ARGUMENTS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* dest = désignation de la variable de destination. * +* func = nom de la fonction assurant le calcul de valeur. * +* arg = argument à fournir à cette fonction. * +* * +* Description : Enregistre la function de conversion du brut à l'utile. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_conversion_in_coder(rented_coder *coder, char *dest, char *func, char *arg) +{ + encoding_spec *spec; /* Définition à compléter */ + conv_func *conv; /* Nouvelle prise en compte */ + + spec = coder->cur_spec; + + spec->conversions = (conv_func *)realloc(spec->conversions, ++spec->conv_count * sizeof(conv_func)); + + conv = &spec->conversions[spec->conv_count - 1]; + + conv->dest = make_string_lower(dest); + conv->func = func; + conv->arg = make_string_lower(arg); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage en cours de libération. * +* * +* Description : Libère de la mémoire toutes les conversions enregistrées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_all_conversion_in_spec(encoding_spec *spec) +{ + size_t i; /* Boucle de parcours */ + conv_func *conv; /* Conversion à traiter */ + + for (i = 0; i < spec->conv_count; i++) + { + conv = &spec->conversions[i]; + + free(conv->dest); + free(conv->func); + free(conv->arg); + + } + + if (spec->conversions != NULL) + { + free(spec->conversions); + spec->conversions = NULL; + } + + spec->conv_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'un encodage à consulter. * +* dest = désignation d'une variable de destination. * +* * +* Description : Recherche une fonction converrtissant une donnée brute. * +* * +* Retour : Structure de conversion trouvée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const conv_func *find_conversion_in_coder_spec(const encoding_spec *spec, const char *dest) +{ + const conv_func *result; /* Conversion à renvoyer */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < spec->conv_count && result == NULL; i++) + if (strcmp(spec->conversions[i].dest, dest) == 0) + result = &spec->conversions[i]; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONDITIONS ET CONSEQUENCES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : variable = désignation de la variable à manipuler. * +* comp = type de comparaison à utiliser. * +* bvalue = valeur binaire à comparer. * +* * +* Description : Crée une expression conditionnelle simple. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_simple_cond_expression(char *variable, CondCompType comp, char *bvalue) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = true; + + result->simple.variable = make_string_lower(variable); + result->simple.comp = comp; + result->simple.bvalue = bvalue; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = première expression à intégrer. * +* operator = type de comparaison à utiliser. * +* b = second expression à intégrer. * +* * +* Description : Crée une expression conditionnelle composée. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_composed_cond_expression(cond_expr *a, CondOpType operator, cond_expr *b) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = false; + + result->composed.a = a; + result->composed.operator = operator; + result->composed.b = b; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = représentation d'expression à traiter. * +* * +* Description : Libère de la mémoire une expression conditionnelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_cond_expr(cond_expr *expr) +{ + if (expr->is_simple) + { + free(expr->simple.variable); + free(expr->simple.bvalue); + } + else + { + free_cond_expr(expr->composed.a); + free_cond_expr(expr->composed.b); + } + + free(expr); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'un encodage à consulter. * +* fd = descripteur d'un flux ouvert en écriture. * +* expr = expression simple ou composée à transposer. * +* * +* Description : Traduit en code une expression de condition. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool write_cond_expr(const encoding_spec *spec, int fd, const cond_expr *expr) +{ + bool result; /* Bilan à renvoyer */ + const dec_bitfield *bf; /* Champ de bits de définition */ + + result = true; + + dprintf(fd, "("); + + if (expr->is_simple) + { + bf = find_named_field_in_spec(spec, expr->simple.variable); + if (bf == NULL) + { + fprintf(stderr, "Error: no bitfield defined the requested variable '%s'.\n", expr->simple.variable); + result = false; + goto wce_exit; + } + + if (bf->length != strlen(expr->simple.bvalue)) + { + fprintf(stderr, "Error: variable '%s' and provided value sizes do not match (%u vs %zu).\n", + expr->simple.variable, bf->length, strlen(expr->simple.bvalue)); + result = false; + goto wce_exit; + } + + dprintf(fd, "raw_%s", expr->simple.variable); + + switch (expr->simple.comp) + { + case CCT_EQUAL: + dprintf(fd, " == "); + break; + case CCT_DIFF: + dprintf(fd, " != "); + break; + } + + dprintf(fd, "b%s", expr->simple.bvalue); + + } + else + { + result = write_cond_expr(spec, fd, expr->composed.a); + if (!result) goto wce_exit; + + switch (expr->composed.operator) + { + case COT_AND: + dprintf(fd, " && "); + break; + case COT_OR: + dprintf(fd, " || "); + break; + } + + result = write_cond_expr(spec, fd, expr->composed.b); + if (!result) goto wce_exit; + + } + + dprintf(fd, ")"); + + wce_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain.* +* expr = représentation d'expression à conserver. * +* action = conséquence associée à la règle. * +* details = éventuel complément d'informations. * +* * +* Description : Ajoute une règle complète à la définition d'un codage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void add_conditional_rule_to_coder(rented_coder *coder, cond_expr *expr, CondActionType action, const char *details) +{ + encoding_spec *spec; /* Définition à compléter */ + extra_rule *rule; /* Nouvelle prise en compte */ + + spec = coder->cur_spec; + + spec->rules = (extra_rule *)realloc(spec->rules, ++spec->rules_count * sizeof(extra_rule)); + + rule = &spec->rules[spec->rules_count - 1]; + + rule->expr = expr; + rule->action = action; + rule->details = make_callable(details, false); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à traiter. * +* * +* Description : Libère de la mémoire des règles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void free_all_coder_spec_rules(encoding_spec *spec) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < spec->rules_count; i++) + { + free_cond_expr(spec->rules[i].expr); + + if (spec->rules[i].details) + free(spec->rules[i].details); + + } + + if (spec->rules != NULL) + { + free(spec->rules); + spec->rules = NULL; + } + + spec->rules_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* fd = descripteur d'un flux ouvert en écriture. * +* spec = spécification servant de base à l'opération. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * +* * +* Description : Traduit en code les éventuelles règles présentes. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool write_coder_spec_rules(const rented_coder *coder, int fd, const encoding_spec *spec, bool *exit) +{ + bool result; /* Bilan à remonter */ + const extra_rule *rule; /* Règle en cours d'écriture */ + size_t i; /* Boucle de parcours */ + + result = true; + + *exit = false; + + for (i = 0; i < spec->rules_count; i++) + { + rule = &spec->rules[i]; + + dprintf(fd, "\t\tif "); + + result = write_cond_expr(spec, fd, rule->expr); + if (!result) break; + + dprintf(fd, "\n"); + dprintf(fd, "\t\t{\n"); + + switch (rule->action) + { + case CAT_SEE: + + if (rule->details == NULL) + { + fprintf(stderr, "Error: directive 'see' must provide additional details.\n"); + result = false; + goto wcsr_exit; + } + + dprintf(fd, "\t\t\tinstr = armv7_read_instr_%s", rule->details); + + /* TODO : adapter les paramètres d'appel selon le 'coder' */ + dprintf(fd, "(_raw);\n"); + + dprintf(fd, "\t\t\tgoto quick_exit;\n"); + + *exit = true; + break; + + } + + dprintf(fd, "\t\t}\n"); + + dprintf(fd, "\n"); + + } + + wcsr_exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* GENERATIONS DE CODE SOURCE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* dir = répertoire final de destination. * +* prefix = type d'encodage à répercuter sur le nom de fichier. * +* name = nom brut du fichier à ouvrir. * +* ext = extension à donner au fichier à ouvrir. * +* exist = indique si le fichier était présent avant. [OUT] * +* * +* Description : Ouvre un fichier en écriture pour y placer du code. * +* * +* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int create_code_file(const rented_coder *coder, const char *dir, const char *prefix, const char *name, char ext, bool *exist) +{ + int result; /* Descripteur à retourner */ + size_t length; /* Taille du nom de fichier */ + char *pathname; /* Chemin d'accès à constituer */ + + length = strlen(coder->outdir) + 1 + strlen(dir) + 1 + strlen(prefix) + strlen(name) + 3; + pathname = (char *)calloc(length, sizeof(char)); + snprintf(pathname, length, "%s/%s/%s%s.%c", coder->outdir, dir, prefix, name, ext); + + *exist = (access(pathname, W_OK) == 0); + + result = open(pathname, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (result == -1) perror("open()"); + + free(pathname); + + if (!*exist && result != -1) + { + dprintf(result, "\n"); + + dprintf(result, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); + dprintf(result, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext); + dprintf(result, " *\n"); + dprintf(result, " * %s\n", coder->copyright); + dprintf(result, " *\n"); + dprintf(result, " * This file is part of Chrysalide.\n"); + dprintf(result, " *\n"); + dprintf(result, " * Chrysalide is free software; you can redistribute it and/or modify\n"); + dprintf(result, " * it under the terms of the GNU General Public License as published by\n"); + dprintf(result, " * the Free Software Foundation; either version 3 of the License, or\n"); + dprintf(result, " * (at your option) any later version.\n"); + dprintf(result, " *\n"); + dprintf(result, " * Chrysalide is distributed in the hope that it will be useful,\n"); + dprintf(result, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + dprintf(result, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + dprintf(result, " * GNU General Public License for more details.\n"); + dprintf(result, " *\n"); + dprintf(result, " * You should have received a copy of the GNU General Public License\n"); + dprintf(result, " * along with Foobar. If not, see <http://www.gnu.org/licenses/>.\n"); + dprintf(result, " */\n"); + + dprintf(result, "\n"); + dprintf(result, "\n"); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain.* +* * +* Description : Débute la définition des fonctions issues des spécifications.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool dump_all_routines_using_coder(const rented_coder *coder) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + string_exch *encoding; /* Type d'encodage visé */ + bool exist; /* Présence du fichier visé ? */ + int header_fd; /* Fichier de déclarations */ + char *dash; /* Présence d'un tiret ? */ + char *filename; /* Nom de fichier commun */ + int code_fd; /* Fichier de définitions */ + + result = true; + + for (i = 0; i < coder->encodings_count && result; i++) + { + encoding = &coder->encodings[i]; + + /* Fichier de déclarations */ + + header_fd = create_code_file(coder, "opcodes", encoding->dest, "opcodes", 'h', &exist); + if (header_fd == -1) return false; + + if (!exist) + { + dprintf(header_fd, "#ifndef %s_OPCODES_OPCODES_H\n", coder->header); + dprintf(header_fd, "#define %s_OPCODES_OPCODES_H\n", coder->header); + + dprintf(header_fd, "\n"); + dprintf(header_fd, "\n"); + dprintf(header_fd, "##INCLUDES##\n"); + dprintf(header_fd, "\n"); + dprintf(header_fd, "\n"); + dprintf(header_fd, "\n"); + + } + + /* Fichier de définitions */ + + dash = strchr(coder->ins, '-'); + + if (dash == NULL) + code_fd = create_code_file(coder, "opcodes", encoding->dest, coder->ins, 'c', &exist); + + else + { + filename = strdup(coder->ins); + + dash = strchr(filename, '-'); + *dash = '\0'; + + code_fd = create_code_file(coder, "opcodes", encoding->dest, filename, 'c', &exist); + + free(filename); + + } + + if (!exist) + { + dprintf(code_fd, "#include \"opcodes.h\"\n"); + dprintf(code_fd, "\n"); + dprintf(code_fd, "##INCLUDES##\n"); + + } + + if (code_fd == -1) + { + close(header_fd); + return false; + } + + /* Production de code... */ + + result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); + + close(header_fd); + close(code_fd); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement d'humain. * +* encoding = sélection de l'encodage à traiter. * +* hfd = flux ouvert en écriture pour les déclarations. * +* cfd = flux ouvert en écriture pour les définitions. * +* * +* Description : Ecrit une partie des fonctions issues des spécifications. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) +{ + bool result; /* Bilan à retourner */ + char *keyword; /* Mot clef appelable en code */ + unsigned int wide; /* Taille des mots */ + size_t i; /* Boucle de parcours */ + encoding_spec *spec; /* Définition à traiter */ + size_t maxlen; /* Taille à compléter */ + + result = true; + + keyword = make_callable(coder->ins, false); + + /* Recherche de la taille des mots */ + + wide = -1; + + for (i = 0; i < coder->specs_count; i++) + { + spec = &coder->specs[i]; + + if (strcmp(encoding->src, spec->prefix) != 0) + continue; + + wide = spec->curpos; + break; + + } + + /* Rien n'a été trouvé à faire... */ + if (wide == -1) goto damsic_exit; + + /* Désassemblage : déclaration */ + + dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins); + dprintf(hfd, "GArchInstruction *%s_read_instr_%s%s(uint%u_t);\n", coder->arch, keyword, coder->details, wide); + dprintf(hfd, "\n"); + + /* Désassemblage : définitions */ + + dprintf(cfd, "\n"); + + dprintf(cfd, "/******************************************************************************\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Description : Décode une instruction de type '%s'.", coder->ins); + + maxlen = 28 - strlen(coder->ins); + + if (maxlen < 28) + dprintf(cfd, "%*s\n", (int)maxlen, "*"); + else + dprintf(cfd, "*\n"); + + dprintf(cfd, " *\n"); + dprintf(cfd, "* Retour : Bilan de l'opération. *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Remarques : - *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "******************************************************************************/\n"); + + dprintf(cfd, "\n"); + + dprintf(cfd, "GArchInstruction *%s_read_instr_%s%s(uint%u_t raw)", coder->arch, keyword, coder->details, wide); + dprintf(cfd, "\n"); + dprintf(cfd, "{"); + dprintf(cfd, "\n"); + + dprintf(cfd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); + + dprintf(cfd, "\n"); + dprintf(cfd, "\tresult = NULL;\n"); + dprintf(cfd, "\n"); + + for (i = 0; i < coder->specs_count && result; i++) + { + spec = &coder->specs[i]; + + if (strcmp(encoding->src, spec->prefix) != 0) + continue; + + result = write_coder_spec_disass(coder, cfd, spec, keyword, wide); + + } + + dprintf(cfd, "\treturn result;\n"); + dprintf(cfd, "\n"); + + dprintf(cfd, "}\n"); + dprintf(cfd, "\n"); + + damsic_exit: + + free(keyword); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain.* +* fd = descripteur d'un flux ouvert en écriture. * +* spec = spécification servant de base à l'opération. * +* keyword = nom clef de l'instruction utilisable dans du code. * +* wide = taille des mots manipulés (en bits). * +* * +* Description : Traduit en code une sous-fonction de désassemblage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool write_coder_spec_disass(const rented_coder *coder, int fd, const encoding_spec *spec, const char *keyword, unsigned int wide) +{ + size_t i; /* Boucle de parcours */ + dec_bitfield *bf; /* Accès confortable à un champ*/ + bool exit; /* Inclusion de sortie rapide ?*/ + syntax_item *item; /* Lien vers un opérande */ + regex_t preg; /* Expression régulière */ + int ret; /* Bilan d'une manipulation */ + const conv_func *conv; /* Moyen de conversion du brut */ + const char *callable; /* Fonction à appeler */ + bool rebuild; /* Construction complexe */ + regmatch_t pmatch[3]; /* Correspondances de chaînes */ + size_t cmplen; /* Taille de comparaison */ + char *cast; /* Macro de transtypage */ + + dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n", + coder->arch, keyword, coder->details, spec->prefix, spec->index, wide); + + dprintf(fd, "\t{\n"); + + dprintf(fd, "\t\tGArchInstruction *instr;\n"); + + /* Déclaration des champs à retrouver */ + + for (i = 0; i < spec->bf_count; i++) + dprintf(fd, "\t\tuint%u_t raw_%s;\n", wide, spec->bitfields[i].name); + + for (i = 0; i < spec->items_count; i++) + if (!spec->items[i].internal) + { + dprintf(fd, "\t\tGArchOperand *op;\n"); + break; + } + + dprintf(fd, "\n"); + + /* Vérification que le décodage est possible */ + + dprintf(fd, "\t\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n", spec->mask, spec->bits); + + dprintf(fd, "\n"); + + /* Définition des champs bruts */ + + for (i = 0; i < spec->bf_count; i++) + { + bf = &spec->bitfields[i]; + dprintf(fd, "\t\traw_%s = (_raw >> %u) & 0x%llx;\n", bf->name, bf->start, (1ull << bf->length) - 1); + } + + dprintf(fd, "\n"); + + /* Inclusion des éventuelles règles */ + + if (!write_coder_spec_rules(coder, fd, spec, &exit)) + return false; + + /* Création de l'instruction en elle-même */ + + dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", coder->arch, coder->ins); + + dprintf(fd, "\n"); + + /* Création des opérandes */ + + bool build_arg_if_needed(const conv_func *conv) + { + + /* TODO : concaténation... */ + + return false; + + } + + ret = regcomp(&preg, "(g_([a-z0-9]*)_instruction)", REG_EXTENDED); + if (ret != 0) + { + fprintf(stderr, "Internal error: bad regular expression.\n"); + return false; + } + + + for (i = 0; i < spec->items_count; i++) + { + item = &spec->items[i]; + + conv = find_conversion_in_coder_spec(spec, item->name); + if (conv == NULL) + { + fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); + return false; + } + + callable = find_macro_in_coder(coder, conv->func); + if (callable == NULL) + { + fprintf(stderr, "Error: expected function to store '%s'.\n", item->name); + return false; + } + + rebuild = build_arg_if_needed(conv); + + if (item->internal) + { + ret = regexec(&preg, callable, sizeof(pmatch) / sizeof(regmatch_t), pmatch, 0); + if (ret == REG_NOMATCH) + { + fprintf(stderr, "Internal error: bad function for dealing wih instruction: '%s'.\n", callable); + return false; + } + + /** + * La variable de résultat est de type 'GArchInstruction', + * donc toute fonction différente de g_arch_instruction_*() attend un transtypage... + */ + + cmplen = MAX(strlen(coder->arch), pmatch[2].rm_eo - pmatch[2].rm_so); + + if (strncmp("arch", &callable[pmatch[2].rm_so], cmplen) == 0) + dprintf(fd, "\t\tif (!%s(instr, %s%s))\n", + callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); + + else + { + cast = strndup(&callable[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); + + cast = make_string_upper(cast); + + dprintf(fd, "\t\tif (!%s(%s(instr), %s%s))\n", + callable, cast, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); + + free(cast); + + } + + dprintf(fd, "\t\t\tgoto bad_exit;\n"); + + } + + else + { + if (strchr(callable, '(') == NULL) + dprintf(fd, "\t\top = %s(%s%s);\n", + callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); + else + dprintf(fd, "\t\top = %s%s%s);\n", + callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); + dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n"); + + dprintf(fd, "\n"); + + if (item->flags & SIF_DECIMAL) + dprintf(fd, "\t\tg_imm_operand_set_display(G_IMM_OPERAND(op), IOD_DEC);\n"); + + dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n"); + + } + + dprintf(fd, "\n"); + + } + + regfree(&preg); + + /* Conclusion de la procédure */ + + if (exit) + { + dprintf(fd, "\t quick_exit:\n"); + dprintf(fd, "\n"); + } + + dprintf(fd, "\t\treturn instr;\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\t bad_exit:\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n"); + dprintf(fd, "\t\treturn NULL;\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\t}\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\tif (result == NULL)\n"); + dprintf(fd, "\t\tresult = %s_decode_%s%s_%s%u(raw);\n", + coder->arch, keyword, coder->details, spec->prefix, spec->index); + + dprintf(fd, "\n"); + + return true; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS DE CHAINES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : str = chaîne de caractères à manipuler. [OUT] * +* * +* Description : Bascule toute une chaîne de caractères en (min|maj)uscules. * +* * +* Retour : Pointeur sur la chaîne fournie. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *_make_string_xxx(char *str, int (* fn) (int)) +{ + size_t max; /* Empleur du parcours */ + size_t i; /* Boucle de parcours */ + + max = strlen(str); + + for (i = 0; i < max; i++) + str[i] = fn(str[i]); + + return str; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = données brutes en provenance de l'analyseur. * +* details = indique la nature de la chaîne à traiter. * +* * +* Description : Traduit une chaîne en élément de fonction C. * +* * +* Retour : Chaîne à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *make_callable(const char *raw, bool details) +{ + char *result; /* Nom formaté à retourner */ + size_t max; /* Empleur du parcours */ + size_t i; /* Boucle de parcours */ + + result = strdup(raw); + + max = strlen(result); + + /* Première passe : on vire les virgules */ + + for (i = 0; i < max; i++) + if (result[i] == ',') + { + memmove(result + i, result + i + 1, max - i - 1); + max--; + } + + result[max] = '\0'; + + /* Deuxième passe : on bascule en minuscules */ + + result = make_string_lower(result); + + /* Troisième passe : on remplace les mauvais caractères */ + + for (i = 0; i < max; i++) + switch (result[i]) + { + case 'a' ... 'z': + case '0' ... '9': + break; + case '-': + result[i] = '_'; + break; + default: + result[i] = (i + 1 == max ? '\0' : '_'); + break; + } + + /** + * Dernière passe : on s'assure que le premier caractère n'est pas une lettre. + * On ajoute ici le préfixe '_' utilisé lors de la génération de prototypes ; + * en cas d'absence de détails, on ne se retrouve ainsi pas avec un '_' isolé. + */ + + if (details && result[0] != '_') + { + max = strlen(result) + 1; + result = (char *)realloc(result, max); + memmove(result + 1, result, max - 1); + result[0] = '_'; + } + + return result; + +} diff --git a/tools/coder.h b/tools/coder.h new file mode 100644 index 0000000..c96f787 --- /dev/null +++ b/tools/coder.h @@ -0,0 +1,158 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * coder.h - prototypes pour la lecture automatisée des spécifications d'architecture + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * 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 _ARCH_ARM_V7_OPDEFS_CODER_H +#define _ARCH_ARM_V7_OPDEFS_CODER_H + + +#include <stdbool.h> + + + +/* Suivi des constructions */ +typedef struct _rented_coder rented_coder; + + + +/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ + + +/* Débute la définition d'une fonction de désassemblage. */ +rented_coder *create_coder(void); + +/* Supprime le codeur de la mémoire. */ +void delete_coder(rented_coder *); + +/* Détermine si les propriétés de base d'un codeur sont là. */ +bool do_basic_checks_with_coder(const rented_coder *); + +/* Spécifie le répertoire de base pour les sorties de code. */ +void set_coder_output_directory(rented_coder *, const char *); + +/* Détermine l'architecture visée par les traitements. */ +void set_coder_arch(rented_coder *, const char *); + +/* Définit la base des protections des fichiers d'en-tête. */ +void set_coder_header_base(rented_coder *, const char *); + +/* Enregistre une correspondance en matière d'encodage. */ +void register_encoding_in_coder(rented_coder *, const char *, const char *); + +/* Constitue la matière d'un système de macros. */ +void define_macro_for_coder(rented_coder *, const char *, const char *); + +/* Enregistre les contours d'une instruction d'assemblage. */ +void save_notes_for_coder(rented_coder *, char *, char *, const char *); + + + +/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ + + + +/* Enregistre une définition supplémentaire. */ +void push_encoding_spec(rented_coder *, char *, unsigned int); + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Note la présence d'un champ remarquable dans une définition. */ +void register_named_field_in_coder(rented_coder *, char *, unsigned int); + +/* Note la présence d'un bit invariable dans une définition. */ +void register_bit_in_coder(rented_coder *, int); + +/* Indique le nombre de bits traités. */ +unsigned int count_coder_bits(const rented_coder *); + + + +/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */ + + +/* Enregistre la présence d'un nouvel opérande. */ +void register_syntax_item_in_coder(rented_coder *, char *, bool); + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Enregistre la function de conversion du brut à l'utile. */ +void register_conversion_in_coder(rented_coder *, char *, char *, char *); + + + +/* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */ + + +/* Types de comparaison */ +typedef enum _CondCompType +{ + CCT_EQUAL, /* Egalité '==' */ + CCT_DIFF /* Différence '!=' */ + +} CondCompType; + +/* Types de combinaison d'expressions */ +typedef enum _CondOpType +{ + COT_AND, /* Combinaison ET ('&&') */ + COT_OR /* Combinaison OU ('||') */ + +} CondOpType; + +/* Conséquence en cas de condition remplie */ +typedef enum _CondActionType +{ + CAT_SEE /* Renvoi vers une instruction */ + +} CondActionType; + + +/* Expression d'une condition */ +typedef struct _cond_expr cond_expr; + + +/* Crée une expression conditionnelle simple. */ +cond_expr *build_simple_cond_expression(char *, CondCompType, char *); + +/* Crée une expression conditionnelle composée. */ +cond_expr *build_composed_cond_expression(cond_expr *, CondOpType, cond_expr *); + +/* Ajoute une règle complète à la définition d'un codage. */ +void add_conditional_rule_to_coder(rented_coder *, cond_expr *, CondActionType, const char *); + + + +/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ + + +/* Débute la définition des fonctions issues des spécifications. */ +bool dump_all_routines_using_coder(const rented_coder *); + + + +#endif /* _ARCH_ARM_V7_OPDEFS_CODER_H */ diff --git a/tools/d2c.mk b/tools/d2c.mk new file mode 100644 index 0000000..78cc374 --- /dev/null +++ b/tools/d2c.mk @@ -0,0 +1,22 @@ + +.NOTPARALLEL: + +d2c_verbose = $(d2c_verbose_@AM_V@) +d2c_verbose_ = $(d2c_verbose_@AM_DEFAULT_V@) +d2c_verbose_0 = @echo " D2C " $<; + +# D2C_BIN = +# D2C_OUTDIR = +# D2C_ARCH = +# D2C_HEADER = +# D2C_ENCODINGS = +# D2C_MACROS = + +SUFFIXES = .g + +.d.g: + $(d2c_verbose)$(D2C_BIN) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $< + @touch $@ + +untabify_disass: + find $(D2C_OUTDIR)/opcodes -name '*c' -exec sed -i 's/\t/ /g' {} \; diff --git a/tools/d2c_gram.y b/tools/d2c_gram.y new file mode 100644 index 0000000..6fc8fb7 --- /dev/null +++ b/tools/d2c_gram.y @@ -0,0 +1,329 @@ + +%{ + +#include <getopt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "coder.h" + + +extern int yylex(); + +extern void free_flex_memory(void); + + +/* Affiche un message d'erreur suite à l'analyse en échec. */ +static int d2c_error(rented_coder *coder, char *s); + +/* Affiche des indications sur l'utilisation du programme. */ +static void show_usage(const char *argv0); + + +%} + + +%code requires { + +/* Pour la définition des expressions conditionnelles... */ +#include "coder.h" + +struct action_tmp +{ + CondActionType action; + const char *details; +}; + +} + +%union { + + char *string; /* Chaîne de caractères #1 */ + const char *cstring; /* Chaîne de caractères #2 */ + + + int integer; + + + cond_expr *expr; /* Expression de déclenchement */ + struct action_tmp tmpa; /* Transfert temporaire */ + +} + +%parse-param { rented_coder *coder } + + +%token COPYRIGHT +%token TITLE +%token INS_NAME INS_DETAILS + +%token ENCODING +%token THUMB ARCH NUMBER +%token ENC_START ENC_END + +%token WORD HALF NAME SIZE BIT + +%token SYNTAX OPERAND_INTERNAL OPERAND_VISIBLE + +%token CONV EQ ARG + +%token RULES IF EXPR_START EQUAL BINVAL EXPR_END AND THEN SEE + + +%type <string> COPYRIGHT INS_NAME +%type <cstring> INS_DETAILS + +%type <integer> NUMBER + +%type <string> NAME +%type <integer> SIZE BIT + +%type <string> OPERAND_INTERNAL OPERAND_VISIBLE + +%type <string> ARG + +%type <expr> rule_cond +%type <string> BINVAL +%type <tmpa> action + + +%% + + +input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } + +name : COPYRIGHT TITLE INS_NAME { save_notes_for_coder(coder, $1, $3, NULL); } + | COPYRIGHT TITLE INS_NAME INS_DETAILS { save_notes_for_coder(coder, $1, $3, $4); } + + + + +encodings : /* empty */ + | encoding encodings + +encoding : ENCODING THUMB NUMBER content { push_encoding_spec(coder, strdup("t"), $3); } + | ENCODING ARCH NUMBER content { push_encoding_spec(coder, strdup("a"), $3); } + + +content : /* empty */ + | bitfield content + | syntax content + | conversions content + | rules content + + +bitfield : HALF bits { if (count_coder_bits(coder) != 16) YYABORT; } + | WORD bits { if (count_coder_bits(coder) != 32) YYABORT; } + +bits : /* empty */ + | NAME SIZE bits { register_named_field_in_coder(coder, $1, $2); } + | BIT bits { register_bit_in_coder(coder, $1); } + + +syntax : SYNTAX operands + +operands : /* empty */ + | operands OPERAND_INTERNAL { register_syntax_item_in_coder(coder, $2, true); } + | operands OPERAND_VISIBLE { register_syntax_item_in_coder(coder, $2, false); } + + +conversions : CONV substitutions + +substitutions : /* empty */ + | substitutions NAME EQ NAME ARG { register_conversion_in_coder(coder, $2, $4, $5); } + + +rules : RULES rules_list + +rules_list : /* empty */ + | rules_list rule + +rule : IF EXPR_START rule_cond EXPR_END THEN action + { add_conditional_rule_to_coder(coder, $3, $6.action, $6.details); } + +rule_cond : NAME EQUAL BINVAL { $$ = build_simple_cond_expression($1, CCT_EQUAL, $3); } + | EXPR_START rule_cond EXPR_END AND EXPR_START rule_cond EXPR_END + { $$ = build_composed_cond_expression($2, COT_AND, $6); } + +action : SEE INS_DETAILS { $$.action = CAT_SEE; $$.details = $2; } + + +%% + + +/****************************************************************************** +* * +* Paramètres : coder = codeur impliqué dans le processus. * +* msg = message d'erreur. * +* * +* Description : Affiche un message d'erreur suite à l'analyse en échec. * +* * +* Retour : 0 * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int d2c_error(rented_coder *coder, char *msg) +{ + printf("yyerror : %s\n", msg); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : argv0 = nombre du programme exécuté. * +* * +* Description : Affiche des indications sur l'utilisation du programme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_usage(const char *argv0) +{ + printf("\n"); + + printf("Usage: %s [options] < file\n", argv0); + + printf("\n"); + + printf("Options:\n"); + + printf("\n"); + + printf("\t-h | --help\t\t\tDisplay this messsage.\n"); + printf("\t-d | --dir <string>\t\tSpecify the main output directory.\n"); + printf("\t-a | --arch <string>\t\tDefine the archicture to handle.\n"); + printf("\t-H | --header <string>\t\tSet the base of the #ifndef / #define game.\n"); + printf("\t-e | --encoding <string>\tDefine encoding prefixes for files.\n"); + printf("\t-m | --macro <string>\t\tRegister some conversion functions.\n"); + + printf("\n"); + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Point d'entrée du programme. * +* * +* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int main(int argc, char **argv) +{ + int result; /* Bilan à retourner */ + rented_coder *coder; /* Codeur à briffer & employer */ + int index; /* Indice de fichier à traiter */ + bool need_help; /* Affichage de l'aide ? */ + bool has_error; /* Erreur dans la ligne de cmd.*/ + int ret; /* Bilan d'une lecture d'arg. */ + char *sep; /* Caratère '=' en coupure */ + + static struct option long_options[] = { + + { "help", no_argument, NULL, 'h' }, + { "dir", required_argument, NULL, 'd' }, + { "arch", required_argument, NULL, 'a' }, + { "header", required_argument, NULL, 'H' }, + { "encoding", required_argument, NULL, 'e' }, + { "macro", required_argument, NULL, 'M' }, + { NULL, 0, NULL, 0 } + + }; + + result = EXIT_SUCCESS; + + coder = create_coder(); + + index = 0; + + need_help = false; + has_error = false; + + while (!has_error) + { + ret = getopt_long(argc, argv, "hd:a:H:e:M:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + need_help = true; + break; + + case 'd': + set_coder_output_directory(coder, optarg); + break; + + case 'a': + set_coder_arch(coder, optarg); + break; + + case 'H': + set_coder_header_base(coder, optarg); + break; + + case 'e': + + sep = strchr(optarg, '='); + has_error = (sep == NULL); + + if (!has_error) + { + *sep = '\0'; + register_encoding_in_coder(coder, optarg, sep + 1); + } + + break; + + case 'M': + + sep = strchr(optarg, '='); + has_error = (sep == NULL); + + if (!has_error) + { + *sep = '\0'; + define_macro_for_coder(coder, optarg, sep + 1); + } + + break; + + } + + } + + if (need_help || has_error || !do_basic_checks_with_coder(coder) || optind != argc) + { + show_usage(argv[0]); + result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE); + goto exit; + } + + result = yyparse(coder); + + exit: + + free_flex_memory(); + + delete_coder(coder); + + return result; + +} diff --git a/tools/d2c_tok.l b/tools/d2c_tok.l new file mode 100644 index 0000000..ae4faa3 --- /dev/null +++ b/tools/d2c_tok.l @@ -0,0 +1,165 @@ + +%{ + +typedef struct _rented_coder rented_coder; + + +#include "d2c-d2c_gram.h" + +#include <ctype.h> +#include <string.h> + + +/* Tente de libérer autant de mémoire que possible... */ +void free_flex_memory(void) ; + + +%} + +%option noyywrap +%option nounput +%option noinput + + +%x comments + +%x ins_name try_details ins_details +%x encoding encoding_type encoding_content + +%x encoding_bits encoding_bits_size + +%x syntax syntax_int syntax_ext + +%x conv_begin conv_content conv_arg + +%x rules_begin rules_content rules_cond rules_cond_binval rules_action rules_actin_see + + +%% + + +[ \t\n]+ { } + +"/*" { BEGIN(comments); } +<comments>"*/" { BEGIN(INITIAL); } +<comments>[^*\n] { } +<comments>"Copyright"[^\n]* { d2c_lval.string = strdup(yytext); return COPYRIGHT; } +<comments>"*" { } +<comments>"\n" { } + + +"@title" { BEGIN(ins_name); return TITLE; } + +<ins_name>[ ][A-Za-z-]+ { d2c_lval.string = strdup(yytext + 1); BEGIN(try_details); return INS_NAME; } +<try_details>[ ] { BEGIN(ins_details); } +<try_details>[\n] { BEGIN(INITIAL); } + +<ins_details>[^\n]* { d2c_lval.cstring = yytext; return INS_DETAILS; } +<ins_details>[\n] { BEGIN(INITIAL); } + + + +"@encoding" { BEGIN(encoding); return ENCODING; } + +<encoding>[ ] { } +<encoding>"(" { BEGIN(encoding_type); } + +<encoding_type>"T" { return THUMB; } +<encoding_type>"A" { return ARCH; } +<encoding_type>[0-9] { d2c_lval.integer = atoi(yytext); return NUMBER; } +<encoding_type>")" { BEGIN(encoding); } + +<encoding>"{" { BEGIN(encoding_content); } +<encoding_content>[ \t\n]+ { } +<encoding_content>"}" { BEGIN(INITIAL); } + + + +<encoding_content>"@half" { BEGIN(encoding_bits); return HALF; } +<encoding_content>"@word" { BEGIN(encoding_bits); return WORD; } + +<encoding_bits>" " { } +<encoding_bits>"\n" { BEGIN(encoding_content); } +<encoding_bits>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } + +<encoding_bits>"(" { BEGIN(encoding_bits_size); } +<encoding_bits_size>[0-9]+ { d2c_lval.integer = atoi(yytext); return SIZE; } +<encoding_bits_size>")" { BEGIN(encoding_bits); } + +<encoding_bits>[01] { d2c_lval.integer = atoi(yytext); return BIT; } + + + +<encoding_content>"@syntax" { BEGIN(syntax); return SYNTAX; } + +<syntax>[ ]+ { } +<syntax>"\n" { BEGIN(encoding_content); } + +<syntax>"{" { BEGIN(syntax_int); } +<syntax_int>[^ \n}]+ { d2c_lval.string = strdup(yytext); return OPERAND_INTERNAL; } +<syntax_int>"}" { BEGIN(syntax); } + +<syntax>"<" { BEGIN(syntax_ext); } +<syntax_ext>[^ \n>]+ { d2c_lval.string = strdup(yytext); return OPERAND_VISIBLE; } +<syntax_ext>">" { BEGIN(syntax); } + + + +<encoding_content>"@conv" { BEGIN(conv_begin); return CONV; } +<conv_begin>[ ]+ { } +<conv_begin>"{" { BEGIN(conv_content); } +<conv_content>"}" { BEGIN(encoding_content); } + +<conv_content>[ \t\n]+ { } +<conv_content>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } +<conv_content>"=" { return EQ; } + +<conv_content>"(" { BEGIN(conv_arg); } +<conv_arg>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return ARG; } +<conv_arg>")" { BEGIN(conv_content); } + + + +<encoding_content>"@rules" { BEGIN(rules_begin); return RULES; } +<rules_begin>[ ]+ { } +<rules_begin>"{" { BEGIN(rules_content); } +<rules_content>[ \t\n]+ { } +<rules_content>"}" { BEGIN(encoding_content); } + +<rules_content>"if" { BEGIN(rules_cond); return IF; } +<rules_cond>[ ]+ { } +<rules_cond>"(" { return EXPR_START; } +<rules_cond>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } +<rules_cond>"==" { return EQUAL; } +<rules_cond>"'" { BEGIN(rules_cond_binval); } +<rules_cond_binval>[01][01]* { d2c_lval.string = strdup(yytext); return BINVAL; } +<rules_cond_binval>"'" { BEGIN(rules_cond); } +<rules_cond>")" { return EXPR_END; } +<rules_cond>"&&" { return AND; } + +<rules_cond>";" { BEGIN(rules_action); return THEN; } +<rules_action>[ ]+ { } +<rules_action>"see " { BEGIN(rules_actin_see); return SEE; } +<rules_actin_see>[^\n]* { d2c_lval.cstring = yytext; BEGIN(rules_content); return INS_DETAILS; } + + +%% + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Tente de libérer autant de mémoire que possible... * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void free_flex_memory(void) +{ + yy_delete_buffer(YY_CURRENT_BUFFER); + +} |