summaryrefslogtreecommitdiff
path: root/tools/d2c/coder.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2014-12-24 00:20:48 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2014-12-24 00:20:48 (GMT)
commit9cab778bfaaca2589a383445e8569d99d73374d5 (patch)
tree29371502a4a816a2c0a42a55dfdcd8b7fde4ffa2 /tools/d2c/coder.c
parent04dfbc68e7cd5036017f097a67ba5f0288ddace0 (diff)
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
Diffstat (limited to 'tools/d2c/coder.c')
-rw-r--r--tools/d2c/coder.c519
1 files changed, 393 insertions, 126 deletions
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 <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#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 <http://www.gnu.org/licenses/>.\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 <http://www.gnu.org/licenses/>.\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;