/* Chrysalide - Outil d'analyse de fichiers binaires * conv.c - substitutions de valeurs depuis un contenu binaire * * Copyright (C) 2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA 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. * * OpenIDA 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 "conv.h" #include #include #include #include #include #include #include #include "helpers.h" /* Types d'expressions représentés */ typedef enum _ConvExprType { CET_NAME, /* Désignation de variable */ CET_NUMBER, /* Valeur codée en dur */ CET_COMPOSED, /* Agrégat de champs divers */ CET_UNARY, /* Opération unaire */ CET_BINARY, /* Opération binaire */ CET_COUNT } ConvExprType; /* Représentation d'une expression de conversion */ struct _conv_expr_t { ConvExprType type; bool declared; /* Expression déjà déclarée ? */ bool defined; /* Expression déjà définie ? */ union { /* CET_NAME */ char *name; /* Désignation de variable */ /* CET_NUMBER */ unsigned long number; /* Valeur durablement définie */ /* CET_COMPOSED */ struct { char **comp_items; /* Elements à agréger */ size_t comp_count; /* Quantité de ces éléments */ }; /* CET_UNARY */ struct { conv_expr_t *un_expr; /* Expression à traiter */ ConvUnaryOperation un_op; /* Type d'opération à mener */ }; /* CET_BINARY */ struct { conv_expr_t *bin_expr1; /* Expression à traiter */ conv_expr_t *bin_expr2; /* Expression à traiter */ ConvBinaryOperation bin_op; /* Type d'opération à mener */ }; }; }; /* Visite une expression en traitant en premier ses composantes. */ typedef bool (* visit_expr_fc) (conv_expr_t *, int, const coding_bits *, const conv_list *, void *); /* Détermine la taille en bits d'une expression donnée. */ static bool compute_conv_expr_size(const conv_expr_t *, const coding_bits *, const conv_list *, unsigned int *); /* Visite une expression en traitant en premier ses composantes. */ static bool visit_conv_expr(conv_expr_t *, visit_expr_fc, int, const coding_bits *, const conv_list *, void *); /* Retrouve si elle existe une variable manipulée. */ static bool find_var_by_name(const coding_bits *, const conv_list *, const char *, raw_bitfield **, conv_func **); /* S'assure du marquage des expressions pre-requises. */ static bool ensure_conv_expr_content_fully_marked(conv_expr_t *, const coding_bits *, const conv_list *); /* S'assure de la déclaration des expressions pre-requises. */ static bool ensure_conv_expr_content_fully_declared(conv_expr_t *, int, const coding_bits *, const conv_list *, unsigned int); /* S'assure de la définition des expressions pre-requises. */ static bool ensure_conv_expr_content_fully_defined(conv_expr_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *); /* Définit une expression utilisée dans une conversion. */ static bool define_conv_expr(conv_expr_t *, int, const coding_bits *, const conv_list *); /* ------------------------ LISTES D'ARGUMENTS DE CONVERSION ------------------------ */ /* Liste d'expressions utilisées en arguments de conversion */ struct _conv_arg_list_t { conv_expr_t **items; /* Liste d'expressions */ size_t count; /* Taille de cette liste */ }; /* S'assure du marquage des expressions pre-requises. */ static bool ensure_arg_list_content_fully_marked(conv_arg_list_t *, const coding_bits *, const conv_list *); /* S'assure de la déclaration des expressions pre-requises. */ static bool ensure_arg_list_content_fully_declared(conv_arg_list_t *, int, const coding_bits *, const conv_list *, unsigned int); /* S'assure de la définition des expressions pre-requises. */ static bool ensure_arg_list_content_fully_defined(conv_arg_list_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *); /* Définit les variables associées à un appel de fonction. */ static bool define_arg_list(conv_arg_list_t *, int, const coding_bits *, const conv_list *); /* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ /* Fonction de conversion */ struct _conv_func { 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 { conv_expr_t *expr; /* Valeur expressive directe */ struct { char *name; /* Fonction de conversion */ conv_arg_list_t *args; /* Liste des arguments */ }; }; }; /* Détermine la taille en bits du résultat d'une fonction. */ static bool compute_conv_func_size(const conv_func *, const coding_bits *, const conv_list *, unsigned int *); #define delete_conv_expr(e) /* ---------------------------- 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 */ }; /****************************************************************************** * * * Paramètres : name = désignation d'une variable quelconque. * * * * Description : Référence une variable en tant qu'expression de conversion. * * * * Retour : Nouvelle expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *build_conv_expr_from_name(char *name) { conv_expr_t *result; /* Structure à retourner */ result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); result->type = CET_NAME; result->name = make_string_lower(name); return result; } /****************************************************************************** * * * Paramètres : number = valeur à conserver dans sa forme brute. * * * * Description : Conserve une valeur en tant qu'expression de conversion. * * * * Retour : Nouvelle expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *build_conv_expr_from_number(unsigned long number) { conv_expr_t *result; /* Structure à retourner */ result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); result->type = CET_NUMBER; result->number = number; return result; } /****************************************************************************** * * * Paramètres : item1 = premier élément à agréger. * * item2 = second élément à agréger. * * * * Description : Construit une base d'expression de conversion composée. * * * * Retour : Nouvelle expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *build_composed_conv_expr(char *item1, char *item2) { conv_expr_t *result; /* Structure à retourner */ result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); result->type = CET_COMPOSED; result->comp_items = (char **)calloc(2, sizeof(char *)); result->comp_count = 2; result->comp_items[0] = make_string_lower(item1); result->comp_items[1] = make_string_lower(item2); return result; } /****************************************************************************** * * * Paramètres : expr = expression déjà en place à compléter. * * item = nouvel élément à agréger. * * * * Description : Etend une base d'expression de conversion composée. * * * * Retour : Expression en place et mise à jour. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *extend_composed_conv_expr(conv_expr_t *expr, char *item) { assert(expr->type == CET_COMPOSED); expr->comp_items = (char **)realloc(expr->comp_items, ++expr->comp_count * sizeof(char *)); expr->comp_items[expr->comp_count - 1] = make_string_lower(item); return expr; } /****************************************************************************** * * * Paramètres : expr = expression à encapsuler. * * op = opération unaire à associer à l'opération. * * * * Description : Traduit une opération unaire sur expression de conversion. * * * * Retour : Nouvelle expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *build_unary_conv_expr(conv_expr_t *expr, ConvUnaryOperation op) { conv_expr_t *result; /* Structure à retourner */ result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); result->type = CET_UNARY; result->un_expr = expr; result->un_op = op; return result; } /****************************************************************************** * * * Paramètres : expr1 = première expression à encapsuler. * * expr2 = seconde expression à encapsuler. * * op = opération binaire à associer à l'opération. * * * * Description : Traduit une opération binaire sur expression de conversion. * * * * Retour : Nouvelle expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_expr_t *build_binary_conv_expr(conv_expr_t *expr1, conv_expr_t *expr2, ConvBinaryOperation op) { conv_expr_t *result; /* Structure à retourner */ result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); result->type = CET_BINARY; result->bin_expr1 = expr1; result->bin_expr2 = expr2; result->bin_op = op; return result; } /****************************************************************************** * * * Paramètres : expr = première expression à 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 d'une expression donnée. * * * * Retour : true si la taille a pu être déterminée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool compute_conv_expr_size(const conv_expr_t *expr, const coding_bits *bits, const conv_list *list, unsigned int *size) { bool result; /* Bilan à retourner */ raw_bitfield *field; /* Eventuel champ brut associé */ conv_func *func; /* Eventuelle fonction liée */ size_t i; /* Boucle de parcours */ unsigned int tmp; /* Stockage temporaire */ switch (expr->type) { case CET_NAME: result = find_var_by_name(bits, list, expr->name, &field, &func); if (result) { if (field != NULL) *size = get_raw_bitfield_length(field); else result = compute_conv_func_size(func, bits, list, size); } break; case CET_COMPOSED: result = true; *size = 0; for (i = 0; i < expr->comp_count && result; i++) { if (isdigit(expr->comp_items[i][0])) *size += strlen(expr->comp_items[i]); else { if (!find_var_by_name(bits, list, expr->comp_items[i], &field, &func)) result = false; else { if (field != NULL) *size += get_raw_bitfield_length(field); else { result = compute_conv_func_size(func, bits, list, &tmp); *size += tmp; } } } } break; case CET_UNARY: result = compute_conv_expr_size(expr->un_expr, bits, list, size); break; case CET_BINARY: result = compute_conv_expr_size(expr->bin_expr1, bits, list, &tmp); if (result) result = compute_conv_expr_size(expr->bin_expr1, bits, list, size); if (tmp > *size) *size = tmp; break; default: result = false; break; } return result; } /****************************************************************************** * * * Paramètres : expr = première expression à encapsuler. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * data = éventuelle donnée à transmettre à chaque visite. * * * * Description : Visite une expression en traitant en premier ses composantes.* * * * Retour : Bilan des traitements effectués. * * * * Remarques : - * * * ******************************************************************************/ static bool visit_conv_expr(conv_expr_t *expr, visit_expr_fc visit, int fd, const coding_bits *bits, const conv_list *list, void *data) { bool result; /* Bilan à retourner */ switch (expr->type) { case CET_UNARY: result = visit_conv_expr(expr->un_expr, visit, fd, bits, list, data); break; case CET_BINARY: result = visit_conv_expr(expr->bin_expr1, visit, fd, bits, list, data); result = visit_conv_expr(expr->bin_expr2, visit, fd, bits, list, data); break; default: result = true; break; } result &= visit(expr, fd, bits, list, data); return result; } /****************************************************************************** * * * Paramètres : bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * name = déssignation de la variable recherchée. * * field = éventuel élement brut de décodage. * * func = éventuelle fonction de conversion pour intermédiaire.* * * * Description : Retrouve si elle existe une variable manipulée. * * * * Retour : Bilan des recherches : trouvaille ou non ? * * * * Remarques : - * * * ******************************************************************************/ static bool find_var_by_name(const coding_bits *bits, const conv_list *list, const char *name, raw_bitfield **field, conv_func **func) { bool result; /* Bilan à retourner */ raw_bitfield *cached_field; /* Champ, version cachée */ conv_func *cached_func; /* Fonction, version cachée */ cached_field = find_named_field_in_bits(bits, name); result = (cached_field != NULL); if (!result) { cached_func = find_named_conv_in_list(list, name); result = (cached_func != NULL); } else cached_func = NULL; if (field != NULL) *field = cached_field; if (func != NULL) *func = cached_func; if (!result) fprintf(stderr, "Variable '%s' not found!\n", name); return result; } /****************************************************************************** * * * Paramètres : expr = première expression à encapsuler. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * * * Description : S'assure du marquage des expressions pre-requises. * * * * Retour : Bilan des traitements effectués. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_conv_expr_content_fully_marked(conv_expr_t *expr, const coding_bits *bits, const conv_list *list) { bool mark_sub_expr(conv_expr_t *sub, int dummy, const coding_bits *bts, const conv_list *lst, void *unused) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ bool mark_by_name(const coding_bits *_bts, const conv_list *_lst, const char *name) { bool found; /* Bilan d'opération à renvoyer*/ raw_bitfield *field; /* Eventuel champ brut associé */ conv_func *func; /* Eventuelle fonction liée */ found = find_var_by_name(bts, lst, name, &field, &func); if (found) { if (field != NULL) mark_raw_bitfield_as_used(field); else /*if (func != NULL) */ mark_conv_func(func, bts, lst); printf(" VAR '%s' found (bf=%d fc=%d)\n", name, !!field, !!func); } else printf(" VAR '%s' not found...\n", name); return found; } /* Il est uniquement nécessaire de s'attacher aux références */ switch (sub->type) { case CET_NAME: result = mark_by_name(bits, lst, sub->name); break; case CET_COMPOSED: result = true; for (i = 0; i < sub->comp_count && result; i++) if (!isdigit(sub->comp_items[i][0])) result = mark_by_name(bits, lst, sub->comp_items[i]); break; default: result = true; break; } return result; } return visit_conv_expr(expr, (visit_expr_fc)mark_sub_expr, -1, bits, list, NULL); } /****************************************************************************** * * * Paramètres : expr = première expression à encapsuler. * * 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. * * wide = taille des mots décodés. * * * * Description : S'assure de la déclaration des expressions pre-requises. * * * * Retour : Bilan des traitements effectués. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_conv_expr_content_fully_declared(conv_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) { bool declare_sub_expr(conv_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, unsigned int *wide) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ /* Si l'expression a déjà été définie lors d'un précédent besoin... */ printf(" sub declared ? %d -- type = %d\n", sub->declared, sub->type); if (sub->declared) return true; bool declare_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, unsigned int _wide, const char *name) { bool found; /* Bilan d'opération à renvoyer*/ conv_func *func; /* Eventuelle fonction liée */ found = find_var_by_name(bts, lst, name, NULL, &func); if (found && func != NULL) { dprintf(_f, "\t\tuint%u_t val_%s;\n", _wide, name); printf("========= DECLARE for '%s'\n", name); found = declare_conv_func(func, _f, _bts, _lst, _wide); printf("========= END DECLARE for '%s'\n", name); } return found; } /* Il est uniquement nécessaire de s'attacher aux références */ switch (sub->type) { case CET_NAME: result = declare_by_name(f, bits, lst, *wide, sub->name); break; case CET_COMPOSED: result = true; for (i = 0; i < sub->comp_count && result; i++) if (!isdigit(sub->comp_items[i][0])) printf("... trying to declare... '%s'\n", sub->comp_items[i]); for (i = 0; i < sub->comp_count && result; i++) if (!isdigit(sub->comp_items[i][0])) result = declare_by_name(f, bits, lst, *wide, sub->comp_items[i]); break; default: result = true; break; } sub->declared = result; return result; } return visit_conv_expr(expr, (visit_expr_fc)declare_sub_expr, fd, bits, list, &wide); } /****************************************************************************** * * * Paramètres : expr = première expression à encapsuler. * * 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. * * * * Description : S'assure de la définition des expressions pre-requises. * * * * Retour : Bilan des traitements effectués. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_conv_expr_content_fully_defined(conv_expr_t *expr, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp) { typedef struct _def_info { const char *arch; const pre_processor *pp; } def_info; def_info info; /* Transmissions au visiteur */ bool define_sub_expr(conv_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, def_info *info) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ /* Si l'expression a déjà été définie lors d'un précédent besoin... */ if (sub->defined) return true; bool define_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, def_info *_info, const char *name) { bool found; /* Bilan d'opération à renvoyer*/ conv_func *func; /* Eventuelle fonction liée */ found = find_var_by_name(bts, lst, name, NULL, &func); if (found && func != NULL) found = define_conv_func(func, false, false, _f, _info->arch, _bts, _lst, _info->pp); return found; } /* Il est uniquement nécessaire de s'attacher aux références */ switch (sub->type) { case CET_NAME: result = define_by_name(f, bits, lst, info, sub->name); break; case CET_COMPOSED: result = true; for (i = 0; i < sub->comp_count && result; i++) if (!isdigit(sub->comp_items[i][0])) result = define_by_name(f, bits, lst, info, sub->comp_items[i]); break; default: result = true; break; } sub->defined = result; return result; } info.arch = arch; info.pp = pp; return visit_conv_expr(expr, (visit_expr_fc)define_sub_expr, fd, bits, list, &info); } /****************************************************************************** * * * Paramètres : expr = première expression à encapsuler. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * * * Description : Définit une expression utilisée dans une conversion. * * * * Retour : Bilan des traitements effectués. * * * * Remarques : - * * * ******************************************************************************/ static bool define_conv_expr(conv_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à retourner */ raw_bitfield *field; /* Eventuel champ brut associé */ conv_func *func; /* Eventuelle fonction liée */ unsigned int max_size; /* Quantité de bits totale */ size_t i; /* Boucle de parcours */ const char *cname; /* Raccourci de confort */ unsigned int used_size; /* Quantité de bits utilisée */ result = true; switch (expr->type) { case CET_NAME: if (!find_var_by_name(bits, list, expr->name, &field, &func)) result = false; else { if (field != NULL) dprintf(fd, "raw_%s", expr->name); else dprintf(fd, "val_%s", expr->name); } break; case CET_NUMBER: dprintf(fd, "%lu", expr->number); break; case CET_COMPOSED: result = compute_conv_expr_size(expr, bits, list, &max_size); printf("MAX SIZE :: %u\n", max_size); for (i = 0; i < expr->comp_count && result; i++) { cname = expr->comp_items[i]; if (i > 0) dprintf(fd, " | "); /* Constante binaire ? */ if (isdigit(cname[0])) { max_size -= strlen(cname); if (max_size == 0) dprintf(fd, "b%s", cname); else dprintf(fd, "b%s << %u", cname, max_size); } /* Ou variable définie ? */ else { result = find_var_by_name(bits, list, cname, &field, &func); if (result) { if (field != NULL) used_size = get_raw_bitfield_length(field); else /*result = */compute_conv_func_size(func, bits, list, &used_size); max_size -= used_size; if (field != NULL) { if (max_size == 0) dprintf(fd, "raw_%s", cname); else dprintf(fd, "raw_%s << %u", cname, max_size); } else { if (max_size == 0) dprintf(fd, "val_%s", cname); else dprintf(fd, "val_%s << %u", cname, max_size); } } } } break; case CET_UNARY: switch (expr->un_op) { case CUO_NOT: dprintf(fd, "!"); break; default: result = false; break; } result &= define_conv_expr(expr->un_expr, fd, bits, list); break; case CET_BINARY: dprintf(fd, "("); result = define_conv_expr(expr->bin_expr1, fd, bits, list); switch (expr->bin_op) { case CBO_EOR: dprintf(fd, " ^ "); break; default: result = false; break; } result &= define_conv_expr(expr->bin_expr2, fd, bits, list); dprintf(fd, ")"); break; default: result = false; break; } return result; } /* ---------------------------------------------------------------------------------- */ /* LISTES D'ARGUMENTS DE CONVERSION */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : expr = expression initial pour constituer une liste. * * * * Description : Crée une liste d'arguments de conversion. * * * * Retour : Nouvelle structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ conv_arg_list_t *build_conv_arg_list(conv_expr_t *expr) { conv_arg_list_t *result; /* Structure à retourner */ result = (conv_arg_list_t *)calloc(1, sizeof(conv_arg_list_t)); result->items = (conv_expr_t **)calloc(1, sizeof(conv_expr_t *)); result->count = 1; result->items[0] = expr; return result; } /****************************************************************************** * * * Paramètres : list = liste d'expressions à supprimer de la mémoire. * * * * Description : Libère la mémoire occupée par une liste d'expressions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_conv_arg_list(conv_arg_list_t *list) { size_t i; /* Boucle de parcours */ for (i = 0; i < list->count; i++) delete_conv_expr(list->items[i]); if (list->items != NULL) free(list->items); free(list); } /****************************************************************************** * * * Paramètres : list = liste d'expressions à supprimer de la mémoire. [OUT] * * expr = expression à ajouter à la liste courante. * * * * Description : Ajoute un élément à une liste d'arguments de conversion. * * * * Retour : Structure en place mise à jour. * * * * Remarques : - * * * ******************************************************************************/ conv_arg_list_t *extend_conv_arg_list(conv_arg_list_t *list, conv_expr_t *expr) { list->items = (conv_expr_t **)realloc(list->items, ++list->count * sizeof(conv_expr_t *)); list->items[list->count - 1] = expr; return list; } /****************************************************************************** * * * Paramètres : args = liste d'expressions à supprimer de la mémoire. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * * * Description : S'assure du marquage des expressions pre-requises. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_arg_list_content_fully_marked(conv_arg_list_t *args, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ result = true; for (i = 0; i < args->count && result; i++) result = ensure_conv_expr_content_fully_marked(args->items[i], bits, list); return result; } /****************************************************************************** * * * Paramètres : args = liste d'expressions à supprimer de la mémoire. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * wide = taille des mots décodés. * * * * Description : S'assure de la déclaration des expressions pre-requises. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_arg_list_content_fully_declared(conv_arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ result = true; for (i = 0; i < args->count && result; i++) result = ensure_conv_expr_content_fully_declared(args->items[i], fd, bits, list, wide); return result; } /****************************************************************************** * * * Paramètres : args = liste d'expressions à supprimer de la mémoire. * * 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. * * * * Description : S'assure de la définition des expressions pre-requises. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool ensure_arg_list_content_fully_defined(conv_arg_list_t *args, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ result = true; for (i = 0; i < args->count && result; i++) result = ensure_conv_expr_content_fully_defined(args->items[i], fd, arch, bits, list, pp); return result; } /****************************************************************************** * * * Paramètres : args = liste d'expressions à supprimer de la mémoire. * * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * * * * Description : Définit les variables associées à un appel de fonction. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool define_arg_list(conv_arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ result = true; for (i = 0; i < args->count && result; i++) { if (i > 0) dprintf(fd, ", "); result = define_conv_expr(args->items[i], fd, bits, list); } return result; } /* ---------------------------------------------------------------------------------- */ /* 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, conv_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, conv_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_conv_expr(func->expr); else { free(func->name); delete_conv_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 : - * * * ******************************************************************************/ static 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_conv_expr_size(func->expr, bits, list, size); return result; } /****************************************************************************** * * * Paramètres : func = fonction de conversion à manipuler. * * 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, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ if (func->is_expr) result = ensure_conv_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. * * 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, unsigned int wide) { bool result; /* Bilan à remonter */ /* Si la fonction a déjà été définie lors d'un précédent besoin... */ printf(" func declared ? %d\n", func->declared); if (func->declared) return true; if (func->is_expr) result = ensure_conv_expr_content_fully_declared(func->expr, fd, bits, list, wide); else result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, wide); func->declared = result; return result; } /****************************************************************************** * * * 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. * * * * 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 result; /* Bilan à remonter */ const char *callable; /* Fonction à appeler */ regex_t preg; /* Expression régulière */ int ret; /* Bilan d'une manipulation */ regmatch_t pmatch[3]; /* Correspondances de chaînes */ size_t cmplen; /* Taille de comparaison */ char *cast; /* Macro de transtypage */ /* 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_conv_expr_content_fully_defined(func->expr, fd, arch, bits, list, pp); else result = ensure_arg_list_content_fully_defined(func->args, fd, arch, bits, list, pp); /* 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) { ret = regcomp(&preg, "(g_([a-z0-9]*)_instruction)", REG_EXTENDED); if (ret != 0) { fprintf(stderr, "Internal error: bad regular expression.\n"); return false; } ret = regexec(&preg, callable, sizeof(pmatch) / sizeof(regmatch_t), pmatch, 0); if (ret == REG_NOMATCH) { fprintf(stderr, "Internal error: bad function for dealing wih instruction: '%s'.\n", callable); result = false; goto dcf_skip_internal; } /** * La variable de résultat est de type 'GArchInstruction', * donc toute fonction différente de g_arch_instruction_*() attend un transtypage... */ cmplen = MAX(strlen(arch), pmatch[2].rm_eo - pmatch[2].rm_so); if (strncmp("arch", &callable[pmatch[2].rm_so], cmplen) == 0) dprintf(fd, "\t\tif (!%s(instr, ", callable); else { cast = strndup(&callable[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); cast = make_string_upper(cast); dprintf(fd, "\t\tif (!%s(%s(instr), ", callable, cast); free(cast); } result &= define_arg_list(func->args, fd, bits, list); dprintf(fd, "))\n"); dcf_skip_internal: regfree(&preg); } /* 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_conv_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"); } 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; }