/* 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 Foobar. If not, see . */ #include "manager.h" #include #include #include #include #include #include "../helpers.h" #include "../qckcall.h" /* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ /* Fonction de conversion */ struct _conv_func { bool used; /* Conversion utilisée ? */ bool intermediate; /* Variable intermédiaire ? */ bool declared; /* Expression déjà déclarée ? */ bool defined; /* Expression déjà définie ? */ 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 */ }; }; }; /* ---------------------------- 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. * * * * Description : Indique la nature d'une conversion : fonction ou expression ?* * * * Retour : Indication sur la constitution interne de la conversion. * * * * Remarques : - * * * ******************************************************************************/ bool is_conv_func_expression(const conv_func *func) { return func->is_expr; } /****************************************************************************** * * * 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 */ func->used = true; func->intermediate |= inter; 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 à manipuler. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * pp = pré-processeur pour les échanges de chaînes. * * wide = taille des mots décodés. * * * * 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 pre_processor *pp, unsigned int wide) { bool result; /* Bilan à remonter */ printf(" -> declaration for '%s': declared ? %d - expr ? %d\n", func->dest, func->declared, func->is_expr); assert(func->used); /* 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, pp, wide); else result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, pp, wide); if (result && func->intermediate) { if (!func->is_expr && is_operand_producer(pp, func->name)) dprintf(fd, "\t\tGArchOperand *val_%s;\n", func->dest); else dprintf(fd, "\t\tuint%u_t val_%s;\n", wide, func->dest); } func->declared = result; return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à consulter. * * * * Description : Indique si une conversion a déjà été définie. * * * * Retour : Etat de la définition. * * * * Remarques : - * * * ******************************************************************************/ bool is_conv_func_already_defined(const conv_func *func) { return func->defined; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * last = précise si la conversion est la dernière. * * internal = indique le type de manipulation finale. * * fd = descripteur d'un flux ouvert en écriture. * * arch = architecture visée par l'opération globale. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * pp = pré-processeur pour les échanges de chaînes. * * 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, bool last, bool internal, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) { bool result; /* Bilan à remonter */ const char *callable; /* Fonction à appeler */ /* Si la fonction a déjà été définie lors d'un précédent besoin... */ if (func->defined) return true; if (func->is_expr) result = ensure_arg_expr_content_fully_defined(func->expr, fd, arch, bits, list, pp, exit); else result = ensure_arg_list_content_fully_defined(func->args, fd, arch, bits, list, pp, exit); /* Nom de la fonction effectivement appelée */ if (!func->is_expr) { callable = find_macro(pp, func->name); if (callable == NULL) callable = func->name; } else callable = NULL; if (last && callable == NULL) { fprintf(stderr, "Error: expected function to store '%s'.\n", func->dest); return false; } /* Dernier niveau : la variable de destination est imposée ! */ if (last) { /* Si l'on doit manipuler une propriété d'instructon... */ if (internal) result = checked_call_instr_func(false, callable, func->args, fd, bits, list, pp); /* Si on doit constituer un opérande à ajouter... */ else { if (strchr(callable, '(') == NULL) dprintf(fd, "\t\top = %s(", callable); else dprintf(fd, "\t\top = %s", callable); result &= define_arg_list(func->args, fd, bits, list); dprintf(fd, ");\n"); } } /* On constitue une variable intermédiaire, dont on peut conserver le nom ! */ else { dprintf(fd, "\t\tval_%s = ", func->dest); if (func->is_expr) result &= define_arg_expr(func->expr, fd, bits, list); else { dprintf(fd, "%s(", callable); result = define_arg_list(func->args, fd, bits, list); dprintf(fd, ")"); } dprintf(fd, ";\n"); if (!func->is_expr && is_operand_producer(pp, func->name)) { dprintf(fd, "\t\tif (val_%s == NULL) goto bad_exit;\n", func->dest); *exit = true; } } 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; } /****************************************************************************** * * * Paramètres : list = liste de fonctions de conversion à consulter. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * pp = pré-processeur pour les échanges de chaînes. * * wide = taille des mots décodés. * * * * Description : Déclare l'ensemble des variables intermédiaires. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool declare_used_intermediate_conversions(const conv_list *list, int fd, const coding_bits *bits, const pre_processor *pp, unsigned int wide) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ conv_func *func; /* Conversion à traiter */ result = true; for (i = 0; i < list->func_count && result; i++) { func = list->functions[i]; if (func->used && func->intermediate) result = declare_conv_func(func, fd, bits, list, pp, wide); } return result; } /****************************************************************************** * * * Paramètres : list = liste de fonctions de conversion à consulter. * * fd = descripteur d'un flux ouvert en écriture. * * arch = architecture visée par l'opération globale. * * bits = gestionnaire des bits d'encodage. * * pp = pré-processeur pour les échanges de chaînes. * * exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : Définit l'ensemble des variables intermédiaires. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool define_used_intermediate_conversions(const conv_list *list, int fd, const char *arch, const coding_bits *bits, const pre_processor *pp, bool *exit) { bool result; /* Bilan à remonter */ bool got_one; /* Suit le nombre d'impressions*/ size_t i; /* Boucle de parcours */ conv_func *func; /* Conversion à traiter */ result = true; got_one = false; for (i = 0; i < list->func_count && result; i++) { func = list->functions[i]; if (func->used && func->intermediate) { result = define_conv_func(func, false, false, fd, arch, bits, list, pp, exit); got_one = true; } } if (got_one) dprintf(fd, "\n"); return result; }