summaryrefslogtreecommitdiff
path: root/tools/d2c/coder.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-04-02 11:58:42 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-04-02 12:39:30 (GMT)
commit1db4ef323b7a76093356ae76268132f3760e1631 (patch)
treefec36ee0ec1b6b2010b62ca4177edca0e31e2114 /tools/d2c/coder.c
parent1bc80837dde03a32b5ab185067f7bd4c499a9850 (diff)
Rewritten the whole instruction definition format.
Diffstat (limited to 'tools/d2c/coder.c')
-rw-r--r--tools/d2c/coder.c1656
1 files changed, 1238 insertions, 418 deletions
diff --git a/tools/d2c/coder.c b/tools/d2c/coder.c
index 65e9605..e286a1d 100644
--- a/tools/d2c/coder.c
+++ b/tools/d2c/coder.c
@@ -27,13 +27,10 @@
#include <assert.h>
#include <fcntl.h>
#include <malloc.h>
-#include <regex.h>
-#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "helpers.h"
@@ -47,8 +44,6 @@
struct _rented_coder
{
const char *input; /* Fichier de définitions */
- InputOutputType type; /* Type des définitions (E/S) */
- const char *outdir; /* Lieu d'enregistrement */
const char *arch; /* Architecture à traiter */
const char *header; /* En-tête pour les en-têtes */
const char *const_prefix; /* Préfixe pour les opérandes */
@@ -61,6 +56,11 @@ struct _rented_coder
char *raw_details; /* Eventuels compléments bruts */
char *details; /* Eventuels compléments */
+ instr_id *id; /* Gestionnaire d'identifiant */
+ instr_desc *desc; /* Gestionnaire de description */
+
+ bool useless; /* Instruction non utilisée */
+
encoding_spec **specs; /* Définitions déjà en place */
size_t specs_count; /* Nombre de ces définitions */
encoding_spec *cur_spec; /* Définition courante */
@@ -69,32 +69,58 @@ struct _rented_coder
+/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */
+
+
+/* Détermine le nombre de bits analysés lors d'un désassemblage. */
+static unsigned int get_bit_width_for_encoding_spec(const rented_coder *, const string_exch *);
+
+
+
/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
-/* S'assure de la présence du répertoire de sortie du code. */
-static bool check_gen_dir(const rented_coder *);
+/* Ouvre un fichier principal en écriture pour y placer du code. */
+static int open_instr_header_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Ouvre un fichier principal en écriture pour y placer du code. */
+static int open_instr_code_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Ouvre un fichier global en écriture pour y placer du code. */
+static int open_global_header_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Imprime dans un flux donné un commentaire de propriété. */
+static void write_header_file_license(int, const output_info *, const char *, const char *);
/* Imprime dans un flux donné un commentaire de propriété. */
-static void write_owner_comments(const rented_coder *, int, const char *, const char *, char);
+static void write_code_file_license(int, const output_info *, const char *, const char *);
+
+/* Initialise le contenu utile du fichier des instructions. */
+static void init_coder_opcodes_file(int, const output_info *, const char *);
+
+/* Initialise le contenu utile d'un fichier d'instructions. */
+static void init_coder_code_file(int, const char *);
+
+/* Centralise l'impression du nom de fonction de désassemblage. */
+static void write_read_function_name(int fd, const char *, const string_exch *, const 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);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_raw(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int);
-/* 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);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_main_raw(const rented_coder *, const output_info *, const string_exch *, int, int);
-/* 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);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_format(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int);
-/* 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);
+/* Initialise le contenu utile du fichier des identifiants. */
+static void init_coder_identifiers_file(int, const output_info *);
-/* 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);
+/* Initialise le contenu utile du fichier des mots clefs. */
+static void init_coder_keywords_file(int, const output_info *);
-/* Ecrit une partie des fonctions issues des spécifications. */
-static bool dump_all_matching_specs_from_format(const rented_coder *, const string_exch *, int, int);
+/* Initialise le contenu utile du fichier des descriptions. */
+static void init_coder_descriptions_file(int, const output_info *);
@@ -105,7 +131,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : pp = préprocesseur déjà chargé à intégrer. *
* *
* Description : Débute la définition d'une fonction de désassemblage. *
* *
@@ -115,16 +141,21 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri
* *
******************************************************************************/
-rented_coder *create_coder(void)
+rented_coder *create_coder(pre_processor *pp)
{
rented_coder *result; /* Structure à renvoyer */
result = (rented_coder *)calloc(1, sizeof(rented_coder));
- result->pp = create_pre_processor();
+ result->pp = pp;
+
+ result->id = create_instruction_id();
+ result->desc = create_instruction_description();
result->cur_spec = create_encoding_spec();
+ result->useless = false;
+
return result;
}
@@ -157,6 +188,9 @@ void delete_coder(rented_coder *coder)
free(coder->details);
}
+ delete_instruction_id(coder->id);
+ delete_instruction_description(coder->desc);
+
for (i = 0; i < coder->specs_count; i++)
delete_encoding_spec(coder->specs[i]);
@@ -184,15 +218,14 @@ void delete_coder(rented_coder *coder)
bool do_basic_checks_with_coder(const rented_coder *coder)
{
- bool result; /* Validité à retourner */
-
+ /*
result = coder->type != IOT_UNDEFINED && coder->outdir != NULL;
result &= coder->arch != NULL && coder->header != NULL;
if (coder->type == IOT_FORMAT)
result &= (coder->const_prefix != NULL);
-
- return result;
+ */
+ return false;
}
@@ -248,32 +281,13 @@ void set_coder_input_file(rented_coder *coder, const char *input)
* Remarques : - *
* *
******************************************************************************/
-
+/*
void set_coder_input_type(rented_coder *coder, InputOutputType type)
{
coder->type = type;
}
-
-
-/******************************************************************************
-* *
-* 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;
-
-}
+*/
/******************************************************************************
@@ -336,23 +350,10 @@ void set_coder_const_prefix(rented_coder *coder, const char *prefix)
}
-/******************************************************************************
-* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* *
-* Description : Fournit le pré-processeur du compilateur. *
-* *
-* Retour : Pré-processeur à manipuler. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-pre_processor *get_coder_pre_proc(const rented_coder *coder)
-{
- return coder->pp;
-}
+/* ---------------------------------------------------------------------------------- */
+/* INFORMATIONS GENERALES */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -392,6 +393,110 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep,
}
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit la désignation nominale d'une instruction. *
+* *
+* Retour : Désignation nominale à libérer de la mémoire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_coder_nominal_name(const rented_coder *coder)
+{
+ char *result; /* Désignation à retourner */
+
+ if (coder->separator == '\0')
+ result = strdup(coder->ins);
+
+ else
+ asprintf(&result, "%s%c%s", coder->ins, coder->separator, coder->raw_details);
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit la désignation complète d'une instruction. *
+* *
+* Retour : Désignation complète à libérer de la mémoire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_coder_code_name(const rented_coder *coder)
+{
+ char *result; /* Désignation à retourner */
+ char *keyword; /* Mot clef appelable en code */
+ char *details; /* Compléments de distinction */
+
+ keyword = make_callable(coder->ins, false);
+
+ if (coder->separator == '\0')
+ result = keyword;
+
+ else
+ {
+ details = make_callable(coder->raw_details, true);
+
+ asprintf(&result, "%s%s", keyword, details);
+
+ free(keyword);
+
+ free(details);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit le gestionnaire des définitions d'identifiant. *
+* *
+* Retour : Structure assurant la définition d'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_id *get_coder_instruction_id(const rented_coder *coder)
+{
+ return coder->id;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit le gestionnaire de description d'identifiant. *
+* *
+* Retour : Structure assurant la description d'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_desc *get_coder_instruction_desc(const rented_coder *coder)
+{
+ return coder->desc;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* REPRESENTATION D'ENCODAGES */
@@ -400,7 +505,7 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep,
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
* *
* Description : Fournit un lien vers les spécifications courantes. *
* *
@@ -448,66 +553,58 @@ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index)
}
-
-/* ---------------------------------------------------------------------------------- */
-/* GENERATIONS DE CODE SOURCE */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* enc_name = désignation du type d'encodage visé. *
* *
-* Description : S'assure de la présence du répertoire de sortie du code. *
+* Description : Détermine le nombre de bits analysés lors d'un désassemblage.*
* *
-* Retour : Bilan de l'opération. *
+* Retour : Nombre de bits interprété. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool check_gen_dir(const rented_coder *coder)
+static unsigned int get_bit_width_for_encoding_spec(const rented_coder *coder, const string_exch *enc_name)
{
- bool has_gen; /* Répertoire de sortie présent*/
- int ret; /* Bilan d'un appel externe */
+ unsigned int result; /* Taille à retourner */
+ size_t i; /* Boucle de parcours */
+ encoding_spec *spec; /* Définition à traiter */
+ coding_bits *bits; /* Gestionnaire de bits */
- has_gen = (access(".gen", F_OK) == 0);
+ result = -1;
- if (has_gen)
+ for (i = 0; i < coder->specs_count; i++)
{
- ret = access(".gen", W_OK | X_OK);
- if (ret == -1)
- {
- perror("access()");
- return false;
- }
+ spec = coder->specs[i];
- }
- else
- {
- ret = mkdir(".gen", 0777);
- if (ret != 0)
- {
- perror("mkdir()");
- return false;
- }
+ if (!has_encoding_spec_prefix(spec, enc_name->src))
+ continue;
+
+ bits = get_bits_in_encoding_spec(spec);
+ result = count_coded_bits(bits);
+ break;
}
- return true;
+ /**
+ * 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(result != -1);
+
+ return result;
}
/******************************************************************************
* *
-* 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. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
* *
-* Description : Imprime dans un flux donné un commentaire de propriété. *
+* Description : Marque une instruction comme non utilisée. *
* *
* Retour : - *
* *
@@ -515,69 +612,59 @@ static bool check_gen_dir(const rented_coder *coder)
* *
******************************************************************************/
-static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext)
+void mark_coder_as_useless(rented_coder *coder)
{
- dprintf(fd, "\n");
+ coder->useless = true;
- 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");
-}
+
+/* ---------------------------------------------------------------------------------- */
+/* GENERATIONS DE CODE SOURCE */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* new = dit si l'opération a abouti à une création. [OUT] *
* *
-* Description : Construit un chemin d'accès à un modèle de fichier de code. *
+* Description : Ouvre un fichier principal en écriture pour y placer du code.*
* *
-* Retour : Chaîne de caractères à libérer de la mémoire après usage. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext)
+static int open_instr_header_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new)
{
- char *result; /* Chaîne construite à renvoyer*/
- size_t length; /* Taille du nom de fichier */
+ int result; /* Descripteur à retourner */
+ char *pathname; /* Chemin d'accès à constituer */
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- if (prefix == NULL)
- {
- length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.tmpl.%c", name, ext);
- }
+ if (prefix != NULL)
+ asprintf(&pathname, "%s%s_opcodes.h", info->directory, prefix);
else
- {
- 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);
- }
+ asprintf(&pathname, "%sopcodes.h", info->directory);
+
+ ret = access(pathname, F_OK);
+
+ *new = (ret != 0);
+
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
+ else
+ flags = O_WRONLY | O_APPEND;
+
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
+
+ free(pathname);
return result;
@@ -587,320 +674,365 @@ static char *build_template_filename(const rented_coder *coder, const char *pref
/******************************************************************************
* *
* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* new = dit si l'opération a abouti à une création. [OUT] *
* *
-* Description : Définit un modèle d'en-tête de définitions. *
+* Description : Ouvre un fichier principal en écriture pour y placer du code.*
* *
-* Retour : Bilan de l'opération. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext)
+static int open_instr_code_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new)
{
+ int result; /* Descripteur à retourner */
+ char *group; /* Regroupement des similarités*/
+ char *sep; /* Eventuelle séparation */
char *pathname; /* Chemin d'accès à constituer */
- bool exist; /* Note une présence établie */
- int fd; /* Flux ouvert pour création */
- const char *valid_prefix; /* Prefix vide au besoin */
- char *uprefix; /* Préfixe en majuscule */
- char *uname; /* Nom en majuscule */
-
- if (!check_gen_dir(coder))
- return false;
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- pathname = build_template_filename(coder, prefix, name, ext);
-
- exist = (access(pathname, W_OK) == 0);
- if (exist)
- {
- free(pathname);
- return true;
- }
+ group = strdup(coder->ins);
- fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644);
- if (fd == -1) perror("open()");
+ sep = index(group, '-');
- free(pathname);
-
- if (fd != -1)
- {
- valid_prefix = prefix != NULL ? prefix : "";
-
- write_owner_comments(coder, fd, valid_prefix, name, ext);
-
- if (ext == 'h')
- {
- uprefix = make_string_upper(strdup(valid_prefix));
- uname = make_string_upper(strdup(name));
+ if (sep != NULL)
+ *sep = '\0';
- dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname);
- dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname);
+ if (prefix != NULL)
+ asprintf(&pathname, "%s%s_%s.c", info->directory, prefix, group);
+ else
+ asprintf(&pathname, "%s%s.c", info->directory, group);
- free(uprefix);
- free(uname);
+ free(group);
- dprintf(fd, "\n");
- dprintf(fd, "\n");
- dprintf(fd, "##INCLUDES##\n");
- dprintf(fd, "\n");
- dprintf(fd, "\n");
- dprintf(fd, "\n");
+ ret = access(pathname, F_OK);
- }
- else
- {
- dprintf(fd, "#include \"%sopcodes.h\"\n", valid_prefix);
- dprintf(fd, "\n");
- dprintf(fd, "##INCLUDES##\n");
+ *new = (ret != 0);
- }
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
+ else
+ flags = O_WRONLY | O_APPEND;
- close(fd);
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
- }
+ free(pathname);
- return (fd != -1);
+ 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. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* new = indique si l'opération a créé le fichier ciblé. [OUT]*
* *
-* Description : Construit un chemin d'accès à un fichier de code source. *
+* Description : Ouvre un fichier global en écriture pour y placer du code. *
* *
-* Retour : Chaîne de caractères à libérer de la mémoire après usage. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext)
+static int open_global_header_file(const rented_coder *coder, const output_info *info, const char *name, bool *new)
{
- 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 */
+ int result; /* Descripteur à retourner */
+ char *pathname; /* Chemin d'accès à constituer */
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- orig = strdup(input);
+ asprintf(&pathname, "%s%s.h", info->directory, name);
- point = strstr(orig, ".");
- if (point != NULL) *point = '\0';
+ ret = access(pathname, F_OK);
- if (prefix == NULL)
- {
- length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.%s.%c", orig, name, ext);
- }
+ *new = (ret != 0);
+
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
else
- {
- 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);
- }
+ flags = O_WRONLY | O_APPEND;
+
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
- free(orig);
+ free(pathname);
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. *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* msg = complément d'information à faire paraître. *
* *
-* 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 *input, const char *prefix, const char *name, char ext)
+static void write_header_file_license(int fd, const output_info *info, const char *name, const char *msg)
{
- int result; /* Descripteur à retourner */
- char *pathname; /* Chemin d'accès à constituer */
-
- if (!check_gen_dir(coder))
- return -1;
+ time_t seconds; /* Temps écoulé depuis T0 */
+ struct tm cur_date; /* Informations sur la date */
- pathname = build_code_filename(coder, input, prefix, name, ext);
+ time(&seconds);
+ localtime_r(&seconds, &cur_date);
- result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (result == -1) perror("open()");
+ dprintf(fd, "\n");
- free(pathname);
+ dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
+ dprintf(fd, " * %s.h - %s %s\n", name, msg, info->arch);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Copyright (C) %d Cyrille Bagard\n", 1900 + cur_date.tm_year);
+ 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n");
+ dprintf(fd, " */\n");
- return result;
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
}
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain.*
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* copyright = droits d'auteur à faire valoir. *
* *
-* Description : Débute la définition des fonctions issues des spécifications.*
+* Description : Imprime dans un flux donné un commentaire de propriété. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool dump_all_routines_using_coder(const rented_coder *coder)
+static void write_code_file_license(int fd, const output_info *info, const char *name, const char *copyright)
{
- bool result; /* Bilan à retourner */
- size_t i; /* Boucle de parcours #1 */
- const string_exch *encoding; /* Type d'encodage visé */
- size_t j; /* Boucle de parcours #2 */
- char *remove; /* Chemin de suppression */
- 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 */
+ dprintf(fd, "\n");
- result = true;
+ dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
+ dprintf(fd, " * %s.c - traduction d'instructions %s\n", name, info->arch);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * %s\n", 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n");
+ dprintf(fd, " */\n");
- for (i = 0; i < count_encodings(coder->pp) && result; i++)
- {
- encoding = find_encoding(coder->pp, i);
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /* On s'assure qu'il existe bien une version pour l'encodage visé... */
+}
- for (j = 0; j < coder->specs_count; j++)
- if (has_encoding_spec_prefix(coder->specs[j], encoding->src))
- break;
- /* Suppressions ? */
- if (j == coder->specs_count)
- {
- /* Fichier de déclarations */
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* prefix = préfixe lié à une sous-branche de l'architecture. *
+* *
+* Description : Initialise le contenu utile du fichier des instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /*
- remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
- */
+static void init_coder_opcodes_file(int fd, const output_info *info, const char *prefix)
+{
+ char *sub; /* Sous-partie à intégrer */
- remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
+ if (prefix != NULL)
+ {
+ sub = strdup(prefix);
+ make_string_upper(sub);
- /* Fichier de définitions */
+ dprintf(fd, "#ifndef _%s_%s_OPCODES_H\n", info->guard, sub);
+ dprintf(fd, "#define _%s_%s_OPCODES_H\n", info->guard, sub);
- dash = strchr(coder->ins, '-');
+ free(sub);
- if (dash == NULL)
- {
- /*
- remove = build_template_filename(coder, encoding->dest, coder->ins, 'c');
- unlink(remove);
- free(remove);
- */
+ }
- remove = build_code_filename(coder, coder->input, encoding->dest, coder->ins, 'c');
- unlink(remove);
- free(remove);
+ else
+ {
+ dprintf(fd, "#ifndef _%s_OPCODES_H\n", info->guard);
+ dprintf(fd, "#define _%s_OPCODES_H\n", info->guard);
+ }
- }
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- else
- {
- filename = strdup(coder->ins);
+ dprintf(fd, "##INCLUDES##\n");
- dash = strchr(filename, '-');
- *dash = '\0';
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /*
- remove = build_template_filename(coder, encoding->dest, filename, 'c');
- unlink(remove);
- free(remove);
- */
+}
- remove = build_code_filename(coder, coder->input, encoding->dest, filename, 'c');
- unlink(remove);
- free(remove);
- }
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* prefix = type d'encodage à répercuter sur un nom de fichier. *
+* *
+* Description : Initialise le contenu utile d'un fichier d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- }
+static void init_coder_code_file(int fd, const char *prefix)
+{
+ if (prefix != NULL)
+ dprintf(fd, "#include \"%s_opcodes.h\"\n", prefix);
+ else
+ dprintf(fd, "#include \"opcodes.h\"\n");
- /* Créations ? */
- else
- {
- /* Fichier de déclarations */
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- if (!create_template_file(coder, encoding->dest, "opcodes", 'h'))
- return false;
+ dprintf(fd, "##INCLUDES##\n");
- header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h');
- if (header_fd == -1) return false;
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /* Fichier de définitions */
+}
- dash = strchr(coder->ins, '-');
- if (dash == NULL)
- {
- if (!create_template_file(coder, encoding->dest, coder->ins, 'c'))
- return false;
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier contenant le code C principal. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c');
+bool output_coder_body(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ const string_exch *enc_name; /* Type d'encodage visé */
+ size_t j; /* Boucle de parcours #2 */
+ int header_fd; /* Fichier de déclarations */
+ char *file; /* Nom de fichier final */
+ bool header_new; /* Note une création d'entête */
+ int code_fd; /* Fichier de définitions */
+ bool code_new; /* Note une création de code */
- }
+ result = true;
- else
+ for (i = 0; i < count_encodings(coder->pp) && result; i++)
+ {
+ enc_name = find_encoding(coder->pp, i);
+
+ for (j = 0; j < coder->specs_count; j++)
+ {
+ /* On s'assure qu'il existe bien une version pour l'encodage visé... */
+ if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src))
+ continue;
+
+ header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new);
+ if (header_fd == -1)
{
- filename = strdup(coder->ins);
+ result = false;
+ goto ocb_exit;
+ }
- dash = strchr(filename, '-');
- *dash = '\0';
+ if (header_new)
+ {
+ if (enc_name->dest == NULL)
+ file = strdup("opcodes");
+ else
+ asprintf(&file, "%s_opcodes", enc_name->dest);
- if (!create_template_file(coder, encoding->dest, filename, 'c'))
- return false;
+ write_header_file_license(header_fd, info, file, "prototypes pour la traduction d'instructions");
- code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c');
+ free(file);
- free(filename);
+ init_coder_opcodes_file(header_fd, info, enc_name->dest);
}
+ code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new);
if (code_fd == -1)
{
- close(header_fd);
+ result = false;
+ goto ocb_exit;
+ }
- /*
- remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
- */
+ if (code_new)
+ {
+ if (enc_name->dest == NULL)
+ file = strdup(coder->ins);
+ else
+ asprintf(&file, "%s_%s", enc_name->dest, coder->ins);
- remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
+ write_code_file_license(code_fd, info, file, coder->copyright);
- return false;
+ free(file);
- }
+ init_coder_code_file(code_fd, enc_name->dest);
- /* Production de code... */
+ }
+ else
+ dprintf(code_fd, "\n");
- switch (coder->type)
+ switch (info->type)
{
case IOT_UNDEFINED:
assert(false);
@@ -908,22 +1040,56 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
break;
case IOT_RAW:
- result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd);
+ result = output_coder_raw(coder, info, enc_name, coder->specs[j], header_fd, code_fd);
break;
case IOT_FORMAT:
- result = dump_all_matching_specs_from_format(coder, encoding, header_fd, code_fd);
+ assert(enc_name->dest == NULL);
+ result = output_coder_format(coder, info, enc_name, coder->specs[j], header_fd, code_fd);
break;
}
- close(header_fd);
- close(code_fd);
+ }
+
+ /* La suite ne concerne que les formats bruts aboutis... */
+ if (!result) break;
+ if (info->type != IOT_RAW) continue;
+
+ for (j = 0; j < coder->specs_count; j++)
+ {
+ /* On s'assure de retrouver une version de l'encodage visé juste avant... */
+ if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src))
+ continue;
+
+ header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new);
+ if (header_fd == -1)
+ {
+ result = false;
+ goto ocb_exit;
+ }
+
+ assert(!header_new);
+
+ code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new);
+ if (code_fd == -1)
+ {
+ result = false;
+ goto ocb_exit;
+ }
+
+ assert(!code_new);
+
+ result = output_coder_main_raw(coder, info, enc_name, header_fd, code_fd);
+
+ break;
}
}
+ ocb_exit:
+
return result;
}
@@ -931,12 +1097,39 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement d'humain. *
+* Paramètres : fd = flux ouvert en écriture. *
+* arch = architecture en cours de traitement. *
+* sub = encodage choisi comme sous-ensemble d'architecture. *
+* name = désignation complète d'une instruction. *
+* *
+* Description : Centralise l'impression du nom de fonction de désassemblage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void write_read_function_name(int fd, const char *arch, const string_exch *sub, const char *name)
+{
+ if (sub->dest == NULL)
+ dprintf(fd, "%s_read_instr_%s", arch, name);
+ else
+ dprintf(fd, "%s_read_%s_instr_%s", arch, sub->dest, name);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
* 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. *
+* Description : Génère ou complète un fichier contenant le code C principal. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -944,55 +1137,152 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
* *
******************************************************************************/
-static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd)
+static bool output_coder_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *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 */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
+ char *prefix; /* Préfixe employé en suffixe */
coding_bits *bits; /* Gestionnaire de bits */
+ unsigned int wide; /* Taille des mots */
size_t maxlen; /* Taille à compléter */
- result = true;
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
- keyword = make_callable(coder->ins, false);
+ name = get_coder_code_name(coder);
- /* Recherche de la taille des mots */
+ prefix = build_encoding_spec_prefix(encoding);
- wide = -1;
+ bits = get_bits_in_encoding_spec(encoding);
+ wide = count_coded_bits(bits);
- for (i = 0; i < coder->specs_count; i++)
+ /* Désassemblage : déclaration */
+
+ if (0 /* TODO : export seulement */)
{
- spec = coder->specs[i];
+ dprintf(hfd, "/* Décode une forme d'instruction de type '%s'. */\n", coder->ins);
- if (!has_encoding_spec_prefix(spec, encoding->src))
- continue;
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
+ dprintf(hfd, "_%s", prefix);
- bits = get_bits_in_encoding_spec(spec);
- wide = count_coded_bits(bits);
- break;
+ dprintf(hfd, "(");
+ dprintf(hfd, "uint%u_t raw", wide);
+ dprintf(hfd, ");\n");
+
+ dprintf(hfd, "\n");
}
- /**
- * 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éfinitions */
+
+ 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 forme d'instruction de type '%s'.", coder->ins);
+
+ maxlen = 20 - strlen(coder->ins);
+
+ if (maxlen < 20)
+ dprintf(cfd, "%*s\n", (int)maxlen, "*");
+ else
+ dprintf(cfd, "*\n");
+
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Remarques : - *\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "******************************************************************************/\n");
+
+ dprintf(cfd, "\n");
+
+ if (1 /* TODO : si pas exportée */)
+ dprintf(cfd, "static ");
+
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s", prefix);
+
+ dprintf(cfd, "(");
+ dprintf(cfd, "uint%u_t raw", wide);
+ dprintf(cfd, ")");
+
+ dprintf(cfd, "\n");
+ dprintf(cfd, "{");
+ dprintf(cfd, "\n");
+
+ result = write_encoding_spec_raw_disass(encoding, cfd, arch, coder->id, coder->pp);
+
+ dprintf(cfd, "}\n");
+ dprintf(cfd, "\n");
+
+ /* Conclusion */
+
+ free(prefix);
+
+ free(name);
+
+ free(arch);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
+* hfd = flux ouvert en écriture pour les déclarations. *
+* cfd = flux ouvert en écriture pour les définitions. *
+* *
+* Description : Génère ou complète un fichier contenant le code C principal. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool output_coder_main_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, int hfd, int cfd)
+{
+ bool result; /* Bilan à retourner */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
+ unsigned int wide; /* Taille des mots */
+ size_t maxlen; /* Taille à compléter */
+ bool first; /* Note un premier appel */
+ size_t i; /* Boucle de parcours */
+ char *prefix; /* Préfixe employé en suffixe */
+
+ result = false;
+
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
+
+ name = get_coder_code_name(coder);
+
+ wide = get_bit_width_for_encoding_spec(coder, enc_name);
/* Désassemblage : déclaration */
dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins);
- dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t);\n",
- coder->arch, encoding->dest, keyword, coder->details, wide);
+
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
+
+ dprintf(hfd, "(");
+ dprintf(hfd, "uint%u_t raw", wide);
+ dprintf(hfd, ");\n");
+
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");
@@ -1006,7 +1296,7 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
else
dprintf(cfd, "*\n");
- dprintf(cfd, " *\n");
+ dprintf(cfd, "* *\n");
dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Remarques : - *\n");
@@ -1015,27 +1305,55 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
dprintf(cfd, "\n");
- dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t raw)",
- coder->arch, encoding->dest, keyword, coder->details, wide);
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
+
+ dprintf(cfd, "(");
+ dprintf(cfd, "uint%u_t raw", wide);
+ dprintf(cfd, ")");
+
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];
+ first = true;
- if (!has_encoding_spec_prefix(spec, encoding->src))
+ for (i = 0; i < coder->specs_count; i++)
+ {
+ if (!has_encoding_spec_prefix(coder->specs[i], enc_name->src))
continue;
- result = write_encoding_spec_disass(spec, cfd, coder->arch, encoding->dest,
- coder->ins, coder->details, wide, coder->pp);
+ result = true;
+
+ prefix = build_encoding_spec_prefix(coder->specs[i]);
+
+ if (first)
+ {
+ dprintf(cfd, "\tresult = ");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s(raw);\n", prefix);
+
+ dprintf(cfd, "\n");
+
+ first = false;
+
+ }
+ else
+ {
+ dprintf(cfd, "\tif (result == NULL)\n");
+
+ dprintf(cfd, "\t\tresult = ");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s(raw);\n", prefix);
+
+ dprintf(cfd, "\n");
+
+ }
+
+ free(prefix);
}
@@ -1045,7 +1363,11 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
dprintf(cfd, "}\n");
dprintf(cfd, "\n");
- free(keyword);
+ /* Conclusion */
+
+ free(name);
+
+ free(arch);
return result;
@@ -1054,12 +1376,14 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement d'humain. *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
* 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. *
+* Description : Génère ou complète un fichier contenant le code C principal. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -1067,25 +1391,24 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
* *
******************************************************************************/
-static bool dump_all_matching_specs_from_format(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd)
+static bool output_coder_format(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *encoding, int hfd, int cfd)
{
bool result; /* Bilan à retourner */
- char *keyword; /* Mot clef appelable en code */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
size_t maxlen; /* Taille à compléter */
- encoding_spec *spec; /* Définition à traiter */
- keyword = make_callable(coder->ins, false);
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
+
+ name = get_coder_code_name(coder);
/* Désassemblage : déclaration */
dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins);
- if (encoding->dest == NULL)
- dprintf(hfd, "GArchInstruction *%s_read_instr_%s%s",
- coder->arch, keyword, coder->details);
- else
- dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s",
- coder->arch, encoding->dest, keyword, coder->details);
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
dprintf(hfd, "(");
dprintf(hfd, "const GArchProcessor *, GProcContext *, const GBinContent *, ");
@@ -1096,8 +1419,6 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
/* Désassemblage : définitions */
- dprintf(cfd, "\n");
-
dprintf(cfd, "/******************************************************************************\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Paramètres : proc = processeur de l'architecture d'exécution. *\n");
@@ -1115,7 +1436,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
else
dprintf(cfd, "*\n");
- dprintf(cfd, " *\n");
+ dprintf(cfd, "* *\n");
dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Remarques : - *\n");
@@ -1124,12 +1445,8 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
dprintf(cfd, "\n");
- if (encoding->dest == NULL)
- dprintf(cfd, "GArchInstruction *%s_read_instr_%s%s",
- coder->arch, keyword, coder->details);
- else
- dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s",
- coder->arch, encoding->dest, keyword, coder->details);
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
dprintf(cfd, "(");
dprintf(cfd, "const GArchProcessor *proc, GProcContext *ctx, const GBinContent *content, ");
@@ -1140,20 +1457,523 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
dprintf(cfd, "{");
dprintf(cfd, "\n");
- assert(coder->specs_count == 1);
+ result = write_encoding_spec_format_disass(encoding, cfd, arch, coder->id, info->fmt_prefix);
- spec = coder->specs[0];
+ dprintf(cfd, "}\n");
+ dprintf(cfd, "\n");
- assert(has_encoding_spec_prefix(spec, encoding->src));
+ /* Conclusion */
- result = write_encoding_spec_format_disass(spec, cfd, coder->arch, encoding->dest,
- coder->ins, coder->separator, coder->raw_details,
- coder->pp, coder->const_prefix);
+ free(name);
- dprintf(cfd, "}\n");
- dprintf(cfd, "\n");
+ free(arch);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des instructions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_opcodes_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+ char *temp; /* Zone de travail temporaire */
+ char *base; /* Identification de fichier */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fcif_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ temp = strdup(pathname);
+ base = basename(temp);
+
+ base[strlen(base) - 2] = '\0';
+
+ make_string_upper(base);
+
+ dprintf(fd, "#endif /* _%s_%s_H */\n", info->guard, base);
+
+ free(temp);
+
+ result = true;
+
+ fcif_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des identifiants. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_identifiers_file(int fd, const output_info *info)
+{
+ dprintf(fd, "#ifndef _%s_IDENTIFIERS_H\n", info->guard);
+ dprintf(fd, "#define _%s_IDENTIFIERS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "/* Enumération de tous les opcodes */\n");
+ dprintf(fd, "typedef enum _%sOpcodes\n", info->arch_cn);
+ dprintf(fd, "{\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les identifiants. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_identifier(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+ instr_id *id; /* Gestionnaire d'identifiant */
+ unsigned int iid; /* Identifiant unique attribué */
+ char *constant; /* Définition d'une constante */
+ char *comment; /* Contenu du commentaire */
+
+ result = false;
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "identifiers", &created);
+ if (fd == -1) goto oci_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "identifiers", "définition des identifiants uniques pour");
+ init_coder_identifiers_file(fd, info);
+ }
+
+ /* Constitution de la constante */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ asprintf(&constant, "%s_%s,", info->id_prefix, name);
+
+ free(name);
+
+ /* Définition du commentaire */
+
+ name = get_coder_nominal_name(coder);
+
+ id = get_coder_instruction_id(coder);
+ iid = get_instruction_id_value(id);
+
+ asprintf(&comment, "%s (0x%0*x)", name, info->id_len, iid);
+
+ free(name);
+
+ /* Impression de la ligne */
+
+ dprintf(fd, " %-40s/* %-28s*/\n", constant, comment);
+
+ free(constant);
+ free(comment);
+
+ result = true;
+
+ oci_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des identifiants. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_identifiers_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fcif_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, " %s_COUNT\n", info->id_prefix);
+ dprintf(fd, "\n");
+
+ dprintf(fd, "} %sOpcodes;\n", info->arch_cn);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_IDENTIFIERS_H */\n", info->guard);
+
+ result = true;
+
+ fcif_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des mots clefs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_keywords_file(int fd, const output_info *info)
+{
+ char *larch; /* Architecture en minuscules */
+
+ dprintf(fd, "#ifndef _%s_KEYWORDS_H\n", info->guard);
+ dprintf(fd, "#define _%s_KEYWORDS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "#include \"identifiers.h\"\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ larch = strdup(info->arch_cn);
+ make_string_lower(larch);
+
+ dprintf(fd, "/* Enumération de tous les mots clefs */\n");
+ dprintf(fd, "static char *_%s_keywords[%s_COUNT] = {\n", larch, info->id_prefix);
+ dprintf(fd, "\n");
+
+ free(larch);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les mots clefs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_keyword(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+
+ result = false;
+
+ /* S'il n'y a pas lieu de traiter l'instruction */
+
+ if (coder->useless)
+ {
+ result = true;
+ goto ock_exit;
+ }
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "keywords", &created);
+ if (fd == -1) goto ock_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "keywords", "définition des mots clefs des instructions");
+ init_coder_keywords_file(fd, info);
+ }
+
+ /* Impression de la colonne */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name);
+
+ free(name);
+
+ /* Impression du mot clef */
+
+ name = get_coder_nominal_name(coder);
+
+ dprintf(fd, "\"%s\",\n", name);
+
+ free(name);
+
+ result = true;
+
+ ock_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des mots clefs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_keywords_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fckf_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "};\n");
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_KEYWORDS_H */\n", info->guard);
+
+ result = true;
+
+ fckf_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des descriptions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_descriptions_file(int fd, const output_info *info)
+{
+ char *larch; /* Architecture en minuscules */
+
+ dprintf(fd, "#ifndef _%s_DESCRIPTIONS_H\n", info->guard);
+ dprintf(fd, "#define _%s_DESCRIPTIONS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "#include \"identifiers.h\"\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ larch = strdup(info->arch_cn);
+ make_string_lower(larch);
+
+ dprintf(fd, "/* Enumération de tous les mots clefs */\n");
+ dprintf(fd, "static char *_%s_descriptions[%s_COUNT] = {\n", larch, info->id_prefix);
+ dprintf(fd, "\n");
+
+ free(larch);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les descriptions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_description(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+
+ result = false;
+
+ /* S'il n'y a pas lieu de traiter l'instruction */
+
+ if (coder->useless)
+ {
+ result = true;
+ goto ock_exit;
+ }
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "descriptions", &created);
+ if (fd == -1) goto ock_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "descriptions", "définition des descriptions des instructions");
+ init_coder_descriptions_file(fd, info);
+ }
+
+ /* Impression de la colonne */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name);
+
+ free(name);
+
+ /* Impression du mot clef */
+
+ name = get_coder_nominal_name(coder);
+
+ dprintf(fd, "\"");
+
+ write_instruction_description(coder->desc, fd);
+
+ dprintf(fd, "\",\n");
+
+ free(name);
+
+ result = true;
+
+ ock_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des descriptions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_descriptions_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fckf_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "};\n");
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_DESCRIPTIONS_H */\n", info->guard);
+
+ result = true;
- free(keyword);
+ fckf_exit:
return result;