/* Chrysalide - Outil d'analyse de fichiers binaires * coder.c - lecture automatisée des spécifications d'architecture * * Copyright (C) 2014-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "coder.h" #include #include #include #include #include #include #include #include #include "helpers.h" /* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ /* Suivi des constructions */ struct _rented_coder { const char *input; /* Fichier de définitions */ pre_processor *pp; /* Pré-processeur avec macros */ char *copyright; /* Récupération des droits */ char *ins; /* Désignation humaine */ char separator; /* Caractère de séparation */ 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 */ }; /* --------------------------- 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 --------------------------- */ /* Ouvre un fichier principal en écriture pour y placer du code. */ static int open_code_file(const rented_coder *, const char *, const char *, bool *); /* Ouvre un fichier global en écriture pour y placer du code. */ static int open_header_file(const char *, const char *, 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_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(const rented_coder *, const output_info *, int, const string_exch *); /* 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); /* 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); /* 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); /* Initialise le contenu utile du fichier des identifiants. */ static void init_coder_identifiers_file(int, const output_info *); /* Initialise le contenu utile du fichier des sous-identifiants. */ static void init_coder_sub_identifiers_file(int, const output_info *); /* Initialise le contenu utile du fichier des mots clefs. */ static void init_coder_keywords_file(int, const output_info *); /* Initialise le contenu utile du fichier des décrochages. */ static void init_coder_hooks_file(int, const output_info *); /* Initialise le contenu utile du fichier des descriptions. */ static void init_coder_descriptions_file(int, const output_info *); /* ---------------------------------------------------------------------------------- */ /* CONSTRUCTION SELON COMMANDES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : pp = préprocesseur déjà chargé à intégrer. * * * * Description : Débute la définition d'une fonction de désassemblage. * * * * Retour : Gestionnaire mis en place. * * * * Remarques : - * * * ******************************************************************************/ rented_coder *create_coder(pre_processor *pp) { rented_coder *result; /* Structure à renvoyer */ result = (rented_coder *)calloc(1, sizeof(rented_coder)); result->pp = pp; result->id = create_instruction_id(); result->desc = create_instruction_description(); result->cur_spec = create_encoding_spec(); result->useless = false; return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : Supprime le codeur de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_coder(rented_coder *coder) { size_t i; /* Boucle de parcours */ delete_pre_processor(coder->pp); if (coder->ins != NULL) free(coder->ins); if (coder->raw_details != NULL) { free(coder->raw_details); 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]); if (coder->specs != NULL) free(coder->specs); delete_encoding_spec(coder->cur_spec); free(coder); } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : Indique le fichier de définition considéré en entrée. * * * * Retour : Fichier de définition à interpréter. * * * * Remarques : - * * * ******************************************************************************/ const char *get_coder_input_file(const rented_coder *coder) { return coder->input; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * input = 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; } /* ---------------------------------------------------------------------------------- */ /* INFORMATIONS GENERALES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain.* * copy = droits de copie en anglais. * * ins = désignation humaine de l'instruction. * * sep = caractère de séparation avant les détails. * * details = compléments d'informations éventuels ou NULL. * * * * Description : Enregistre les contours d'une instruction d'assemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep, const char *details) { coder->copyright = copy; coder->ins = make_string_lower(ins); coder->separator = sep; if (details != NULL) { coder->raw_details = strdup(details); coder->details = make_callable(details, true); } else { coder->raw_details = strdup(""); coder->details = strdup(""); } } /****************************************************************************** * * * 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 */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : Fournit un lien vers les spécifications courantes. * * * * Retour : Spécification en cours d'édition. * * * * Remarques : - * * * ******************************************************************************/ encoding_spec *get_current_encoding_spec(const rented_coder *coder) { return coder->cur_spec; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * prefix = distinction principale entre les définitions. * * index = distinction secondaire entre les définitions. * * * * Description : Enregistre une définition supplémentaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) { encoding_spec *spec; /* Définition à compléter */ spec = coder->cur_spec; if (prefix != NULL) define_encoding_spec_code_name(spec, prefix, index); coder->specs = (encoding_spec **)realloc(coder->specs, ++coder->specs_count * sizeof(encoding_spec *)); coder->specs[coder->specs_count - 1] = spec; coder->cur_spec = create_encoding_spec(); } /****************************************************************************** * * * Paramètres : coder = gestion automatique de l'écriture de code. * * enc_name = désignation du type d'encodage visé. * * * * Description : Détermine le nombre de bits analysés lors d'un désassemblage.* * * * Retour : Nombre de bits interprété. * * * * Remarques : - * * * ******************************************************************************/ static unsigned int get_bit_width_for_encoding_spec(const rented_coder *coder, const string_exch *enc_name) { unsigned int result; /* Taille à retourner */ size_t i; /* Boucle de parcours */ encoding_spec *spec; /* Définition à traiter */ coding_bits *bits; /* Gestionnaire de bits */ result = -1; for (i = 0; i < coder->specs_count; i++) { spec = coder->specs[i]; if (!has_encoding_spec_prefix(spec, enc_name->src)) continue; bits = get_bits_in_encoding_spec(spec); result = count_coded_bits(bits); break; } /** * 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. * * * * Description : Marque une instruction comme non utilisée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void mark_coder_as_useless(rented_coder *coder) { coder->useless = true; } /* ---------------------------------------------------------------------------------- */ /* GENERATIONS DE CODE SOURCE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * info = précisions quant à la génération. * * * * Description : Crée la désignation principale d'une instruction. * * * * Retour : Identifiant à libérer après usage. * * * * Remarques : - * * * ******************************************************************************/ char *build_coder_main_identifier(const rented_coder *coder, const output_info *info) { char *result; /* Chaîne construite à renvoyer*/ char *filename; /* Nom de fichier modifiable */ char *sub; /* Compartimentage à insérer */ char *name; /* Désignation à manipuler */ if (info->filename_reuse > 0) { filename = strdup(coder->input); sub = basename(filename); if (info->filename_reuse < strlen(sub)) sub[info->filename_reuse] = '\0'; } name = get_coder_code_name(coder); make_string_upper(name); if (info->filename_reuse > 0) asprintf(&result, "%s_%s_%s", info->id_prefix, sub, name); else asprintf(&result, "%s_%s", info->id_prefix, name); free(name); if (info->filename_reuse > 0) free(filename); return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * path = chemin du répertoire de sortie. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * new = dit si l'opération a abouti à une création. [OUT] * * * * Description : Ouvre un fichier principal en écriture pour y placer du code.* * * * Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static int open_code_file(const rented_coder *coder, const char *path, 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 */ int ret; /* Test d'existence du fichier */ int flags; /* Mode d'accès au fichier */ group = strdup(coder->ins); sep = index(group, '-'); if (sep != NULL) *sep = '\0'; if (prefix != NULL) asprintf(&pathname, "%s%s_%s.c", path, prefix, group); else asprintf(&pathname, "%s%s.c", path, group); free(group); 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; } /****************************************************************************** * * * Paramètres : path = chemin du répertoire de sortie. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom du fichier ciblé par l'opération. * * new = indique si l'opération a créé le fichier. [OUT] * * * * Description : Ouvre un fichier global en écriture pour y placer du code. * * * * Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static int open_header_file(const char *path, const char *prefix, const char *name, bool *new) { 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 */ asprintf(&pathname, "%s%s.h", path, name); if (prefix != NULL) asprintf(&pathname, "%s%s_%s.h", path, prefix, name); else asprintf(&pathname, "%s%s.h", path, name); 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; } /****************************************************************************** * * * 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 : Imprime dans un flux donné un commentaire de propriété. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void write_header_file_license(int fd, const output_info *info, const char *name, const char *msg) { time_t seconds; /* Temps écoulé depuis T0 */ struct tm cur_date; /* Informations sur la date */ time(&seconds); localtime_r(&seconds, &cur_date); dprintf(fd, "\n"); 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 .\n"); dprintf(fd, " */\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); } /****************************************************************************** * * * 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 : Imprime dans un flux donné un commentaire de propriété. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void write_code_file_license(int fd, const output_info *info, const char *name, const char *copyright) { dprintf(fd, "\n"); 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 .\n"); dprintf(fd, " */\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); } /****************************************************************************** * * * 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 : - * * * ******************************************************************************/ static void init_coder_opcodes_file(int fd, const output_info *info, const char *prefix) { char *sub; /* Sous-partie à intégrer */ if (prefix != NULL) { sub = strdup(prefix); make_string_upper(sub); dprintf(fd, "#ifndef _%s_%s_OPCODES_H\n", info->guard, sub); dprintf(fd, "#define _%s_%s_OPCODES_H\n", info->guard, sub); free(sub); } 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"); dprintf(fd, "##INCLUDES##\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); } /****************************************************************************** * * * 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"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "##INCLUDES##\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); 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 contenant le code C principal. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ 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; 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_header_file(info->directory, enc_name->dest, "opcodes", &header_new); if (header_fd == -1) { result = false; goto ocb_exit; } if (header_new) { if (enc_name->dest == NULL) file = strdup("opcodes"); else asprintf(&file, "%s_opcodes", enc_name->dest); write_header_file_license(header_fd, info, file, "prototypes pour la traduction d'instructions"); free(file); init_coder_opcodes_file(header_fd, info, enc_name->dest); } code_fd = open_code_file(coder, info->directory, enc_name->dest, &code_new); if (code_fd == -1) { result = false; goto ocb_exit; } if (code_new) { if (enc_name->dest == NULL) file = strdup(coder->ins); else asprintf(&file, "%s_%s", enc_name->dest, coder->ins); write_code_file_license(code_fd, info, file, coder->copyright); free(file); init_coder_code_file(code_fd, enc_name->dest); } else dprintf(code_fd, "\n"); switch (info->type) { case IOT_UNDEFINED: assert(false); result = false; break; case IOT_RAW: result = output_coder_raw(coder, info, enc_name, coder->specs[j], header_fd, code_fd); break; case IOT_FORMAT: assert(j == 0); assert(enc_name->dest == NULL); result = output_coder_format(coder, info, enc_name, coder->specs[j], header_fd, code_fd); break; } } /* 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_header_file(info->directory, enc_name->dest, "opcodes", &header_new); if (header_fd == -1) { result = false; goto ocb_exit; } assert(!header_new); code_fd = open_code_file(coder, info->directory, 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; } /****************************************************************************** * * * Paramètres : coder = gestion automatique de l'écriture de code. * * info = précisions quant à la génération. * * fd = flux ouvert en écriture. * * enc = encodage choisi comme sous-ensemble d'architecture. * * * * Description : Centralise l'impression du nom de fonction de désassemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void write_read_function_name(const rented_coder *coder, const output_info *info, int fd, const string_exch *enc) { char *arch; /* Architecture à traiter */ char *filename; /* Nom de fichier modifiable */ char *sub; /* Compartimentage à insérer */ char *name; /* Désignation à manipuler */ /* Préparations */ arch = strdup(info->arch_cn); make_string_lower(arch); if (info->filename_reuse > 0) { filename = strdup(coder->input); sub = basename(filename); if (info->filename_reuse < strlen(sub)) sub[info->filename_reuse] = '\0'; make_string_lower(sub); } name = get_coder_code_name(coder); /* Impressions */ if (enc->dest == NULL) dprintf(fd, "%s_read_instr", arch); else dprintf(fd, "%s_read_%s_instr", arch, enc->dest); if (info->filename_reuse > 0) dprintf(fd, "_%s", sub); dprintf(fd, "_%s", name); /* Sortie propre */ free(name); if (info->filename_reuse > 0) free(filename); free(arch); } /****************************************************************************** * * * 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 : Génère ou complète un fichier contenant le code C principal. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ 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 *arch; /* Architecture à traiter */ 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 */ char *constant; /* Définition d'une constante */ arch = strdup(info->arch_cn); make_string_lower(arch); prefix = build_encoding_spec_prefix(encoding); bits = get_bits_in_encoding_spec(encoding); wide = count_coded_bits(bits); /* Désassemblage : déclaration */ if (0 /* TODO : export seulement */) { dprintf(hfd, "/* Décode une forme d'instruction de type '%s'. */\n", coder->ins); dprintf(hfd, "GArchInstruction *"); write_read_function_name(coder, info, hfd, enc_name); dprintf(hfd, "_%s", prefix); 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, "* 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(coder, info, cfd, enc_name); dprintf(cfd, "_%s", prefix); dprintf(cfd, "("); dprintf(cfd, "uint%u_t raw", wide); dprintf(cfd, ")"); dprintf(cfd, "\n"); dprintf(cfd, "{"); dprintf(cfd, "\n"); constant = build_coder_main_identifier(coder, info); result = write_encoding_spec_raw_disass(encoding, cfd, arch, constant, coder->pp); free(constant); dprintf(cfd, "}\n"); dprintf(cfd, "\n"); /* Conclusion */ free(prefix); 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 */ 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; 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 *"); write_read_function_name(coder, info, hfd, enc_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, "* Paramètres : raw = données brutes à analyser. *\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Description : Décode une instruction de type '%s'.", coder->ins); maxlen = 28 - strlen(coder->ins); if (maxlen < 28) dprintf(cfd, "%*s\n", (int)maxlen, "*"); else dprintf(cfd, "*\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Retour : 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"); dprintf(cfd, "GArchInstruction *"); write_read_function_name(coder, info, cfd, enc_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"); first = true; for (i = 0; i < coder->specs_count; i++) { if (!has_encoding_spec_prefix(coder->specs[i], enc_name->src)) continue; result = true; prefix = build_encoding_spec_prefix(coder->specs[i]); if (first) { dprintf(cfd, "\tresult = "); write_read_function_name(coder, info, cfd, enc_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(coder, info, cfd, enc_name); dprintf(cfd, "_%s(raw);\n", prefix); dprintf(cfd, "\n"); } free(prefix); } dprintf(cfd, "\treturn result;\n"); dprintf(cfd, "\n"); dprintf(cfd, "}\n"); dprintf(cfd, "\n"); 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é. * * 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 : Génère ou complète un fichier contenant le code C principal. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ 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 *arch; /* Architecture à traiter */ size_t maxlen; /* Taille à compléter */ char *constant; /* Définition d'une constante */ arch = strdup(info->arch_cn); make_string_lower(arch); /* Désassemblage : déclaration */ dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins); dprintf(hfd, "GArchInstruction *"); write_read_function_name(coder, info, hfd, enc_name); dprintf(hfd, "("); dprintf(hfd, "const GArchProcessor *, GProcContext *, const GBinContent *, "); dprintf(hfd, "vmpa2t *, GExeFormat *"); dprintf(hfd, ");\n"); dprintf(hfd, "\n"); /* Désassemblage : définitions */ dprintf(cfd, "/******************************************************************************\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Paramètres : proc = processeur de l'architecture d'exécution. *\n"); dprintf(cfd, "* ctx = contexte associé à la phase de désassemblage. *\n"); dprintf(cfd, "* content = flux de données à analyser. *\n"); dprintf(cfd, "* pos = position courante dans ce flux. [OUT] *\n"); dprintf(cfd, "* format = format du fichier contenant le code. *\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Description : Décode une instruction de type '%s'.", coder->ins); maxlen = 28 - strlen(coder->ins); if (maxlen < 28) dprintf(cfd, "%*s\n", (int)maxlen, "*"); else dprintf(cfd, "*\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Retour : 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"); dprintf(cfd, "GArchInstruction *"); write_read_function_name(coder, info, cfd, enc_name); dprintf(cfd, "("); dprintf(cfd, "const GArchProcessor *proc, GProcContext *ctx, const GBinContent *content, "); dprintf(cfd, "vmpa2t *pos, GExeFormat *format"); dprintf(cfd, ")"); dprintf(cfd, "\n"); dprintf(cfd, "{"); dprintf(cfd, "\n"); constant = build_coder_main_identifier(coder, info); result = write_encoding_spec_format_disass(encoding, cfd, arch, constant, info->fmt_prefix); free(constant); dprintf(cfd, "}\n"); dprintf(cfd, "\n"); /* Conclusion */ 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 *constant; /* Définition d'une constante */ char *name; /* Désignation à manipuler */ instr_id *id; /* Gestionnaire d'identifiant */ unsigned int iid; /* Identifiant unique attribué */ char *comment; /* Contenu du commentaire */ char *aligned; /* Adaptation pour l'alignement*/ result = false; /* Ouverture de la destination */ fd = open_header_file(info->directory, NULL, "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 */ constant = build_coder_main_identifier(coder, info); /* 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 */ asprintf(&aligned, "%s,", constant); dprintf(fd, " %-40s/* %-28s*/\n", aligned, comment); free(aligned); 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 sous-identifiants.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void init_coder_sub_identifiers_file(int fd, const output_info *info) { dprintf(fd, "#ifndef _%s_SUBIDENTIFIERS_H\n", info->guard); dprintf(fd, "#define _%s_SUBIDENTIFIERS_H\n", info->guard); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "/* Enumération de tous les opcodes */\n"); dprintf(fd, "typedef enum _%sSyntax\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 créant les sous-identifiants. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool output_coder_sub_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 *constant; /* Définition d'une constante */ size_t i; /* Boucle de parcours */ result = false; /* Ouverture de la destination */ fd = open_header_file(info->directory, NULL, "subidentifiers", &created); if (fd == -1) goto ocsi_exit; if (created) { write_header_file_license(fd, info, "subidentifiers", "définition des sous-identifiants uniques pour"); init_coder_sub_identifiers_file(fd, info); } /* Impression des sous-identifiants */ constant = build_coder_main_identifier(coder, info); result = true; for (i = 0; i < coder->specs_count && result; i++) result = write_encoding_spec_subid(coder->specs[i], fd, constant); free(constant); ocsi_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 sous-identifiants. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool fini_coder_sub_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_ENC_COUNT\n", info->id_prefix); dprintf(fd, "\n"); dprintf(fd, "} %sSyntax;\n", info->arch_cn); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "#endif /* _%s_SUBIDENTIFIERS_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"); switch (info->type) { case IOT_UNDEFINED: assert(false); break; case IOT_RAW: dprintf(fd, "#include \"subidentifiers.h\"\n"); break; case IOT_FORMAT: dprintf(fd, "#include \"identifiers.h\"\n"); break; } 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_%sCOUNT] = {\n", larch, info->id_prefix, info->type == IOT_RAW ? "ENC_" : ""); 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 *constant; /* Définition d'une constante */ size_t i; /* Boucle de parcours */ 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_header_file(info->directory, NULL, "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); } /* Lancement des impressions */ constant = build_coder_main_identifier(coder, info); result = true; for (i = 0; i < coder->specs_count && result; i++) switch (info->type) { case IOT_UNDEFINED: assert(false); result = false; break; case IOT_RAW: result = write_encoding_spec_keywords(coder->specs[i], fd, constant); break; case IOT_FORMAT: assert(i == 0); /* Impression de la colonne */ dprintf(fd, "\t[%s] = ", constant); /* Impression du mot clef */ name = get_coder_nominal_name(coder); dprintf(fd, "\"%s\",\n", name); free(name); break; } free(constant); 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 décrochages. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void init_coder_hooks_file(int fd, const output_info *info) { char *larch; /* Architecture en minuscules */ dprintf(fd, "#ifndef _%s_HOOKS_H\n", info->guard); dprintf(fd, "#define _%s_HOOKS_H\n", info->guard); dprintf(fd, "\n"); dprintf(fd, "\n"); switch (info->type) { case IOT_UNDEFINED: assert(false); break; case IOT_RAW: dprintf(fd, "#include \"subidentifiers.h\"\n"); break; case IOT_FORMAT: dprintf(fd, "#include \"identifiers.h\"\n"); break; } dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "##INCLUDES##\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); larch = strdup(info->arch_cn); make_string_lower(larch); dprintf(fd, "/* Définitions des décrochages pour l'établissement d'instructions */\n"); dprintf(fd, "static const instr_hook_fc _%s_hooks[%s_%sCOUNT][IPH_COUNT] = {\n", larch, info->id_prefix, info->type == IOT_RAW ? "ENC_" : ""); 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 décrochages. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool output_coder_hooks(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 *constant; /* Définition d'une constante */ size_t i; /* Boucle de parcours */ result = false; /* S'il n'y a pas lieu de traiter l'instruction */ if (coder->useless) { result = true; goto och_exit; } /* Ouverture de la destination */ fd = open_header_file(info->directory, NULL, "hooks", &created); if (fd == -1) goto och_exit; if (created) { write_header_file_license(fd, info, "hooks", "définition des décrochages pour instructions"); init_coder_hooks_file(fd, info); } /* Lancement des impressions */ constant = build_coder_main_identifier(coder, info); result = true; for (i = 0; i < coder->specs_count && result; i++) switch (info->type) { case IOT_UNDEFINED: assert(false); result = false; break; case IOT_RAW: result = write_encoding_spec_hooks(coder->specs[i], fd, constant, true); break; case IOT_FORMAT: assert(i == 0); result = write_encoding_spec_hooks(coder->specs[i], fd, constant, false); break; } free(constant); och_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 décrochages. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool fini_coder_hooks_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 fchf_exit; } dprintf(fd, "\n"); dprintf(fd, "};\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "#endif /* _%s_HOOKS_H */\n", info->guard); result = true; fchf_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 *constant; /* Définition d'une constante */ char *name; /* Désignation à manipuler */ result = false; /* S'il n'y a pas lieu de traiter l'instruction */ if (coder->useless) { result = true; goto ocd_exit; } /* Ouverture de la destination */ fd = open_header_file(info->directory, NULL, "descriptions", &created); if (fd == -1) goto ocd_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 */ constant = build_coder_main_identifier(coder, info); dprintf(fd, "\t[%s] = ", constant); free(constant); /* 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; ocd_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; fckf_exit: return result; }