diff options
Diffstat (limited to 'src/analysis/scan/exprs/call.c')
-rw-r--r-- | src/analysis/scan/exprs/call.c | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c new file mode 100644 index 0000000..3997ff6 --- /dev/null +++ b/src/analysis/scan/exprs/call.c @@ -0,0 +1,467 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call.c - organisation d'un appel à un élément de scan enregistré + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "call.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "call-int.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des appels de fonction avec arguments. */ +static void g_scan_pending_call_class_init(GScanPendingCallClass *); + +/* Initialise une instance d'appel de fonction avec arguments. */ +static void g_scan_pending_call_init(GScanPendingCall *); + +/* Supprime toutes les références externes. */ +static void g_scan_pending_call_dispose(GScanPendingCall *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_pending_call_finalize(GScanPendingCall *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *, GScanContext *, GScanScope *, GScanExpression **); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_pending_call_copy(GScanPendingCall *, const GScanPendingCall *); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GScanPendingCall, g_scan_pending_call, G_TYPE_SCAN_NAMED_ACCESS); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des appels de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_class_init(GScanPendingCallClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + GScanNamedAccessClass *access; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_call_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_pending_call_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_pending_call_reduce; + + access = G_SCAN_NAMED_ACCESS_CLASS(klass); + + access->copy = (copy_scan_access_fc)g_scan_pending_call_copy; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser. * +* * +* Description : Initialise une instance d'appel de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_init(GScanPendingCall *call) +{ + call->args = NULL; + call->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_dispose(GScanPendingCall *call) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < call->count; i++) + g_clear_object(&call->args[i]); + + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->dispose(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_finalize(GScanPendingCall *call) +{ + if (call->args != NULL) + free(call->args); + + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->finalize(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PENDING_CALL, NULL); + + if (!g_scan_pending_call_create(G_SCAN_PENDING_CALL(result), target, args, count)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Met en place une expression d'appel. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pending_call_create(GScanPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(call), target); + if (!result) goto exit; + + call->args = malloc(count * sizeof(GScanExpression *)); + call->count = count; + + for (i = 0; i < count; i++) + { + call->args[i] = args[i]; + g_object_ref(G_OBJECT(args[i])); + } + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanNamedAccess *access; /* Autre vision de l'expression*/ + GScanRegisteredItem *resolved; /* Cible concrète obtenue */ + size_t i; /* Boucle de parcours #1 */ + GScanExpression *arg; /* Argument réduit à échanger */ + GScanExpression *new; /* Nouvelle réduction obtenue */ + ScanReductionState state; /* Etat synthétisé d'un élément*/ + size_t k; /* Boucle de parcours #2 */ + GScanExpression **new_args; /* Nouvelle séquence d'args. */ + GObject *final; /* Expression ou élément ? */ + bool valid; /* Validité de l'élément */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + + access = G_SCAN_NAMED_ACCESS(expr); + + resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope); + + if (resolved == NULL) + result = SRS_UNRESOLVABLE; + + else + { + result = SRS_PENDING; + + /* Actualisation nécessaire des arguments ? */ + + new_args = NULL; + + for (i = 0; i < expr->count; i++) + { + arg = expr->args[i]; + + state = g_scan_expression_reduce(arg, ctx, scope, &new); + if (state == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + break; + } + + if (state == SRS_WAIT_FOR_SCAN) + result = SRS_WAIT_FOR_SCAN; + + if (new != arg) + { + if (new_args == NULL) + { + new_args = calloc(expr->count, sizeof(GScanExpression *)); + + for (k = 0; k < i; k++) + { + new_args[k] = expr->args[k]; + g_object_ref(G_OBJECT(new_args[k])); + } + + } + + new_args[i] = new; + + } + + else + { + if (new_args != NULL) + new_args[i] = new; + + else + g_object_unref(G_OBJECT(new)); + + } + + } + + /* Suite des traitements */ + + if (result == SRS_WAIT_FOR_SCAN) + { + /** + * Si changement il y a eu... + */ + if (new_args != NULL) + { + *out = g_scan_pending_call_new(NULL, new_args, expr->count); + + /** + * Fonctionnement équivalent de : + * g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved); + */ + G_SCAN_NAMED_ACCESS(*out)->resolved = resolved; + g_object_ref(G_OBJECT(resolved)); + + if (G_SCAN_NAMED_ACCESS(expr)->next != NULL) + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next); + + } + + } + + else if (result == SRS_PENDING) + { + if (new_args == NULL) + valid = g_scan_registered_item_run_call(resolved, + expr->args, + expr->count, + ctx, scope, &final); + else + valid = g_scan_registered_item_run_call(resolved, + new_args, + expr->count, + ctx, scope, &final); + + if (valid && final != NULL) + { + /** + * Si le produit de l'appel à la fonction est une expression d'évaluation + * classique, alors ce produit constitue la réduction finale de la chaîne. + * + * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne. + */ + if (!G_IS_SCAN_REGISTERED_ITEM(final)) + { + if (access->next != NULL) + result = SRS_UNRESOLVABLE; + + else + { + *out = G_SCAN_EXPRESSION(final); + g_object_ref(G_OBJECT(final)); + + result = SRS_REDUCED; + + } + + } + else + { + assert(access->next != NULL); + + new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final)); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + g_object_unref(G_OBJECT(new_next)); + + } + + } + + else + result = SRS_UNRESOLVABLE; + + g_clear_object(&final); + + } + + /* Libération locale des arguments reconstruits */ + + if (new_args != NULL) + { + for (i = 0; i < expr->count; i++) + g_clear_object(&new_args[i]); + } + + g_object_unref(G_OBJECT(resolved)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * +* * +* Description : Reproduit un accès en place dans une nouvelle instance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_copy(GScanPendingCall *dest, const GScanPendingCall *src) +{ + GScanNamedAccessClass *class; /* Classe parente à solliciter */ + size_t i; /* Boucle de parcours */ + + class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_call_parent_class); + + class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src)); + + dest->args = malloc(src->count * sizeof(GScanExpression *)); + dest->count = src->count; + + for (i = 0; i < src->count; i++) + { + dest->args[i] = src->args[i]; + g_object_ref(G_OBJECT(src->args[i])); + } + +} |