/* Chrysalide - Outil d'analyse de fichiers binaires * spec.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 Foobar. If not, see . */ #include "spec.h" #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 */ asm_syntax *syntax; /* Calligraphe d'assemblage */ conv_list *conversions; /* Conversions des données */ instr_hooks *hooks; /* Fonctions complémentaires */ decoding_rules *rules; /* Règles supplémentaires */ }; /****************************************************************************** * * * 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->syntax = create_asm_syntax(); result->conversions = create_conv_list(); result->hooks = create_instr_hooks(); result->rules = create_decoding_rules(); 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) { delete_operands_format(spec->format); delete_coding_bits(spec->bits); delete_asm_syntax(spec->syntax); delete_conv_list(spec->conversions); delete_instr_hooks(spec->hooks); delete_decoding_rules(spec->rules); 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 : 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 l'indicateur des écritures correctes d'assembleur. * * * * Retour : Structure assurant la gestion des éléments de syntaxe. * * * * Remarques : - * * * ******************************************************************************/ asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec) { return spec->syntax; } /****************************************************************************** * * * Paramètres : spec = spécification d'encodage à consulter. * * * * Description : Fournit la liste des fonctions de conversion. * * * * Retour : Structure assurant la gestion des fonctions de conversion. * * * * Remarques : - * * * ******************************************************************************/ conv_list *get_conversions_in_encoding_spec(const encoding_spec *spec) { return spec->conversions; } /****************************************************************************** * * * 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 à consulter. * * * * Description : Fournit un ensemble de règles supplémentaires éventuel. * * * * Retour : Structure assurant la gestion de ces règles. * * * * Remarques : - * * * ******************************************************************************/ decoding_rules *get_rules_in_encoding_spec(const encoding_spec *spec) { return spec->rules; } /****************************************************************************** * * * 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. * * subarch = sous-catégorie de cette même architecture. * * ins = désignation première de l'instruction manipulée. * * details = particularités de l'instruction. * * wide = taille des mots manipulés (en bits). * * 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_disass(const encoding_spec *spec, int fd, const char *arch, const char *subarch, const char *ins, const char *details, unsigned int wide, const pre_processor *pp) { bool result; /* Bilan à retourner */ bool bad_exit; /* Ajout d'une sortie d'échec ?*/ char *keyword; /* Mot clef appelable en code */ bool quick_exit; /* Inclusion de sortie rapide ?*/ const char *new_ins; /* Nouvelle définition de nom */ char *encoding_fc; /* Spécification d'encodage */ char *cast; /* Conversion vers le format */ result = true; bad_exit = false; keyword = make_callable(ins, false); dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n", arch, keyword, details, spec->lprefix, spec->index, wide); dprintf(fd, "\t{\n"); dprintf(fd, "\t\tGArchInstruction *instr;\n"); /* Déclaration des champs à retrouver */ result &= mark_syntax_items(spec->syntax, spec->bits, spec->conversions); result &= mark_decoding_rules(spec->rules, spec->bits, spec->conversions); result &= declare_used_bits_fields(spec->bits, fd, wide); result &= declare_used_intermediate_conversions(spec->conversions, fd, spec->bits, pp, wide); result &= declare_syntax_items(spec->syntax, fd, spec->bits, spec->conversions, wide); dprintf(fd, "\n"); result &= declare_hook_functions(spec->hooks, false, fd); /* Vérification que le décodage est possible */ result &= check_bits_correctness(spec->bits, fd); dprintf(fd, "\n"); /* Définition des champs bruts */ result &= define_used_bits_fields(spec->bits, fd); result &= define_used_intermediate_conversions(spec->conversions, fd, arch, spec->bits, pp, &bad_exit); /* Inclusion des éventuelles règles */ quick_exit = false; result &= write_decoding_rules(spec->rules, false, CAT_SEE, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); result &= write_decoding_rules(spec->rules, false, CAT_UNPREDICTABLE, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); /* Création de l'instruction en elle-même */ new_ins = get_new_keyword_from_syntax_items(spec->syntax); dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", arch, new_ins != NULL ? new_ins : ins); dprintf(fd, "\n"); /* Inscriptions des éventuelles fonctions ou propriété à lier */ result &= write_hook_functions(spec->hooks, false, fd); result &= write_decoding_rules(spec->rules, false, CAT_CHECKED_CALL, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); result &= write_decoding_rules(spec->rules, false, CAT_CALL, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); /* Création des opérandes */ result &= define_syntax_items(spec->syntax, fd, arch, spec->bits, spec->conversions, pp, &bad_exit); /* Conclusion de la procédure */ if (quick_exit) { dprintf(fd, "\t quick_exit:\n"); dprintf(fd, "\n"); } /* Encodage en dernier lieu */ asprintf(&encoding_fc, "g_%s_instruction_set_encoding", arch); cast = build_cast_if_needed(encoding_fc); dprintf(fd, "\t\t%s(%s(instr), \"%s\");\n", encoding_fc, cast, spec->prefix); free(cast); free(encoding_fc); /* Conclusion globale */ dprintf(fd, "\n"); dprintf(fd, "\t\treturn instr;\n"); dprintf(fd, "\n"); if (bad_exit) { dprintf(fd, "\t bad_exit:\n"); dprintf(fd, "\n"); dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n"); dprintf(fd, "\t\treturn NULL;\n"); dprintf(fd, "\n"); } dprintf(fd, "\t}\n"); dprintf(fd, "\n"); dprintf(fd, "\tif (result == NULL)\n"); dprintf(fd, "\t\tresult = %s_decode_%s%s_%s%u(raw);\n", arch, keyword, details, spec->lprefix, spec->index); dprintf(fd, "\n"); free(keyword); 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. * * subarch = sous-catégorie de cette même architecture. * * ins = désignation première de l'instruction manipulée. * * sep = caractère de séparation avant les détails. * * details = particularités de l'instruction. * * pp = pré-processeur pour les échanges de chaînes. * * 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 *subarch, const char *ins, char sep, const char *details, const pre_processor *pp, const char *prefix) { bool result; /* Bilan à retourner */ bool quick_exit; /* Inclusion de sortie rapide ?*/ bool bad_exit; /* Ajout d'une sortie d'échec ?*/ const char *new_ins; /* Nouvelle définition de nom */ result = true; /* 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"); result &= declare_hook_functions(spec->hooks, true, fd); /* Création de l'instruction en elle-même */ new_ins = get_new_keyword_from_syntax_items(spec->syntax); if (new_ins != NULL) dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, new_ins); else { if (sep == '\0') dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, ins); else dprintf(fd, "\tresult = g_%s_instruction_new(\"%s%c%s\");\n", arch, ins, sep, details); } dprintf(fd, "\n"); /* Inscriptions des éventuelles fonctions ou propriété à lier */ result &= write_hook_functions(spec->hooks, true, fd); quick_exit = false; result &= write_decoding_rules(spec->rules, true, CAT_CHECKED_CALL, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); result &= write_decoding_rules(spec->rules, true, CAT_CALL, fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); /* Création des opérandes */ dprintf(fd, "\tendian = g_arch_processor_get_endianness(G_ARCH_PROCESSOR(proc));\n"); dprintf(fd, "\n"); bad_exit = false; result &= define_operands_loading(spec->format, fd, arch, prefix, &bad_exit); /* Conclusion de la procédure */ dprintf(fd, "\treturn result;\n"); dprintf(fd, "\n"); if (quick_exit || bad_exit) { if (quick_exit) dprintf(fd, " quick_exit:\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"); } return result; }