diff options
Diffstat (limited to 'src/analysis/scan/exprs/call.c')
-rw-r--r-- | src/analysis/scan/exprs/call.c | 280 |
1 files changed, 180 insertions, 100 deletions
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c index dde627c..2fd1ff1 100644 --- a/src/analysis/scan/exprs/call.c +++ b/src/analysis/scan/exprs/call.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * call.c - organisation d'un appel à un élément de scan enregistré * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -38,27 +38,27 @@ /* Initialise la classe des appels de fonction avec arguments. */ -static void g_pending_call_class_init(GPendingCallClass *); +static void g_scan_pending_call_class_init(GScanPendingCallClass *); /* Initialise une instance d'appel de fonction avec arguments. */ -static void g_pending_call_init(GPendingCall *); +static void g_scan_pending_call_init(GScanPendingCall *); /* Supprime toutes les références externes. */ -static void g_pending_call_dispose(GPendingCall *); +static void g_scan_pending_call_dispose(GScanPendingCall *); /* Procède à la libération totale de la mémoire. */ -static void g_pending_call_finalize(GPendingCall *); +static void g_scan_pending_call_finalize(GScanPendingCall *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_pending_call_copy(GPendingCall *, const GPendingCall *); - /* Réduit une expression à une forme plus simple. */ -static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, GScanExpression **); +static ScanReductionState g_scan_pending_call_reduce(GScanPendingCall *, GScanContext *, GScanScope *, GScanExpression **); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_pending_call_copy(GScanPendingCall *, const GScanPendingCall *); @@ -68,7 +68,7 @@ static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); +G_DEFINE_TYPE(GScanPendingCall, g_scan_pending_call, G_TYPE_SCAN_NAMED_ACCESS); /****************************************************************************** @@ -83,21 +83,25 @@ G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); * * ******************************************************************************/ -static void g_pending_call_class_init(GPendingCallClass *klass) +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_pending_call_dispose; - object->finalize = (GObjectFinalizeFunc)g_pending_call_finalize; + 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->copy = (copy_expr_fc)g_pending_call_copy; - expr->reduce = (reduce_expr_fc)g_pending_call_reduce; + 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; } @@ -114,7 +118,7 @@ static void g_pending_call_class_init(GPendingCallClass *klass) * * ******************************************************************************/ -static void g_pending_call_init(GPendingCall *call) +static void g_scan_pending_call_init(GScanPendingCall *call) { call->args = NULL; call->count = 0; @@ -134,14 +138,14 @@ static void g_pending_call_init(GPendingCall *call) * * ******************************************************************************/ -static void g_pending_call_dispose(GPendingCall *call) +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_pending_call_parent_class)->dispose(G_OBJECT(call)); + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->dispose(G_OBJECT(call)); } @@ -158,12 +162,12 @@ static void g_pending_call_dispose(GPendingCall *call) * * ******************************************************************************/ -static void g_pending_call_finalize(GPendingCall *call) +static void g_scan_pending_call_finalize(GScanPendingCall *call) { if (call->args != NULL) free(call->args); - G_OBJECT_CLASS(g_pending_call_parent_class)->finalize(G_OBJECT(call)); + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->finalize(G_OBJECT(call)); } @@ -182,13 +186,13 @@ static void g_pending_call_finalize(GPendingCall *call) * * ******************************************************************************/ -GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) +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_PENDING_CALL, NULL); + result = g_object_new(G_TYPE_SCAN_PENDING_CALL, NULL); - if (!g_pending_call_create(G_PENDING_CALL(result), target, args, count)) + if (!g_scan_pending_call_create(G_SCAN_PENDING_CALL(result), target, args, count)) g_clear_object(&result); return result; @@ -211,12 +215,12 @@ GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpressio * * ******************************************************************************/ -bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) +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_named_access_create(G_NAMED_ACCESS(call), target); + result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(call), target); if (!result) goto exit; call->args = malloc(count * sizeof(GScanExpression *)); @@ -243,37 +247,6 @@ bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GSc /****************************************************************************** * * -* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - size_t i; /* Boucle de parcours */ - - class = G_SCAN_EXPRESSION_CLASS(g_pending_call_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->args = malloc(src->count * sizeof(GScanExpression *)); - dest->count = src->count; - - for (i = 0; i < src->count; i++) - dest->args[i] = g_scan_expression_duplicate(src->args[i]); - -} - - -/****************************************************************************** -* * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * * scope = portée courante des variables locales. * @@ -287,89 +260,196 @@ static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) * * ******************************************************************************/ -static bool g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static ScanReductionState g_scan_pending_call_reduce(GScanPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - bool result; /* Bilan à retourner */ - GNamedAccess *new; /* Eventuel étage suivant */ - GPendingCall *new_call; /* Version en appel */ - size_t i; /* Boucle de parcours */ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanNamedAccess *access; /* Autre vision de l'expression*/ + GRegisteredItem *resolved; /* Cible concrète obtenue */ + size_t i; /* Boucle de parcours #1 */ GScanExpression *arg; /* Argument réduit à échanger */ - GObject *final; /* Expression ou élément ? */ + 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. */ GScanExpression *new_next; /* Nouvelle version du suivant */ + GObject *final; /* Expression ou élément ? */ + bool valid; /* Validité de l'élément */ - result = _g_named_access_reduce(G_NAMED_ACCESS(expr), ctx, scope, out); + access = G_SCAN_NAMED_ACCESS(expr); - if (result && *out != NULL) - { - assert(G_IS_NAMED_ACCESS(*out)); + resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope); + + if (resolved == NULL) + result = SRS_UNRESOLVABLE; - new = G_NAMED_ACCESS(*out); - *out = NULL; + else + { + result = SRS_PENDING; - assert(new->target == NULL); - assert(G_IS_PENDING_CALL(new)); - assert(G_IS_REGISTERED_ITEM(new->resolved)); + /* Actualisation nécessaire des arguments ? */ - new_call = G_PENDING_CALL(new); + new_args = NULL; - for (i = 0; i < new_call->count; i++) + for (i = 0; i < expr->count; i++) { - result = g_scan_expression_reduce(new_call->args[i], ctx, scope, &arg); - if (!result) goto exit; + arg = expr->args[i]; - if (arg != NULL) + state = g_scan_expression_reduce(arg, ctx, scope, &new); + if (state == SRS_UNRESOLVABLE) { - g_object_unref(G_OBJECT(new_call->args[i])); - new_call->args[i] = arg; + 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[i]; + g_object_ref(G_OBJECT(new_args[k])); + } + + } + + new_args[i] = new; + + } + + else + { + if (new_args != NULL) + new_args[i] = new; + } } - result = g_registered_item_run_call(new->resolved, - new_call->args, - new_call->count, - ctx, scope, &final); + /* Suite des traitements */ - if (result && final != NULL) + if (result == SRS_WAIT_FOR_SCAN) { /** - * 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. + * Si changement il y a eu... */ - if (!G_IS_REGISTERED_ITEM(final)) + if (new_args != NULL) { - assert(new->next == NULL); - *out = G_SCAN_EXPRESSION(final); + *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_registered_item_run_call(resolved, + expr->args, + expr->count, + ctx, scope, &final); else - { - assert(new->next != NULL); + valid = g_registered_item_run_call(resolved, + new_args, + expr->count, + ctx, scope, &final); - new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); - assert(G_IS_NAMED_ACCESS(new_next)); + 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_REGISTERED_ITEM(final)) + { + assert(access->next == NULL); - g_named_access_set_base(G_NAMED_ACCESS(new_next), G_REGISTERED_ITEM(final)); + *out = G_SCAN_EXPRESSION(final); - result = g_scan_expression_reduce(new_next, ctx, scope, out); + result = SRS_REDUCED; - if (result && *out == NULL) - *out = new_next; + } else + { + assert(access->next != NULL); + + new_next = g_scan_named_access_duplicate(access->next, resolved); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + g_object_unref(G_OBJECT(new_next)); + } + } + else + result = SRS_UNRESOLVABLE; + } - exit: + /* Libération locale des arguments reconstruits */ - g_object_unref(G_OBJECT(new)); + 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])); + } + +} |