/* Chrysalide - Outil d'analyse de fichiers binaires * encoding.c - représentation complète d'un encodage * * 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 "encoding.h" #include #include #include #include #include #include "helpers.h" #include "qckcall.h" /* Mémorisation d'un encodage complet */ struct _encoding_spec { char *prefix; /* Distinction principale */ char *lprefix; /* Distinction en minuscules */ unsigned int index; /* Distinction secondaire */ operands_format *format; /* Définition des opérandes */ coding_bits *bits; /* Encodage des bits associés */ instr_hooks *hooks; /* Fonctions complémentaires */ encoding_syntax **syntaxes; /* Définitions déjà en place */ size_t syntax_count; /* Nombre de ces définitions */ }; /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau suivi de l'encodage d'une instruction. * * * * Retour : Nouvelle structure prête à emploi. * * * * Remarques : - * * * ******************************************************************************/ encoding_spec *create_encoding_spec(void) { encoding_spec *result; /* Définition vierge à renvoyer*/ result = (encoding_spec *)calloc(1, sizeof(encoding_spec)); result->format = create_operands_format(); result->bits = create_coding_bits(); result->hooks = create_instr_hooks(); return result; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à libérer de la mémoire. * * * * Description : Supprime de la mémoire un suivi d'encodage d'une instruction.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_encoding_spec(encoding_spec *spec) { size_t i; /* Boucle de parcours */ delete_operands_format(spec->format); delete_coding_bits(spec->bits); delete_instr_hooks(spec->hooks); if (spec->syntaxes != NULL) { for (i = 0; i < spec->syntax_count; i++) delete_encoding_syntax(spec->syntaxes[i]); free(spec->syntaxes); } free(spec); } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à compléter. * * prefix = distinction principale entre les définitions. * * index = distinction secondaire entre les définitions. * * * * Description : Définit le nom de code d'une spécification d'encodage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void define_encoding_spec_code_name(encoding_spec *spec, char *prefix, unsigned int index) { spec->prefix = prefix; spec->lprefix = make_string_lower(strdup(prefix)); spec->index = index; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * prefix = distinction principale entre les définitions. * * * * Description : Indique si une spécification se range dans une catégorie. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ bool has_encoding_spec_prefix(const encoding_spec *spec, const char *prefix) { bool result; /* Bilan à renvoyer */ if (spec->prefix == NULL && prefix == NULL) result = true; else if (spec->prefix != NULL && prefix != NULL) result = strcmp(spec->prefix, prefix) == 0; else result = false; return result; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Construit la distinction propre à un encodage. * * * * Retour : Distinction à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ char *build_encoding_spec_prefix(const encoding_spec *spec) { char *result; /* Chaîne à retourner */ assert(spec->lprefix); asprintf(&result, "%s%u", spec->lprefix, spec->index); return result; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Fournit le gestionnaire des définitions d'opérandes. * * * * Retour : Structure assurant la définition des opérandes. * * * * Remarques : - * * * ******************************************************************************/ operands_format *get_format_in_encoding_spec(const encoding_spec *spec) { return spec->format; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Fournit le gestionnaire des bits d'un encodage d'instruction.* * * * Retour : Structure assurant le suivi des bits. * * * * Remarques : - * * * ******************************************************************************/ coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec) { return spec->bits; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Fournit la liste des fonctions à lier à une instruction. * * * * Retour : Structure assurant la gestion des fonctions de conversion. * * * * Remarques : - * * * ******************************************************************************/ instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec) { return spec->hooks; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à étendre. * * * * Description : Enregistre une définition de syntaxe supplémentaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void push_new_encoding_syntax(encoding_spec *spec) { encoding_syntax *syntax; /* Définition à compléter */ syntax = create_encoding_syntax(); spec->syntaxes = realloc(spec->syntaxes, ++spec->syntax_count * sizeof(encoding_syntax *)); spec->syntaxes[spec->syntax_count - 1] = syntax; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Fournit un lien vers la définition de syntaxe courante. * * * * Retour : Définition en cours d'édition. * * * * Remarques : - * * * ******************************************************************************/ encoding_syntax *get_current_encoding_syntax(const encoding_spec *spec) { encoding_syntax *result; /* Définition à retourner */ if (spec->syntax_count == 0) result = NULL; else result = spec->syntaxes[spec->syntax_count - 1]; return result; } /****************************************************************************** * * * Paramètres : spec = spécification servant de base à l'opération. * * fd = descripteur d'un flux ouvert en écriture. * * arch = architecture visée par l'opération. * * id = désignation de l'identifiant d'instruction. * * pp = pré-processeur pour les échanges de chaînes. * * * * Description : Traduit en code une sous-fonction de désassemblage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool write_encoding_spec_raw_disass(const encoding_spec *spec, int fd, const char *arch, const char *id, const pre_processor *pp) { bool result; /* Bilan à retourner */ bool openbar; /* Syntaxe unique par défaut ? */ disass_assert *dassert; /* Eventuelles conditions */ char *suffix; /* Complément d'identifiant */ char *sid; /* Base de sous-identifiant */ size_t i; /* Boucle de parcours */ bool op_decl; /* Suivi des déclaration #1 */ bool imm_decl; /* Suivi des déclaration #2 */ bool bad_exit; /* Ajout d'une sortie d'échec ?*/ bool quick_exit; /* Inclusion de sortie rapide ?*/ char *encoding_fc; /* Spécification d'encodage */ char *cast; /* Conversion vers le format */ result = true; /* Détermination de la forme du code */ openbar = (spec->syntax_count == 1); if (openbar) { dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]); openbar = is_disass_assert_empty(dassert); } else { for (i = 0; i < spec->syntax_count && result; i++) { dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]); if (is_disass_assert_empty(dassert)) { fprintf(stderr, "The syntax definition #%zu has no entry conditions!\n", i); result = false; } } } if (!result) goto wesrd_exit; /* Déclarations préalables */ dprintf(fd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); for (i = 0; i < spec->syntax_count && result; i++) result = mark_syntax_items(spec->syntaxes[i], spec->bits); if (!result) goto wesrd_exit; result = declare_used_bits_fields(spec->bits, fd); if (!result) goto wesrd_exit; if (openbar) { result = declare_encoding_syntax(spec->syntaxes[0], fd, spec->bits); if (!result) goto wesrd_exit; } dprintf(fd, "\n"); /* Vérification que le décodage est possible */ result &= check_bits_correctness(spec->bits, fd); if (!result) goto wesrd_exit; dprintf(fd, "\n"); /* Initialisation du resultat d'un point de vue global */ if (!openbar) { dprintf(fd, "\tresult = NULL;\n"); dprintf(fd, "\n"); } /* Définition des champs bruts */ result = define_used_bits_fields(spec->bits, fd); if (!result) goto wesrd_exit; suffix = build_encoding_spec_prefix(spec); make_string_upper(suffix); asprintf(&sid, "%s_%s", id, suffix); free(suffix); for (i = 0; i < spec->syntax_count && result; i++) { if (spec->syntax_count > 1) result = write_encoding_syntax(spec->syntaxes[i], fd, arch, spec->bits, openbar, id, sid, &i, &bad_exit); else result = write_encoding_syntax(spec->syntaxes[i], fd, arch, spec->bits, openbar, id, sid, NULL, &bad_exit); } free(sid); if (!result) goto wesrd_exit; /* Encodage en dernier lieu */ asprintf(&encoding_fc, "g_%s_instruction_set_encoding", arch); cast = build_cast_if_needed(encoding_fc); if (!openbar) dprintf(fd, "\tif (result != NULL)\n"); dprintf(fd, "\t%s%s(%s(result), \"%s\");\n", openbar ? "" : "\t", encoding_fc, cast, spec->prefix); free(cast); free(encoding_fc); dprintf(fd, "\n"); /* Conclusion globale */ dprintf(fd, "\treturn result;\n"); dprintf(fd, "\n"); if (bad_exit) { dprintf(fd, " bad_exit:\n"); dprintf(fd, "\n"); dprintf(fd, "\tg_object_unref(G_OBJECT(result));\n"); dprintf(fd, "\treturn NULL;\n"); dprintf(fd, "\n"); } wesrd_exit: return result; } /****************************************************************************** * * * Paramètres : spec = spécification servant de base à l'opération. * * fd = descripteur d'un flux ouvert en écriture. * * arch = architecture visée par l'opération. * * id = identifiant unique attribué à l'instruction. * * prefix = préfixe pour le type de définitions d'opérandes. * * * * Description : Traduit en code une sous-fonction de désassemblage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const char *arch, const char *id, const char *prefix) { bool result; /* Bilan à retourner */ bool bad_exit; /* Ajout d'une sortie d'échec ?*/ conv_list *conversions; /* Conversions de la syntaxe */ decoding_rules *rules; /* Règles de la syntaxe */ /* Déclarations préalables */ dprintf(fd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); dprintf(fd, "\tSourceEndian endian; /* Boutisme lié au binaire */\n"); dprintf(fd, "\n"); /* Création de l'instruction en elle-même */ dprintf(fd, "\tresult = g_%s_instruction_new(%s);\n", arch, id); dprintf(fd, "\n"); bad_exit = false; assert(spec->syntax_count <= 1); if (spec->syntax_count > 0) { conversions = get_conversions_in_encoding_syntax(spec->syntaxes[0]); rules = get_rules_in_encoding_syntax(spec->syntaxes[0]); result = write_decoding_rules(rules, CAT_CHECKED_CALL, fd, arch, spec->bits, conversions, "", &bad_exit); if (!result) goto wesfd_exit; result = write_decoding_rules(rules, CAT_CALL, fd, arch, spec->bits, conversions, "", &bad_exit); if (!result) goto wesfd_exit; } /* Création des opérandes */ dprintf(fd, "\tendian = g_arch_processor_get_endianness(proc);\n"); dprintf(fd, "\n"); result = define_operands_loading(spec->format, fd, arch, prefix, &bad_exit); if (!result) goto wesfd_exit; /* Conclusion de la procédure */ dprintf(fd, "\treturn result;\n"); dprintf(fd, "\n"); if (bad_exit) { if (bad_exit) dprintf(fd, " bad_exit:\n"); dprintf(fd, "\n"); dprintf(fd, "\tg_object_unref(G_OBJECT(result));\n"); dprintf(fd, "\treturn NULL;\n"); dprintf(fd, "\n"); } wesfd_exit: return result; } /****************************************************************************** * * * Paramètres : spec = spécification servant de base à l'opération. * * fd = descripteur d'un flux ouvert en écriture. * * name = désignation de l'identifiant d'instruction. * * * * Description : Imprime les mots clefs de chaque syntaxe. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool write_encoding_spec_keywords(const encoding_spec *spec, int fd, const char *name) { bool result; /* Bilan à retourner */ char *suffix; /* Complément d'identifiant */ size_t i; /* Boucle de parcours */ asm_pattern *pattern; /* Définition d'assemblage */ const char *keyword; /* Mot clef principal */ result = true; suffix = build_encoding_spec_prefix(spec); make_string_upper(suffix); for (i = 0; i < spec->syntax_count; i++) { /* Impression de la colonne */ if (spec->syntax_count == 1) dprintf(fd, "\t[%s_%s]", name, suffix); else dprintf(fd, "\t[%s_%s_%zu]", name, suffix, i); /* Impression des décrochages */ pattern = get_asm_pattern_in_encoding_syntax(spec->syntaxes[i]); keyword = get_keyword_from_asm_pattern(pattern); dprintf(fd, " = \"%s\",\n", keyword); } free(suffix); return result; } /****************************************************************************** * * * Paramètres : spec = spécification servant de base à l'opération. * * fd = descripteur d'un flux ouvert en écriture. * * name = désignation de l'identifiant d'instruction. * * * * Description : Imprime la définition d'un sous-identifiant pour un encodage.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool write_encoding_spec_subid(const encoding_spec *spec, int fd, const char *name) { bool result; /* Bilan à retourner */ char *suffix; /* Complément d'identifiant */ size_t i; /* Boucle de parcours */ instr_id *subid; /* Sous-identifiant de syntaxe */ unsigned int idval; /* Identifiant unique attribué */ result = true; suffix = build_encoding_spec_prefix(spec); make_string_upper(suffix); for (i = 0; i < spec->syntax_count; i++) { subid = get_encoding_syntax_subid(spec->syntaxes[i]); idval = get_instruction_id_value(subid); if (spec->syntax_count == 1) dprintf(fd, "\t%s_%s = %u,\n", name, suffix, idval); else dprintf(fd, "\t%s_%s_%zu = %u,\n", name, suffix, i, idval); } free(suffix); return result; } /****************************************************************************** * * * Paramètres : spec = spécification servant de base à l'opération. * * fd = descripteur d'un flux ouvert en écriture. * * name = désignation de l'identifiant d'instruction. * * refine = utilisation d'un identifiant plus précis ? * * * * Description : Imprime d'éventuels décrochages spécifiés pour un encodage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool write_encoding_spec_hooks(const encoding_spec *spec, int fd, const char *name, bool refine) { bool result; /* Bilan à retourner */ char *suffix; /* Complément d'identifiant */ size_t i; /* Boucle de parcours */ if (!has_hook_functions(spec->hooks)) result = true; else { if (refine) { suffix = build_encoding_spec_prefix(spec); make_string_upper(suffix); for (i = 0; i < spec->syntax_count; i++) { /* Impression de la colonne */ if (spec->syntax_count == 1) dprintf(fd, "\t[%s_%s]", name, suffix); else dprintf(fd, "\t[%s_%s_%zu]", name, suffix, i); /* Impression des décrochages */ dprintf(fd, " = {\n", name); result = write_hook_functions(spec->hooks, fd); dprintf(fd, "\t},\n", name); } free(suffix); } else { /* Impression de la colonne */ dprintf(fd, "\t[%s]", name); /* Impression des décrochages */ dprintf(fd, " = {\n", name); result = write_hook_functions(spec->hooks, fd); dprintf(fd, "\t},\n", name); } } return result; }