summaryrefslogtreecommitdiff
path: root/tools/d2c/assert
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-04-02 11:58:42 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-04-02 12:39:30 (GMT)
commit1db4ef323b7a76093356ae76268132f3760e1631 (patch)
treefec36ee0ec1b6b2010b62ca4177edca0e31e2114 /tools/d2c/assert
parent1bc80837dde03a32b5ab185067f7bd4c499a9850 (diff)
Rewritten the whole instruction definition format.
Diffstat (limited to 'tools/d2c/assert')
-rw-r--r--tools/d2c/assert/Makefile.am37
-rw-r--r--tools/d2c/assert/decl.h37
-rw-r--r--tools/d2c/assert/grammar.y133
-rw-r--r--tools/d2c/assert/manager.c365
-rw-r--r--tools/d2c/assert/manager.h80
-rw-r--r--tools/d2c/assert/tokens.l41
6 files changed, 693 insertions, 0 deletions
diff --git a/tools/d2c/assert/Makefile.am b/tools/d2c/assert/Makefile.am
new file mode 100644
index 0000000..34d5b1c
--- /dev/null
+++ b/tools/d2c/assert/Makefile.am
@@ -0,0 +1,37 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p assert_
+
+AM_LFLAGS = -P assert_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=assert_get_lineno \
+ -Dyy_scan_string=assert__scan_string \
+ -Dyy_delete_buffer=assert__delete_buffer
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
+
+
+noinst_LTLIBRARIES = libd2cassert.la
+
+.NOTPARALLEL: $(noinst_LTLIBRARIES)
+
+libd2cassert_la_SOURCES = \
+ decl.h \
+ manager.h manager.c \
+ tokens.l \
+ grammar.y
+
+# _GNU_SOURCE : asprintf
+libd2cassert_la_CFLAGS = -D_GNU_SOURCE
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+EXTRA_DIST = tokens.h
diff --git a/tools/d2c/assert/decl.h b/tools/d2c/assert/decl.h
new file mode 100644
index 0000000..b18edbc
--- /dev/null
+++ b/tools/d2c/assert/decl.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ASSERT_DECL_H
+#define _TOOLS_D2C_ASSERT_DECL_H
+
+
+#include "manager.h"
+
+
+
+/* Interprête des données relatives à une série de conditions. */
+bool load_assertions_from_raw_block(disass_assert *, const char *);
+
+
+
+#endif /* _TOOLS_D2C_ASSERT_DECL_H */
diff --git a/tools/d2c/assert/grammar.y b/tools/d2c/assert/grammar.y
new file mode 100644
index 0000000..3db47e6
--- /dev/null
+++ b/tools/d2c/assert/grammar.y
@@ -0,0 +1,133 @@
+
+%{
+
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(disass_assert *, char *);
+
+%}
+
+
+%code requires {
+
+#include "decl.h"
+
+}
+
+
+%union {
+
+ char *string; /* Chaîne de caractères */
+
+ struct
+ {
+ char *field; /* Nom de champ de bits */
+ DisassCondOp op; /* Opération impliquée */
+ char *value; /* Valeur soumise à condition */
+
+ } cond_info;
+
+}
+
+
+%define api.pure full
+
+%parse-param { disass_assert *dassert }
+
+%code provides {
+
+#define YY_DECL \
+ int assert_lex(YYSTYPE *yylvalp)
+
+YY_DECL;
+
+}
+
+
+%token CR
+%token EQ NE
+%token AND OR
+%token FIELD VALUE
+
+%type <cond_info> condition
+%type <string> FIELD
+%type <string> VALUE
+
+
+%%
+
+
+assert : /* empty */
+ | conditions assert
+
+conditions : condition { register_disass_assert(dassert, DCG_UNIQ, $1.field, $1.op, $1.value); }
+ | condition AND and_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+ | condition OR or_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+and_conds : condition { register_disass_assert(dassert, DCG_AND, $1.field, $1.op, $1.value); }
+ | condition AND and_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+or_conds : condition { register_disass_assert(dassert, DCG_OR, $1.field, $1.op, $1.value); }
+ | condition AND or_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+condition : FIELD EQ VALUE { $$.field = $1; $$.op = DCO_EQ; $$.value = $3; }
+ | FIELD NE VALUE { $$.field = $1; $$.op = DCO_NE; $$.value = $3; }
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = structure impliquée dans le processus. *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(disass_assert *dassert, char *msg)
+{
+ printf("assert yyerror line %d: %s\n", yyget_lineno(), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = structure à constituer à partir de données lues. *
+* raw = données brutes à analyser. *
+* *
+* Description : Interprête des données relatives à une série de conditions. *
+* *
+* Retour : true si l'opération s'est bien déroulée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_assertions_from_raw_block(disass_assert *dassert, const char *raw)
+{
+ bool result; /* Bilan à faire remonter */
+ YY_BUFFER_STATE state; /* Support d'analyse */
+ int status; /* Bilan de l'analyse */
+
+ state = yy_scan_string(raw);
+
+ status = yyparse(dassert);
+
+ result = (status == 0);
+
+ yy_delete_buffer(state);
+
+ return result;
+
+}
diff --git a/tools/d2c/assert/manager.c b/tools/d2c/assert/manager.c
new file mode 100644
index 0000000..54e9101
--- /dev/null
+++ b/tools/d2c/assert/manager.c
@@ -0,0 +1,365 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.c - désassemblage sous condition
+ *
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "manager.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../helpers.h"
+
+
+
+/* Elément d'une condition décodée */
+typedef struct _def_cond
+{
+ char *field; /* Désignation du champ */
+ DisassCondOp op; /* Opération de comparaison */
+ char *value; /* Désignation de la valeur */
+
+ char *lower; /* Version minuscule */
+
+} def_cond;
+
+/* Ligne de condition(s) */
+typedef struct _cond_line
+{
+ def_cond *conditions; /* Conditions à vérifier */
+ size_t count; /* Taille de cette liste */
+
+ DisassCondGroup group; /* Type du groupe */
+
+} cond_line;
+
+/* Représentation de l'ensemble de conditions préalables */
+struct _disass_assert
+{
+ cond_line *lines; /* Lignes de conditions */
+ size_t count; /* Taille de cette liste */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un nouveau gestionnaire de conditions de désassemblage. *
+* *
+* Retour : Nouvelle structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+disass_assert *create_disass_assert(void)
+{
+ disass_assert *result; /* Définition vierge à renvoyer*/
+
+ result = (disass_assert *)calloc(1, sizeof(disass_assert));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à libérer.*
+* *
+* Description : Supprime de la mémoire un gestionnaire de conditions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_disass_assert(disass_assert *dassert)
+{
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne à compléter */
+ size_t j; /* Boucle de parcours #2 */
+
+ for (i = 0; i < dassert->count; i++)
+ {
+ line = &dassert->lines[i];
+
+ for (j = 0; j < line->count; j++)
+ {
+ free(line->conditions[j].field);
+ free(line->conditions[j].value);
+
+ free(line->conditions[j].lower);
+
+ }
+
+ if (line->conditions != NULL)
+ free(line->conditions);
+
+ }
+
+ if (dassert->lines != NULL)
+ free(dassert->lines);
+
+ free(dassert);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* group = type du groupe de conditions attendues. *
+* field = champ de bits à prendre en compte. *
+* op = type d'opération impliquée. *
+* value = valeur soumise à condition. *
+* *
+* Description : Initie une nouvelle condition à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void register_disass_assert(disass_assert *dassert, DisassCondGroup group, char *field, DisassCondOp op, char *value)
+{
+ cond_line *new; /* Nouvelle ligne de conditions*/
+
+ dassert->lines = (cond_line *)realloc(dassert->lines,
+ ++dassert->count * sizeof(cond_line));
+
+ new = &dassert->lines[dassert->count - 1];
+
+ new->conditions = NULL;
+ new->count = 0;
+
+ new->group = group;
+
+ extend_disass_assert(dassert, field, op, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* field = champ de bits à prendre en compte. *
+* op = type d'opération impliquée. *
+* value = valeur soumise à condition. *
+* *
+* Description : Enregistre une nouvelle condition à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_disass_assert(disass_assert *dassert, char *field, DisassCondOp op, char *value)
+{
+ cond_line *line; /* Ligne à compléter */
+ def_cond *new; /* Nouvelle définition */
+
+ assert(dassert->count > 0);
+
+ line = &dassert->lines[dassert->count - 1];
+
+ line->conditions = (def_cond *)realloc(line->conditions,
+ ++line->count * sizeof(def_cond));
+
+ new = &line->conditions[line->count - 1];
+
+ new->field = field;
+ new->op = op;
+ new->value = value;
+
+ new->lower = strdup(field);
+ make_string_lower(new->lower);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* *
+* Description : Indique la présence de conditions à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool is_disass_assert_empty(const disass_assert *dassert)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (dassert->count == 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à marquer.*
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Marque les éléments de condition effectivement utilisés. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool mark_disass_assert(const disass_assert *dassert, const coding_bits *bits)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne de condition(s) */
+ size_t j; /* Boucle de parcours #2 */
+ def_cond *cond; /* Condition à marquer */
+ raw_bitfield *rf; /* Champ de bits à marquer */
+
+ result = true;
+
+ for (i = 0; i < dassert->count && result; i++)
+ {
+ line = &dassert->lines[i];
+
+ for (j = 0; j < line->count && result; j++)
+ {
+ cond = &line->conditions[j];
+
+ rf = find_named_field_in_bits(bits, cond->lower);
+
+ if (rf == NULL)
+ {
+ fprintf(stderr, "Unknown bitfield '%s' for condition!\n", cond->field);
+ result = false;
+ }
+
+ else
+ mark_raw_bitfield_as_used(rf);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à définir.*
+* fd = descripteur d'un flux ouvert en écriture. *
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Définit les éléments de condition à appliquer. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_disass_assert(const disass_assert *dassert, int fd, const coding_bits *bits)
+{
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne de condition(s) */
+ size_t j; /* Boucle de parcours #2 */
+ def_cond *cond; /* Condition à marquer */
+ raw_bitfield *rf; /* Champ de bits à marquer */
+
+ for (i = 0; i < dassert->count; i++)
+ {
+ line = &dassert->lines[i];
+
+ if (i > 0)
+ dprintf(fd, " && ");
+
+ if (dassert->count > 1 && line->count > 1)
+ dprintf(fd, "(");
+
+ for (j = 0; j < line->count; j++)
+ {
+ cond = &line->conditions[j];
+
+ rf = find_named_field_in_bits(bits, cond->lower);
+
+ assert(rf != NULL);
+
+ if (j > 0)
+ switch (line->group)
+ {
+ case DCG_UNIQ:
+ assert(false);
+ break;
+
+ case DCG_AND:
+ dprintf(fd, " && ");
+ break;
+
+ case DCG_OR:
+ dprintf(fd, " || ");
+ break;
+
+ }
+
+ write_raw_bitfield(rf, fd);
+
+ switch (cond->op)
+ {
+ case DCO_EQ:
+ dprintf(fd, " == ");
+ break;
+
+ case DCO_NE:
+ dprintf(fd, " != ");
+ break;
+
+ }
+
+ dprintf(fd, "b%s", cond->value);
+
+ }
+
+ if (dassert->count > 1 && line->count > 1)
+ dprintf(fd, ")");
+
+ }
+
+ return true;
+
+}
diff --git a/tools/d2c/assert/manager.h b/tools/d2c/assert/manager.h
new file mode 100644
index 0000000..042c2e0
--- /dev/null
+++ b/tools/d2c/assert/manager.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.h - prototypes pour le désassemblage sous condition
+ *
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ASSERT_MANAGER_H
+#define _TOOLS_D2C_ASSERT_MANAGER_H
+
+
+#include <stdbool.h>
+
+
+#include "../bits/manager.h"
+
+
+
+/* Définition d'opération conditionnelle */
+
+typedef enum _DisassCondOp
+{
+ DCO_EQ, /* Egalité */
+ DCO_NE /* Différence */
+
+} DisassCondOp;
+
+typedef enum _DisassCondGroup
+{
+ DCG_UNIQ, /* Condition unique */
+ DCG_AND, /* Obligation */
+ DCG_OR /* Complémentarité */
+
+} DisassCondGroup;
+
+
+/* Représentation de l'ensemble de conditions préalables */
+typedef struct _disass_assert disass_assert;
+
+
+/* Crée un nouveau gestionnaire de conditions de désassemblage. */
+disass_assert *create_disass_assert(void);
+
+/* Supprime de la mémoire un gestionnaire de conditions. */
+void delete_disass_assert(disass_assert *);
+
+/* Initie une nouvelle condition à vérifier. */
+void register_disass_assert(disass_assert *, DisassCondGroup, char *, DisassCondOp, char *);
+
+/* Enregistre une nouvelle condition à vérifier. */
+void extend_disass_assert(disass_assert *, char *, DisassCondOp, char *);
+
+/* Indique la présence de conditions à vérifier. */
+bool is_disass_assert_empty(const disass_assert *);
+
+/* Marque les éléments de condition effectivement utilisés. */
+bool mark_disass_assert(const disass_assert *, const coding_bits *);
+
+/* Définit les éléments de condition à appliquer. */
+bool define_disass_assert(const disass_assert *, int, const coding_bits *);
+
+
+
+#endif /* _TOOLS_D2C_ASSERT_MANAGER_H */
diff --git a/tools/d2c/assert/tokens.l b/tools/d2c/assert/tokens.l
new file mode 100644
index 0000000..192bcc7
--- /dev/null
+++ b/tools/d2c/assert/tokens.l
@@ -0,0 +1,41 @@
+
+%top {
+
+#include "grammar.h"
+
+}
+
+
+%option noyywrap
+%option nounput
+%option noinput
+%option yylineno
+%option stack
+%option noyy_top_state
+%option noyy_push_state
+%option noyy_pop_state
+
+
+%%
+
+
+[ \t\n] { }
+
+"==" { return EQ; }
+"!=" { return NE; }
+
+"&&" { return AND; }
+"||" { return OR; }
+
+[A-Za-z_][A-Za-z0-9_]* { yylvalp->string = strdup(yytext); return FIELD; }
+
+[01]+ { yylvalp->string = strdup(yytext); return VALUE; }
+
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c assert block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
+%%