/* Chrysalide - Outil d'analyse de fichiers binaires * manager.c - substitutions de valeurs depuis un contenu binaire * * Copyright (C) 2016-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 "manager.h" #include #include #include #include #include #include #include "../helpers.h" #include "../qckcall.h" /* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ /* Fonction de conversion */ struct _conv_func { char *dest; /* Variable de destination */ bool is_expr; /* Choix du contenu réel */ union { arg_expr_t *expr; /* Valeur expressive directe */ struct { char *name; /* Fonction de conversion */ arg_list_t *args; /* Liste des arguments */ }; }; bool used_as_inter; /* Variable intermédiaire ? */ bool used_as_op; /* Opérande finale d'instruct° */ bool declared; /* Expression déjà déclarée ? */ bool defined; /* Expression déjà définie ? */ }; /* Indique si l'utilisation en intermédiaire est brute ou non. */ static bool is_conv_func_raw_as_inter(const conv_func *); /* ---------------------------- ENSEMBLES DE CONVERSIONS ---------------------------- */ /* Liste des fonctions de conversions présentes */ struct _conv_list { conv_func **functions; /* Fonctions de conversion */ size_t func_count; /* Nombre de ces fonctions */ }; /* ---------------------------------------------------------------------------------- */ /* CONVERSION DES ARGUMENTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : dest = désignation de la variable de destination. * * expr = expression dont la valeur est à assigner. * * * * Description : Définit une conversion à partir d'une simple expression. * * * * Retour : Structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_func *make_conv_from_expr(char *dest, arg_expr_t *expr) { conv_func *result; /* Conversion à retourner */ result = (conv_func *)calloc(1, sizeof(conv_func)); result->dest = make_string_lower(dest); result->is_expr = true; result->expr = expr; return result; } /****************************************************************************** * * * Paramètres : dest = désignation de la variable de destination. * * func = nom de la fonction assurant le calcul de valeur. * * args = argument(s) à fournir à cette fonction. * * * * Description : Définit une conversion à partir d'une function à appeler. * * * * Retour : Structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_func *make_conv_from_func(char *dest, char *func, arg_list_t *args) { conv_func *result; /* Conversion à retourner */ result = (conv_func *)calloc(1, sizeof(conv_func)); result->dest = make_string_lower(dest); result->is_expr = false; result->name = func; result->args = args; return result; } /****************************************************************************** * * * Paramètres : func = éléments de conversion à supprimer de la mémoire. * * * * Description : Libère de la mémoire une conversion enregistrée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_conv_func(conv_func *func) { if (func->is_expr) delete_arg_expr(func->expr); else { free(func->name); delete_arg_list(func->args); } free(func); } /****************************************************************************** * * * Paramètres : func = fonction de conversion à consulter. * * * * Description : Indique la variable de destination d'une conversion. * * * * Retour : Désignation humaine de la variable de destination. * * * * Remarques : - * * * ******************************************************************************/ const char *get_conv_dest_name(const conv_func *func) { return func->dest; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à consulter. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * size = taille déterminée avec précision. [OUT] * * * * Description : Détermine la taille en bits du résultat d'une fonction. * * * * Retour : true si la taille a pu être déterminée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool compute_conv_func_size(const conv_func *func, const coding_bits *bits, const conv_list *list, unsigned int *size) { bool result; /* Bilan à retourner */ result = func->is_expr; if (result) result = compute_arg_expr_size(func->expr, bits, list, size); return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * inter = note un résultat de conversion comme intermédiaire. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * * * Description : Marque les champs utilisés par une fonction de conversion. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool mark_conv_func(conv_func *func, bool inter, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ if (inter) func->used_as_inter = true; else { assert(!func->is_expr); func->used_as_op = true; } if (func->is_expr) result = ensure_arg_expr_content_fully_marked(func->expr, bits, list); else result = ensure_arg_list_content_fully_marked(func->args, bits, list); return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à consulter. * * * * Description : Indique si l'utilisation en intermédiaire est brute ou non. * * * * Retour : true si une variable brute est à manipuler, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool is_conv_func_raw_as_inter(const conv_func *func) { bool result; /* Résultat à faire remonter */ if (func->is_expr) result = true; else result = (strcmp(func->name, "UInt") == 0); return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * fd = descripteur d'un flux ouvert en écriture. * * inter = note un résultat de conversion comme intermédiaire. * * * * Description : Imprime la désignation de la destination d'une conversion. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void write_conv_func(conv_func *func, int fd, bool inter) { bool as_raw; /* Choix logique du format */ if (inter) as_raw = is_conv_func_raw_as_inter(func); else as_raw = false; if (as_raw) dprintf(fd, "val_%s", func->dest); else dprintf(fd, "op_%s", func->dest); } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * tab = décalage éventuel selon l'inclusion. * * * * Description : Déclare les variables associées à une fonction de conversion.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab) { bool result; /* Bilan à remonter */ bool as_raw; /* Choix logique du format */ unsigned int wide; /* Taille des mots */ off_t start; /* Point de départ dans le code*/ off_t end; /* Point d'arrivée dans le code*/ assert(func->used_as_inter || func->used_as_op); /** * Si la fonction a déjà été définie lors d'un précédent besoin... */ if (func->declared) return true; if (func->is_expr) result = ensure_arg_expr_content_fully_declared(func->expr, fd, bits, list, tab); else result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, tab); if (result) { if (func->used_as_inter) { as_raw = is_conv_func_raw_as_inter(func); /** * Si la variable intermédiaire n'est pas brute, deux cas de figure * sont possibles : * * - la variable est un objet purement intermédiaire. * - la variable est un object qui sera également utilisé en opérande. * * Dans les deux cas, on laisse la déclaration en tant qu'opérande * rédiger la déclaration car il s'agit de déclarations identiques. */ if (as_raw) { wide = count_coded_bits(bits); start = lseek(fd, 0, SEEK_CUR); dprintf(fd, "\t%suint%u_t ", tab, wide); write_conv_func(func, fd, true); dprintf(fd, ";"); end = lseek(fd, 0, SEEK_CUR); dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/"); dprintf(fd, "* Champ brut à décoder */\n"); } } if (func->used_as_op || (func->used_as_inter && !as_raw)) { start = lseek(fd, 0, SEEK_CUR); dprintf(fd, "\t%sGArchOperand *", tab); write_conv_func(func, fd, false); dprintf(fd, ";"); end = lseek(fd, 0, SEEK_CUR); dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/"); dprintf(fd, "* Opérande à intégrer */\n"); } } func->declared = result; return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * tab = décalage éventuel selon l'inclusion. * * optional = indique si l'opérande finale est optionnelle. * * exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : Définit les variables associées à une fonction de conversion.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool define_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool optional, bool *exit) { bool result; /* Bilan à remonter */ bool as_raw; /* Choix logique du format */ /** * Si la fonction a déjà été définie lors d'un précédent besoin... */ if (func->defined) { // TODO : faire un object_ref() si c'est un objet //assert(0); return true; } if (func->is_expr) result = ensure_arg_expr_content_fully_defined(func->expr, fd, bits, list, tab, exit); else result = ensure_arg_list_content_fully_defined(func->args, fd, bits, list, tab, exit); if (result) { if (func->used_as_inter) { as_raw = is_conv_func_raw_as_inter(func); /** * Se référer au besoin aux commentaires de declare_conv_func(). */ if (as_raw) { dprintf(fd, "\t%s", tab); write_conv_func(func, fd, true); dprintf(fd, " = "); if (func->is_expr) result = define_arg_expr(func->expr, fd, bits, list); else { assert(strcmp(func->name, "UInt") == 0); assert(get_arg_list_size(func->args) == 1); result = define_arg_list(func->args, fd, bits, list); } dprintf(fd, ";\n"); dprintf(fd, "\n"); } } if (func->used_as_op || (func->used_as_inter && !as_raw)) { dprintf(fd, "\t%s", tab); write_conv_func(func, fd, false); dprintf(fd, " = %s(", func->name); result = define_arg_list(func->args, fd, bits, list); dprintf(fd, ");\n"); if (optional) { if (as_raw) { fprintf(stderr, "%s can not be optional and used as intermediate value as the same time!\n", func->dest); result = false; } } else { dprintf(fd, "\t%sif (", tab); write_conv_func(func, fd, false); dprintf(fd, " == NULL) goto bad_exit;\n"); *exit = true; } dprintf(fd, "\n"); } func->defined = result; } return result; } /* ---------------------------------------------------------------------------------- */ /* ENSEMBLES DE CONVERSIONS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouvelle liste vierge de fonctions de conversion. * * * * Retour : Nouvelle structure prête à emploi. * * * * Remarques : - * * * ******************************************************************************/ conv_list *create_conv_list(void) { conv_list *result; /* Définition vierge à renvoyer*/ result = (conv_list *)calloc(1, sizeof(conv_list)); return result; } /****************************************************************************** * * * Paramètres : list = ensemble de fonctions de conversion à supprimer. * * * * Description : Supprime de la mémoire une de fonctions de conversion. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_conv_list(conv_list *list) { size_t i; /* Boucle de parcours */ for (i = 0; i < list->func_count; i++) delete_conv_func(list->functions[i]); if (list->functions != NULL) free(list->functions); free(list); } /****************************************************************************** * * * Paramètres : list = liste de fonctions de conversion à compléter. * * func = nom de la fonction assurant le calcul de valeur. * * * * Description : Enregistre une function de conversion du brut à l'utile. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void register_conversion(conv_list *list, conv_func *func) { list->functions = (conv_func **)realloc(list->functions, ++list->func_count * sizeof(conv_func *)); list->functions[list->func_count - 1] = func; } /****************************************************************************** * * * Paramètres : list = liste de fonctions de conversion à consulter. * * name = désignation humaine du champ à retrouver. * * * * Description : Recherche un résultat précis dans une liste de fonctions. * * * * Retour : Structure associée au résulat trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ conv_func *find_named_conv_in_list(const conv_list *list, const char *name) { conv_func *result; /* Fonction à retourner */ size_t i; /* Boucle de parcours */ const char *dest; /* Nom de variable existante */ result = NULL; for (i = 0; i < list->func_count && result == NULL; i++) { dest = get_conv_dest_name(list->functions[i]); if (strcmp(dest, name) == 0) result = list->functions[i]; } return result; }