From 9cab778bfaaca2589a383445e8569d99d73374d5 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 24 Dec 2014 00:20:48 +0000 Subject: Improved the generation of source code: there are now templates and one file per instruction. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@443 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 28 ++ src/arch/arm/v7/opcodes/Makefile.am | 119 +-------- src/arch/arm/v7/opdefs/Makefile.am | 43 +-- tools/d2c/coder.c | 519 +++++++++++++++++++++++++++--------- tools/d2c/coder.h | 3 + tools/d2c/d2c.mk | 8 +- tools/d2c/d2c_genmakefile.sh | 187 +++++++++++++ tools/d2c/d2c_gram.y | 7 +- tools/d2c/globalgen.mk | 12 + 9 files changed, 648 insertions(+), 278 deletions(-) create mode 100644 tools/d2c/d2c_genmakefile.sh create mode 100644 tools/d2c/globalgen.mk diff --git a/ChangeLog b/ChangeLog index 58f7624..a75ae31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +14-12-24 Cyrille Bagard + + * src/arch/arm/v7/opcodes/Makefile.am: + Fix libarcharmv7opcodes_la_SOURCES by relying on a generated sources list + and an external generated included Makefile. + + * src/arch/arm/v7/opdefs/Makefile.am: + Clean/simplify the Makefile by using the new 'd2c_genmakefile.sh' script. + + * tools/d2c/coder.c: + * tools/d2c/coder.h: + Improve the generation of source code: there are now templates and one + file per instruction. It is up to an external tool (here the script + called 'd2c_genmakefile.sh') to produce a Makefile providing a way to + reassemble contents. Depedencies are thus better handled. + + * tools/d2c/d2c_genmakefile.sh: + New entry: generate a Makefile extension for dealing with code parts. + + * tools/d2c/d2c_gram.y: + Update arguments for the compiler. + + * tools/d2c/d2c.mk: + Update code. + + * tools/d2c/globalgen.mk: + New entry: provide silent rules for an external Makefile. + 14-12-16 Cyrille Bagard * src/analysis/disass/fetch.c: diff --git a/src/arch/arm/v7/opcodes/Makefile.am b/src/arch/arm/v7/opcodes/Makefile.am index 0bff196..fd67ff3 100644 --- a/src/arch/arm/v7/opcodes/Makefile.am +++ b/src/arch/arm/v7/opcodes/Makefile.am @@ -1,122 +1,9 @@ +include gencode.mk + noinst_LTLIBRARIES = libarcharmv7opcodes.la -# ls *c | grep -v thumb | sort | sed 's/^/\t/' | sed 's/$/\t\t\\/' -libarcharmv7opcodes_la_SOURCES = \ - arm_adc.c \ - arm_add.c \ - arm_and.c \ - arm_b.c \ - arm_bic.c \ - arm_bl.c \ - arm_bx.c \ - arm_cbnz.c \ - arm_cmn.c \ - arm_cmp.c \ - arm_eor.c \ - arm_ldr.c \ - arm_ldrb.c \ - arm_lsl.c \ - arm_mla.c \ - arm_mls.c \ - arm_mov.c \ - arm_mul.c \ - arm_mvn.c \ - arm_nop.c \ - arm_orr.c \ - arm_pop.c \ - arm_push.c \ - arm_rsb.c \ - arm_rsc.c \ - arm_sbc.c \ - arm_smlal.c \ - arm_smull.c \ - arm_str.c \ - arm_strb.c \ - arm_sub.c \ - arm_subs.c \ - arm_teq.c \ - arm_tst.c \ - arm_umaal.c \ - arm_umlal.c \ - arm_umull.c \ - arm_yield.c \ - thumb_16_adc.c \ - thumb_16_add.c \ - thumb_16_and.c \ - thumb_16_b.c \ - thumb_16_bic.c \ - thumb_16_bl.c \ - thumb_16_bx.c \ - thumb_16_cbnz.c \ - thumb_16_cmn.c \ - thumb_16_cmp.c \ - thumb_16_eor.c \ - thumb_16_ldr.c \ - thumb_16_ldrb.c \ - thumb_16_lsl.c \ - thumb_16_mla.c \ - thumb_16_mls.c \ - thumb_16_mov.c \ - thumb_16_mul.c \ - thumb_16_mvn.c \ - thumb_16_nop.c \ - thumb_16_orr.c \ - thumb_16_pop.c \ - thumb_16_push.c \ - thumb_16_rsb.c \ - thumb_16_rsc.c \ - thumb_16_sbc.c \ - thumb_16_smlal.c \ - thumb_16_smull.c \ - thumb_16_str.c \ - thumb_16_strb.c \ - thumb_16_sub.c \ - thumb_16_subs.c \ - thumb_16_teq.c \ - thumb_16_tst.c \ - thumb_16_umaal.c \ - thumb_16_umlal.c \ - thumb_16_umull.c \ - thumb_16_yield.c \ - thumb_32_adc.c \ - thumb_32_add.c \ - thumb_32_and.c \ - thumb_32_b.c \ - thumb_32_bic.c \ - thumb_32_bl.c \ - thumb_32_bx.c \ - thumb_32_cbnz.c \ - thumb_32_cmn.c \ - thumb_32_cmp.c \ - thumb_32_eor.c \ - thumb_32_ldr.c \ - thumb_32_ldrb.c \ - thumb_32_lsl.c \ - thumb_32_mla.c \ - thumb_32_mls.c \ - thumb_32_mov.c \ - thumb_32_mul.c \ - thumb_32_mvn.c \ - thumb_32_nop.c \ - thumb_32_orr.c \ - thumb_32_pop.c \ - thumb_32_push.c \ - thumb_32_rsb.c \ - thumb_32_rsc.c \ - thumb_32_sbc.c \ - thumb_32_smlal.c \ - thumb_32_smull.c \ - thumb_32_str.c \ - thumb_32_strb.c \ - thumb_32_sub.c \ - thumb_32_subs.c \ - thumb_32_teq.c \ - thumb_32_tst.c \ - thumb_32_umaal.c \ - thumb_32_umlal.c \ - thumb_32_umull.c \ - thumb_32_yield.c +libarcharmv7opcodes_la_SOURCES = $(GENERATED_FILES) libarcharmv7opcodes_la_LIBADD = diff --git a/src/arch/arm/v7/opdefs/Makefile.am b/src/arch/arm/v7/opdefs/Makefile.am index 4330d36..2687a92 100644 --- a/src/arch/arm/v7/opdefs/Makefile.am +++ b/src/arch/arm/v7/opdefs/Makefile.am @@ -3,6 +3,7 @@ include ../../../../../tools/d2c/d2c.mk D2C_BIN = ../../../../../tools/d2c/d2c +GEN_BIN = ../../../../../tools/d2c/d2c_genmakefile.sh D2C_OUTDIR = $(PWD)/.. @@ -83,40 +84,24 @@ ARMV7_DEFS = \ subs_B9320.d -all: $(ARMV7_DEFS:.d=.g) untabify_disass fix_includes_in_c finish_disass +all: $(ARMV7_DEFS:.d=.g) generate_final_makefile fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass -fix_includes_in_c: - @for f in `find ../opcodes -name '*c'`; do \ +generate_final_makefile: + $(GEN_BIN) ../opcodes/ ../opdefs/.gen ../../../../../tools/d2c/globalgen.mk arm thumb_32 thumb_16 + +fix_includes_in_c_templates: + @for f in `find .gen/ -name '*tmpl.c'`; do \ if grep -q '##INCLUDES##' $$f; then \ $(fix_verbose)sed -i 's/##INCLUDES##/\n#include "..\/instruction.h"\n#include "..\/..\/instruction.h"\n#include "..\/helpers.h"\n#include "..\/..\/..\/..\/common\/bconst.h"\n\n/' $$f; \ fi; \ done -finish_disass: finish_disass_t16 finish_disass_t32 finish_disass_arm - -finish_disass_t16: $(D2C_OUTDIR)/opcodes/thumb_16_opcodes.h - @if grep -q '##INCLUDES##' $<; then \ - $(fix2_verbose)sed -i 's/##INCLUDES##/#include\ \n\n#include "..\/..\/..\/instruction.h"/' $< ; \ - fi - @if ! grep -q 'endif' $<; then \ - $(fix2_verbose)echo -en "\n\n#endif /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ; \ - fi - -finish_disass_t32: $(D2C_OUTDIR)/opcodes/thumb_32_opcodes.h - @if grep -q '##INCLUDES##' $<; then \ - $(fix2_verbose)sed -i 's/##INCLUDES##/#include\ \n\n#include "..\/..\/..\/instruction.h"/' $< ; \ - fi - @if ! grep -q 'endif' $<; then \ - $(fix2_verbose)echo -en "\n\n#endif /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ; \ - fi - -finish_disass_arm: $(D2C_OUTDIR)/opcodes/arm_opcodes.h - @if grep -q '##INCLUDES##' $<; then \ - $(fix2_verbose)sed -i 's/##INCLUDES##/#include\ \n\n#include "..\/..\/..\/instruction.h"/' $< ; \ - fi - @if ! grep -q 'endif' $<; then \ - $(fix2_verbose)echo -en "\n\n#endif /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ; \ - fi +fix_includes_in_h_templates: + @for f in `find .gen/ -name '*tmpl.h'`; do \ + if grep -q '##INCLUDES##' $$f; then \ + $(fix_verbose)sed -i 's/##INCLUDES##/#include\ \n\n#include "..\/..\/..\/instruction.h"/' $$f ; \ + fi; \ + done clean: - rm -f $(ARMV7_DEFS:.d=.g) $(D2C_OUTDIR)/opcodes/*c $(D2C_OUTDIR)/opcodes/{thumb_16_,thumb_32_,}opcodes.h + rm -rf $(ARMV7_DEFS:.d=.g) .gen diff --git a/tools/d2c/coder.c b/tools/d2c/coder.c index b4bf21f..c709bcf 100644 --- a/tools/d2c/coder.c +++ b/tools/d2c/coder.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "helpers.h" @@ -41,12 +43,10 @@ /* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ - - - /* Suivi des constructions */ struct _rented_coder { + const char *input; /* Fichier de définitions */ const char *outdir; /* Lieu d'enregistrement */ const char *arch; /* Architecture à traiter */ const char *header; /* En-tête pour les en-têtes */ @@ -65,50 +65,26 @@ struct _rented_coder +/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ -/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ - - - - - -/* --------------------------- 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; - - - - - - - -/* ---------------------------- 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; +/* S'assure de la présence du répertoire de sortie du code. */ +static bool check_gen_dir(const rented_coder *); +/* Imprime dans un flux donné un commentaire de propriété. */ +static void write_owner_comments(const rented_coder *, int, const char *, const char *, char); +/* Construit un chemin d'accès à un modèle de fichier de code. */ +static char *build_template_filename(const rented_coder *, const char *, const char *, char); -/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ +/* Définit un modèle d'en-tête de définitions. */ +static bool create_template_file(const rented_coder *, const char *, const char *, char); +/* Construit un chemin d'accès à un fichier de code source. */ +static char *build_code_filename(const rented_coder *, const char *, const char *, const char *, char); /* 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 *); +static int create_code_file(const rented_coder *, const char *, const char *, const char *, char); /* 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); @@ -206,6 +182,26 @@ bool do_basic_checks_with_coder(const rented_coder *coder) /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* outdir = fichier de définitions à venir lire. * +* * +* Description : Spécifie le fichier de définition à prendre en entrée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_coder_input_file(rented_coder *coder, const char *input) +{ + coder->input = input; + +} + + +/****************************************************************************** +* * +* 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. * @@ -370,67 +366,273 @@ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* dir = répertoire final de destination. * +* * +* Description : S'assure de la présence du répertoire de sortie du code. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool check_gen_dir(const rented_coder *coder) +{ + bool has_gen; /* Répertoire de sortie présent*/ + int ret; /* Bilan d'un appel externe */ + + has_gen = (access(".gen", F_OK) == 0); + + if (has_gen) + { + ret = access(".gen", W_OK | X_OK); + if (ret == -1) + { + perror("access()"); + return false; + } + + } + else + { + ret = mkdir(".gen", 0777); + if (ret != 0) + { + perror("mkdir()"); + return false; + } + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* fd = descripteur de flux ouvert en écriture. * * 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. * +* Description : Imprime dans un flux donné un commentaire de propriété. * * * -* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static int create_code_file(const rented_coder *coder, const char *dir, const char *prefix, const char *name, char ext, bool *exist) +static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext) { - int result; /* Descripteur à retourner */ - size_t length; /* Taille du nom de fichier */ - char *pathname; /* Chemin d'accès à constituer */ + dprintf(fd, "\n"); + + dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); + dprintf(fd, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext); + dprintf(fd, " *\n"); + dprintf(fd, " * %s\n", coder->copyright); + dprintf(fd, " *\n"); + dprintf(fd, " * This file is part of Chrysalide.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n"); + dprintf(fd, " * it under the terms of the GNU General Public License as published by\n"); + dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n"); + dprintf(fd, " * (at your option) any later version.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n"); + dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + dprintf(fd, " * GNU General Public License for more details.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * You should have received a copy of the GNU General Public License\n"); + dprintf(fd, " * along with Foobar. If not, see .\n"); + dprintf(fd, " */\n"); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); - 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()"); +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* prefix = type d'encodage à répercuter sur le nom de fichier. * +* name = nom brut du fichier à ouvrir. * +* ext = extension à donner au fichier à ouvrir. * +* * +* Description : Construit un chemin d'accès à un modèle de fichier de code. * +* * +* Retour : Chaîne de caractères à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext) +{ + char *result; /* Chaîne construite à renvoyer*/ + size_t length; /* Taille du nom de fichier */ + + length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(prefix) + 1 + strlen(name) + 3; + result = (char *)calloc(length, sizeof(char)); + snprintf(result, length, ".gen/%s.%s.tmpl.%c", prefix, name, ext); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* prefix = type d'encodage à répercuter sur le nom de fichier. * +* name = nom brut du fichier à ouvrir. * +* ext = extension à donner au fichier à ouvrir. * +* * +* Description : Définit un modèle d'en-tête de définitions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext) +{ + char *pathname; /* Chemin d'accès à constituer */ + bool exist; /* Note une présence établie */ + int fd; /* Flux ouvert pour création */ + char *uprefix; /* Préfixe en majuscule */ + char *uname; /* Nom en majuscule */ + + if (!check_gen_dir(coder)) + return false; + + pathname = build_template_filename(coder, prefix, name, ext); + + exist = (access(pathname, W_OK) == 0); + if (exist) + { + free(pathname); + return true; + } + + fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644); + if (fd == -1) perror("open()"); free(pathname); - if (!*exist && result != -1) + if (fd != -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 .\n"); - dprintf(result, " */\n"); - - dprintf(result, "\n"); - dprintf(result, "\n"); + write_owner_comments(coder, fd, prefix, name, ext); + + if (ext == 'h') + { + uprefix = make_string_upper(strdup(prefix)); + uname = make_string_upper(strdup(name)); + + dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname); + dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname); + + free(uprefix); + free(uname); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "##INCLUDES##\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + } + else + { + dprintf(fd, "#include \"%sopcodes.h\"\n", prefix); + dprintf(fd, "\n"); + dprintf(fd, "##INCLUDES##\n"); + + } + + close(fd); } + return (fd != -1); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* intput = fichier d'entrée initial à référencer. * +* prefix = type d'encodage à répercuter sur le nom de fichier. * +* name = nom brut du fichier à ouvrir. * +* ext = extension à donner au fichier à ouvrir. * +* * +* Description : Construit un chemin d'accès à un fichier de code source. * +* * +* Retour : Chaîne de caractères à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext) +{ + char *result; /* Chaîne construite à renvoyer*/ + char *orig; /* Fichier d'origine tronqué */ + char *point; /* Position d'un point */ + size_t length; /* Taille du nom de fichier */ + + orig = strdup(input); + + point = strstr(orig, "."); + if (point != NULL) *point = '\0'; + + length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(prefix) + 1 + strlen(name) + 3; + result = (char *)calloc(length, sizeof(char)); + snprintf(result, length, ".gen/%s.%s.%s.%c", orig, prefix, name, ext); + + free(orig); + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* intput = fichier d'entrée initial à référencer. * +* prefix = type d'encodage à répercuter sur le nom de fichier. * +* name = nom brut du fichier à ouvrir. * +* ext = extension à donner au fichier à ouvrir. * +* * +* 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 *input, const char *prefix, const char *name, char ext) +{ + int result; /* Descripteur à retourner */ + char *pathname; /* Chemin d'accès à constituer */ + + if (!check_gen_dir(coder)) + return -1; + + pathname = build_code_filename(coder, input, prefix, name, ext); + + result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (result == -1) perror("open()"); + + free(pathname); + return result; } @@ -451,11 +653,11 @@ static int create_code_file(const rented_coder *coder, const char *dir, const ch bool dump_all_routines_using_coder(const rented_coder *coder) { bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ + size_t i; /* Boucle de parcours #1 */ const string_exch *encoding; /* Type d'encodage visé */ - bool exist; /* Présence du fichier visé ? */ + size_t j; /* Boucle de parcours #2 */ + char *remove; /* Chemin de suppression */ int header_fd; /* Fichier de déclarations */ - char *uname; /* Nom en majuscule */ char *dash; /* Présence d'un tiret ? */ char *filename; /* Nom de fichier commun */ int code_fd; /* Fichier de définitions */ @@ -466,69 +668,132 @@ bool dump_all_routines_using_coder(const rented_coder *coder) { encoding = find_encoding(coder->pp, i); - /* Fichier de déclarations */ + /* On s'assure qu'il existe bien une version pour l'encodage visé... */ - header_fd = create_code_file(coder, "opcodes", encoding->dest, "opcodes", 'h', &exist); - if (header_fd == -1) return false; + for (j = 0; j < coder->specs_count; j++) + if (has_encoding_spec_prefix(coder->specs[j], encoding->src)) + break; - if (!exist) + /* Suppressions ? */ + if (j == coder->specs_count) { - uname = make_string_upper(strdup(encoding->dest)); + /* Fichier de déclarations */ - dprintf(header_fd, "#ifndef %s_%sOPCODES_OPCODES_H\n", coder->header, uname); - dprintf(header_fd, "#define %s_%sOPCODES_OPCODES_H\n", coder->header, uname); + /* + remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); + unlink(remove); + free(remove); + */ - free(uname); + remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); + unlink(remove); + free(remove); - 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, '-'); - /* Fichier de définitions */ + if (dash == NULL) + { + /* + remove = build_template_filename(coder, encoding->dest, coder->ins, 'c'); + unlink(remove); + free(remove); + */ - dash = strchr(coder->ins, '-'); + remove = build_code_filename(coder, coder->input, encoding->dest, coder->ins, 'c'); + unlink(remove); + free(remove); - if (dash == NULL) - code_fd = create_code_file(coder, "opcodes", encoding->dest, coder->ins, 'c', &exist); + } - else - { - filename = strdup(coder->ins); + else + { + filename = strdup(coder->ins); - dash = strchr(filename, '-'); - *dash = '\0'; + dash = strchr(filename, '-'); + *dash = '\0'; - code_fd = create_code_file(coder, "opcodes", encoding->dest, filename, 'c', &exist); + /* + remove = build_template_filename(coder, encoding->dest, filename, 'c'); + unlink(remove); + free(remove); + */ - free(filename); + remove = build_code_filename(coder, coder->input, encoding->dest, filename, 'c'); + unlink(remove); + free(remove); + + } } - if (!exist) + /* Créations ? */ + else { - dprintf(code_fd, "#include \"%sopcodes.h\"\n", encoding->dest); - dprintf(code_fd, "\n"); - dprintf(code_fd, "##INCLUDES##\n"); + /* Fichier de déclarations */ - } + if (!create_template_file(coder, encoding->dest, "opcodes", 'h')) + return false; - if (code_fd == -1) - { - close(header_fd); - return false; - } + header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h'); + if (header_fd == -1) return false; + + /* Fichier de définitions */ + + dash = strchr(coder->ins, '-'); + + if (dash == NULL) + { + if (!create_template_file(coder, encoding->dest, coder->ins, 'c')) + return false; + + code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c'); + + } + + else + { + filename = strdup(coder->ins); + + dash = strchr(filename, '-'); + *dash = '\0'; - /* Production de code... */ + if (!create_template_file(coder, encoding->dest, filename, 'c')) + return false; - result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); + code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c'); - close(header_fd); - close(code_fd); + free(filename); + + } + + if (code_fd == -1) + { + close(header_fd); + + /* + remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); + unlink(remove); + free(remove); + */ + + remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); + unlink(remove); + free(remove); + + return false; + + } + + /* Production de code... */ + + result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); + + close(header_fd); + close(code_fd); + + } } @@ -583,8 +848,12 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st } - /* Rien n'a été trouvé à faire... */ - if (wide == -1) goto damsic_exit; + /** + * Rien n'a été trouvé à faire... + * Cette situation doit normalement être écartée par l'appelant, + * afin d'éviter de constituer des fichiers vides. + */ + assert(wide != -1); /* Désassemblage : déclaration */ @@ -649,8 +918,6 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st dprintf(cfd, "}\n"); dprintf(cfd, "\n"); - damsic_exit: - free(keyword); return result; diff --git a/tools/d2c/coder.h b/tools/d2c/coder.h index e72764c..aadb2d4 100644 --- a/tools/d2c/coder.h +++ b/tools/d2c/coder.h @@ -50,6 +50,9 @@ 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 fichier de définition à prendre en entrée. */ +void set_coder_input_file(rented_coder *, const char *); + /* Spécifie le répertoire de base pour les sorties de code. */ void set_coder_output_directory(rented_coder *, const char *); diff --git a/tools/d2c/d2c.mk b/tools/d2c/d2c.mk index 25596cf..36bb38e 100644 --- a/tools/d2c/d2c.mk +++ b/tools/d2c/d2c.mk @@ -9,10 +9,6 @@ fix_verbose = $(fix_verbose_@AM_V@) fix_verbose_ = $(fix_verbose_@AM_DEFAULT_V@) fix_verbose_0 = echo " FIX " `basename $$f`; -fix2_verbose = $(fix2_verbose_@AM_V@) -fix2_verbose_ = $(fix2_verbose_@AM_DEFAULT_V@) -fix2_verbose_0 = echo " FIX " `basename $<`; - # D2C_BIN = # D2C_OUTDIR = # D2C_ARCH = @@ -23,9 +19,9 @@ fix2_verbose_0 = echo " FIX " `basename $<`; SUFFIXES = .g .d.g: - $(d2c_verbose)$(D2C_BIN) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $< + $(d2c_verbose)$(D2C_BIN) -i $< -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $< @touch $@ # Merci http://www.commandlinefu.com/commands/view/10276/grep-tab-t untabify_disass: - find $(D2C_OUTDIR)/opcodes -name '*c' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \; + @find .gen/ -name '*[ch]' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \; diff --git a/tools/d2c/d2c_genmakefile.sh b/tools/d2c/d2c_genmakefile.sh new file mode 100644 index 0000000..bd5c379 --- /dev/null +++ b/tools/d2c/d2c_genmakefile.sh @@ -0,0 +1,187 @@ +#!/bin/sh + +if [ $# -lt 4 ]; then + + echo "Usage: $0 > ${MAKEFILE_TMP} + + +$echo "include ${globalmk}" >> ${MAKEFILE_TMP} +$echo >> ${MAKEFILE_TMP} + +OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d . -f 3 | sort | uniq` + +# Génération des en-têtes de décodage + +for arch in $*; +do + $echo -n "${arch}_HEADER_FILES =" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP} + + has_header="" + + for op in $OPCODES; + do + template="${input}/*${arch}_.${op}.c" + + sources=`ls $template 2> /dev/null` + + if [ -z "${sources}" ]; then + continue + fi + + for src in ${sources}; + do + has_header="yes" + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t" >> ${MAKEFILE_TMP} + $echo -n ${src} | sed "s/${op}.c$/opcodes.h/" >> ${MAKEFILE_TMP} + done + + done + + $echo >> ${MAKEFILE_TMP} + $echo >> ${MAKEFILE_TMP} + + $echo -n "${arch}_opcodes.h: " >> ${MAKEFILE_TMP} + $echo "\$(${arch}_HEADER_FILES)" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP} + + if [ -z "${has_header}" ]; then + + $echo -e "\techo > \$@" >> ${MAKEFILE_TMP} + + else + + $echo -e "\t\$(cini_verbose)cat ${input}/${arch}_.opcodes.tmpl.h > \$@" >> ${MAKEFILE_TMP} + $echo -e "\t\$(cgen_verbose)cat \$^ >> \$@" >> ${MAKEFILE_TMP} + $echo -e "\t\$(cfini_verbose)echo >> \$@" >> ${MAKEFILE_TMP} + $echo -en "\t\$(cfini_verbose)echo \"#endif\t /* " >> ${MAKEFILE_TMP} + $echo -en '`cat \$@ | grep "#define" | cut -d " " -f 2`' >> ${MAKEFILE_TMP} + $echo -e " */\" >> \$@" >> ${MAKEFILE_TMP} + + fi + + $echo >> ${MAKEFILE_TMP} + +done + +$echo >> ${MAKEFILE_TMP} + + +# Génération des codes d'instructions + +for op in $OPCODES; +do + for arch in $*; + do + template="${input}/*${arch}_.${op}.c" + + sources=`ls $template 2> /dev/null` + + if [ -z "${sources}" ]; then + continue + fi + + $echo -n "${op}_${arch}_FILES =" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP} + + for src in ${sources}; + do + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP} + done + + $echo >> ${MAKEFILE_TMP} + $echo >> ${MAKEFILE_TMP} + + $echo -n "${arch}_${op}.c: " >> ${MAKEFILE_TMP} + $echo "\$(${op}_${arch}_FILES)" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP} + + $echo -e "\t\$(cini_verbose)cat ${input}/${arch}_.${op}.tmpl.c > \$@" >> ${MAKEFILE_TMP} + $echo -e "\t\$(cgen_verbose)cat \$^ >> \$@" >> ${MAKEFILE_TMP} + + $echo >> ${MAKEFILE_TMP} + + done + +done + +$echo >> ${MAKEFILE_TMP} + +# Génération de la liste des sources + +$echo -n "GENERATED_FILES =" >> ${MAKEFILE_TMP} + +for arch in $*; +do + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t${arch}_opcodes.h" >> ${MAKEFILE_TMP} + + for op in $OPCODES; + do + template="${input}/*${arch}_.${op}.c" + + sources=`ls $template 2> /dev/null` + + if [ ! -z "${sources}" ]; then + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t${arch}_${op}.c" >> ${MAKEFILE_TMP} + continue + fi + + done + +done + +$echo >> ${MAKEFILE_TMP} + +$echo >> ${MAKEFILE_TMP} + +# Validation finale + +if [ ! -f ]; then + + rm -rf ${MAKEFILE_EXT} + mv ${MAKEFILE_TMP} ${MAKEFILE_EXT} + +else + + hash_tmp=`md5sum ${MAKEFILE_TMP} | cut -d ' ' -f 1` + hash_ext=`md5sum ${MAKEFILE_EXT} | cut -d ' ' -f 1` + + if [ "${hash_tmp}" = "${hash_ext}" ]; then + + rm -f ${MAKEFILE_TMP} + + echo "${MAKEFILE_EXT} is up to date." + + else + + rm -f ${MAKEFILE_EXT} + mv ${MAKEFILE_TMP} ${MAKEFILE_EXT} + + echo "${MAKEFILE_EXT} is updated." + + fi + +fi + +cd ${OLDPWD} diff --git a/tools/d2c/d2c_gram.y b/tools/d2c/d2c_gram.y index 5ae93c8..b1519a1 100644 --- a/tools/d2c/d2c_gram.y +++ b/tools/d2c/d2c_gram.y @@ -354,6 +354,7 @@ int main(int argc, char **argv) static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, + { "input", required_argument, NULL, 'i' }, { "dir", required_argument, NULL, 'd' }, { "arch", required_argument, NULL, 'a' }, { "header", required_argument, NULL, 'H' }, @@ -374,7 +375,7 @@ int main(int argc, char **argv) while (!has_error) { - ret = getopt_long(argc, argv, "hd:a:H:e:M:", long_options, &index); + ret = getopt_long(argc, argv, "hi:d:a:H:e:M:", long_options, &index); if (ret == -1) break; switch (ret) @@ -383,6 +384,10 @@ int main(int argc, char **argv) need_help = true; break; + case 'i': + set_coder_input_file(coder, optarg); + break; + case 'd': set_coder_output_directory(coder, optarg); break; diff --git a/tools/d2c/globalgen.mk b/tools/d2c/globalgen.mk new file mode 100644 index 0000000..ede457a --- /dev/null +++ b/tools/d2c/globalgen.mk @@ -0,0 +1,12 @@ + +cini_verbose = $(cini_verbose_@AM_V@) +cini_verbose_ = $(cini_verbose_@AM_DEFAULT_V@) +cini_verbose_0 = @echo " INIT " `basename $@`; + +cgen_verbose = $(cgen_verbose_@AM_V@) +cgen_verbose_ = $(cgen_verbose_@AM_DEFAULT_V@) +cgen_verbose_0 = @echo " GEN " `basename $@`; + +cfini_verbose = $(cfini_verbose_@AM_V@) +cfini_verbose_ = $(cfini_verbose_@AM_DEFAULT_V@) +cfini_verbose_0 = @echo " FINI " `basename $@`; -- cgit v0.11.2-87-g4458