/* 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 Foobar. If not, see . */ #include "coder.h" #include #include #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 */ 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 */ 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 */ 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 */ }; /* --------------------------- 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 *); /* Imprime dans un flux donné un commentaire de propriété. */ static void write_owner_comments(const rented_coder *, int, const char *, const char *, char); /* Construit un chemin d'accès à un modèle de fichier de code. */ static char *build_template_filename(const rented_coder *, const char *, const char *, char); /* Définit un modèle d'en-tête de définitions. */ static bool create_template_file(const rented_coder *, const char *, const char *, char); /* Construit un chemin d'accès à un fichier de code source. */ static char *build_code_filename(const rented_coder *, const char *, const char *, const char *, char); /* Ouvre un fichier en écriture pour y placer du code. */ static int create_code_file(const rented_coder *, const char *, const char *, const char *, char); /* 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); /* 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); /* ---------------------------------------------------------------------------------- */ /* CONSTRUCTION SELON COMMANDES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : - * * * * Description : Débute la définition d'une fonction de désassemblage. * * * * Retour : Gestionnaire mis en place. * * * * Remarques : - * * * ******************************************************************************/ rented_coder *create_coder(void) { rented_coder *result; /* Structure à renvoyer */ result = (rented_coder *)calloc(1, sizeof(rented_coder)); result->pp = create_pre_processor(); result->cur_spec = create_encoding_spec(); return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : Supprime le codeur de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_coder(rented_coder *coder) { size_t i; /* Boucle de parcours */ delete_pre_processor(coder->pp); if (coder->ins != NULL) free(coder->ins); if (coder->raw_details != NULL) { free(coder->raw_details); free(coder->details); } 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 : Détermine si les propriétés de base d'un codeur sont là. * * * * Retour : Bilan de l'état opérationnel. * * * * Remarques : - * * * ******************************************************************************/ bool do_basic_checks_with_coder(const rented_coder *coder) { 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; } /****************************************************************************** * * * 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; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * type = type de définition à attendre. * * * * Description : Spécifie le type de format à prendre en compte (E/S). * * * * Retour : - * * * * 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; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * arch = désignation pour le code de l'architecture lue. * * * * Description : Détermine l'architecture visée par les traitements. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void set_coder_arch(rented_coder *coder, const char *arch) { coder->arch = arch; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * header = base des définitions de protection d'en-têtes. * * * * Description : Définit la base des protections des fichiers d'en-tête. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void set_coder_header_base(rented_coder *coder, const char *header) { coder->header = header; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * prefix = préfixe pour les types d'opérandes. * * * * Description : Définit le préfixe pour les opérandes chargées par format. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void set_coder_const_prefix(rented_coder *coder, const char *prefix) { coder->const_prefix = 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; } /****************************************************************************** * * * 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(""); } } /* ---------------------------------------------------------------------------------- */ /* 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(); } /* ---------------------------------------------------------------------------------- */ /* GENERATIONS DE CODE SOURCE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : S'assure de la présence du répertoire de sortie du code. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool check_gen_dir(const rented_coder *coder) { bool has_gen; /* Répertoire de sortie présent*/ int ret; /* Bilan d'un appel externe */ has_gen = (access(".gen", F_OK) == 0); if (has_gen) { ret = access(".gen", W_OK | X_OK); if (ret == -1) { perror("access()"); return false; } } else { ret = mkdir(".gen", 0777); if (ret != 0) { perror("mkdir()"); return false; } } return true; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * fd = descripteur de flux ouvert en écriture. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom brut du fichier à ouvrir. * * ext = extension à donner au fichier à ouvrir. * * * * Description : Imprime dans un flux donné un commentaire de propriété. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext) { dprintf(fd, "\n"); dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); dprintf(fd, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext); dprintf(fd, " *\n"); dprintf(fd, " * %s\n", coder->copyright); dprintf(fd, " *\n"); dprintf(fd, " * This file is part of Chrysalide.\n"); dprintf(fd, " *\n"); dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n"); dprintf(fd, " * it under the terms of the GNU General Public License as published by\n"); dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n"); dprintf(fd, " * (at your option) any later version.\n"); dprintf(fd, " *\n"); dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n"); dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); dprintf(fd, " * GNU General Public License for more details.\n"); dprintf(fd, " *\n"); dprintf(fd, " * You should have received a copy of the GNU General Public License\n"); dprintf(fd, " * along with Foobar. If not, see .\n"); dprintf(fd, " */\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom brut du fichier à ouvrir. * * ext = extension à donner au fichier à ouvrir. * * * * Description : Construit un chemin d'accès à un modèle de fichier de code. * * * * Retour : Chaîne de caractères à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext) { char *result; /* Chaîne construite à renvoyer*/ size_t length; /* Taille du nom de fichier */ 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); } 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); } return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom brut du fichier à ouvrir. * * ext = extension à donner au fichier à ouvrir. * * * * Description : Définit un modèle d'en-tête de définitions. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext) { char *pathname; /* Chemin d'accès à constituer */ bool exist; /* Note une présence établie */ int fd; /* Flux ouvert pour création */ 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; pathname = build_template_filename(coder, prefix, name, ext); exist = (access(pathname, W_OK) == 0); if (exist) { free(pathname); return true; } fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644); if (fd == -1) perror("open()"); free(pathname); if (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)); dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname); dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname); free(uprefix); free(uname); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "##INCLUDES##\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); dprintf(fd, "\n"); } else { dprintf(fd, "#include \"%sopcodes.h\"\n", valid_prefix); dprintf(fd, "\n"); dprintf(fd, "##INCLUDES##\n"); } close(fd); } return (fd != -1); } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * intput = fichier d'entrée initial à référencer. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom brut du fichier à ouvrir. * * ext = extension à donner au fichier à ouvrir. * * * * Description : Construit un chemin d'accès à un fichier de code source. * * * * Retour : Chaîne de caractères à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext) { char *result; /* Chaîne construite à renvoyer*/ char *orig; /* Fichier d'origine tronqué */ char *point; /* Position d'un point */ size_t length; /* Taille du nom de fichier */ orig = strdup(input); point = strstr(orig, "."); if (point != NULL) *point = '\0'; 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); } 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); } free(orig); return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * * intput = fichier d'entrée initial à référencer. * * prefix = type d'encodage à répercuter sur le nom de fichier. * * name = nom brut du fichier à ouvrir. * * ext = extension à donner au fichier à ouvrir. * * * * Description : Ouvre un fichier en écriture pour y placer du code. * * * * Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static int create_code_file(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext) { int result; /* Descripteur à retourner */ char *pathname; /* Chemin d'accès à constituer */ if (!check_gen_dir(coder)) return -1; pathname = build_code_filename(coder, input, prefix, name, ext); result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (result == -1) perror("open()"); free(pathname); return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain.* * * * Description : Débute la définition des fonctions issues des spécifications.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool dump_all_routines_using_coder(const rented_coder *coder) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #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 */ result = true; for (i = 0; i < count_encodings(coder->pp) && result; i++) { encoding = find_encoding(coder->pp, i); /* 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 */ /* remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); unlink(remove); free(remove); */ remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); unlink(remove); free(remove); /* Fichier de définitions */ dash = strchr(coder->ins, '-'); 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 { filename = strdup(coder->ins); dash = strchr(filename, '-'); *dash = '\0'; /* 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); } } /* Créations ? */ else { /* Fichier de déclarations */ if (!create_template_file(coder, encoding->dest, "opcodes", 'h')) return false; header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h'); if (header_fd == -1) return false; /* Fichier de définitions */ dash = strchr(coder->ins, '-'); if (dash == NULL) { if (!create_template_file(coder, encoding->dest, coder->ins, 'c')) return false; code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c'); } else { filename = strdup(coder->ins); dash = strchr(filename, '-'); *dash = '\0'; if (!create_template_file(coder, encoding->dest, filename, 'c')) return false; code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c'); free(filename); } if (code_fd == -1) { close(header_fd); /* remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); unlink(remove); free(remove); */ remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); unlink(remove); free(remove); return false; } /* Production de code... */ switch (coder->type) { case IOT_UNDEFINED: assert(false); result = false; break; case IOT_RAW: result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); break; case IOT_FORMAT: result = dump_all_matching_specs_from_format(coder, encoding, header_fd, code_fd); break; } close(header_fd); close(code_fd); } } return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement d'humain. * * encoding = sélection de l'encodage à traiter. * * hfd = flux ouvert en écriture pour les déclarations. * * cfd = flux ouvert en écriture pour les définitions. * * * * Description : Ecrit une partie des fonctions issues des spécifications. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) { bool result; /* Bilan à retourner */ char *keyword; /* Mot clef appelable en code */ unsigned int wide; /* Taille des mots */ size_t i; /* Boucle de parcours */ encoding_spec *spec; /* Définition à traiter */ coding_bits *bits; /* Gestionnaire de bits */ size_t maxlen; /* Taille à compléter */ result = true; keyword = make_callable(coder->ins, false); /* Recherche de la taille des mots */ wide = -1; for (i = 0; i < coder->specs_count; i++) { spec = coder->specs[i]; if (!has_encoding_spec_prefix(spec, encoding->src)) continue; bits = get_bits_in_encoding_spec(spec); wide = 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(wide != -1); /* 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, "\n"); /* Désassemblage : définitions */ dprintf(cfd, "\n"); dprintf(cfd, "/******************************************************************************\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Description : Décode une instruction de type '%s'.", coder->ins); maxlen = 28 - strlen(coder->ins); if (maxlen < 28) dprintf(cfd, "%*s\n", (int)maxlen, "*"); else dprintf(cfd, "*\n"); dprintf(cfd, " *\n"); dprintf(cfd, "* Retour : 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 *%s_read_%sinstr_%s%s(uint%u_t raw)", coder->arch, encoding->dest, keyword, coder->details, wide); dprintf(cfd, "\n"); dprintf(cfd, "{"); dprintf(cfd, "\n"); dprintf(cfd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); dprintf(cfd, "\n"); dprintf(cfd, "\tresult = NULL;\n"); dprintf(cfd, "\n"); for (i = 0; i < coder->specs_count && result; i++) { spec = coder->specs[i]; if (!has_encoding_spec_prefix(spec, encoding->src)) continue; result = write_encoding_spec_disass(spec, cfd, coder->arch, encoding->dest, coder->ins, coder->details, wide, coder->pp); } dprintf(cfd, "\treturn result;\n"); dprintf(cfd, "\n"); dprintf(cfd, "}\n"); dprintf(cfd, "\n"); free(keyword); return result; } /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement d'humain. * * encoding = sélection de l'encodage à traiter. * * hfd = flux ouvert en écriture pour les déclarations. * * cfd = flux ouvert en écriture pour les définitions. * * * * Description : Ecrit une partie des fonctions issues des spécifications. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) { bool result; /* Bilan à retourner */ char *keyword; /* Mot clef appelable en code */ size_t maxlen; /* Taille à compléter */ encoding_spec *spec; /* Définition à traiter */ keyword = make_callable(coder->ins, false); /* 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, "("); 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, "* *\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"); 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, "("); 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"); assert(coder->specs_count == 1); spec = coder->specs[0]; assert(has_encoding_spec_prefix(spec, encoding->src)); result = write_encoding_spec_format_disass(spec, cfd, coder->arch, encoding->dest, coder->ins, coder->separator, coder->raw_details, coder->pp, coder->const_prefix); dprintf(cfd, "}\n"); dprintf(cfd, "\n"); free(keyword); return result; }