/* Chrysalide - Outil d'analyse de fichiers binaires
* rules.h - prototypes pour les variations de décodage selon certaines conditions
*
* 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 "rules.h"
#include
#include
#include
#include "helpers.h"
/* -------------------------- CONDITIONS DE DECLENCHEMENTS -------------------------- */
/* Expression d'une condition */
struct _cond_expr
{
bool is_simple; /* Sélection de champ */
union
{
struct
{
char *variable; /* Variable manipulée */
CondCompType comp; /* Type de comparaison */
char *bvalue; /* Valeur binaire comparée */
} simple;
struct
{
cond_expr *a; /* Première sous-expression */
CondOpType operator; /* Relation entre expressions */
cond_expr *b; /* Seconde sous-expression */
} composed;
};
};
/* Libère de la mémoire une expression conditionnelle. */
static void delete_cond_expr(cond_expr *);
/* Traduit en code une expression de condition. */
static bool write_cond_expr(const cond_expr *, int, const coding_bits *);
/* ------------------------- REGLES ET ACTIONS CONSEQUENTES ------------------------- */
/* Règle particulière */
typedef struct _extra_rule
{
cond_expr *expr; /* Expression de déclenchement */
CondActionType action; /* Conséquence d'une validation*/
char *details; /* Eventuel complément d'info. */
} extra_rule;
/* Règles de décodage supplémentaires */
struct _decoding_rules
{
extra_rule *extra; /* Règles conditionnelles */
size_t extra_count; /* Nombre de ces règles */
};
/* ---------------------------------------------------------------------------------- */
/* CONDITIONS DE DECLENCHEMENTS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : variable = désignation de la variable à manipuler. *
* comp = type de comparaison à utiliser. *
* bvalue = valeur binaire à comparer. *
* *
* Description : Crée une expression conditionnelle simple. *
* *
* Retour : Structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
cond_expr *build_simple_cond_expression(char *variable, CondCompType comp, char *bvalue)
{
cond_expr *result; /* Structure à retourner */
result = (cond_expr *)calloc(1, sizeof(cond_expr));
result->is_simple = true;
result->simple.variable = make_string_lower(variable);
result->simple.comp = comp;
result->simple.bvalue = bvalue;
return result;
}
/******************************************************************************
* *
* Paramètres : a = première expression à intégrer. *
* operator = type de comparaison à utiliser. *
* b = second expression à intégrer. *
* *
* Description : Crée une expression conditionnelle composée. *
* *
* Retour : Structure mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
cond_expr *build_composed_cond_expression(cond_expr *a, CondOpType operator, cond_expr *b)
{
cond_expr *result; /* Structure à retourner */
result = (cond_expr *)calloc(1, sizeof(cond_expr));
result->is_simple = false;
result->composed.a = a;
result->composed.operator = operator;
result->composed.b = b;
return result;
}
/******************************************************************************
* *
* Paramètres : expr = représentation d'expression à traiter. *
* *
* Description : Libère de la mémoire une expression conditionnelle. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void delete_cond_expr(cond_expr *expr)
{
if (expr->is_simple)
{
free(expr->simple.variable);
free(expr->simple.bvalue);
}
else
{
delete_cond_expr(expr->composed.a);
delete_cond_expr(expr->composed.b);
}
free(expr);
}
/******************************************************************************
* *
* Paramètres : expr = expression simple ou composée à transposer. *
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* *
* Description : Traduit en code une expression de condition. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool write_cond_expr(const cond_expr *expr, int fd, const coding_bits *bits)
{
bool result; /* Bilan à renvoyer */
const raw_bitfield *bf; /* Champ de bits de définition */
result = true;
dprintf(fd, "(");
if (expr->is_simple)
{
bf = find_named_field_in_bits(bits, expr->simple.variable);
if (bf == NULL)
{
fprintf(stderr, "Error: no bitfield defined the requested variable '%s'.\n", expr->simple.variable);
result = false;
goto wce_exit;
}
if (get_raw_bitfield_length(bf) != strlen(expr->simple.bvalue))
{
fprintf(stderr, "Error: variable '%s' and provided value sizes do not match (%u vs %zu).\n",
expr->simple.variable, get_raw_bitfield_length(bf), strlen(expr->simple.bvalue));
result = false;
goto wce_exit;
}
dprintf(fd, "raw_%s", expr->simple.variable);
switch (expr->simple.comp)
{
case CCT_EQUAL:
dprintf(fd, " == ");
break;
case CCT_DIFF:
dprintf(fd, " != ");
break;
}
dprintf(fd, "b%s", expr->simple.bvalue);
}
else
{
result = write_cond_expr(expr->composed.a, fd, bits);
if (!result) goto wce_exit;
switch (expr->composed.operator)
{
case COT_AND:
dprintf(fd, " && ");
break;
case COT_OR:
dprintf(fd, " || ");
break;
}
result = write_cond_expr(expr->composed.b, fd, bits);
if (!result) goto wce_exit;
}
dprintf(fd, ")");
wce_exit:
return result;
}
/* ---------------------------------------------------------------------------------- */
/* REGLES ET ACTIONS CONSEQUENTES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouveau rassemblement de règles de décodage. *
* *
* Retour : Nouvelle structure prête à emploi. *
* *
* Remarques : - *
* *
******************************************************************************/
decoding_rules *create_decoding_rules(void)
{
decoding_rules *result; /* Définition vierge à renvoyer*/
result = (decoding_rules *)calloc(1, sizeof(decoding_rules));
return result;
}
/******************************************************************************
* *
* Paramètres : rules = ensemble de règles de décodage à supprimer. *
* *
* Description : Supprime de la mémoire un ensemble de règles supplémentaires.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void delete_decoding_rules(decoding_rules *rules)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < rules->extra_count; i++)
{
delete_cond_expr(rules->extra[i].expr);
if (rules->extra[i].details)
free(rules->extra[i].details);
}
if (rules->extra != NULL)
free(rules->extra);
free(rules);
}
/******************************************************************************
* *
* Paramètres : rules = ensemble de règles à compléter. *
* expr = représentation d'expression à conserver. *
* action = conséquence associée à la règle. *
* details = éventuel complément d'informations. *
* *
* Description : Ajoute une règle complète à la définition d'un codage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void register_conditional_rule(decoding_rules *rules, cond_expr *expr, CondActionType action, const char *details)
{
extra_rule *rule; /* Nouvelle prise en compte */
rules->extra = (extra_rule *)realloc(rules->extra, ++rules->extra_count * sizeof(extra_rule));
rule = &rules->extra[rules->extra_count - 1];
rule->expr = expr;
rule->action = action;
rule->details = (details != NULL ? make_callable(details, false) : NULL);
}
/******************************************************************************
* *
* Paramètres : rules = ensemble de règles à consulter. *
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : Traduit en code les éventuelles règles présentes. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool write_decoding_rules(decoding_rules *rules, int fd, const coding_bits *bits, bool *exit)
{
bool result; /* Bilan à remonter */
const extra_rule *rule; /* Règle en cours d'écriture */
size_t i; /* Boucle de parcours */
result = true;
*exit = false;
for (i = 0; i < rules->extra_count; i++)
{
rule = &rules->extra[i];
dprintf(fd, "\t\tif ");
result = write_cond_expr(rule->expr, fd, bits);
if (!result) break;
dprintf(fd, "\n");
dprintf(fd, "\t\t{\n");
switch (rule->action)
{
case CAT_SEE:
if (rule->details == NULL)
{
fprintf(stderr, "Error: directive 'see' must provide additional details.\n");
result = false;
goto wcsr_exit;
}
dprintf(fd, "\t\t\tinstr = armv7_read_instr_%s", rule->details);
/* TODO : adapter les paramètres d'appel selon le 'coder' */
dprintf(fd, "(_raw);\n");
dprintf(fd, "\t\t\tgoto quick_exit;\n");
*exit = true;
break;
case CAT_UNPREDICTABLE:
break;
}
dprintf(fd, "\t\t}\n");
dprintf(fd, "\n");
}
wcsr_exit:
return result;
}