diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2018-04-02 11:58:42 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2018-04-02 12:39:30 (GMT) |
commit | 1db4ef323b7a76093356ae76268132f3760e1631 (patch) | |
tree | fec36ee0ec1b6b2010b62ca4177edca0e31e2114 /tools | |
parent | 1bc80837dde03a32b5ab185067f7bd4c499a9850 (diff) |
Rewritten the whole instruction definition format.
Diffstat (limited to 'tools')
63 files changed, 4551 insertions, 1741 deletions
diff --git a/tools/d2c/Makefile.am b/tools/d2c/Makefile.am index 5b9eb48..c07e16f 100644 --- a/tools/d2c/Makefile.am +++ b/tools/d2c/Makefile.am @@ -22,26 +22,34 @@ bin_PROGRAMS = d2c d2c_SOURCES = \ coder.h coder.c \ - tokens.l \ - grammar.y \ + d2c.c \ + decl.h \ + encoding.h encoding.c \ helpers.h helpers.c \ manual.h \ pproc.h pproc.c \ qckcall.h qckcall.c \ - spec.h spec.c + syntax.h syntax.c \ + tokens.l \ + grammar.y # _GNU_SOURCE : asprintf d2c_CFLAGS = -D_GNU_SOURCE d2c_LDADD = \ + assert/libd2cassert.la \ bits/libd2cbits.la \ conv/libd2cconv.la \ + desc/libd2cdesc.la \ format/libd2cformat.la \ hooks/libd2chooks.la \ + id/libd2cid.la \ + pattern/libd2cpattern.la \ rules/libd2crules.la \ - syntax/libd2csyntax.la \ args/libd2cargs.la +d2c_LDFLAGS = -lm + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h @@ -51,4 +59,4 @@ CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h EXTRA_DIST = tokens.h d2c_genmakefile.sh -SUBDIRS = args bits conv format hooks rules syntax +SUBDIRS = args assert bits conv desc format hooks id pattern rules diff --git a/tools/d2c/args/Makefile.am b/tools/d2c/args/Makefile.am index 1a2647c..3c4ef38 100644 --- a/tools/d2c/args/Makefile.am +++ b/tools/d2c/args/Makefile.am @@ -26,6 +26,9 @@ libd2cargs_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2cargs_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/args/grammar.y b/tools/d2c/args/grammar.y index 41512a9..b038e22 100644 --- a/tools/d2c/args/grammar.y +++ b/tools/d2c/args/grammar.y @@ -78,7 +78,8 @@ right_op : FORCE_EXPR arg_expr { operand->func = NULL; operand->expr = $2; } call : NAME OP arg_list CP { $$.func = $1; $$.args = $3; } -arg_list : arg_expr { $$ = build_arg_list($1); } +arg_list : /* empty */ { $$ = build_empty_arg_list(); } + | arg_expr { $$ = build_arg_list($1); } | arg_list COMMA arg_expr { $$ = extend_arg_list($1, $3); } arg_expr : NAME { $$ = build_arg_expr_from_name($1); } diff --git a/tools/d2c/args/manager.c b/tools/d2c/args/manager.c index 3cd215d..8e1ef4d 100644 --- a/tools/d2c/args/manager.c +++ b/tools/d2c/args/manager.c @@ -132,10 +132,10 @@ struct _arg_expr_t /* Visite une expression en traitant en premier ses composantes. */ -typedef bool (* visit_expr_fc) (arg_expr_t *, int, const coding_bits *, const conv_list *, void *); +typedef bool (* visit_expr_fc) (arg_expr_t *); /* Visite une expression en traitant en premier ses composantes. */ -static bool visit_arg_expr(arg_expr_t *, visit_expr_fc, int, const coding_bits *, const conv_list *, void *); +static bool visit_arg_expr(arg_expr_t *, visit_expr_fc); /* 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 **); @@ -641,11 +641,8 @@ bool compute_arg_expr_size(const arg_expr_t *expr, const coding_bits *bits, cons /****************************************************************************** * * -* 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. * +* Paramètres : expr = première expression encapsulée. * +* visit = fonction à appeler pour chaque élément recontré. * * * * Description : Visite une expression en traitant en premier ses composantes.* * * @@ -655,29 +652,32 @@ bool compute_arg_expr_size(const arg_expr_t *expr, const coding_bits *bits, cons * * ******************************************************************************/ -static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit, int fd, const coding_bits *bits, const conv_list *list, void *data) +static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit) { bool result; /* Bilan à retourner */ switch (expr->type) { case CET_LOGICAL: - result = visit_arg_expr(expr->logical_expr1, visit, fd, bits, list, data); - result = visit_arg_expr(expr->logical_expr2, visit, fd, bits, list, data); + result = visit_arg_expr(expr->logical_expr1, visit); + if (result) + result = visit_arg_expr(expr->logical_expr2, visit); break; case CET_UNARY: - result = visit_arg_expr(expr->un_expr, visit, fd, bits, list, data); + result = visit_arg_expr(expr->un_expr, visit); break; case CET_CONDITIONAL: - result = visit_arg_expr(expr->cond_expr1, visit, fd, bits, list, data); - result = visit_arg_expr(expr->cond_expr2, visit, fd, bits, list, data); + result = visit_arg_expr(expr->cond_expr1, visit); + if (result) + result = visit_arg_expr(expr->cond_expr2, visit); break; case CET_BINARY: - result = visit_arg_expr(expr->bin_expr1, visit, fd, bits, list, data); - result = visit_arg_expr(expr->bin_expr2, visit, fd, bits, list, data); + result = visit_arg_expr(expr->bin_expr1, visit); + if (result) + result = visit_arg_expr(expr->bin_expr2, visit); break; default: @@ -686,7 +686,8 @@ static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit, int fd, const } - result &= visit(expr, fd, bits, list, data); + if (result) + result = visit(expr); return result; @@ -729,9 +730,6 @@ static bool find_var_by_name(const coding_bits *bits, const conv_list *list, con if (field != NULL) *field = cached_field; if (func != NULL) *func = cached_func; - if (!result) - fprintf(stderr, "Variable '%s' not found!\n", name); - return result; } @@ -753,31 +751,27 @@ static bool find_var_by_name(const coding_bits *bits, const conv_list *list, con bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *bits, const conv_list *list) { - bool mark_sub_expr(arg_expr_t *sub, int dummy, const coding_bits *bts, const conv_list *lst, void *unused) + bool mark_sub_expr(arg_expr_t *sub) { 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 mark_by_name(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); + found = find_var_by_name(bits, list, name, &field, &func); if (found) { if (field != NULL) mark_raw_bitfield_as_used(field); else /*if (func != NULL) */ - mark_conv_func(func, true, bts, lst); - - printf(" VAR '%s' found (bf=%d fc=%d)\n", name, !!field, !!func); - + mark_conv_func(func, true, bits, list); } - else printf(" VAR '%s' not found...\n", name); return found; @@ -787,7 +781,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b switch (sub->type) { case CET_NAME: - /* result = */mark_by_name(bits, lst, sub->name); + /* result = */mark_by_name(sub->name); result = true; break; @@ -795,7 +789,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b 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]); + result = mark_by_name(sub->comp_items[i]); break; default: @@ -808,7 +802,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b } - return visit_arg_expr(expr, (visit_expr_fc)mark_sub_expr, -1, bits, list, NULL); + return visit_arg_expr(expr, (visit_expr_fc)mark_sub_expr); } @@ -820,8 +814,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b * 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. * -* wide = taille des mots décodés. * +* tab = décalage éventuel selon l'inclusion. * * * * Description : S'assure de la déclaration des expressions pre-requises. * * * @@ -831,15 +824,17 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b * * ******************************************************************************/ -bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide) +bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const char *tab) { - bool declare_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, unsigned int *wideptr) + bool declare_sub_expr(arg_expr_t *sub) { 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); + /** + * Si l'expression a déjà été définie lors d'un précédent besoin... + */ + if (sub->declared) return true; bool declare_by_name(const char *name) @@ -847,30 +842,10 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi bool found; /* Bilan d'opération à renvoyer*/ conv_func *func; /* Eventuelle fonction liée */ - found = find_var_by_name(bts, lst, name, NULL, &func); + found = find_var_by_name(bits, list, name, NULL, &func); if (found && func != NULL) - { - printf("========= DECLARE for '%s'\n", name); - found = declare_conv_func(func, fd, bits, list, pp, wide); - printf("========= END DECLARE for '%s'\n", name); - - /** - * Si on déclare les variables suivantes dans declare_conv_func(), - * elles seront également déclarées pour les fonctions de conversion - * racine à partir de declare_syntax_items(), ce qui ne convient pas - * car les appels racine servent directement d'arguments. - */ - - /* - if (is_conv_func_expression(func)) - dprintf(_f, "\t\tuint%u_t val_%s; // Ho\n", _wide, name); // FIXME - else - dprintf(_f, "\t\tGArchOperand *val_%s;;;;;\n", name); // FIXME - */ - - - } + found = declare_conv_func(func, fd, bits, list, tab); return found; @@ -903,7 +878,7 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi } - return visit_arg_expr(expr, (visit_expr_fc)declare_sub_expr, fd, bits, list, &wide); + return visit_arg_expr(expr, (visit_expr_fc)declare_sub_expr); } @@ -912,10 +887,9 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi * * * 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. * +* tab = décalage éventuel selon l'inclusion. * * exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : S'assure de la définition des expressions pre-requises. * @@ -926,18 +900,9 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi * * ******************************************************************************/ -bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) +bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit) { - typedef struct _def_info - { - const char *arch; - const pre_processor *pp; - - } def_info; - - def_info info; /* Transmissions au visiteur */ - - bool define_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, def_info *info) + bool define_sub_expr(arg_expr_t *sub) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ @@ -945,15 +910,15 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char /* 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 define_by_name(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); + found = find_var_by_name(bits, list, name, NULL, &func); if (found && func != NULL) - found = define_conv_func(func, false, false, _f, _info->arch, _bts, _lst, _info->pp, exit); + found = define_conv_func(func, fd, bits, list, tab, false, exit); return found; @@ -963,7 +928,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char switch (sub->type) { case CET_NAME: - /* result = */define_by_name(f, bits, lst, info, sub->name); + /* result = */define_by_name(sub->name); result = true; break; @@ -971,7 +936,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char 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]); + result = define_by_name(sub->comp_items[i]); break; default: @@ -986,10 +951,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char } - info.arch = arch; - info.pp = pp; - - return visit_arg_expr(expr, (visit_expr_fc)define_sub_expr, fd, bits, list, &info); + return visit_arg_expr(expr, (visit_expr_fc)define_sub_expr); } @@ -1031,9 +993,9 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co else { if (field != NULL) - dprintf(fd, "raw_%s", expr->name); + write_raw_bitfield(field, fd); else - dprintf(fd, "val_%s", expr->name); + write_conv_func(func, fd, true); } break; @@ -1103,17 +1065,15 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co if (field != NULL) { - if (max_size == 0) - dprintf(fd, "raw_%s", cname); - else - dprintf(fd, "raw_%s << %u", cname, max_size); + write_raw_bitfield(field, fd); + if (max_size > 0) + dprintf(fd, " << %u", max_size); } else { - if (max_size == 0) - dprintf(fd, "val_%s", cname); - else - dprintf(fd, "val_%s << %u", cname, max_size); + write_conv_func(func, fd, true); + if (max_size > 0) + dprintf(fd, " << %u", max_size); } } @@ -1204,6 +1164,32 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co /****************************************************************************** * * +* Paramètres : - * +* * +* Description : Crée une liste vide d'arguments de conversion. * +* * +* Retour : Nouvelle structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +arg_list_t *build_empty_arg_list(void) +{ + arg_list_t *result; /* Structure à retourner */ + + result = (arg_list_t *)calloc(1, sizeof(arg_list_t)); + + result->items = NULL; + result->count = 0; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression initial pour constituer une liste. * * * * Description : Crée une liste d'arguments de conversion. * @@ -1283,6 +1269,26 @@ arg_list_t *extend_arg_list(arg_list_t *list, arg_expr_t *expr) /****************************************************************************** * * +* Paramètres : args = liste d'expressions à traiter. * +* * +* Description : Indique le nombre d'arguments présents dans la liste. * +* * +* Retour : Nombre positif ou nul. * +* * +* Remarques : - * +* * +******************************************************************************/ +#ifndef NDEBUG +size_t get_arg_list_size(const arg_list_t *args) +{ + return args->count; + +} +#endif + + +/****************************************************************************** +* * * 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. * @@ -1316,8 +1322,7 @@ bool ensure_arg_list_content_fully_marked(arg_list_t *args, const coding_bits *b * fd = descripteur d'un flux ouvert en écriture. * * bits = gestionnaire des bits d'encodage. * * list = liste de l'ensemble des fonctions de conversion. * -* pp = pré-processeur pour les échanges de chaînes. * -* wide = taille des mots décodés. * +* tab = décalage éventuel selon l'inclusion. * * * * Description : S'assure de la déclaration des expressions pre-requises. * * * @@ -1327,7 +1332,7 @@ bool ensure_arg_list_content_fully_marked(arg_list_t *args, const coding_bits *b * * ******************************************************************************/ -bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide) +bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const char *tab) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ @@ -1335,7 +1340,7 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi result = true; for (i = 0; i < args->count && result; i++) - result = ensure_arg_expr_content_fully_declared(args->items[i], fd, bits, list, pp, wide); + result = ensure_arg_expr_content_fully_declared(args->items[i], fd, bits, list, tab); return result; @@ -1346,10 +1351,9 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi * * * 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. * +* tab = décalage éventuel selon l'inclusion. * * exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : S'assure de la définition des expressions pre-requises. * @@ -1360,7 +1364,7 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi * * ******************************************************************************/ -bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) +bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ @@ -1368,7 +1372,7 @@ bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const char result = true; for (i = 0; i < args->count && result; i++) - result = ensure_arg_expr_content_fully_defined(args->items[i], fd, arch, bits, list, pp, exit); + result = ensure_arg_expr_content_fully_defined(args->items[i], fd, bits, list, tab, exit); return result; diff --git a/tools/d2c/args/manager.h b/tools/d2c/args/manager.h index 9332b2b..de69105 100644 --- a/tools/d2c/args/manager.h +++ b/tools/d2c/args/manager.h @@ -25,7 +25,10 @@ #define _TOOLS_D2C_ARGS_MANAGER_H -#include "../pproc.h" +#ifndef NDEBUG +# include <sys/types.h> +#endif + #include "../bits/manager.h" @@ -105,10 +108,10 @@ bool compute_arg_expr_size(const arg_expr_t *, const coding_bits *, const conv_l bool ensure_arg_expr_content_fully_marked(arg_expr_t *, const coding_bits *, const conv_list *); /* S'assure de la déclaration des expressions pre-requises. */ -bool ensure_arg_expr_content_fully_declared(arg_expr_t *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int); +bool ensure_arg_expr_content_fully_declared(arg_expr_t *, int, const coding_bits *, const conv_list *, const char *); /* S'assure de la définition des expressions pre-requises. */ -bool ensure_arg_expr_content_fully_defined(arg_expr_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); +bool ensure_arg_expr_content_fully_defined(arg_expr_t *, int, const coding_bits *, const conv_list *, const char *, bool *); /* Définit une expression utilisée dans une conversion. */ bool define_arg_expr(const arg_expr_t *, int, const coding_bits *, const conv_list *); @@ -122,6 +125,9 @@ bool define_arg_expr(const arg_expr_t *, int, const coding_bits *, const conv_li typedef struct _arg_list_t arg_list_t; +/* Crée une liste vide d'arguments de conversion. */ +arg_list_t *build_empty_arg_list(void); + /* Crée une liste d'arguments de conversion. */ arg_list_t *build_arg_list(arg_expr_t *); @@ -131,14 +137,19 @@ void delete_arg_list(arg_list_t *); /* Ajoute un élément à une liste d'arguments de conversion. */ arg_list_t *extend_arg_list(arg_list_t *, arg_expr_t *); +/* Indique le nombre d'arguments présents dans la liste. */ +#ifndef NDEBUG +size_t get_arg_list_size(const arg_list_t *); +#endif + /* S'assure du marquage des expressions pre-requises. */ bool ensure_arg_list_content_fully_marked(arg_list_t *, const coding_bits *, const conv_list *); /* S'assure de la déclaration des expressions pre-requises. */ -bool ensure_arg_list_content_fully_declared(arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int); +bool ensure_arg_list_content_fully_declared(arg_list_t *, int, const coding_bits *, const conv_list *, const char *); /* S'assure de la définition des expressions pre-requises. */ -bool ensure_arg_list_content_fully_defined(arg_list_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); +bool ensure_arg_list_content_fully_defined(arg_list_t *, int, const coding_bits *, const conv_list *, const char *, bool *); /* Définit les variables associées à un appel de fonction. */ bool define_arg_list(const arg_list_t *, int, const coding_bits *, const conv_list *); diff --git a/tools/d2c/args/tokens.l b/tools/d2c/args/tokens.l index 9851f62..9645ba2 100644 --- a/tools/d2c/args/tokens.l +++ b/tools/d2c/args/tokens.l @@ -51,7 +51,7 @@ <binval>[01][01]* { yylvalp->string = strdup(yytext); return BINVAL; } <binval>"'" { yy_pop_state(); } -\"[^\"]*\" { yylvalp->string = strndup(yytext + 1, strlen(yytext) - 2); printf("str = '%s'\n", yylvalp->string); return STRING; } +\"[^\"]*\" { yylvalp->string = strndup(yytext + 1, strlen(yytext) - 2); return STRING; } "0x" { yy_push_state(hexval); } <hexval>[0-9a-f][0-9a-f]* { yylvalp->string = strdup(yytext); yy_pop_state(); return HEXVAL; } @@ -71,5 +71,12 @@ [ ]+ { } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c args block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + %% 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); + } + +%% diff --git a/tools/d2c/bits/Makefile.am b/tools/d2c/bits/Makefile.am index b1d79b6..0d8beb8 100644 --- a/tools/d2c/bits/Makefile.am +++ b/tools/d2c/bits/Makefile.am @@ -26,6 +26,9 @@ libd2cbits_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2cbits_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/bits/manager.c b/tools/d2c/bits/manager.c index 4999680..560bade 100644 --- a/tools/d2c/bits/manager.c +++ b/tools/d2c/bits/manager.c @@ -29,6 +29,7 @@ #include <malloc.h> #include <stdint.h> #include <string.h> +#include <unistd.h> #include "../helpers.h" @@ -114,6 +115,25 @@ void mark_raw_bitfield_as_used(raw_bitfield *field) } +/****************************************************************************** +* * +* Paramètres : field = champ de bits à traiter. * +* fd = descripteur d'un flux ouvert en écriture. * +* * +* Description : Imprime la désignation d'un champ de bits dans du code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void write_raw_bitfield(const raw_bitfield *field, int fd) +{ + dprintf(fd, "raw_%s", field->name); + +} + @@ -294,13 +314,30 @@ raw_bitfield *find_named_field_in_bits(const coding_bits *bits, const char *name * * ******************************************************************************/ -bool declare_used_bits_fields(const coding_bits *bits, int fd, unsigned int wide) +bool declare_used_bits_fields(const coding_bits *bits, int fd) { + unsigned int wide; /* Taille des mots */ size_t i; /* Boucle de parcours */ + off_t start; /* Point de départ dans le code*/ + off_t end; /* Point d'arrivée dans le code*/ + + wide = count_coded_bits(bits); for (i = 0; i < bits->bf_count; i++) if (bits->fields[i].used) - dprintf(fd, "\t\tuint%u_t raw_%s;\n", wide, bits->fields[i].name); + { + start = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "\tuint%u_t ", wide); + write_raw_bitfield(&bits->fields[i], fd); + dprintf(fd, ";"); + + end = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "%*s", 42 - (int)(end - start), "/"); + dprintf(fd, "* Champ brut à décoder */\n"); + + } return true; @@ -325,22 +362,22 @@ bool check_bits_correctness(const coding_bits *bits, int fd) switch (bits->curpos) { case 8: - dprintf(fd, "\t\tif ((raw & 0x%" PRIx8 ") != 0x%" PRIx8 ") return NULL;\n", + dprintf(fd, "\tif ((raw & 0x%" PRIx8 ") != 0x%" PRIx8 ") return NULL;\n", (uint8_t)bits->mask, (uint8_t)bits->bits); break; case 16: - dprintf(fd, "\t\tif ((raw & 0x%" PRIx16 ") != 0x%" PRIx16 ") return NULL;\n", + dprintf(fd, "\tif ((raw & 0x%" PRIx16 ") != 0x%" PRIx16 ") return NULL;\n", (uint16_t)bits->mask, (uint16_t)bits->bits); break; case 32: - dprintf(fd, "\t\tif ((raw & 0x%" PRIx32 ") != 0x%" PRIx32 ") return NULL;\n", + dprintf(fd, "\tif ((raw & 0x%" PRIx32 ") != 0x%" PRIx32 ") return NULL;\n", (uint32_t)bits->mask, (uint32_t)bits->bits); break; case 64: - dprintf(fd, "\t\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n", + dprintf(fd, "\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n", bits->mask, bits->bits); break; @@ -377,7 +414,9 @@ bool define_used_bits_fields(const coding_bits *bits, int fd) rf = &bits->fields[i]; if (!rf->used) continue; - dprintf(fd, "\t\traw_%s = (_raw >> %u) & 0x%llx;\n", rf->name, rf->start, (1ull << rf->length) - 1); + dprintf(fd, "\t"); + write_raw_bitfield(rf, fd); + dprintf(fd, " = (raw >> %u) & 0x%llx;\n", rf->start, (1ull << rf->length) - 1); got_one = true; diff --git a/tools/d2c/bits/manager.h b/tools/d2c/bits/manager.h index f696250..71d9055 100644 --- a/tools/d2c/bits/manager.h +++ b/tools/d2c/bits/manager.h @@ -44,6 +44,8 @@ unsigned int get_raw_bitfield_length(const raw_bitfield *); /* Marque un champ de bits comme étant utile. */ void mark_raw_bitfield_as_used(raw_bitfield *); +/* Imprime la désignation d'un champ de bits dans du code. */ +void write_raw_bitfield(const raw_bitfield *, int); @@ -74,7 +76,7 @@ unsigned int count_coded_bits(const coding_bits *); raw_bitfield *find_named_field_in_bits(const coding_bits *, const char *); /* Déclare les variables C associées aux champs de bits. */ -bool declare_used_bits_fields(const coding_bits *, int, unsigned int); +bool declare_used_bits_fields(const coding_bits *, int); /* Vérifie que les bits fixes correspondent au masque attendu. */ bool check_bits_correctness(const coding_bits *, int); diff --git a/tools/d2c/bits/tokens.l b/tools/d2c/bits/tokens.l index 99fb96d..4879f4f 100644 --- a/tools/d2c/bits/tokens.l +++ b/tools/d2c/bits/tokens.l @@ -29,5 +29,11 @@ [01] { yylvalp->integer = atoi(yytext); return BIT; } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c bits block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } %% diff --git a/tools/d2c/coder.c b/tools/d2c/coder.c index 65e9605..e286a1d 100644 --- a/tools/d2c/coder.c +++ b/tools/d2c/coder.c @@ -27,13 +27,10 @@ #include <assert.h> #include <fcntl.h> #include <malloc.h> -#include <regex.h> -#include <stdint.h> #include <stdio.h> #include <string.h> +#include <time.h> #include <unistd.h> -#include <sys/stat.h> -#include <sys/types.h> #include "helpers.h" @@ -47,8 +44,6 @@ struct _rented_coder { const char *input; /* Fichier de définitions */ - InputOutputType type; /* Type des définitions (E/S) */ - const char *outdir; /* Lieu d'enregistrement */ const char *arch; /* Architecture à traiter */ const char *header; /* En-tête pour les en-têtes */ const char *const_prefix; /* Préfixe pour les opérandes */ @@ -61,6 +56,11 @@ struct _rented_coder char *raw_details; /* Eventuels compléments bruts */ char *details; /* Eventuels compléments */ + instr_id *id; /* Gestionnaire d'identifiant */ + instr_desc *desc; /* Gestionnaire de description */ + + bool useless; /* Instruction non utilisée */ + encoding_spec **specs; /* Définitions déjà en place */ size_t specs_count; /* Nombre de ces définitions */ encoding_spec *cur_spec; /* Définition courante */ @@ -69,32 +69,58 @@ struct _rented_coder +/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ + + +/* Détermine le nombre de bits analysés lors d'un désassemblage. */ +static unsigned int get_bit_width_for_encoding_spec(const rented_coder *, const string_exch *); + + + /* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ -/* S'assure de la présence du répertoire de sortie du code. */ -static bool check_gen_dir(const rented_coder *); +/* Ouvre un fichier principal en écriture pour y placer du code. */ +static int open_instr_header_file(const rented_coder *, const output_info *, const char *, bool *); + +/* Ouvre un fichier principal en écriture pour y placer du code. */ +static int open_instr_code_file(const rented_coder *, const output_info *, const char *, bool *); + +/* Ouvre un fichier global en écriture pour y placer du code. */ +static int open_global_header_file(const rented_coder *, const output_info *, const char *, bool *); + +/* Imprime dans un flux donné un commentaire de propriété. */ +static void write_header_file_license(int, const output_info *, const char *, const char *); /* Imprime dans un flux donné un commentaire de propriété. */ -static void write_owner_comments(const rented_coder *, int, const char *, const char *, char); +static void write_code_file_license(int, const output_info *, const char *, const char *); + +/* Initialise le contenu utile du fichier des instructions. */ +static void init_coder_opcodes_file(int, const output_info *, const char *); + +/* Initialise le contenu utile d'un fichier d'instructions. */ +static void init_coder_code_file(int, const char *); + +/* Centralise l'impression du nom de fonction de désassemblage. */ +static void write_read_function_name(int fd, const char *, const string_exch *, const char *); -/* Construit un chemin d'accès à un modèle de fichier de code. */ -static char *build_template_filename(const rented_coder *, const char *, const char *, char); +/* Génère ou complète un fichier contenant le code C principal. */ +static bool output_coder_raw(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int); -/* Définit un modèle d'en-tête de définitions. */ -static bool create_template_file(const rented_coder *, const char *, const char *, char); +/* Génère ou complète un fichier contenant le code C principal. */ +static bool output_coder_main_raw(const rented_coder *, const output_info *, const string_exch *, int, int); -/* Construit un chemin d'accès à un fichier de code source. */ -static char *build_code_filename(const rented_coder *, const char *, const char *, const char *, char); +/* Génère ou complète un fichier contenant le code C principal. */ +static bool output_coder_format(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int); -/* Ouvre un fichier en écriture pour y placer du code. */ -static int create_code_file(const rented_coder *, const char *, const char *, const char *, char); +/* Initialise le contenu utile du fichier des identifiants. */ +static void init_coder_identifiers_file(int, const output_info *); -/* Ecrit une partie des fonctions issues des spécifications. */ -static bool dump_all_matching_specs_in_coder(const rented_coder *, const string_exch *, int, int); +/* Initialise le contenu utile du fichier des mots clefs. */ +static void init_coder_keywords_file(int, const output_info *); -/* Ecrit une partie des fonctions issues des spécifications. */ -static bool dump_all_matching_specs_from_format(const rented_coder *, const string_exch *, int, int); +/* Initialise le contenu utile du fichier des descriptions. */ +static void init_coder_descriptions_file(int, const output_info *); @@ -105,7 +131,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri /****************************************************************************** * * -* Paramètres : - * +* Paramètres : pp = préprocesseur déjà chargé à intégrer. * * * * Description : Débute la définition d'une fonction de désassemblage. * * * @@ -115,16 +141,21 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri * * ******************************************************************************/ -rented_coder *create_coder(void) +rented_coder *create_coder(pre_processor *pp) { rented_coder *result; /* Structure à renvoyer */ result = (rented_coder *)calloc(1, sizeof(rented_coder)); - result->pp = create_pre_processor(); + result->pp = pp; + + result->id = create_instruction_id(); + result->desc = create_instruction_description(); result->cur_spec = create_encoding_spec(); + result->useless = false; + return result; } @@ -157,6 +188,9 @@ void delete_coder(rented_coder *coder) free(coder->details); } + delete_instruction_id(coder->id); + delete_instruction_description(coder->desc); + for (i = 0; i < coder->specs_count; i++) delete_encoding_spec(coder->specs[i]); @@ -184,15 +218,14 @@ void delete_coder(rented_coder *coder) bool do_basic_checks_with_coder(const rented_coder *coder) { - bool result; /* Validité à retourner */ - + /* result = coder->type != IOT_UNDEFINED && coder->outdir != NULL; result &= coder->arch != NULL && coder->header != NULL; if (coder->type == IOT_FORMAT) result &= (coder->const_prefix != NULL); - - return result; + */ + return false; } @@ -248,32 +281,13 @@ void set_coder_input_file(rented_coder *coder, const char *input) * Remarques : - * * * ******************************************************************************/ - +/* void set_coder_input_type(rented_coder *coder, InputOutputType type) { coder->type = type; } - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* outdir = répertoire de génération des fichiers. * -* * -* Description : Spécifie le répertoire de base pour les sorties de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void set_coder_output_directory(rented_coder *coder, const char *outdir) -{ - coder->outdir = outdir; - -} +*/ /****************************************************************************** @@ -336,23 +350,10 @@ void set_coder_const_prefix(rented_coder *coder, const char *prefix) } -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* * -* Description : Fournit le pré-processeur du compilateur. * -* * -* Retour : Pré-processeur à manipuler. * -* * -* Remarques : - * -* * -******************************************************************************/ - -pre_processor *get_coder_pre_proc(const rented_coder *coder) -{ - return coder->pp; -} +/* ---------------------------------------------------------------------------------- */ +/* INFORMATIONS GENERALES */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -392,6 +393,110 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep, } +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Fournit la désignation nominale d'une instruction. * +* * +* Retour : Désignation nominale à libérer de la mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *get_coder_nominal_name(const rented_coder *coder) +{ + char *result; /* Désignation à retourner */ + + if (coder->separator == '\0') + result = strdup(coder->ins); + + else + asprintf(&result, "%s%c%s", coder->ins, coder->separator, coder->raw_details); + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Fournit la désignation complète d'une instruction. * +* * +* Retour : Désignation complète à libérer de la mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *get_coder_code_name(const rented_coder *coder) +{ + char *result; /* Désignation à retourner */ + char *keyword; /* Mot clef appelable en code */ + char *details; /* Compléments de distinction */ + + keyword = make_callable(coder->ins, false); + + if (coder->separator == '\0') + result = keyword; + + else + { + details = make_callable(coder->raw_details, true); + + asprintf(&result, "%s%s", keyword, details); + + free(keyword); + + free(details); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Fournit le gestionnaire des définitions d'identifiant. * +* * +* Retour : Structure assurant la définition d'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +instr_id *get_coder_instruction_id(const rented_coder *coder) +{ + return coder->id; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* * +* Description : Fournit le gestionnaire de description d'identifiant. * +* * +* Retour : Structure assurant la description d'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +instr_desc *get_coder_instruction_desc(const rented_coder *coder) +{ + return coder->desc; + +} + + /* ---------------------------------------------------------------------------------- */ /* REPRESENTATION D'ENCODAGES */ @@ -400,7 +505,7 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep, /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * * Description : Fournit un lien vers les spécifications courantes. * * * @@ -448,66 +553,58 @@ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) } - -/* ---------------------------------------------------------------------------------- */ -/* GENERATIONS DE CODE SOURCE */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* Paramètres : coder = gestion automatique de l'écriture de code. * +* enc_name = désignation du type d'encodage visé. * * * -* Description : S'assure de la présence du répertoire de sortie du code. * +* Description : Détermine le nombre de bits analysés lors d'un désassemblage.* * * -* Retour : Bilan de l'opération. * +* Retour : Nombre de bits interprété. * * * * Remarques : - * * * ******************************************************************************/ -static bool check_gen_dir(const rented_coder *coder) +static unsigned int get_bit_width_for_encoding_spec(const rented_coder *coder, const string_exch *enc_name) { - bool has_gen; /* Répertoire de sortie présent*/ - int ret; /* Bilan d'un appel externe */ + unsigned int result; /* Taille à retourner */ + size_t i; /* Boucle de parcours */ + encoding_spec *spec; /* Définition à traiter */ + coding_bits *bits; /* Gestionnaire de bits */ - has_gen = (access(".gen", F_OK) == 0); + result = -1; - if (has_gen) + for (i = 0; i < coder->specs_count; i++) { - ret = access(".gen", W_OK | X_OK); - if (ret == -1) - { - perror("access()"); - return false; - } + spec = coder->specs[i]; - } - else - { - ret = mkdir(".gen", 0777); - if (ret != 0) - { - perror("mkdir()"); - return false; - } + if (!has_encoding_spec_prefix(spec, enc_name->src)) + continue; + + bits = get_bits_in_encoding_spec(spec); + result = count_coded_bits(bits); + break; } - return true; + /** + * Rien n'a été trouvé à faire... + * Cette situation doit normalement être écartée par l'appelant, + * afin d'éviter de constituer des fichiers vides. + */ + assert(result != -1); + + return result; } /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* fd = descripteur de flux ouvert en écriture. * -* prefix = type d'encodage à répercuter sur le nom de fichier. * -* name = nom brut du fichier à ouvrir. * -* ext = extension à donner au fichier à ouvrir. * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * * * -* Description : Imprime dans un flux donné un commentaire de propriété. * +* Description : Marque une instruction comme non utilisée. * * * * Retour : - * * * @@ -515,69 +612,59 @@ static bool check_gen_dir(const rented_coder *coder) * * ******************************************************************************/ -static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext) +void mark_coder_as_useless(rented_coder *coder) { - dprintf(fd, "\n"); + coder->useless = true; - dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); - dprintf(fd, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext); - dprintf(fd, " *\n"); - dprintf(fd, " * %s\n", coder->copyright); - dprintf(fd, " *\n"); - dprintf(fd, " * This file is part of Chrysalide.\n"); - dprintf(fd, " *\n"); - dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n"); - dprintf(fd, " * it under the terms of the GNU General Public License as published by\n"); - dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n"); - dprintf(fd, " * (at your option) any later version.\n"); - dprintf(fd, " *\n"); - dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n"); - dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); - dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); - dprintf(fd, " * GNU General Public License for more details.\n"); - dprintf(fd, " *\n"); - dprintf(fd, " * You should have received a copy of the GNU General Public License\n"); - dprintf(fd, " * along with Foobar. If not, see <http://www.gnu.org/licenses/>.\n"); - dprintf(fd, " */\n"); +} - dprintf(fd, "\n"); - dprintf(fd, "\n"); -} + +/* ---------------------------------------------------------------------------------- */ +/* GENERATIONS DE CODE SOURCE */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * * prefix = type d'encodage à répercuter sur le nom de fichier. * -* name = nom brut du fichier à ouvrir. * -* ext = extension à donner au fichier à ouvrir. * +* new = dit si l'opération a abouti à une création. [OUT] * * * -* Description : Construit un chemin d'accès à un modèle de fichier de code. * +* Description : Ouvre un fichier principal en écriture pour y placer du code.* * * -* Retour : Chaîne de caractères à libérer de la mémoire après usage. * +* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext) +static int open_instr_header_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new) { - char *result; /* Chaîne construite à renvoyer*/ - size_t length; /* Taille du nom de fichier */ + int result; /* Descripteur à retourner */ + char *pathname; /* Chemin d'accès à constituer */ + int ret; /* Test d'existence du fichier */ + int flags; /* Mode d'accès au fichier */ - if (prefix == NULL) - { - length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(name) + 3; - result = (char *)calloc(length, sizeof(char)); - snprintf(result, length, ".gen/%s.tmpl.%c", name, ext); - } + if (prefix != NULL) + asprintf(&pathname, "%s%s_opcodes.h", info->directory, prefix); else - { - length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(prefix) + 1 + strlen(name) + 3; - result = (char *)calloc(length, sizeof(char)); - snprintf(result, length, ".gen/%s.%s.tmpl.%c", prefix, name, ext); - } + asprintf(&pathname, "%sopcodes.h", info->directory); + + ret = access(pathname, F_OK); + + *new = (ret != 0); + + if (*new) + flags = O_WRONLY | O_CREAT; + else + flags = O_WRONLY | O_APPEND; + + result = open(pathname, flags, 0644); + if (result == -1) perror("open()"); + + free(pathname); return result; @@ -587,320 +674,365 @@ static char *build_template_filename(const rented_coder *coder, const char *pref /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * * prefix = type d'encodage à répercuter sur le nom de fichier. * -* name = nom brut du fichier à ouvrir. * -* ext = extension à donner au fichier à ouvrir. * +* new = dit si l'opération a abouti à une création. [OUT] * * * -* Description : Définit un modèle d'en-tête de définitions. * +* Description : Ouvre un fichier principal en écriture pour y placer du code.* * * -* Retour : Bilan de l'opération. * +* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext) +static int open_instr_code_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new) { + int result; /* Descripteur à retourner */ + char *group; /* Regroupement des similarités*/ + char *sep; /* Eventuelle séparation */ char *pathname; /* Chemin d'accès à constituer */ - bool exist; /* Note une présence établie */ - int fd; /* Flux ouvert pour création */ - const char *valid_prefix; /* Prefix vide au besoin */ - char *uprefix; /* Préfixe en majuscule */ - char *uname; /* Nom en majuscule */ - - if (!check_gen_dir(coder)) - return false; + int ret; /* Test d'existence du fichier */ + int flags; /* Mode d'accès au fichier */ - pathname = build_template_filename(coder, prefix, name, ext); - - exist = (access(pathname, W_OK) == 0); - if (exist) - { - free(pathname); - return true; - } + group = strdup(coder->ins); - fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644); - if (fd == -1) perror("open()"); + sep = index(group, '-'); - free(pathname); - - if (fd != -1) - { - valid_prefix = prefix != NULL ? prefix : ""; - - write_owner_comments(coder, fd, valid_prefix, name, ext); - - if (ext == 'h') - { - uprefix = make_string_upper(strdup(valid_prefix)); - uname = make_string_upper(strdup(name)); + if (sep != NULL) + *sep = '\0'; - dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname); - dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname); + if (prefix != NULL) + asprintf(&pathname, "%s%s_%s.c", info->directory, prefix, group); + else + asprintf(&pathname, "%s%s.c", info->directory, group); - free(uprefix); - free(uname); + free(group); - dprintf(fd, "\n"); - dprintf(fd, "\n"); - dprintf(fd, "##INCLUDES##\n"); - dprintf(fd, "\n"); - dprintf(fd, "\n"); - dprintf(fd, "\n"); + ret = access(pathname, F_OK); - } - else - { - dprintf(fd, "#include \"%sopcodes.h\"\n", valid_prefix); - dprintf(fd, "\n"); - dprintf(fd, "##INCLUDES##\n"); + *new = (ret != 0); - } + if (*new) + flags = O_WRONLY | O_CREAT; + else + flags = O_WRONLY | O_APPEND; - close(fd); + result = open(pathname, flags, 0644); + if (result == -1) perror("open()"); - } + free(pathname); - return (fd != -1); + return result; } /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* intput = fichier d'entrée initial à référencer. * -* prefix = type d'encodage à répercuter sur le nom de fichier. * -* name = nom brut du fichier à ouvrir. * -* ext = extension à donner au fichier à ouvrir. * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * +* name = nom du fichier ciblé par l'opération. * +* new = indique si l'opération a créé le fichier ciblé. [OUT]* * * -* Description : Construit un chemin d'accès à un fichier de code source. * +* Description : Ouvre un fichier global en écriture pour y placer du code. * * * -* Retour : Chaîne de caractères à libérer de la mémoire après usage. * +* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext) +static int open_global_header_file(const rented_coder *coder, const output_info *info, const char *name, bool *new) { - char *result; /* Chaîne construite à renvoyer*/ - char *orig; /* Fichier d'origine tronqué */ - char *point; /* Position d'un point */ - size_t length; /* Taille du nom de fichier */ + int result; /* Descripteur à retourner */ + char *pathname; /* Chemin d'accès à constituer */ + int ret; /* Test d'existence du fichier */ + int flags; /* Mode d'accès au fichier */ - orig = strdup(input); + asprintf(&pathname, "%s%s.h", info->directory, name); - point = strstr(orig, "."); - if (point != NULL) *point = '\0'; + ret = access(pathname, F_OK); - if (prefix == NULL) - { - length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(name) + 3; - result = (char *)calloc(length, sizeof(char)); - snprintf(result, length, ".gen/%s.%s.%c", orig, name, ext); - } + *new = (ret != 0); + + if (*new) + flags = O_WRONLY | O_CREAT; else - { - length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(prefix) + 1 + strlen(name) + 3; - result = (char *)calloc(length, sizeof(char)); - snprintf(result, length, ".gen/%s.%s.%s.%c", orig, prefix, name, ext); - } + flags = O_WRONLY | O_APPEND; + + result = open(pathname, flags, 0644); + if (result == -1) perror("open()"); - free(orig); + free(pathname); return result; } + /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* intput = fichier d'entrée initial à référencer. * -* prefix = type d'encodage à répercuter sur le nom de fichier. * -* name = nom brut du fichier à ouvrir. * -* ext = extension à donner au fichier à ouvrir. * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* name = nom du fichier ciblé par l'opération. * +* msg = complément d'information à faire paraître. * * * -* Description : Ouvre un fichier en écriture pour y placer du code. * +* Description : Imprime dans un flux donné un commentaire de propriété. * * * -* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static int create_code_file(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext) +static void write_header_file_license(int fd, const output_info *info, const char *name, const char *msg) { - int result; /* Descripteur à retourner */ - char *pathname; /* Chemin d'accès à constituer */ - - if (!check_gen_dir(coder)) - return -1; + time_t seconds; /* Temps écoulé depuis T0 */ + struct tm cur_date; /* Informations sur la date */ - pathname = build_code_filename(coder, input, prefix, name, ext); + time(&seconds); + localtime_r(&seconds, &cur_date); - result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (result == -1) perror("open()"); + dprintf(fd, "\n"); - free(pathname); + dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); + dprintf(fd, " * %s.h - %s %s\n", name, msg, info->arch); + dprintf(fd, " *\n"); + dprintf(fd, " * Copyright (C) %d Cyrille Bagard\n", 1900 + cur_date.tm_year); + dprintf(fd, " *\n"); + dprintf(fd, " * This file is part of Chrysalide.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n"); + dprintf(fd, " * it under the terms of the GNU General Public License as published by\n"); + dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n"); + dprintf(fd, " * (at your option) any later version.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n"); + dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + dprintf(fd, " * GNU General Public License for more details.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * You should have received a copy of the GNU General Public License\n"); + dprintf(fd, " * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n"); + dprintf(fd, " */\n"); - return result; + dprintf(fd, "\n"); + dprintf(fd, "\n"); } /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement de l'humain.* +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* name = nom du fichier ciblé par l'opération. * +* copyright = droits d'auteur à faire valoir. * * * -* Description : Débute la définition des fonctions issues des spécifications.* +* Description : Imprime dans un flux donné un commentaire de propriété. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool dump_all_routines_using_coder(const rented_coder *coder) +static void write_code_file_license(int fd, const output_info *info, const char *name, const char *copyright) { - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours #1 */ - const string_exch *encoding; /* Type d'encodage visé */ - size_t j; /* Boucle de parcours #2 */ - char *remove; /* Chemin de suppression */ - int header_fd; /* Fichier de déclarations */ - char *dash; /* Présence d'un tiret ? */ - char *filename; /* Nom de fichier commun */ - int code_fd; /* Fichier de définitions */ + dprintf(fd, "\n"); - result = true; + dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); + dprintf(fd, " * %s.c - traduction d'instructions %s\n", name, info->arch); + dprintf(fd, " *\n"); + dprintf(fd, " * %s\n", copyright); + dprintf(fd, " *\n"); + dprintf(fd, " * This file is part of Chrysalide.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n"); + dprintf(fd, " * it under the terms of the GNU General Public License as published by\n"); + dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n"); + dprintf(fd, " * (at your option) any later version.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n"); + dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + dprintf(fd, " * GNU General Public License for more details.\n"); + dprintf(fd, " *\n"); + dprintf(fd, " * You should have received a copy of the GNU General Public License\n"); + dprintf(fd, " * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n"); + dprintf(fd, " */\n"); - for (i = 0; i < count_encodings(coder->pp) && result; i++) - { - encoding = find_encoding(coder->pp, i); + dprintf(fd, "\n"); + dprintf(fd, "\n"); - /* On s'assure qu'il existe bien une version pour l'encodage visé... */ +} - for (j = 0; j < coder->specs_count; j++) - if (has_encoding_spec_prefix(coder->specs[j], encoding->src)) - break; - /* Suppressions ? */ - if (j == coder->specs_count) - { - /* Fichier de déclarations */ +/****************************************************************************** +* * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* prefix = préfixe lié à une sous-branche de l'architecture. * +* * +* Description : Initialise le contenu utile du fichier des instructions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - /* - remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); - unlink(remove); - free(remove); - */ +static void init_coder_opcodes_file(int fd, const output_info *info, const char *prefix) +{ + char *sub; /* Sous-partie à intégrer */ - remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); - unlink(remove); - free(remove); + if (prefix != NULL) + { + sub = strdup(prefix); + make_string_upper(sub); - /* Fichier de définitions */ + dprintf(fd, "#ifndef _%s_%s_OPCODES_H\n", info->guard, sub); + dprintf(fd, "#define _%s_%s_OPCODES_H\n", info->guard, sub); - dash = strchr(coder->ins, '-'); + free(sub); - if (dash == NULL) - { - /* - remove = build_template_filename(coder, encoding->dest, coder->ins, 'c'); - unlink(remove); - free(remove); - */ + } - remove = build_code_filename(coder, coder->input, encoding->dest, coder->ins, 'c'); - unlink(remove); - free(remove); + else + { + dprintf(fd, "#ifndef _%s_OPCODES_H\n", info->guard); + dprintf(fd, "#define _%s_OPCODES_H\n", info->guard); + } - } + dprintf(fd, "\n"); + dprintf(fd, "\n"); - else - { - filename = strdup(coder->ins); + dprintf(fd, "##INCLUDES##\n"); - dash = strchr(filename, '-'); - *dash = '\0'; + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); - /* - remove = build_template_filename(coder, encoding->dest, filename, 'c'); - unlink(remove); - free(remove); - */ +} - remove = build_code_filename(coder, coder->input, encoding->dest, filename, 'c'); - unlink(remove); - free(remove); - } +/****************************************************************************** +* * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* prefix = type d'encodage à répercuter sur un nom de fichier. * +* * +* Description : Initialise le contenu utile d'un fichier d'instructions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - } +static void init_coder_code_file(int fd, const char *prefix) +{ + if (prefix != NULL) + dprintf(fd, "#include \"%s_opcodes.h\"\n", prefix); + else + dprintf(fd, "#include \"opcodes.h\"\n"); - /* Créations ? */ - else - { - /* Fichier de déclarations */ + dprintf(fd, "\n"); + dprintf(fd, "\n"); - if (!create_template_file(coder, encoding->dest, "opcodes", 'h')) - return false; + dprintf(fd, "##INCLUDES##\n"); - header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h'); - if (header_fd == -1) return false; + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); - /* Fichier de définitions */ +} - dash = strchr(coder->ins, '-'); - if (dash == NULL) - { - if (!create_template_file(coder, encoding->dest, coder->ins, 'c')) - return false; +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * +* * +* Description : Génère ou complète un fichier contenant le code C principal. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c'); +bool output_coder_body(const rented_coder *coder, const output_info *info) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours #1 */ + const string_exch *enc_name; /* Type d'encodage visé */ + size_t j; /* Boucle de parcours #2 */ + int header_fd; /* Fichier de déclarations */ + char *file; /* Nom de fichier final */ + bool header_new; /* Note une création d'entête */ + int code_fd; /* Fichier de définitions */ + bool code_new; /* Note une création de code */ - } + result = true; - else + for (i = 0; i < count_encodings(coder->pp) && result; i++) + { + enc_name = find_encoding(coder->pp, i); + + for (j = 0; j < coder->specs_count; j++) + { + /* On s'assure qu'il existe bien une version pour l'encodage visé... */ + if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src)) + continue; + + header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new); + if (header_fd == -1) { - filename = strdup(coder->ins); + result = false; + goto ocb_exit; + } - dash = strchr(filename, '-'); - *dash = '\0'; + if (header_new) + { + if (enc_name->dest == NULL) + file = strdup("opcodes"); + else + asprintf(&file, "%s_opcodes", enc_name->dest); - if (!create_template_file(coder, encoding->dest, filename, 'c')) - return false; + write_header_file_license(header_fd, info, file, "prototypes pour la traduction d'instructions"); - code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c'); + free(file); - free(filename); + init_coder_opcodes_file(header_fd, info, enc_name->dest); } + code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new); if (code_fd == -1) { - close(header_fd); + result = false; + goto ocb_exit; + } - /* - remove = build_template_filename(coder, encoding->dest, "opcodes", 'h'); - unlink(remove); - free(remove); - */ + if (code_new) + { + if (enc_name->dest == NULL) + file = strdup(coder->ins); + else + asprintf(&file, "%s_%s", enc_name->dest, coder->ins); - remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h'); - unlink(remove); - free(remove); + write_code_file_license(code_fd, info, file, coder->copyright); - return false; + free(file); - } + init_coder_code_file(code_fd, enc_name->dest); - /* Production de code... */ + } + else + dprintf(code_fd, "\n"); - switch (coder->type) + switch (info->type) { case IOT_UNDEFINED: assert(false); @@ -908,22 +1040,56 @@ bool dump_all_routines_using_coder(const rented_coder *coder) break; case IOT_RAW: - result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); + result = output_coder_raw(coder, info, enc_name, coder->specs[j], header_fd, code_fd); break; case IOT_FORMAT: - result = dump_all_matching_specs_from_format(coder, encoding, header_fd, code_fd); + assert(enc_name->dest == NULL); + result = output_coder_format(coder, info, enc_name, coder->specs[j], header_fd, code_fd); break; } - close(header_fd); - close(code_fd); + } + + /* La suite ne concerne que les formats bruts aboutis... */ + if (!result) break; + if (info->type != IOT_RAW) continue; + + for (j = 0; j < coder->specs_count; j++) + { + /* On s'assure de retrouver une version de l'encodage visé juste avant... */ + if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src)) + continue; + + header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new); + if (header_fd == -1) + { + result = false; + goto ocb_exit; + } + + assert(!header_new); + + code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new); + if (code_fd == -1) + { + result = false; + goto ocb_exit; + } + + assert(!code_new); + + result = output_coder_main_raw(coder, info, enc_name, header_fd, code_fd); + + break; } } + ocb_exit: + return result; } @@ -931,12 +1097,39 @@ bool dump_all_routines_using_coder(const rented_coder *coder) /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement d'humain. * +* Paramètres : fd = flux ouvert en écriture. * +* arch = architecture en cours de traitement. * +* sub = encodage choisi comme sous-ensemble d'architecture. * +* name = désignation complète d'une instruction. * +* * +* Description : Centralise l'impression du nom de fonction de désassemblage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void write_read_function_name(int fd, const char *arch, const string_exch *sub, const char *name) +{ + if (sub->dest == NULL) + dprintf(fd, "%s_read_instr_%s", arch, name); + else + dprintf(fd, "%s_read_%s_instr_%s", arch, sub->dest, name); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion automatique de l'écriture de code. * +* info = précisions quant à la génération. * +* enc_name = désignation du type d'encodage visé. * * encoding = sélection de l'encodage à traiter. * * hfd = flux ouvert en écriture pour les déclarations. * * cfd = flux ouvert en écriture pour les définitions. * * * -* Description : Ecrit une partie des fonctions issues des spécifications. * +* Description : Génère ou complète un fichier contenant le code C principal. * * * * Retour : Bilan de l'opération. * * * @@ -944,55 +1137,152 @@ bool dump_all_routines_using_coder(const rented_coder *coder) * * ******************************************************************************/ -static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) +static bool output_coder_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *encoding, int hfd, int cfd) { bool result; /* Bilan à retourner */ - char *keyword; /* Mot clef appelable en code */ - unsigned int wide; /* Taille des mots */ - size_t i; /* Boucle de parcours */ - encoding_spec *spec; /* Définition à traiter */ + char *arch; /* Architecture à traiter */ + char *name; /* Désignation à manipuler */ + char *prefix; /* Préfixe employé en suffixe */ coding_bits *bits; /* Gestionnaire de bits */ + unsigned int wide; /* Taille des mots */ size_t maxlen; /* Taille à compléter */ - result = true; + arch = strdup(info->arch_cn); + make_string_lower(arch); - keyword = make_callable(coder->ins, false); + name = get_coder_code_name(coder); - /* Recherche de la taille des mots */ + prefix = build_encoding_spec_prefix(encoding); - wide = -1; + bits = get_bits_in_encoding_spec(encoding); + wide = count_coded_bits(bits); - for (i = 0; i < coder->specs_count; i++) + /* Désassemblage : déclaration */ + + if (0 /* TODO : export seulement */) { - spec = coder->specs[i]; + dprintf(hfd, "/* Décode une forme d'instruction de type '%s'. */\n", coder->ins); - if (!has_encoding_spec_prefix(spec, encoding->src)) - continue; + dprintf(hfd, "GArchInstruction *"); + write_read_function_name(hfd, arch, enc_name, name); + dprintf(hfd, "_%s", prefix); - bits = get_bits_in_encoding_spec(spec); - wide = count_coded_bits(bits); - break; + dprintf(hfd, "("); + dprintf(hfd, "uint%u_t raw", wide); + dprintf(hfd, ");\n"); + + dprintf(hfd, "\n"); } - /** - * Rien n'a été trouvé à faire... - * Cette situation doit normalement être écartée par l'appelant, - * afin d'éviter de constituer des fichiers vides. - */ - assert(wide != -1); + /* Désassemblage : définitions */ + + dprintf(cfd, "/******************************************************************************\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Description : Décode une forme d'instruction de type '%s'.", coder->ins); + + maxlen = 20 - strlen(coder->ins); + + if (maxlen < 20) + dprintf(cfd, "%*s\n", (int)maxlen, "*"); + else + dprintf(cfd, "*\n"); + + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "* Remarques : - *\n"); + dprintf(cfd, "* *\n"); + dprintf(cfd, "******************************************************************************/\n"); + + dprintf(cfd, "\n"); + + if (1 /* TODO : si pas exportée */) + dprintf(cfd, "static "); + + dprintf(cfd, "GArchInstruction *"); + write_read_function_name(cfd, arch, enc_name, name); + dprintf(cfd, "_%s", prefix); + + dprintf(cfd, "("); + dprintf(cfd, "uint%u_t raw", wide); + dprintf(cfd, ")"); + + dprintf(cfd, "\n"); + dprintf(cfd, "{"); + dprintf(cfd, "\n"); + + result = write_encoding_spec_raw_disass(encoding, cfd, arch, coder->id, coder->pp); + + dprintf(cfd, "}\n"); + dprintf(cfd, "\n"); + + /* Conclusion */ + + free(prefix); + + free(name); + + free(arch); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion automatique de l'écriture de code. * +* info = précisions quant à la génération. * +* enc_name = désignation du type d'encodage visé. * +* hfd = flux ouvert en écriture pour les déclarations. * +* cfd = flux ouvert en écriture pour les définitions. * +* * +* Description : Génère ou complète un fichier contenant le code C principal. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool output_coder_main_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, int hfd, int cfd) +{ + bool result; /* Bilan à retourner */ + char *arch; /* Architecture à traiter */ + char *name; /* Désignation à manipuler */ + unsigned int wide; /* Taille des mots */ + size_t maxlen; /* Taille à compléter */ + bool first; /* Note un premier appel */ + size_t i; /* Boucle de parcours */ + char *prefix; /* Préfixe employé en suffixe */ + + result = false; + + arch = strdup(info->arch_cn); + make_string_lower(arch); + + name = get_coder_code_name(coder); + + wide = get_bit_width_for_encoding_spec(coder, enc_name); /* Désassemblage : déclaration */ dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins); - dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t);\n", - coder->arch, encoding->dest, keyword, coder->details, wide); + + dprintf(hfd, "GArchInstruction *"); + write_read_function_name(hfd, arch, enc_name, name); + + dprintf(hfd, "("); + dprintf(hfd, "uint%u_t raw", wide); + dprintf(hfd, ");\n"); + dprintf(hfd, "\n"); /* Désassemblage : définitions */ - dprintf(cfd, "\n"); - dprintf(cfd, "/******************************************************************************\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n"); @@ -1006,7 +1296,7 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st else dprintf(cfd, "*\n"); - dprintf(cfd, " *\n"); + dprintf(cfd, "* *\n"); dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Remarques : - *\n"); @@ -1015,27 +1305,55 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st dprintf(cfd, "\n"); - dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t raw)", - coder->arch, encoding->dest, keyword, coder->details, wide); + dprintf(cfd, "GArchInstruction *"); + write_read_function_name(cfd, arch, enc_name, name); + + dprintf(cfd, "("); + dprintf(cfd, "uint%u_t raw", wide); + dprintf(cfd, ")"); + dprintf(cfd, "\n"); dprintf(cfd, "{"); dprintf(cfd, "\n"); dprintf(cfd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); - - dprintf(cfd, "\n"); - dprintf(cfd, "\tresult = NULL;\n"); dprintf(cfd, "\n"); - for (i = 0; i < coder->specs_count && result; i++) - { - spec = coder->specs[i]; + first = true; - if (!has_encoding_spec_prefix(spec, encoding->src)) + for (i = 0; i < coder->specs_count; i++) + { + if (!has_encoding_spec_prefix(coder->specs[i], enc_name->src)) continue; - result = write_encoding_spec_disass(spec, cfd, coder->arch, encoding->dest, - coder->ins, coder->details, wide, coder->pp); + result = true; + + prefix = build_encoding_spec_prefix(coder->specs[i]); + + if (first) + { + dprintf(cfd, "\tresult = "); + write_read_function_name(cfd, arch, enc_name, name); + dprintf(cfd, "_%s(raw);\n", prefix); + + dprintf(cfd, "\n"); + + first = false; + + } + else + { + dprintf(cfd, "\tif (result == NULL)\n"); + + dprintf(cfd, "\t\tresult = "); + write_read_function_name(cfd, arch, enc_name, name); + dprintf(cfd, "_%s(raw);\n", prefix); + + dprintf(cfd, "\n"); + + } + + free(prefix); } @@ -1045,7 +1363,11 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st dprintf(cfd, "}\n"); dprintf(cfd, "\n"); - free(keyword); + /* Conclusion */ + + free(name); + + free(arch); return result; @@ -1054,12 +1376,14 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st /****************************************************************************** * * -* Paramètres : coder = gestion par la machine en remplacement d'humain. * +* Paramètres : coder = gestion automatique de l'écriture de code. * +* info = précisions quant à la génération. * +* enc_name = désignation du type d'encodage visé. * * encoding = sélection de l'encodage à traiter. * * hfd = flux ouvert en écriture pour les déclarations. * * cfd = flux ouvert en écriture pour les définitions. * * * -* Description : Ecrit une partie des fonctions issues des spécifications. * +* Description : Génère ou complète un fichier contenant le code C principal. * * * * Retour : Bilan de l'opération. * * * @@ -1067,25 +1391,24 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st * * ******************************************************************************/ -static bool dump_all_matching_specs_from_format(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) +static bool output_coder_format(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *encoding, int hfd, int cfd) { bool result; /* Bilan à retourner */ - char *keyword; /* Mot clef appelable en code */ + char *arch; /* Architecture à traiter */ + char *name; /* Désignation à manipuler */ size_t maxlen; /* Taille à compléter */ - encoding_spec *spec; /* Définition à traiter */ - keyword = make_callable(coder->ins, false); + arch = strdup(info->arch_cn); + make_string_lower(arch); + + name = get_coder_code_name(coder); /* Désassemblage : déclaration */ dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins); - if (encoding->dest == NULL) - dprintf(hfd, "GArchInstruction *%s_read_instr_%s%s", - coder->arch, keyword, coder->details); - else - dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s", - coder->arch, encoding->dest, keyword, coder->details); + dprintf(hfd, "GArchInstruction *"); + write_read_function_name(hfd, arch, enc_name, name); dprintf(hfd, "("); dprintf(hfd, "const GArchProcessor *, GProcContext *, const GBinContent *, "); @@ -1096,8 +1419,6 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const /* Désassemblage : définitions */ - dprintf(cfd, "\n"); - dprintf(cfd, "/******************************************************************************\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Paramètres : proc = processeur de l'architecture d'exécution. *\n"); @@ -1115,7 +1436,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const else dprintf(cfd, "*\n"); - dprintf(cfd, " *\n"); + dprintf(cfd, "* *\n"); dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n"); dprintf(cfd, "* *\n"); dprintf(cfd, "* Remarques : - *\n"); @@ -1124,12 +1445,8 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const dprintf(cfd, "\n"); - if (encoding->dest == NULL) - dprintf(cfd, "GArchInstruction *%s_read_instr_%s%s", - coder->arch, keyword, coder->details); - else - dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s", - coder->arch, encoding->dest, keyword, coder->details); + dprintf(cfd, "GArchInstruction *"); + write_read_function_name(cfd, arch, enc_name, name); dprintf(cfd, "("); dprintf(cfd, "const GArchProcessor *proc, GProcContext *ctx, const GBinContent *content, "); @@ -1140,20 +1457,523 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const dprintf(cfd, "{"); dprintf(cfd, "\n"); - assert(coder->specs_count == 1); + result = write_encoding_spec_format_disass(encoding, cfd, arch, coder->id, info->fmt_prefix); - spec = coder->specs[0]; + dprintf(cfd, "}\n"); + dprintf(cfd, "\n"); - assert(has_encoding_spec_prefix(spec, encoding->src)); + /* Conclusion */ - result = write_encoding_spec_format_disass(spec, cfd, coder->arch, encoding->dest, - coder->ins, coder->separator, coder->raw_details, - coder->pp, coder->const_prefix); + free(name); - dprintf(cfd, "}\n"); - dprintf(cfd, "\n"); + free(arch); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pathname = chemin d'accès au fichier à traiter. * +* info = précisions quant à la génération. * +* * +* Description : Finalise le contenu utile du fichier des instructions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool fini_coder_opcodes_file(const char *pathname, const output_info *info) +{ + bool result; /* Bilan à retourner */ + int fd; /* Flux ouvert en écriture */ + char *temp; /* Zone de travail temporaire */ + char *base; /* Identification de fichier */ + + result = false; + + fd = open(pathname, O_WRONLY | O_APPEND, 0644); + if (fd == -1) + { + perror("open()"); + goto fcif_exit; + } + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + temp = strdup(pathname); + base = basename(temp); + + base[strlen(base) - 2] = '\0'; + + make_string_upper(base); + + dprintf(fd, "#endif /* _%s_%s_H */\n", info->guard, base); + + free(temp); + + result = true; + + fcif_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* * +* Description : Initialise le contenu utile du fichier des identifiants. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_coder_identifiers_file(int fd, const output_info *info) +{ + dprintf(fd, "#ifndef _%s_IDENTIFIERS_H\n", info->guard); + dprintf(fd, "#define _%s_IDENTIFIERS_H\n", info->guard); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + dprintf(fd, "/* Enumération de tous les opcodes */\n"); + dprintf(fd, "typedef enum _%sOpcodes\n", info->arch_cn); + dprintf(fd, "{\n"); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * +* * +* Description : Génère ou complète un fichier constituant les identifiants. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool output_coder_identifier(const rented_coder *coder, const output_info *info) +{ + bool result; /* Bilan à retourner */ + bool created; /* Note une création */ + int fd; /* Flux ouvert en écriture */ + char *name; /* Désignation à manipuler */ + instr_id *id; /* Gestionnaire d'identifiant */ + unsigned int iid; /* Identifiant unique attribué */ + char *constant; /* Définition d'une constante */ + char *comment; /* Contenu du commentaire */ + + result = false; + + /* Ouverture de la destination */ + + fd = open_global_header_file(coder, info, "identifiers", &created); + if (fd == -1) goto oci_exit; + + if (created) + { + write_header_file_license(fd, info, "identifiers", "définition des identifiants uniques pour"); + init_coder_identifiers_file(fd, info); + } + + /* Constitution de la constante */ + + name = get_coder_code_name(coder); + make_string_upper(name); + + asprintf(&constant, "%s_%s,", info->id_prefix, name); + + free(name); + + /* Définition du commentaire */ + + name = get_coder_nominal_name(coder); + + id = get_coder_instruction_id(coder); + iid = get_instruction_id_value(id); + + asprintf(&comment, "%s (0x%0*x)", name, info->id_len, iid); + + free(name); + + /* Impression de la ligne */ + + dprintf(fd, " %-40s/* %-28s*/\n", constant, comment); + + free(constant); + free(comment); + + result = true; + + oci_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pathname = chemin d'accès au fichier à traiter. * +* info = précisions quant à la génération. * +* * +* Description : Finalise le contenu utile du fichier des identifiants. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool fini_coder_identifiers_file(const char *pathname, const output_info *info) +{ + bool result; /* Bilan à retourner */ + int fd; /* Flux ouvert en écriture */ + + result = false; + + fd = open(pathname, O_WRONLY | O_APPEND, 0644); + if (fd == -1) + { + perror("open()"); + goto fcif_exit; + } + + dprintf(fd, "\n"); + dprintf(fd, " %s_COUNT\n", info->id_prefix); + dprintf(fd, "\n"); + + dprintf(fd, "} %sOpcodes;\n", info->arch_cn); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + dprintf(fd, "#endif /* _%s_IDENTIFIERS_H */\n", info->guard); + + result = true; + + fcif_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* * +* Description : Initialise le contenu utile du fichier des mots clefs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_coder_keywords_file(int fd, const output_info *info) +{ + char *larch; /* Architecture en minuscules */ + + dprintf(fd, "#ifndef _%s_KEYWORDS_H\n", info->guard); + dprintf(fd, "#define _%s_KEYWORDS_H\n", info->guard); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "#include \"identifiers.h\"\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + larch = strdup(info->arch_cn); + make_string_lower(larch); + + dprintf(fd, "/* Enumération de tous les mots clefs */\n"); + dprintf(fd, "static char *_%s_keywords[%s_COUNT] = {\n", larch, info->id_prefix); + dprintf(fd, "\n"); + + free(larch); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * +* * +* Description : Génère ou complète un fichier constituant les mots clefs. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool output_coder_keyword(const rented_coder *coder, const output_info *info) +{ + bool result; /* Bilan à retourner */ + bool created; /* Note une création */ + int fd; /* Flux ouvert en écriture */ + char *name; /* Désignation à manipuler */ + + result = false; + + /* S'il n'y a pas lieu de traiter l'instruction */ + + if (coder->useless) + { + result = true; + goto ock_exit; + } + + /* Ouverture de la destination */ + + fd = open_global_header_file(coder, info, "keywords", &created); + if (fd == -1) goto ock_exit; + + if (created) + { + write_header_file_license(fd, info, "keywords", "définition des mots clefs des instructions"); + init_coder_keywords_file(fd, info); + } + + /* Impression de la colonne */ + + name = get_coder_code_name(coder); + make_string_upper(name); + + dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name); + + free(name); + + /* Impression du mot clef */ + + name = get_coder_nominal_name(coder); + + dprintf(fd, "\"%s\",\n", name); + + free(name); + + result = true; + + ock_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pathname = chemin d'accès au fichier à traiter. * +* info = précisions quant à la génération. * +* * +* Description : Finalise le contenu utile du fichier des mots clefs. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool fini_coder_keywords_file(const char *pathname, const output_info *info) +{ + bool result; /* Bilan à retourner */ + int fd; /* Flux ouvert en écriture */ + + result = false; + + fd = open(pathname, O_WRONLY | O_APPEND, 0644); + if (fd == -1) + { + perror("open()"); + goto fckf_exit; + } + + dprintf(fd, "\n"); + dprintf(fd, "};\n"); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + dprintf(fd, "#endif /* _%s_KEYWORDS_H */\n", info->guard); + + result = true; + + fckf_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : fd = flux ouvert en écriture mis à disposition. * +* info = précisions quant à la génération. * +* * +* Description : Initialise le contenu utile du fichier des descriptions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_coder_descriptions_file(int fd, const output_info *info) +{ + char *larch; /* Architecture en minuscules */ + + dprintf(fd, "#ifndef _%s_DESCRIPTIONS_H\n", info->guard); + dprintf(fd, "#define _%s_DESCRIPTIONS_H\n", info->guard); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "#include \"identifiers.h\"\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + larch = strdup(info->arch_cn); + make_string_lower(larch); + + dprintf(fd, "/* Enumération de tous les mots clefs */\n"); + dprintf(fd, "static char *_%s_descriptions[%s_COUNT] = {\n", larch, info->id_prefix); + dprintf(fd, "\n"); + + free(larch); + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* info = précisions quant à la génération. * +* * +* Description : Génère ou complète un fichier constituant les descriptions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool output_coder_description(const rented_coder *coder, const output_info *info) +{ + bool result; /* Bilan à retourner */ + bool created; /* Note une création */ + int fd; /* Flux ouvert en écriture */ + char *name; /* Désignation à manipuler */ + + result = false; + + /* S'il n'y a pas lieu de traiter l'instruction */ + + if (coder->useless) + { + result = true; + goto ock_exit; + } + + /* Ouverture de la destination */ + + fd = open_global_header_file(coder, info, "descriptions", &created); + if (fd == -1) goto ock_exit; + + if (created) + { + write_header_file_license(fd, info, "descriptions", "définition des descriptions des instructions"); + init_coder_descriptions_file(fd, info); + } + + /* Impression de la colonne */ + + name = get_coder_code_name(coder); + make_string_upper(name); + + dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name); + + free(name); + + /* Impression du mot clef */ + + name = get_coder_nominal_name(coder); + + dprintf(fd, "\""); + + write_instruction_description(coder->desc, fd); + + dprintf(fd, "\",\n"); + + free(name); + + result = true; + + ock_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pathname = chemin d'accès au fichier à traiter. * +* info = précisions quant à la génération. * +* * +* Description : Finalise le contenu utile du fichier des descriptions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool fini_coder_descriptions_file(const char *pathname, const output_info *info) +{ + bool result; /* Bilan à retourner */ + int fd; /* Flux ouvert en écriture */ + + result = false; + + fd = open(pathname, O_WRONLY | O_APPEND, 0644); + if (fd == -1) + { + perror("open()"); + goto fckf_exit; + } + + dprintf(fd, "\n"); + dprintf(fd, "};\n"); + + dprintf(fd, "\n"); + dprintf(fd, "\n"); + dprintf(fd, "\n"); + + dprintf(fd, "#endif /* _%s_DESCRIPTIONS_H */\n", info->guard); + + result = true; - free(keyword); + fckf_exit: return result; diff --git a/tools/d2c/coder.h b/tools/d2c/coder.h index 682dfe6..66ab66c 100644 --- a/tools/d2c/coder.h +++ b/tools/d2c/coder.h @@ -28,8 +28,10 @@ #include <stdbool.h> +#include "encoding.h" #include "pproc.h" -#include "spec.h" +#include "desc/manager.h" +#include "id/manager.h" @@ -41,18 +43,8 @@ typedef struct _rented_coder rented_coder; /* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ -/* Type d'entrée/sortie attendues */ -typedef enum _InputOutputType -{ - IOT_UNDEFINED, /* Type non défini */ - IOT_RAW, /* Lecture de contenu brut */ - IOT_FORMAT /* Définition d'opérandes */ - -} InputOutputType; - - /* Débute la définition d'une fonction de désassemblage. */ -rented_coder *create_coder(void); +rented_coder *create_coder(pre_processor *); /* Supprime le codeur de la mémoire. */ void delete_coder(rented_coder *); @@ -67,10 +59,7 @@ const char *get_coder_input_file(const rented_coder *); void set_coder_input_file(rented_coder *, const char *); /* Spécifie le type de format à prendre en compte (E/S). */ -void set_coder_input_type(rented_coder *, InputOutputType); - -/* Spécifie le répertoire de base pour les sorties de code. */ -void set_coder_output_directory(rented_coder *, const char *); +//void set_coder_input_type(rented_coder *, InputOutputType); /* Détermine l'architecture visée par les traitements. */ void set_coder_arch(rented_coder *, const char *); @@ -81,66 +70,94 @@ void set_coder_header_base(rented_coder *, const char *); /* Définit le préfixe pour les opérandes chargées par format. */ void set_coder_const_prefix(rented_coder *, const char *); -/* Fournit le pré-processeur du compilateur. */ -pre_processor *get_coder_pre_proc(const rented_coder *); -/* Enregistre les contours d'une instruction d'assemblage. */ -void save_notes_for_coder(rented_coder *, char *, char *, char, const char *); +/* ----------------------------- INFORMATIONS GENERALES ----------------------------- */ -/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ +/* Enregistre les contours d'une instruction d'assemblage. */ +void save_notes_for_coder(rented_coder *, char *, char *, char, const char *); +/* Fournit la désignation nominale d'une instruction. */ +char *get_coder_nominal_name(const rented_coder *); -/* Fournit un lien vers les spécifications courantes. */ -encoding_spec *get_current_encoding_spec(const rented_coder *); +/* Fournit la désignation complète d'une instruction. */ +char *get_coder_code_name(const rented_coder *); -/* Enregistre une définition supplémentaire. */ -void push_encoding_spec(rented_coder *, char *, unsigned int); +/* Fournit le gestionnaire des définitions d'identifiant. */ +instr_id *get_coder_instruction_id(const rented_coder *); +/* Fournit le gestionnaire de description d'identifiant. */ +instr_desc *get_coder_instruction_desc(const rented_coder *); -/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ +/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ -/* Note la présence d'un champ remarquable dans une définition. */ -void register_named_field_in_coder(rented_coder *, char *, unsigned int); -/* Note la présence d'un bit invariable dans une définition. */ -void register_bit_in_coder(rented_coder *, int); +/* Fournit un lien vers les spécifications courantes. */ +encoding_spec *get_current_encoding_spec(const rented_coder *); -/* Indique le nombre de bits traités. */ -//unsigned int count_coder_bits(const rented_coder *); +/* Enregistre une définition supplémentaire. */ +void push_encoding_spec(rented_coder *, char *, unsigned int); +/* Marque une instruction comme non utilisée. */ +void mark_coder_as_useless(rented_coder *coder); -/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */ +/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ -/* Enregistre la présence d'un nouvel opérande. */ -void register_syntax_item_in_coder(rented_coder *, char *, bool); +/* Type d'entrée/sortie attendues */ +typedef enum _InputOutputType +{ + IOT_UNDEFINED, /* Type non défini */ + IOT_RAW, /* Lecture de contenu brut */ + IOT_FORMAT /* Définition d'opérandes */ +} InputOutputType; -/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ +/* Regroupement des informations utiles à la génération */ +typedef struct _output_info +{ + const char *directory; /* Répertoire de destination */ + InputOutputType type; /* Type des définitions (E/S) */ + const char *arch; /* Architecture à traiter */ + const char *arch_cn; /* Nom de code de l'archi. */ + const char *guard; /* Portion de macro globale */ + const char *fmt_prefix; /* Préfixe pour les opérandes */ -/* Enregistre la function de conversion du brut à l'utile. */ -void register_conversion_in_coder(rented_coder *, conv_func *); + const char *id_prefix; /* Préfixe pour les constantes */ + int id_len; /* Largeur des identifiants */ +} output_info; -/* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */ +/* Génère ou complète un fichier contenant le code C principal. */ +bool output_coder_body(const rented_coder *, const output_info *); +/* Finalise le contenu utile du fichier des instructions. */ +bool fini_coder_opcodes_file(const char *, const output_info *); +/* Génère ou complète un fichier constituant les identifiants. */ +bool output_coder_identifier(const rented_coder *, const output_info *); +/* Finalise le contenu utile du fichier des identifiants. */ +bool fini_coder_identifiers_file(const char *, const output_info *); +/* Génère ou complète un fichier constituant les mots clefs. */ +bool output_coder_keyword(const rented_coder *, const output_info *); -/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ +/* Finalise le contenu utile du fichier des mots clefs. */ +bool fini_coder_keywords_file(const char *, const output_info *); +/* Génère ou complète un fichier constituant les descriptions. */ +bool output_coder_description(const rented_coder *, const output_info *); -/* Débute la définition des fonctions issues des spécifications. */ -bool dump_all_routines_using_coder(const rented_coder *); +/* Finalise le contenu utile du fichier des descriptions. */ +bool fini_coder_descriptions_file(const char *, const output_info *); diff --git a/tools/d2c/conv/Makefile.am b/tools/d2c/conv/Makefile.am index d2d495b..a22d5f7 100644 --- a/tools/d2c/conv/Makefile.am +++ b/tools/d2c/conv/Makefile.am @@ -26,6 +26,9 @@ libd2cconv_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2cconv_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/conv/manager.c b/tools/d2c/conv/manager.c index 555ea38..33518db 100644 --- a/tools/d2c/conv/manager.c +++ b/tools/d2c/conv/manager.c @@ -29,6 +29,7 @@ #include <malloc.h> #include <stdbool.h> #include <string.h> +#include <unistd.h> #include "../helpers.h" @@ -42,11 +43,6 @@ /* Fonction de conversion */ struct _conv_func { - bool used; /* Conversion utilisée ? */ - bool intermediate; /* Variable intermédiaire ? */ - 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 */ @@ -64,9 +60,18 @@ struct _conv_func }; + bool used_as_inter; /* Variable intermédiaire ? */ + bool used_as_op; /* Opérande finale d'instruct° */ + bool declared; /* Expression déjà déclarée ? */ + bool defined; /* Expression déjà définie ? */ + }; +/* Indique si l'utilisation en intermédiaire est brute ou non. */ +static bool is_conv_func_raw_as_inter(const conv_func *); + + /* ---------------------------- ENSEMBLES DE CONVERSIONS ---------------------------- */ @@ -196,25 +201,6 @@ const char *get_conv_dest_name(const conv_func *func) /****************************************************************************** * * * Paramètres : func = fonction de conversion à consulter. * -* * -* Description : Indique la nature d'une conversion : fonction ou expression ?* -* * -* Retour : Indication sur la constitution interne de la conversion. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool is_conv_func_expression(const conv_func *func) -{ - return func->is_expr; - -} - - -/****************************************************************************** -* * -* 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] * @@ -260,8 +246,13 @@ bool mark_conv_func(conv_func *func, bool inter, const coding_bits *bits, const { bool result; /* Bilan à remonter */ - func->used = true; - func->intermediate |= inter; + if (inter) + func->used_as_inter = true; + else + { + assert(!func->is_expr); + func->used_as_op = true; + } if (func->is_expr) result = ensure_arg_expr_content_fully_marked(func->expr, bits, list); @@ -275,69 +266,160 @@ bool mark_conv_func(conv_func *func, bool inter, const coding_bits *bits, const /****************************************************************************** * * -* 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. * -* pp = pré-processeur pour les échanges de chaînes. * -* wide = taille des mots décodés. * +* Paramètres : func = fonction de conversion à consulter. * * * -* Description : Déclare les variables associées à une fonction de conversion.* +* Description : Indique si l'utilisation en intermédiaire est brute ou non. * * * -* Retour : Bilan de l'opération. * +* Retour : true si une variable brute est à manipuler, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide) +static bool is_conv_func_raw_as_inter(const conv_func *func) { - bool result; /* Bilan à remonter */ + bool result; /* Résultat à faire remonter */ - printf(" -> declaration for '%s': declared ? %d - expr ? %d\n", - func->dest, func->declared, func->is_expr); + if (func->is_expr) + result = true; + else + result = (strcmp(func->name, "UInt") == 0); - assert(func->used); + return result; - /* Si la fonction a déjà été définie lors d'un précédent besoin... */ - if (func->declared) return true; +} - if (func->is_expr) - result = ensure_arg_expr_content_fully_declared(func->expr, fd, bits, list, pp, wide); - else - result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, pp, wide); - if (result && func->intermediate) - { - if (!func->is_expr && is_operand_producer(pp, func->name)) - dprintf(fd, "\t\tGArchOperand *val_%s;\n", func->dest); - else - dprintf(fd, "\t\tuint%u_t val_%s;\n", wide, func->dest); - } - func->declared = result; +/****************************************************************************** +* * +* Paramètres : func = fonction de conversion à manipuler. * +* fd = descripteur d'un flux ouvert en écriture. * +* inter = note un résultat de conversion comme intermédiaire. * +* * +* Description : Imprime la désignation de la destination d'une conversion. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - return result; +void write_conv_func(conv_func *func, int fd, bool inter) +{ + bool as_raw; /* Choix logique du format */ + + if (inter) + as_raw = is_conv_func_raw_as_inter(func); + else + as_raw = false; + + if (as_raw) + dprintf(fd, "val_%s", func->dest); + else + dprintf(fd, "op_%s", func->dest); } /****************************************************************************** * * -* Paramètres : func = fonction de conversion à consulter. * +* 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. * +* tab = décalage éventuel selon l'inclusion. * * * -* Description : Indique si une conversion a déjà été définie. * +* Description : Déclare les variables associées à une fonction de conversion.* * * -* Retour : Etat de la définition. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -bool is_conv_func_already_defined(const conv_func *func) +bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab) { - return func->defined; + bool result; /* Bilan à remonter */ + bool as_raw; /* Choix logique du format */ + unsigned int wide; /* Taille des mots */ + off_t start; /* Point de départ dans le code*/ + off_t end; /* Point d'arrivée dans le code*/ + + assert(func->used_as_inter || func->used_as_op); + + /** + * Si la fonction a déjà été définie lors d'un précédent besoin... + */ + if (func->declared) return true; + + if (func->is_expr) + result = ensure_arg_expr_content_fully_declared(func->expr, fd, bits, list, tab); + + else + result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, tab); + + if (result) + { + if (func->used_as_inter) + { + as_raw = is_conv_func_raw_as_inter(func); + + /** + * Si la variable intermédiaire n'est pas brute, deux cas de figure + * sont possibles : + * + * - la variable est un objet purement intermédiaire. + * - la variable est un object qui sera également utilisé en opérande. + * + * Dans les deux cas, on laisse la déclaration en tant qu'opérande + * rédiger la déclaration car il s'agit de déclarations identiques. + */ + + if (as_raw) + { + wide = count_coded_bits(bits); + + start = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "\t%suint%u_t ", tab, wide); + + write_conv_func(func, fd, true); + + dprintf(fd, ";"); + + end = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/"); + dprintf(fd, "* Champ brut à décoder */\n"); + + } + + } + + if (func->used_as_op || (func->used_as_inter && !as_raw)) + { + start = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "\t%sGArchOperand *", tab); + + write_conv_func(func, fd, false); + + dprintf(fd, ";"); + + end = lseek(fd, 0, SEEK_CUR); + + dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/"); + dprintf(fd, "* Opérande à intégrer */\n"); + + } + + } + + func->declared = result; + + return result; } @@ -345,13 +427,11 @@ bool is_conv_func_already_defined(const conv_func *func) /****************************************************************************** * * * 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. * +* tab = décalage éventuel selon l'inclusion. * +* optional = indique si l'opérande finale est optionnelle. * * exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : Définit les variables associées à une fonction de conversion.* @@ -362,89 +442,109 @@ bool is_conv_func_already_defined(const conv_func *func) * * ******************************************************************************/ -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 *exit) +bool define_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool optional, bool *exit) { bool result; /* Bilan à remonter */ - const char *callable; /* Fonction à appeler */ + bool as_raw; /* Choix logique du format */ - /* Si la fonction a déjà été définie lors d'un précédent besoin... */ - if (func->defined) return true; + /** + * Si la fonction a déjà été définie lors d'un précédent besoin... + */ + if (func->defined) + { + // TODO : faire un object_ref() si c'est un objet + //assert(0); + + return true; + + } if (func->is_expr) - result = ensure_arg_expr_content_fully_defined(func->expr, fd, arch, bits, list, pp, exit); + result = ensure_arg_expr_content_fully_defined(func->expr, fd, bits, list, tab, exit); else - result = ensure_arg_list_content_fully_defined(func->args, fd, arch, bits, list, pp, exit); - - /* Nom de la fonction effectivement appelée */ + result = ensure_arg_list_content_fully_defined(func->args, fd, bits, list, tab, exit); - if (!func->is_expr) + if (result) { - callable = find_macro(pp, func->name); + if (func->used_as_inter) + { + as_raw = is_conv_func_raw_as_inter(func); - if (callable == NULL) - callable = func->name; + /** + * Se référer au besoin aux commentaires de declare_conv_func(). + */ - } - else callable = NULL; + if (as_raw) + { + dprintf(fd, "\t%s", tab); - if (last && callable == NULL) - { - fprintf(stderr, "Error: expected function to store '%s'.\n", func->dest); - return false; - } + write_conv_func(func, fd, true); - /* Dernier niveau : la variable de destination est imposée ! */ - if (last) - { - /* Si l'on doit manipuler une propriété d'instructon... */ - if (internal) - result = checked_call_instr_func(false, callable, func->args, fd, bits, list, pp); + dprintf(fd, " = "); - /* 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); + if (func->is_expr) + result = define_arg_expr(func->expr, fd, bits, list); - result &= define_arg_list(func->args, fd, bits, list); + else + { + assert(strcmp(func->name, "UInt") == 0); + assert(get_arg_list_size(func->args) == 1); - dprintf(fd, ");\n"); + result = define_arg_list(func->args, fd, bits, list); - } + } - } + dprintf(fd, ";\n"); + 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_arg_expr(func->expr, fd, bits, list); + } - else + if (func->used_as_op || (func->used_as_inter && !as_raw)) { - dprintf(fd, "%s(", callable); + dprintf(fd, "\t%s", tab); + + write_conv_func(func, fd, false); + + dprintf(fd, " = %s(", func->name); result = define_arg_list(func->args, fd, bits, list); - dprintf(fd, ")"); + dprintf(fd, ");\n"); - } + if (optional) + { + if (as_raw) + { + fprintf(stderr, "%s can not be optional and used as intermediate value as the same time!\n", + func->dest); - dprintf(fd, ";\n"); + result = false; + + } + + } + + else + { + dprintf(fd, "\t%sif (", tab); + + write_conv_func(func, fd, false); + + dprintf(fd, " == NULL) goto bad_exit;\n"); + + *exit = true; + + } + + dprintf(fd, "\n"); - if (!func->is_expr && is_operand_producer(pp, func->name)) - { - dprintf(fd, "\t\tif (val_%s == NULL) goto bad_exit;\n", func->dest); - *exit = true; } - } + func->defined = result; - func->defined = result; + } return result; @@ -562,91 +662,3 @@ conv_func *find_named_conv_in_list(const conv_list *list, const char *name) return result; } - - -/****************************************************************************** -* * -* Paramètres : list = liste de fonctions de conversion à consulter. * -* fd = descripteur d'un flux ouvert en écriture. * -* bits = gestionnaire des bits d'encodage. * -* pp = pré-processeur pour les échanges de chaînes. * -* wide = taille des mots décodés. * -* * -* Description : Déclare l'ensemble des variables intermédiaires. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool declare_used_intermediate_conversions(const conv_list *list, int fd, const coding_bits *bits, const pre_processor *pp, unsigned int wide) -{ - bool result; /* Bilan à remonter */ - size_t i; /* Boucle de parcours */ - conv_func *func; /* Conversion à traiter */ - - result = true; - - for (i = 0; i < list->func_count && result; i++) - { - func = list->functions[i]; - - if (func->used && func->intermediate) - result = declare_conv_func(func, fd, bits, list, pp, wide); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : list = liste de fonctions de conversion à consulter. * -* fd = descripteur d'un flux ouvert en écriture. * -* arch = architecture visée par l'opération globale. * -* bits = gestionnaire des bits d'encodage. * -* pp = pré-processeur pour les échanges de chaînes. * -* exit = exprime le besoin d'une voie de sortie. [OUT] * -* * -* Description : Définit l'ensemble des variables intermédiaires. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool define_used_intermediate_conversions(const conv_list *list, int fd, const char *arch, const coding_bits *bits, const pre_processor *pp, bool *exit) -{ - bool result; /* Bilan à remonter */ - bool got_one; /* Suit le nombre d'impressions*/ - size_t i; /* Boucle de parcours */ - conv_func *func; /* Conversion à traiter */ - - result = true; - - got_one = false; - - for (i = 0; i < list->func_count && result; i++) - { - func = list->functions[i]; - - if (func->used && func->intermediate) - { - result = define_conv_func(func, false, false, fd, arch, bits, list, pp, exit); - - got_one = true; - - } - - } - - if (got_one) - dprintf(fd, "\n"); - - return result; - -} diff --git a/tools/d2c/conv/manager.h b/tools/d2c/conv/manager.h index db6e325..035635c 100644 --- a/tools/d2c/conv/manager.h +++ b/tools/d2c/conv/manager.h @@ -53,23 +53,20 @@ void delete_conv_func(conv_func *); /* Indique la variable de destination d'une conversion. */ const char *get_conv_dest_name(const conv_func *); -/* Indique la nature d'une conversion : fonction ou expression ? */ -bool is_conv_func_expression(const conv_func *); - /* Détermine la taille en bits du résultat d'une fonction. */ bool compute_conv_func_size(const conv_func *, const coding_bits *, const conv_list *, unsigned int *); /* Marque les champs utilisés par une fonction de conversion. */ bool mark_conv_func(conv_func *, bool, const coding_bits *, const conv_list *); -/* Déclare les variables associées à une fonction de conversion. */ -bool declare_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int); +/* Imprime la désignation de la destination d'une conversion. */ +void write_conv_func(conv_func *, int, bool); -/* Indique si une conversion a déjà été définie. */ -bool is_conv_func_already_defined(const conv_func *); +/* Déclare les variables associées à une fonction de conversion. */ +bool declare_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const char *); /* Définit les variables associées à une fonction de conversion. */ -bool define_conv_func(conv_func *, bool, bool, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); +bool define_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const char *, bool, bool *); @@ -92,12 +89,6 @@ void register_conversion(conv_list *, conv_func *); /* Recherche un résultat précis dans une liste de fonctions. */ conv_func *find_named_conv_in_list(const conv_list *, const char *); -/* Déclare l'ensemble des variables intermédiaires. */ -bool declare_used_intermediate_conversions(const conv_list *, int, const coding_bits *, const pre_processor *, unsigned int); - -/* Définit l'ensemble des variables intermédiaires. */ -bool define_used_intermediate_conversions(const conv_list *, int, const char *, const coding_bits *, const pre_processor *, bool *); - #endif /* _TOOLS_D2C_CONV_MANAGER_H */ diff --git a/tools/d2c/conv/tokens.l b/tools/d2c/conv/tokens.l index ef6b958..f1d196d 100644 --- a/tools/d2c/conv/tokens.l +++ b/tools/d2c/conv/tokens.l @@ -28,5 +28,12 @@ <raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; } <raw_line>"\n" { yy_pop_state(); } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c conv block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + %% diff --git a/tools/d2c/d2c.c b/tools/d2c/d2c.c new file mode 100644 index 0000000..2f10d20 --- /dev/null +++ b/tools/d2c/d2c.c @@ -0,0 +1,351 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * d2c.c - compilation d'asbtractions d'instructions + * + * Copyright (C) 2018 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 <assert.h> +#include <getopt.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "coder.h" +#include "decl.h" + + + +/* Affiche des indications sur l'utilisation du programme. */ +static void show_usage(const char *); + + +/* Commandes générales supportées */ +typedef enum _AvailableD2cCommand +{ + ADC_NONE, /* Aucune action renseignée */ + ADC_COMPILE, /* Créations principales */ + ADC_FINI /* Finition de fichier global */ + +} AvailableD2cCommand; + + + +/****************************************************************************** +* * +* Paramètres : argv0 = nombre du programme exécuté. * +* * +* Description : Affiche des indications sur l'utilisation du programme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_usage(const char *argv0) +{ + printf("\n"); + + printf("Usage: %s [options] <input file>\n", argv0); + + printf("\n"); + + printf("General options:\n"); + + printf("\n"); + + printf("\t-h | --help\t\t\tDisplay this messsage.\n"); + printf("\t-x | --exec <cc|fini>\t\tRun as compiler mode or complete the generation.\n"); + printf("\t-o | --outdir <string>\t\tSpecify the main output directory.\n"); + printf("\t-t | --type <raw|format>\tSet the type of the input file.\n"); + printf("\t-a | --arch <string>\t\tDefine the archicture to handle (CamelCase allowed).\n"); + printf("\t-n | --name <string>\t\tSet the name of the archicture for source code (CamelCase allowed).\n"); + printf("\t-G | --guard <string>\t\tSet the base of the header macros guards.\n"); + printf("\t-e | --encoding <none|string>\tDefine one encoding prefix for files.\n"); + + printf("\n"); + + printf("\t--id-prefix <string>\t\tDefine a common prefix for all uniq identifiers.\n"); + printf("\t--id-expected <number>\t\tProvide the expected number of instructions.\n"); + + printf("\n"); + + printf("Format specific options:\n"); + + printf("\n"); + + printf("\t--op-prefix <string>\t\tDefine a prefix to format operand type constants.\n"); + + printf("\n"); + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Point d'entrée du programme. * +* * +* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int main(int argc, char **argv) +{ + int result; /* Bilan à retourner */ + bool need_help; /* Affichage de l'aide ? */ + AvailableD2cCommand execute; /* Exécution globale attendue */ + output_info info; /* Regroupement d'infos utiles */ + pre_processor *pp; /* Pré-processeur avec macros */ + bool has_error; /* Erreur dans la ligne de cmd.*/ + int index; /* Indice d'argument à traiter */ + int ret; /* Bilan d'une lecture d'arg. */ + char *sep; /* Caratère '=' en coupure */ + unsigned long int expected; /* Nombre total de définitions */ + rented_coder *coder; /* Codeur à briffer & employer */ + bool status; /* Bilan d'une génération */ + char *temp; /* Zone de travail temporaire */ + char *base; /* Identification de fichier */ + char *underscore; /* Dernier caractère '_' */ + + static struct option long_options[] = { + + { "help", no_argument, NULL, 'h' }, + { "exec", required_argument, NULL, 'x' }, + { "outdir", required_argument, NULL, 'o' }, + { "type", required_argument, NULL, 't' }, + { "arch", required_argument, NULL, 'a' }, + { "name", required_argument, NULL, 'n' }, + { "guard", required_argument, NULL, 'G' }, + { "encoding", required_argument, NULL, 'e' }, + + { "id-prefix", required_argument, NULL, 0x100 }, + { "id-expected",required_argument, NULL, 0x101 }, + + { "op-prefix", required_argument, NULL, 0x200 }, + + { NULL, 0, NULL, 0 } + + }; + + /* Récupération des commandes */ + + need_help = false; + execute = ADC_NONE; + memset(&info, 0, sizeof(info)); + + pp = create_pre_processor(); + + has_error = false; + + while (!has_error) + { + ret = getopt_long(argc, argv, "hx:o:t:a:n:e:G:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + need_help = true; + break; + + case 'x': + + if (strcmp(optarg, "cc") == 0) + execute = ADC_COMPILE; + + else if (strcmp(optarg, "fini") == 0) + execute = ADC_FINI; + + else + has_error = true; + + break; + + case 'o': + info.directory = optarg; + break; + + case 't': + + if (strcmp(optarg, "raw") == 0) + info.type = IOT_RAW; + + else if (strcmp(optarg, "format") == 0) + info.type = IOT_FORMAT; + + else + has_error = true; + + break; + + case 'a': + info.arch = optarg; + break; + + case 'n': + info.arch_cn = optarg; + break; + + case 'G': + info.guard = optarg; + break; + + case 'e': + + if (strcmp(optarg, "none") == 0) + register_empty_encoding(pp); + + else + { + sep = strchr(optarg, '='); + has_error = (sep == NULL); + + if (!has_error) + { + *sep = '\0'; + register_encoding(pp, optarg, sep + 1); + } + + } + + break; + + case 0x100: + info.id_prefix = optarg; + break; + + case 0x101: + expected = strtoul(optarg, NULL, 10); + info.id_len = (int)ceil(log(expected) / log(16));; + break; + + case 0x200: + info.fmt_prefix = optarg; + break; + + default: + has_error = true; + break; + + } + + } + + /* Vérifications supplémentaires */ + + if (execute == ADC_NONE) + has_error = true; + + if (info.directory == NULL || info.arch == NULL || info.arch_cn == NULL || info.guard == NULL) + has_error = true; + + if (need_help || has_error || (optind + 1) != argc) + { + show_usage(argv[0]); + result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE); + goto exit; + } + + /* Execution attendue */ + + result = EXIT_FAILURE; + + switch (execute) + { + case ADC_COMPILE: + + coder = process_definition_file(argv[optind], pp); + if (coder == NULL) goto exit; + + status = output_coder_body(coder, &info); + if (!status) goto clean_exit; + + status = output_coder_identifier(coder, &info); + if (!status) goto clean_exit; + + if (info.type == IOT_FORMAT) + { + status = output_coder_keyword(coder, &info); + if (!status) goto clean_exit; + } + + status = output_coder_description(coder, &info); + if (!status) goto clean_exit; + + break; + + case ADC_FINI: + + coder = NULL; + + temp = strdup(argv[optind]); + base = basename(temp); + + underscore = rindex(base, '_'); + + if (underscore == NULL && strcmp(base, "opcodes.h") == 0) + status = fini_coder_opcodes_file(argv[optind], &info); + + else if (underscore != NULL && strcmp(underscore, "_opcodes.h") == 0) + status = fini_coder_opcodes_file(argv[optind], &info); + + else if (strcmp(base, "identifiers.h") == 0) + status = fini_coder_identifiers_file(argv[optind], &info); + + else if (info.type == IOT_FORMAT && strcmp(base, "keywords.h") == 0) + status = fini_coder_keywords_file(argv[optind], &info); + + else if (strcmp(base, "descriptions.h") == 0) + status = fini_coder_descriptions_file(argv[optind], &info); + + else + status = false; + + free(temp); + + if (!status) goto exit; + + break; + + default: + assert(false); + break; + + } + + result = EXIT_SUCCESS; + + clean_exit: + + if (coder != NULL) + delete_coder(coder); + + exit: + + return result; + +} diff --git a/tools/d2c/d2c.mk b/tools/d2c/d2c.mk index dbc9b83..10bd226 100644 --- a/tools/d2c/d2c.mk +++ b/tools/d2c/d2c.mk @@ -5,20 +5,27 @@ d2c_verbose = $(d2c_verbose_@AM_V@) d2c_verbose_ = $(d2c_verbose_@AM_DEFAULT_V@) d2c_verbose_0 = @echo " D2C " $<; +fini_verbose = $(fini_verbose_@AM_V@) +fini_verbose_ = $(fini_verbose_@AM_DEFAULT_V@) +fini_verbose_0 = echo " FINI " `basename $$f`; + fix_verbose = $(fix_verbose_@AM_V@) fix_verbose_ = $(fix_verbose_@AM_DEFAULT_V@) fix_verbose_0 = echo " FIX " `basename $$f`; # D2C_BIN = -# D2C_TYPE = +# GEN_BIN = + # D2C_OUTDIR = +# D2C_TYPE = # D2C_ARCH = -# D2C_HEADER = +# D2C_ARCH_CN = +# D2C_GUARD = # D2C_ENCODINGS = -# D2C_MACROS = -# D2C_OPERANDS = -# D2C_PREFIX = +# D2C_ID_PREFIX = +# D2C_ID_COUNT = +# D2C_SPECIFIC = # FIXED_C_INCLUDES = # FIXED_H_INCLUDES = @@ -27,25 +34,36 @@ fix_verbose_0 = echo " FIX " `basename $$f`; SUFFIXES = .g .d.g: - $(d2c_verbose)$(D2C_BIN) -i $< -t $(D2C_TYPE) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) $(D2C_OPERANDS) -p "$(D2C_PREFIX)" + $(d2c_verbose)$(D2C_BIN) -x cc -o $(D2C_OUTDIR) -t $(D2C_TYPE) -a $(D2C_ARCH) -n $(D2C_ARCH_CN) \ + -G $(D2C_GUARD) $(D2C_ENCODINGS) --id-prefix=$(D2C_ID_PREFIX) --id-expected=$(D2C_ID_COUNT) \ + $(D2C_SPECIFIC) $< @touch $@ -d2c_final_rules: fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass +d2c_final_rules: finish_headers fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass + +finish_headers: + @for f in `find $(D2C_OUTDIR) -type f -name '*.h'`; do \ + grep -q '#endif' $$f && continue; \ + $(fini_verbose)$(D2C_BIN) -x fini -o $(D2C_OUTDIR) -t $(D2C_TYPE) -a $(D2C_ARCH) -n $(D2C_ARCH_CN) \ + -G $(D2C_GUARD) $(D2C_ENCODINGS) --id-prefix=$(D2C_ID_PREFIX) --id-expected=$(D2C_ID_COUNT) \ + $(D2C_SPECIFIC) $$f \ + || ( echo "Can not complete $$f" ; exit 1 ) ; \ + done fix_includes_in_c_templates: - @for f in `find .gen/ -name '*tmpl.c'`; do \ - if grep -q '##INCLUDES##' $$f; then \ - $(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_C_INCLUDES)@' $$f; \ - fi; \ + @for f in `find $(D2C_OUTDIR) -type f -name '*.c'`; do \ + if grep -q '##INCLUDES##' $$f; then \ + $(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_C_INCLUDES)@' $$f; \ + fi; \ done fix_includes_in_h_templates: - @for f in `find .gen/ -name '*tmpl.h'`; do \ - if grep -q '##INCLUDES##' $$f; then \ + @for f in `find $(D2C_OUTDIR) -type f -name '*.h'`; do \ + if grep -q '##INCLUDES##' $$f; then \ $(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_H_INCLUDES)@' $$f ; \ - fi; \ + fi; \ done # Merci http://www.commandlinefu.com/commands/view/10276/grep-tab-t untabify_disass: - @find .gen/ -name '*[ch]' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \; + @find $(D2C_OUTDIR) -type f -name '*.[ch]' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \; diff --git a/tools/d2c/d2c_genmakefile.sh b/tools/d2c/d2c_genmakefile.sh index be303e0..d01fa6c 100755 --- a/tools/d2c/d2c_genmakefile.sh +++ b/tools/d2c/d2c_genmakefile.sh @@ -1,17 +1,15 @@ #!/bin/sh -if [ $# -lt 4 ]; then +if [ $# -lt 2 ]; then - echo "Usage: $0 <working dir> <input dir> <global mk> <arch [arch [arch ...]]" + echo "Usage: $0 <opcodes dir> <arch [arch [arch ...]]" exit 1 fi workingdir=$1 -input=$2 -globalmk=$3 -shift 3 +shift 1 OLDPWD=$PWD @@ -23,124 +21,37 @@ cd ${workingdir} echo=`which echo` rm -f ${MAKEFILE_TMP} -$echo >> ${MAKEFILE_TMP} -$echo "include ${globalmk}" >> ${MAKEFILE_TMP} -$echo >> ${MAKEFILE_TMP} +# Génération de la liste des sources -if [ "$1" = "-" ]; then - OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d. -f2 | sort | uniq` -else - OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d. -f3 | sort | uniq` -fi +$echo >> ${MAKEFILE_TMP} -# Génération des en-têtes de décodage +$echo -n "GENERATED_FILES = " >> ${MAKEFILE_TMP} for arch in $*; do if [ ${arch} = "-" ]; then arch_name="" - arch_name_dotted="" else arch_name="${arch}_" - arch_name_dotted="${arch}_." fi - $echo -n "${arch_name}HEADER_FILES =" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP} - - has_header="" + SOURCES=`find . -type f -name "${arch_name}*.h" -exec basename {} \; | sort` - for op in $OPCODES; + for src in $SOURCES; do - template="${input}/*.${arch_name_dotted}${op}.c" - - sources=`ls $template 2> /dev/null` - - if [ -z "${sources}" ]; then - continue - fi - - for src in ${sources}; - do - has_header="yes" - $echo -ne " \\" >> ${MAKEFILE_TMP} - $echo -ne "\n\t" >> ${MAKEFILE_TMP} - $echo -n ${src} | sed "s/${op}.c$/opcodes.h/" >> ${MAKEFILE_TMP} - done + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP} done - $echo >> ${MAKEFILE_TMP} - $echo >> ${MAKEFILE_TMP} - - $echo -n "${arch_name}opcodes.h: " >> ${MAKEFILE_TMP} - $echo "\$(${arch_name}HEADER_FILES)" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP} - - if [ -z "${has_header}" ]; then - - $echo -e "\techo > \$@" >> ${MAKEFILE_TMP} - - else - - $echo -e "\t\$(cini_verbose)cat ${input}/${arch_name_dotted}opcodes.tmpl.h > \$@" >> ${MAKEFILE_TMP} - $echo -e "\t\$(cgen_verbose)cat \$^ >> \$@" >> ${MAKEFILE_TMP} - $echo -e "\t\$(cfini_verbose)echo >> \$@" >> ${MAKEFILE_TMP} - $echo -en "\t\$(cfini_verbose)echo \"#endif\t /* " >> ${MAKEFILE_TMP} - $echo -en '`cat \$@ | grep "#define" | cut -d " " -f 2`' >> ${MAKEFILE_TMP} - $echo -e " */\" >> \$@" >> ${MAKEFILE_TMP} - - fi - - $echo >> ${MAKEFILE_TMP} - -done + SOURCES=`find . -type f -name "${arch_name}*.c" -exec basename {} \; | sort` -$echo >> ${MAKEFILE_TMP} - -# Génération des codes d'instructions - -for op in $OPCODES; -do - for arch in $*; + for src in $SOURCES; do - if [ ${arch} = "-" ]; then - arch_name="" - arch_name_dotted="" - else - arch_name="${arch}_" - arch_name_dotted="${arch}_." - fi - - template="${input}/*.${arch_name_dotted}${op}.c" - - sources=`ls $template 2> /dev/null` - - if [ -z "${sources}" ]; then - continue - fi - - $echo -n "${op}_${arch_name}FILES =" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP} - - for src in ${sources}; - do - $echo -ne " \\" >> ${MAKEFILE_TMP} - $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP} - done - - $echo >> ${MAKEFILE_TMP} - $echo >> ${MAKEFILE_TMP} - - $echo -n "${arch_name}${op}.c: " >> ${MAKEFILE_TMP} - $echo -n "\$(${op}_${arch_name}FILES)" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP} - $echo " ${arch_name}opcodes.h" >> ${MAKEFILE_TMP} - - $echo -e "\t\$(cini_verbose)cat ${input}/${arch_name_dotted}${op}.tmpl.c > \$@" >> ${MAKEFILE_TMP} - $echo -ne "\t\$(cgen_verbose)cat \$(" >> ${MAKEFILE_TMP} - $echo -ne "${op}_${arch_name}FILES" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP} - $echo -e ") >> \$@" >> ${MAKEFILE_TMP} - - $echo >> ${MAKEFILE_TMP} + $echo -ne " \\" >> ${MAKEFILE_TMP} + $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP} done @@ -148,48 +59,13 @@ done $echo >> ${MAKEFILE_TMP} -# Génération de la liste des sources - -$echo -n "GENERATED_FILES =" >> ${MAKEFILE_TMP} - -for arch in $*; -do - if [ ${arch} = "-" ]; then - arch_name="" - arch_name_dotted="" - else - arch_name="${arch}_" - arch_name_dotted="${arch}_." - fi - - $echo -ne " \\" >> ${MAKEFILE_TMP} - $echo -ne "\n\t${arch_name}opcodes.h" >> ${MAKEFILE_TMP} - - for op in $OPCODES; - do - template="${input}/*.${arch_name_dotted}${op}.c" - - sources=`ls $template 2> /dev/null` - - if [ ! -z "${sources}" ]; then - $echo -ne " \\" >> ${MAKEFILE_TMP} - $echo -ne "\n\t${arch_name}${op}.c" >> ${MAKEFILE_TMP} - continue - fi - - done - -done - $echo >> ${MAKEFILE_TMP} -$echo >> ${MAKEFILE_TMP} # Validation finale -if [ ! -f ]; then +if [ ! -f ${MAKEFILE_EXT} ]; then - rm -rf ${MAKEFILE_EXT} mv ${MAKEFILE_TMP} ${MAKEFILE_EXT} else diff --git a/tools/d2c/decl.h b/tools/d2c/decl.h new file mode 100644 index 0000000..c2a001d --- /dev/null +++ b/tools/d2c/decl.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * decl.h - déclarations de prototypes utiles + * + * Copyright (C) 2018 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_DECL_H +#define _TOOLS_D2C_DECL_H + + +#include "coder.h" + + + +/* Charge en mémoire la définition contenue dans un fichier. */ +rented_coder *process_definition_file(const char *, pre_processor *); + + + +#endif /* _TOOLS_D2C_BITS_DECL_H */ diff --git a/tools/d2c/desc/Makefile.am b/tools/d2c/desc/Makefile.am new file mode 100644 index 0000000..d680c84 --- /dev/null +++ b/tools/d2c/desc/Makefile.am @@ -0,0 +1,10 @@ + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) + + +noinst_LTLIBRARIES = libd2cdesc.la + +.NOTPARALLEL: $(noinst_LTLIBRARIES) + +libd2cdesc_la_SOURCES = \ + manager.h manager.c diff --git a/tools/d2c/desc/manager.c b/tools/d2c/desc/manager.c new file mode 100644 index 0000000..5e2efa7 --- /dev/null +++ b/tools/d2c/desc/manager.c @@ -0,0 +1,166 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.c - enregistrement d'une description complète + * + * Copyright (C) 2016-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 <ctype.h> +#include <malloc.h> +#include <string.h> + + + +/* Mémorisation de la description d'un identifiant */ +struct _instr_desc +{ + char *text; /* Contenu humainement lisible */ + +}; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau gestionnaire de définitions d'identifiant. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +instr_desc *create_instruction_description(void) +{ + instr_desc *result; /* Définition vierge à renvoyer*/ + + result = (instr_desc *)calloc(1, sizeof(instr_desc)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : desc = gestionnaire de définition de description à libérer. * +* * +* Description : Supprime de la mémoire un gestionnaire de description. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_instruction_description(instr_desc *desc) +{ + if (desc->text != NULL) + free(desc->text); + + free(desc); + +} + + +/****************************************************************************** +* * +* Paramètres : desc = gestionnaire de définition de description à traiter. * +* text = valeur du contenu à mémoriser. * +* * +* Description : Définit le contenu textuel d'une description. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_instruction_description(instr_desc *desc, const char *text) +{ + const char *start; /* Départ réel du contenu */ + size_t len; /* Taille maximale à parcourir */ + char *iter; /* Boucle de parcours */ + + for (start = text; *start != '\0'; start++) + if (!isspace(*start)) + break; + + desc->text = strdup(start); + + len = strlen(desc->text); + + if (len > 0) + { + for (iter = desc->text + len - 1; + iter != desc->text; + iter--) + { + if (isspace(*iter)) + *iter = '\0'; + else + break; + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : desc = gestionnaire de définition de description à traiter. * +* fd = flux ouvert en écriture. * +* * +* Description : Imprime la description associée à une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void write_instruction_description(const instr_desc *desc, int fd) +{ + const char *iter; /* Boucle de parcours */ + + for (iter = desc->text; *iter != '\0'; iter++) + switch (*iter) + { + case '\n': + dprintf(fd, "\\n"); + break; + + case '"': + dprintf(fd, "\\\""); + break; + + default: + dprintf(fd, "%c", *iter); + break; + + } + +} diff --git a/tools/d2c/desc/manager.h b/tools/d2c/desc/manager.h new file mode 100644 index 0000000..45cc262 --- /dev/null +++ b/tools/d2c/desc/manager.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.h - prototypes pour l'enregistrement d'une description complète + * + * Copyright (C) 2018 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_DESC_MANAGER_H +#define _TOOLS_D2C_DESC_MANAGER_H + + + +/* Mémorisation de la description d'un identifiant */ +typedef struct _instr_desc instr_desc; + + +/* Crée un nouveau gestionnaire de définitions d'identifiant. */ +instr_desc *create_instruction_description(void); + +/* Supprime de la mémoire un gestionnaire de description. */ +void delete_instruction_description(instr_desc *); + +/* Définit le contenu textuel d'une description. */ +void set_instruction_description(instr_desc *, const char *); + +/* Imprime la description associée à une instruction. */ +void write_instruction_description(const instr_desc *, int); + + + +#endif /* _TOOLS_D2C_DESC_MANAGER_H */ diff --git a/tools/d2c/spec.c b/tools/d2c/encoding.c index 4bf4307..052fc04 100644 --- a/tools/d2c/spec.c +++ b/tools/d2c/encoding.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * spec.c - représentation complète d'un encodage + * encoding.c - représentation complète d'un encodage * * Copyright (C) 2014-2017 Cyrille Bagard * @@ -21,9 +21,10 @@ */ -#include "spec.h" +#include "encoding.h" +#include <assert.h> #include <malloc.h> #include <regex.h> #include <stdio.h> @@ -45,10 +46,10 @@ struct _encoding_spec operands_format *format; /* Définition des opérandes */ coding_bits *bits; /* Encodage des bits associés */ - asm_syntax *syntax; /* Calligraphe d'assemblage */ - conv_list *conversions; /* Conversions des données */ instr_hooks *hooks; /* Fonctions complémentaires */ - decoding_rules *rules; /* Règles supplémentaires */ + + encoding_syntax **syntaxes; /* Définitions déjà en place */ + size_t syntax_count; /* Nombre de ces définitions */ }; @@ -75,10 +76,7 @@ encoding_spec *create_encoding_spec(void) result->format = create_operands_format(); result->bits = create_coding_bits(); - result->syntax = create_asm_syntax(); - result->conversions = create_conv_list(); result->hooks = create_instr_hooks(); - result->rules = create_decoding_rules(); return result; @@ -99,13 +97,21 @@ encoding_spec *create_encoding_spec(void) void delete_encoding_spec(encoding_spec *spec) { + size_t i; /* Boucle de parcours */ + delete_operands_format(spec->format); delete_coding_bits(spec->bits); - delete_asm_syntax(spec->syntax); - delete_conv_list(spec->conversions); delete_instr_hooks(spec->hooks); - delete_decoding_rules(spec->rules); + + if (spec->syntaxes != NULL) + { + for (i = 0; i < spec->syntax_count; i++) + delete_encoding_syntax(spec->syntaxes[i]); + + free(spec->syntaxes); + + } free(spec); @@ -170,17 +176,21 @@ bool has_encoding_spec_prefix(const encoding_spec *spec, const char *prefix) * * * Paramètres : spec = spécification d'encodage à consulter. * * * -* Description : Fournit le gestionnaire des définitions d'opérandes. * +* Description : Construit la distinction propre à un encodage. * * * -* Retour : Structure assurant la définition des opérandes * +* Retour : Distinction à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ -operands_format *get_format_in_encoding_spec(const encoding_spec *spec) +char *build_encoding_spec_prefix(const encoding_spec *spec) { - return spec->format; + char *result; /* Chaîne à retourner */ + + asprintf(&result, "%s%u", spec->lprefix, spec->index); + + return result; } @@ -189,17 +199,17 @@ operands_format *get_format_in_encoding_spec(const encoding_spec *spec) * * * Paramètres : spec = spécification d'encodage à consulter. * * * -* Description : Fournit le gestionnaire des bits d'un encodage d'instruction.* +* Description : Fournit le gestionnaire des définitions d'opérandes. * * * -* Retour : Structure assurant le suivi des bits. * +* Retour : Structure assurant la définition des opérandes. * * * * Remarques : - * * * ******************************************************************************/ -coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec) +operands_format *get_format_in_encoding_spec(const encoding_spec *spec) { - return spec->bits; + return spec->format; } @@ -208,17 +218,17 @@ coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec) * * * Paramètres : spec = spécification d'encodage à consulter. * * * -* Description : Fournit l'indicateur des écritures correctes d'assembleur. * +* Description : Fournit le gestionnaire des bits d'un encodage d'instruction.* * * -* Retour : Structure assurant la gestion des éléments de syntaxe. * +* Retour : Structure assurant le suivi des bits. * * * * Remarques : - * * * ******************************************************************************/ -asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec) +coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec) { - return spec->syntax; + return spec->bits; } @@ -227,7 +237,7 @@ asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec) * * * Paramètres : spec = spécification d'encodage à consulter. * * * -* Description : Fournit la liste des fonctions de conversion. * +* Description : Fournit la liste des fonctions à lier à une instruction. * * * * Retour : Structure assurant la gestion des fonctions de conversion. * * * @@ -235,28 +245,33 @@ asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec) * * ******************************************************************************/ -conv_list *get_conversions_in_encoding_spec(const encoding_spec *spec) +instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec) { - return spec->conversions; + return spec->hooks; } /****************************************************************************** * * -* Paramètres : spec = spécification d'encodage à consulter. * +* Paramètres : spec = spécification d'encodage à étendre. * * * -* Description : Fournit la liste des fonctions à lier à une instruction. * +* Description : Enregistre une définition de syntaxe supplémentaire. * * * -* Retour : Structure assurant la gestion des fonctions de conversion. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec) +void push_new_encoding_syntax(encoding_spec *spec) { - return spec->hooks; + encoding_syntax *syntax; /* Définition à compléter */ + + syntax = create_encoding_syntax(); + + spec->syntaxes = realloc(spec->syntaxes, ++spec->syntax_count * sizeof(encoding_syntax *)); + spec->syntaxes[spec->syntax_count - 1] = syntax; } @@ -265,31 +280,36 @@ instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec) * * * Paramètres : spec = spécification d'encodage à consulter. * * * -* Description : Fournit un ensemble de règles supplémentaires éventuel. * +* Description : Fournit un lien vers la définition de syntaxe courante. * * * -* Retour : Structure assurant la gestion de ces règles. * +* Retour : Définition en cours d'édition. * * * * Remarques : - * * * ******************************************************************************/ -decoding_rules *get_rules_in_encoding_spec(const encoding_spec *spec) +encoding_syntax *get_current_encoding_syntax(const encoding_spec *spec) { - return spec->rules; + encoding_syntax *result; /* Définition à retourner */ + + if (spec->syntax_count == 0) + result = NULL; + + else + result = spec->syntaxes[spec->syntax_count - 1]; + + return result; } /****************************************************************************** * * -* Paramètres : spec = spécification servant de base à l'opération. * -* fd = descripteur d'un flux ouvert en écriture. * -* arch = architecture visée par l'opération. * -* subarch = sous-catégorie de cette même architecture. * -* ins = désignation première de l'instruction manipulée. * -* details = particularités de l'instruction. * -* wide = taille des mots manipulés (en bits). * -* pp = pré-processeur pour les échanges de chaînes. * +* Paramètres : spec = spécification servant de base à l'opération. * +* fd = descripteur d'un flux ouvert en écriture. * +* arch = architecture visée par l'opération. * +* id = identifiant unique attribué à l'instruction. * +* pp = pré-processeur pour les échanges de chaînes. * * * * Description : Traduit en code une sous-fonction de désassemblage. * * * @@ -299,96 +319,115 @@ decoding_rules *get_rules_in_encoding_spec(const encoding_spec *spec) * * ******************************************************************************/ -bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *arch, const char *subarch, const char *ins, const char *details, unsigned int wide, const pre_processor *pp) +bool write_encoding_spec_raw_disass(const encoding_spec *spec, int fd, const char *arch, const instr_id *id, const pre_processor *pp) { bool result; /* Bilan à retourner */ - bool bad_exit; /* Ajout d'une sortie d'échec ?*/ - char *keyword; /* Mot clef appelable en code */ - bool quick_exit; /* Inclusion de sortie rapide ?*/ - const char *new_ins; /* Nouvelle définition de nom */ - char *encoding_fc; /* Spécification d'encodage */ - char *cast; /* Conversion vers le format */ + bool openbar; /* Syntaxe unique par défaut ? */ + disass_assert *dassert; /* Eventuelles conditions */ + size_t i; /* Boucle de parcours */ - result = true; - bad_exit = false; - keyword = make_callable(ins, false); - dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n", - arch, keyword, details, spec->lprefix, spec->index, wide); - dprintf(fd, "\t{\n"); - dprintf(fd, "\t\tGArchInstruction *instr;\n"); + bool op_decl; /* Suivi des déclaration #1 */ + bool imm_decl; /* Suivi des déclaration #2 */ - /* Déclaration des champs à retrouver */ + bool bad_exit; /* Ajout d'une sortie d'échec ?*/ + bool quick_exit; /* Inclusion de sortie rapide ?*/ - result &= mark_syntax_items(spec->syntax, spec->bits, spec->conversions); - result &= mark_decoding_rules(spec->rules, spec->bits, spec->conversions); - result &= declare_used_bits_fields(spec->bits, fd, wide); + char *encoding_fc; /* Spécification d'encodage */ + char *cast; /* Conversion vers le format */ - result &= declare_used_intermediate_conversions(spec->conversions, fd, spec->bits, pp, wide); - result &= declare_syntax_items(spec->syntax, fd, spec->bits, spec->conversions, wide); - dprintf(fd, "\n"); + /*************** + * + * + * REAL ONE + * + * + * + **********************/ - result &= declare_hook_functions(spec->hooks, false, fd); - /* Vérification que le décodage est possible */ - result &= check_bits_correctness(spec->bits, fd); - dprintf(fd, "\n"); + result = true; - /* Définition des champs bruts */ + /* Détermination de la forme du code */ - result &= define_used_bits_fields(spec->bits, fd); + openbar = (spec->syntax_count == 1); - result &= define_used_intermediate_conversions(spec->conversions, fd, arch, spec->bits, pp, &bad_exit); + if (openbar) + { + dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]); + openbar = is_disass_assert_empty(dassert); + } - /* Inclusion des éventuelles règles */ + else + { + for (i = 0; i < spec->syntax_count && result; i++) + { + dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]); - quick_exit = false; + if (is_disass_assert_empty(dassert)) + { + fprintf(stderr, "The syntax definition #%zu has no entry conditions!\n", i); + result = false; + } - result &= write_decoding_rules(spec->rules, false, CAT_SEE, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + } - result &= write_decoding_rules(spec->rules, false, CAT_UNPREDICTABLE, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + } - /* Création de l'instruction en elle-même */ + if (!result) + goto wesrd_exit; + + /* Déclarations préalables */ - new_ins = get_new_keyword_from_syntax_items(spec->syntax); + dprintf(fd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n"); + + for (i = 0; i < spec->syntax_count && result; i++) + result = mark_syntax_items(spec->syntaxes[i], spec->bits); - dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", arch, new_ins != NULL ? new_ins : ins); + if (!result) + goto wesrd_exit; + + result = declare_used_bits_fields(spec->bits, fd); + if (!result) goto wesrd_exit; + + if (openbar) + { + result = declare_encoding_syntax(spec->syntaxes[0], fd, spec->bits); + if (!result) goto wesrd_exit; + } dprintf(fd, "\n"); - /* Inscriptions des éventuelles fonctions ou propriété à lier */ + result = declare_hook_functions(spec->hooks, fd); + if (!result) goto wesrd_exit; - result &= write_hook_functions(spec->hooks, false, fd); + /* Vérification que le décodage est possible */ - result &= write_decoding_rules(spec->rules, false, CAT_CHECKED_CALL, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + result &= check_bits_correctness(spec->bits, fd); + if (!result) goto wesrd_exit; - result &= write_decoding_rules(spec->rules, false, CAT_CALL, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + dprintf(fd, "\n"); - /* Création des opérandes */ + /* Définition des champs bruts */ - result &= define_syntax_items(spec->syntax, fd, arch, spec->bits, spec->conversions, pp, &bad_exit); + result = define_used_bits_fields(spec->bits, fd); + if (!result) goto wesrd_exit; - /* Conclusion de la procédure */ + for (i = 0; i < spec->syntax_count && result; i++) + result = write_encoding_syntax(spec->syntaxes[i], fd, arch, spec->bits, openbar, &bad_exit); - if (quick_exit) - { - dprintf(fd, "\t quick_exit:\n"); - dprintf(fd, "\n"); - } + if (!result) + goto wesrd_exit; /* Encodage en dernier lieu */ @@ -396,43 +435,38 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a cast = build_cast_if_needed(encoding_fc); - dprintf(fd, "\t\t%s(%s(instr), \"%s\");\n", encoding_fc, cast, spec->prefix); + dprintf(fd, "\t%s(%s(result), \"%s\");\n", encoding_fc, cast, spec->prefix); free(cast); free(encoding_fc); - /* Conclusion globale */ - dprintf(fd, "\n"); - dprintf(fd, "\t\treturn instr;\n"); + /* Inscriptions des éventuelles fonctions ou propriété à lier */ + + result = write_hook_functions(spec->hooks, fd); + if (!result) goto wesrd_exit; + + /* Conclusion globale */ + + dprintf(fd, "\treturn result;\n"); dprintf(fd, "\n"); if (bad_exit) { - dprintf(fd, "\t bad_exit:\n"); + dprintf(fd, " bad_exit:\n"); dprintf(fd, "\n"); - dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n"); - dprintf(fd, "\t\treturn NULL;\n"); + dprintf(fd, "\tg_object_unref(G_OBJECT(result));\n"); + dprintf(fd, "\treturn NULL;\n"); dprintf(fd, "\n"); } - dprintf(fd, "\t}\n"); - - dprintf(fd, "\n"); - - dprintf(fd, "\tif (result == NULL)\n"); - dprintf(fd, "\t\tresult = %s_decode_%s%s_%s%u(raw);\n", - arch, keyword, details, spec->lprefix, spec->index); - - dprintf(fd, "\n"); - - free(keyword); + wesrd_exit: return result; @@ -441,15 +475,11 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a /****************************************************************************** * * -* Paramètres : spec = spécification servant de base à l'opération. * -* fd = descripteur d'un flux ouvert en écriture. * -* arch = architecture visée par l'opération. * -* subarch = sous-catégorie de cette même architecture. * -* ins = désignation première de l'instruction manipulée. * -* sep = caractère de séparation avant les détails. * -* details = particularités de l'instruction. * -* pp = pré-processeur pour les échanges de chaînes. * -* prefix = préfixe pour le type de définitions d'opérandes. * +* Paramètres : spec = spécification servant de base à l'opération. * +* fd = descripteur d'un flux ouvert en écriture. * +* arch = architecture visée par l'opération. * +* id = identifiant unique attribué à l'instruction. * +* prefix = préfixe pour le type de définitions d'opérandes. * * * * Description : Traduit en code une sous-fonction de désassemblage. * * * @@ -459,14 +489,13 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a * * ******************************************************************************/ -bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const char *arch, const char *subarch, const char *ins, char sep, const char *details, const pre_processor *pp, const char *prefix) +bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const char *arch, const instr_id *id, const char *prefix) { bool result; /* Bilan à retourner */ - bool quick_exit; /* Inclusion de sortie rapide ?*/ + unsigned int iid; /* Identifiant unique attribué */ bool bad_exit; /* Ajout d'une sortie d'échec ?*/ - const char *new_ins; /* Nouvelle définition de nom */ - - result = true; + conv_list *conversions; /* Conversions de la syntaxe */ + decoding_rules *rules; /* Règles de la syntaxe */ /* Déclarations préalables */ @@ -475,45 +504,47 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const dprintf(fd, "\n"); - result &= declare_hook_functions(spec->hooks, true, fd); + result = declare_hook_functions(spec->hooks, fd); + if (!result) goto wesfd_exit; /* Création de l'instruction en elle-même */ - new_ins = get_new_keyword_from_syntax_items(spec->syntax); + iid = get_instruction_id_value(id); - if (new_ins != NULL) - dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, new_ins); - else - { - if (sep == '\0') - dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, ins); - else - dprintf(fd, "\tresult = g_%s_instruction_new(\"%s%c%s\");\n", arch, ins, sep, details); - } + dprintf(fd, "\tresult = g_%s_instruction_new(0x%x);\n", arch, iid); dprintf(fd, "\n"); /* Inscriptions des éventuelles fonctions ou propriété à lier */ - result &= write_hook_functions(spec->hooks, true, fd); + result = write_hook_functions(spec->hooks, fd); + if (!result) goto wesfd_exit; + + bad_exit = false; + + assert(spec->syntax_count <= 1); + + if (spec->syntax_count > 0) + { + conversions = get_conversions_in_encoding_syntax(spec->syntaxes[0]); + rules = get_rules_in_encoding_syntax(spec->syntaxes[0]); - quick_exit = false; + result = write_decoding_rules(rules, CAT_CHECKED_CALL, fd, arch, spec->bits, conversions, "", &bad_exit); + if (!result) goto wesfd_exit; - result &= write_decoding_rules(spec->rules, true, CAT_CHECKED_CALL, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + result = write_decoding_rules(rules, CAT_CALL, fd, arch, spec->bits, conversions, "", &bad_exit); + if (!result) goto wesfd_exit; - result &= write_decoding_rules(spec->rules, true, CAT_CALL, - fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit); + } /* Création des opérandes */ - dprintf(fd, "\tendian = g_arch_processor_get_endianness(G_ARCH_PROCESSOR(proc));\n"); + dprintf(fd, "\tendian = g_arch_processor_get_endianness(proc);\n"); dprintf(fd, "\n"); - bad_exit = false; - - result &= define_operands_loading(spec->format, fd, arch, prefix, &bad_exit); + result = define_operands_loading(spec->format, fd, arch, prefix, &bad_exit); + if (!result) goto wesfd_exit; /* Conclusion de la procédure */ @@ -521,11 +552,8 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const dprintf(fd, "\n"); - if (quick_exit || bad_exit) + if (bad_exit) { - if (quick_exit) - dprintf(fd, " quick_exit:\n"); - if (bad_exit) dprintf(fd, " bad_exit:\n"); @@ -538,6 +566,8 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const } + wesfd_exit: + return result; } diff --git a/tools/d2c/spec.h b/tools/d2c/encoding.h index e449587..787a3ca 100644 --- a/tools/d2c/spec.h +++ b/tools/d2c/encoding.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * spec.h - prototypes pour la représentation complète d'un encodage + * encoding.h - prototypes pour la représentation complète d'un encodage * * Copyright (C) 2014-2017 Cyrille Bagard * @@ -21,20 +21,19 @@ */ -#ifndef _TOOLS_D2C_SPEC_H -#define _TOOLS_D2C_SPEC_H +#ifndef _TOOLS_D2C_ENCODING_H +#define _TOOLS_D2C_ENCODING_H #include <stdbool.h> #include "pproc.h" +#include "syntax.h" #include "bits/manager.h" -#include "conv/manager.h" #include "format/manager.h" #include "hooks/manager.h" -#include "rules/manager.h" -#include "syntax/manager.h" +#include "id/manager.h" @@ -54,30 +53,30 @@ void define_encoding_spec_code_name(encoding_spec *, char *, unsigned int); /* Indique si une spécification se range dans une catégorie. */ bool has_encoding_spec_prefix(const encoding_spec *, const char *); +/* Construit la distinction propre à un encodage. */ +char *build_encoding_spec_prefix(const encoding_spec *spec); + /* Fournit le gestionnaire des définitions d'opérandes. */ operands_format *get_format_in_encoding_spec(const encoding_spec *); /* Fournit le gestionnaire des bits d'un encodage d'instruction. */ coding_bits *get_bits_in_encoding_spec(const encoding_spec *); -/* Fournit l'indicateur des écritures correctes d'assembleur. */ -asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *); - -/* Fournit la liste des fonctions de conversion. */ -conv_list *get_conversions_in_encoding_spec(const encoding_spec *); - /* Fournit la liste des fonctions à lier à une instruction. */ instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *); -/* Fournit un ensemble de règles supplémentaires éventuel. */ -decoding_rules *get_rules_in_encoding_spec(const encoding_spec *); +/* Enregistre une définition de syntaxe supplémentaire. */ +void push_new_encoding_syntax(encoding_spec *); + +/* Fournit un lien vers la définition de syntaxe courante. */ +encoding_syntax *get_current_encoding_syntax(const encoding_spec *); /* Traduit en code une sous-fonction de désassemblage. */ -bool write_encoding_spec_disass(const encoding_spec *, int, const char *, const char *, const char *, const char *, unsigned int, const pre_processor *); +bool write_encoding_spec_raw_disass(const encoding_spec *, int, const char *, const instr_id *, const pre_processor *); /* Traduit en code une sous-fonction de désassemblage. */ -bool write_encoding_spec_format_disass(const encoding_spec *, int, const char *, const char *, const char *, char, const char *, const pre_processor *, const char *); +bool write_encoding_spec_format_disass(const encoding_spec *, int, const char *, const instr_id *, const char *); -#endif /* _TOOLS_D2C_SPEC_H */ +#endif /* _TOOLS_D2C_ENCODING_H */ diff --git a/tools/d2c/format/Makefile.am b/tools/d2c/format/Makefile.am index c40b38e..8061804 100644 --- a/tools/d2c/format/Makefile.am +++ b/tools/d2c/format/Makefile.am @@ -26,6 +26,9 @@ libd2cformat_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2cformat_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/format/tokens.l b/tools/d2c/format/tokens.l index 9dd9301..5db4afa 100644 --- a/tools/d2c/format/tokens.l +++ b/tools/d2c/format/tokens.l @@ -21,4 +21,12 @@ [A-Za-z0-9_]* { yylvalp->string = strdup(yytext); return OPS_TYPE; } "|" { return OR; } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c format block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + + %% diff --git a/tools/d2c/globalgen.mk b/tools/d2c/globalgen.mk deleted file mode 100644 index ede457a..0000000 --- a/tools/d2c/globalgen.mk +++ /dev/null @@ -1,12 +0,0 @@ - -cini_verbose = $(cini_verbose_@AM_V@) -cini_verbose_ = $(cini_verbose_@AM_DEFAULT_V@) -cini_verbose_0 = @echo " INIT " `basename $@`; - -cgen_verbose = $(cgen_verbose_@AM_V@) -cgen_verbose_ = $(cgen_verbose_@AM_DEFAULT_V@) -cgen_verbose_0 = @echo " GEN " `basename $@`; - -cfini_verbose = $(cfini_verbose_@AM_V@) -cfini_verbose_ = $(cfini_verbose_@AM_DEFAULT_V@) -cfini_verbose_0 = @echo " FINI " `basename $@`; diff --git a/tools/d2c/grammar.y b/tools/d2c/grammar.y index 063d22b..0c79f04 100644 --- a/tools/d2c/grammar.y +++ b/tools/d2c/grammar.y @@ -1,13 +1,14 @@ %{ -#include <getopt.h> +#include <getopt.h>////// #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> +#include "decl.h" #include "tokens.h" @@ -27,79 +28,124 @@ static void *map_input_data(const char *, size_t *); #include "coder.h" #include "helpers.h" +#include "syntax.h" #include "args/decl.h" +#include "assert/decl.h" #include "bits/decl.h" #include "conv/decl.h" #include "format/decl.h" #include "hooks/decl.h" +#include "id/decl.h" +#include "pattern/decl.h" #include "rules/decl.h" -#include "syntax/decl.h" - - -#define handle_coder_format(c, r) \ - ({ \ - encoding_spec *__spec; \ - operands_format *__format; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __format = get_format_in_encoding_spec(__spec); \ - __status = load_format_from_raw_line(__format, r); \ - if (!__status) YYABORT; \ + + +#define handle_coder_id(c, r) \ + ({ \ + instr_id *__id; \ + bool __status; \ + __id = get_coder_instruction_id(c); \ + __status = load_id_from_raw_line(__id, r); \ + if (!__status) YYABORT; \ + }) + +#define handle_coder_desc(c, r) \ + ({ \ + instr_desc *__desc; \ + __desc = get_coder_instruction_desc(c); \ + set_instruction_description(__desc, r); \ + }) + +#define handle_coder_format(c, r) \ + ({ \ + encoding_spec *__spec; \ + operands_format *__format; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __format = get_format_in_encoding_spec(__spec); \ + __status = load_format_from_raw_line(__format, r); \ + if (!__status) YYABORT; \ }) -#define handle_coder_bits(c, e, r) \ - ({ \ - encoding_spec *__spec; \ - coding_bits *__bits; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __bits = get_bits_in_encoding_spec(__spec); \ - __status = load_bits_from_raw_line(__bits, e, r); \ - if (!__status) YYABORT; \ +#define handle_coder_bits(c, e, r) \ + ({ \ + encoding_spec *__spec; \ + coding_bits *__bits; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __bits = get_bits_in_encoding_spec(__spec); \ + __status = load_bits_from_raw_line(__bits, e, r); \ + if (!__status) YYABORT; \ }) -#define handle_coder_syntax(c, r) \ - ({ \ - encoding_spec *__spec; \ - asm_syntax *__syntax; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __syntax = get_syntax_in_encoding_spec(__spec); \ - __status = load_syntax_from_raw_line(__syntax, r); \ - if (!__status) YYABORT; \ +#define push_coder_new_syntax(c) \ + ({ \ + encoding_spec *__spec; \ + __spec = get_current_encoding_spec(c); \ + push_new_encoding_syntax(__spec); \ }) -#define handle_coder_conversions(c, r) \ - ({ \ - encoding_spec *__spec; \ - conv_list *__list; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __list = get_conversions_in_encoding_spec(__spec); \ - __status = load_convs_from_raw_block(__list, r); \ - if (!__status) YYABORT; \ +#define handle_coder_asm(c, r) \ + ({ \ + encoding_spec *__spec; \ + encoding_syntax *__syntax; \ + asm_pattern *__pattern; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __syntax = get_current_encoding_syntax(__spec); \ + __pattern = get_asm_pattern_in_encoding_syntax(__syntax); \ + __status = load_asm_pattern_from_raw_line(__pattern, r); \ + if (!__status) YYABORT; \ }) -#define handle_coder_hooks(c, r) \ - ({ \ - encoding_spec *__spec; \ - instr_hooks *__hooks;; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __hooks = get_hooks_in_encoding_spec(__spec); \ - __status = load_hooks_from_raw_line(__hooks, r); \ - if (!__status) YYABORT; \ +#define handle_coder_conversions(c, r) \ + ({ \ + encoding_spec *__spec; \ + encoding_syntax *__syntax; \ + conv_list *__list; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __syntax = get_current_encoding_syntax(__spec); \ + __list = get_conversions_in_encoding_syntax(__syntax); \ + __status = load_convs_from_raw_block(__list, r); \ + if (!__status) YYABORT; \ }) -#define handle_coder_rules(c, r) \ - ({ \ - encoding_spec *__spec; \ - decoding_rules *__rules; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __rules = get_rules_in_encoding_spec(__spec); \ - __status = load_rules_from_raw_block(__rules, r); \ - if (!__status) YYABORT; \ +#define handle_coder_assertions(c, r) \ + ({ \ + encoding_spec *__spec; \ + encoding_syntax *__syntax; \ + disass_assert *__dassert; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __syntax = get_current_encoding_syntax(__spec); \ + __dassert = get_assertions_for_encoding_syntax(__syntax); \ + __status = load_assertions_from_raw_block(__dassert, r); \ + if (!__status) YYABORT; \ + }) + +#define handle_coder_hooks(c, r) \ + ({ \ + encoding_spec *__spec; \ + instr_hooks *__hooks;; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __hooks = get_hooks_in_encoding_spec(__spec); \ + __status = load_hooks_from_raw_line(__hooks, r); \ + if (!__status) YYABORT; \ + }) + +#define handle_coder_rules(c, r) \ + ({ \ + encoding_spec *__spec; \ + encoding_syntax *__syntax; \ + decoding_rules *__rules; \ + bool __status; \ + __spec = get_current_encoding_spec(c); \ + __syntax = get_current_encoding_syntax(__spec); \ + __rules = get_rules_in_encoding_syntax(__syntax); \ + __status = load_rules_from_raw_block(__rules, r); \ + if (!__status) YYABORT; \ }) } @@ -138,16 +184,17 @@ YY_DECL; %token COPYRIGHT %token TITLE %token INS_NAME INS_SEP INS_DETAILS +%token ID %token DESC %token ENCODING %token TYPE NUMBER %token ENC_START ENC_END -%token FORMAT +%token FORMAT UNUSED %token WORD HALF %token SYNTAX -%token CONV +%token ASSERT CONV ASM %token HOOKS %token RULES @@ -167,13 +214,15 @@ YY_DECL; %% -input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } - | name desc encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } +input : name id desc encodings + | name id encodings name : COPYRIGHT TITLE INS_NAME { save_notes_for_coder(coder, $1, $3, '\0', NULL); } | COPYRIGHT TITLE INS_NAME INS_SEP INS_DETAILS { save_notes_for_coder(coder, $1, $3, $4, $5); } -desc : DESC RAW_LINE +id : ID RAW_LINE { handle_coder_id(coder, $2); } + +desc : DESC RAW_BLOCK { handle_coder_desc(coder, $2); } encodings : /* empty */ | encoding encodings @@ -186,38 +235,50 @@ encoding : ENCODING TYPE NUMBER format_encoding { push_encoding_spec(coder, $2, /* Définitions à l'aide d'un format défini */ format_encoding : format format_content + | unused_format format : FORMAT RAW_LINE { handle_coder_format(coder, $2); } +unused_format : UNUSED RAW_LINE { handle_coder_format(coder, $2); mark_coder_as_useless(coder); } + format_content : /* empty */ - | hooks format_content - | rules format_content + | SYNTAX { push_coder_new_syntax(coder); } format_syntax + | hooks format_syntax + +format_syntax : /* empty */ + | rules format_syntax /* Définitions à l'aide de données brutes */ raw_encoding : bitfield raw_content +bitfield : HALF RAW_LINE { handle_coder_bits(coder, 16, $2); } + | WORD RAW_LINE { handle_coder_bits(coder, 32, $2); } + raw_content : /* empty */ - | syntax raw_content - | conversions raw_content + | SYNTAX { push_coder_new_syntax(coder); } raw_syntax raw_content | hooks raw_content - | rules raw_content -bitfield : HALF RAW_LINE { handle_coder_bits(coder, 16, $2); } - | WORD RAW_LINE { handle_coder_bits(coder, 32, $2); } +raw_syntax : /* empty */ + | assertions raw_syntax + | conversions raw_syntax + | asm raw_syntax + | rules raw_syntax -syntax : SYNTAX RAW_LINE { handle_coder_syntax(coder, $2); } +assertions : ASSERT RAW_BLOCK { handle_coder_assertions(coder, $2); } conversions : CONV RAW_BLOCK { handle_coder_conversions(coder, $2); } +asm : ASM RAW_LINE { handle_coder_asm(coder, $2); } -/* Définitions communes */ -hooks : HOOKS RAW_BLOCK { handle_coder_hooks(coder, $2); } +/* Définitions communes */ rules : RULES RAW_BLOCK { handle_coder_rules(coder, $2); } +hooks : HOOKS RAW_BLOCK { handle_coder_hooks(coder, $2); } + %% @@ -238,7 +299,7 @@ rules : RULES RAW_BLOCK { handle_coder_rules(coder, $2); } static int yyerror(rented_coder *coder, char *temp, char *msg) { - printf("yyerror line %d: %s\n", yyget_lineno(), msg); + printf("YYERROR line %d: %s\n", yyget_lineno(), msg); return 0; @@ -247,46 +308,6 @@ static int yyerror(rented_coder *coder, char *temp, char *msg) /****************************************************************************** * * -* Paramètres : argv0 = nombre du programme exécuté. * -* * -* Description : Affiche des indications sur l'utilisation du programme. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void show_usage(const char *argv0) -{ - printf("\n"); - - printf("Usage: %s [options]\n", argv0); - - printf("\n"); - - printf("Options:\n"); - - printf("\n"); - - printf("\t-h | --help\t\t\tDisplay this messsage.\n"); - printf("\t-i | --input <file>\t\tProvide the input file containing the description.\n"); - printf("\t-t | --type <raw|format>\tSet the type of the input file.\n"); - printf("\t-d | --dir <string>\t\tSpecify the main output directory.\n"); - printf("\t-a | --arch <string>\t\tDefine the archicture to handle.\n"); - printf("\t-H | --header <string>\t\tSet the base of the #ifndef / #define game.\n"); - printf("\t-e | --encoding <none|string>\tDefine encoding prefixes for files.\n"); - printf("\t-M | --macro <string>\t\tRegister some conversion functions.\n"); - printf("\t-n | --operand <string>\t\tRegister a function producing final operands.\n"); - printf("\t-p | --prefix <string>\t\tDefine a prefix to format operand type constants (see -t).\n"); - - printf("\n"); - -} - - -/****************************************************************************** -* * * Paramètres : filename = chemin du fichier à charger en mémoire. * * length = taille de l'espace mémoie à mettre en place. [OUT]* * * @@ -344,155 +365,47 @@ static void *map_input_data(const char *filename, size_t *length) /****************************************************************************** * * -* Paramètres : argc = nombre d'arguments dans la ligne de commande. * -* argv = arguments de la ligne de commande. * +* Paramètres : filename = chemin d'accès à un fichier à traiter. * +* pp = préprocesseur déjà chargé à intégrer. * * * -* Description : Point d'entrée du programme. * +* Description : Charge en mémoire la définition contenue dans un fichier. * * * -* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. * +* Retour : Définition chargée ou NULL en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ -int main(int argc, char **argv) +rented_coder *process_definition_file(const char *filename, pre_processor *pp) { - int result; /* Bilan à retourner */ - rented_coder *coder; /* Codeur à briffer & employer */ - int index; /* Indice de fichier à traiter */ - bool need_help; /* Affichage de l'aide ? */ - bool has_error; /* Erreur dans la ligne de cmd.*/ - int ret; /* Bilan d'une lecture d'arg. */ - char *sep; /* Caratère '=' en coupure */ + rented_coder *result; /* Codeur à briffer et renvoyer*/ size_t length; /* Nombre d'octets à traiter */ char *content; /* Contenu brut à analyser */ char *temp; /* Zone de travail temporaire */ YY_BUFFER_STATE state; /* Contexte d'analyse */ + int status; /* Bilan d'une analyse */ - static struct option long_options[] = { - - { "help", no_argument, NULL, 'h' }, - { "input", required_argument, NULL, 'i' }, - { "type", required_argument, NULL, 't' }, - { "dir", required_argument, NULL, 'd' }, - { "arch", required_argument, NULL, 'a' }, - { "header", required_argument, NULL, 'H' }, - { "encoding", required_argument, NULL, 'e' }, - { "macro", required_argument, NULL, 'M' }, - { "operand", required_argument, NULL, 'n' }, - { "prefix", required_argument, NULL, 'p' }, - { NULL, 0, NULL, 0 } - - }; - - result = EXIT_SUCCESS; - - coder = create_coder(); - - index = 0; - - need_help = false; - has_error = false; - - while (!has_error) - { - ret = getopt_long(argc, argv, "hi:t:d:a:H:e:M:n:p:", long_options, &index); - if (ret == -1) break; - - switch (ret) - { - case 'h': - need_help = true; - break; - - case 'i': - set_coder_input_file(coder, optarg); - break; - - case 't': - if (strcmp(optarg, "raw") == 0) - set_coder_input_type(coder, IOT_RAW); - else if (strcmp(optarg, "format") == 0) - set_coder_input_type(coder, IOT_FORMAT); - break; - - case 'd': - set_coder_output_directory(coder, optarg); - break; - - case 'a': - set_coder_arch(coder, optarg); - break; - - case 'H': - set_coder_header_base(coder, optarg); - break; - - case 'e': - - if (strcmp(optarg, "none") == 0) - register_empty_encoding(get_coder_pre_proc(coder)); - - else - { - sep = strchr(optarg, '='); - has_error = (sep == NULL); - - if (!has_error) - { - *sep = '\0'; - register_encoding(get_coder_pre_proc(coder), optarg, sep + 1); - } - - } - - break; - - case 'M': - - sep = strchr(optarg, '='); - has_error = (sep == NULL); - - if (!has_error) - { - *sep = '\0'; - define_macro(get_coder_pre_proc(coder), optarg, sep + 1); - } - - break; - - case 'n': - register_as_operand_producer(get_coder_pre_proc(coder), optarg); - break; - - case 'p': - set_coder_const_prefix(coder, optarg); - break; - - } - - } - - if (need_help || has_error || !do_basic_checks_with_coder(coder) || optind != argc) - { - show_usage(argv[0]); - result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE); - printf("need help ? %d - result = %d vs %d\n", need_help, result, EXIT_SUCCESS); - goto exit; - } - - content = map_input_data(get_coder_input_file(coder), &length); + content = map_input_data(filename, &length); if (content == MAP_FAILED) { - result = EXIT_FAILURE; + result = NULL; goto exit; } + result = create_coder(pp); + set_coder_input_file(result, filename); + temp = (char *)calloc(length, sizeof(char)); state = d2c__scan_bytes(content, length); - result = yyparse(coder, temp); + status = yyparse(result, temp); + + if (status == EXIT_FAILURE) + { + delete_coder(result); + result = NULL; + } yy_delete_buffer(state); @@ -502,8 +415,6 @@ int main(int argc, char **argv) exit: - delete_coder(coder); - return result; } diff --git a/tools/d2c/helpers.c b/tools/d2c/helpers.c index 8cc71cb..3f79bc1 100644 --- a/tools/d2c/helpers.c +++ b/tools/d2c/helpers.c @@ -125,7 +125,7 @@ char *make_callable(const char *raw, bool details) { max = strlen(result) + 1; result = (char *)realloc(result, max); - memmove(result + 1, result, max - 1); + memmove(result + 1, result, max); result[0] = '_'; } diff --git a/tools/d2c/hooks/Makefile.am b/tools/d2c/hooks/Makefile.am index 27d88ec..c049ac5 100644 --- a/tools/d2c/hooks/Makefile.am +++ b/tools/d2c/hooks/Makefile.am @@ -26,6 +26,9 @@ libd2chooks_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2chooks_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/hooks/manager.c b/tools/d2c/hooks/manager.c index ff2749b..02544d0 100644 --- a/tools/d2c/hooks/manager.c +++ b/tools/d2c/hooks/manager.c @@ -134,7 +134,6 @@ void register_hook_function(instr_hooks *hooks, char *type, char *name) /****************************************************************************** * * * Paramètres : hooks = gestionnaire d'un ensemble de fonctions associées. * -* top = indique si l'écriture se réalise au plus haut niveau.* * fd = descripteur d'un flux ouvert en écriture. * * * * Description : Déclare des opérations complémentaires pour une instruction. * @@ -145,7 +144,7 @@ void register_hook_function(instr_hooks *hooks, char *type, char *name) * * ******************************************************************************/ -bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd) +bool declare_hook_functions(const instr_hooks *hooks, int fd) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours #1 */ @@ -176,27 +175,18 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd) if (hooks->func_count > 0) { - if (!top) - dprintf(fd, "\t"); - dprintf(fd, "\tstatic const instr_hook_fc hooks[IPH_COUNT] = {\n\n"); for (i = 0; i < (sizeof(hook_types) / sizeof(hook_types[0])); i++) { func = find_hook_by_name(hooks, hook_types[i]); - if (!top) - dprintf(fd, "\t"); - dprintf(fd, "\t\t[IPH_%s] = (instr_hook_fc)%s,\n", hook_types[i], func != NULL ? func->name : "NULL"); } dprintf(fd, "\n"); - if (!top) - dprintf(fd, "\t"); - dprintf(fd, "\t};\n"); dprintf(fd, "\n"); @@ -211,7 +201,6 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd) /****************************************************************************** * * * Paramètres : hooks = gestionnaire d'un ensemble de fonctions associées. * -* top = indique si l'écriture se réalise au plus haut niveau.* * fd = descripteur d'un flux ouvert en écriture. * * * * Description : Associe dans le code des fonctions à une instruction. * @@ -222,7 +211,7 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd) * * ******************************************************************************/ -bool write_hook_functions(const instr_hooks *hooks, bool top, int fd) +bool write_hook_functions(const instr_hooks *hooks, int fd) { bool result; /* Bilan à retourner */ @@ -230,11 +219,7 @@ bool write_hook_functions(const instr_hooks *hooks, bool top, int fd) if (hooks->func_count > 0) { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\tg_arch_instruction_set_hooks(%s, hooks);\n", - top ? "result" : "instr"); + dprintf(fd, "\tg_arch_instruction_set_hooks(result, hooks);\n"); dprintf(fd, "\n"); diff --git a/tools/d2c/hooks/manager.h b/tools/d2c/hooks/manager.h index c502ab0..3647b74 100644 --- a/tools/d2c/hooks/manager.h +++ b/tools/d2c/hooks/manager.h @@ -44,10 +44,10 @@ void delete_instr_hooks(instr_hooks *); void register_hook_function(instr_hooks *, char *, char *); /* Déclare des opérations complémentaires pour une instruction. */ -bool declare_hook_functions(const instr_hooks *, bool, int); +bool declare_hook_functions(const instr_hooks *, int); /* Associe dans le code des fonctions à une instruction. */ -bool write_hook_functions(const instr_hooks *, bool, int); +bool write_hook_functions(const instr_hooks *, int); diff --git a/tools/d2c/hooks/tokens.l b/tools/d2c/hooks/tokens.l index 6aebe87..1f72d2c 100644 --- a/tools/d2c/hooks/tokens.l +++ b/tools/d2c/hooks/tokens.l @@ -16,11 +16,17 @@ %% -" " { } +[ \t\n] { } -[ \t\n]+ { } [a-z_][a-z0-9_]* { yylvalp->string = strdup(yytext); return NAME; } "=" { return EQ; } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c hooks block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + %% diff --git a/tools/d2c/syntax/Makefile.am b/tools/d2c/id/Makefile.am index 7529978..c3d18b8 100644 --- a/tools/d2c/syntax/Makefile.am +++ b/tools/d2c/id/Makefile.am @@ -6,26 +6,29 @@ BUILT_SOURCES = grammar.h # 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 syntax_ +AM_YFLAGS = -v -d -p id_ -AM_LFLAGS = -P syntax_ -o lex.yy.c --header-file=tokens.h \ - -Dyyget_lineno=syntax_get_lineno \ - -Dyy_scan_string=syntax__scan_string \ - -Dyy_delete_buffer=syntax__delete_buffer +AM_LFLAGS = -P id_ -o lex.yy.c --header-file=tokens.h \ + -Dyyget_lineno=id_get_lineno \ + -Dyy_scan_string=id__scan_string \ + -Dyy_delete_buffer=id__delete_buffer AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) -noinst_LTLIBRARIES = libd2csyntax.la +noinst_LTLIBRARIES = libd2cid.la .NOTPARALLEL: $(noinst_LTLIBRARIES) -libd2csyntax_la_SOURCES = \ +libd2cid_la_SOURCES = \ decl.h \ manager.h manager.c \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2cid_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/id/decl.h b/tools/d2c/id/decl.h new file mode 100644 index 0000000..0c3b3e2 --- /dev/null +++ b/tools/d2c/id/decl.h @@ -0,0 +1,40 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * decl.h - déclarations de prototypes utiles + * + * Copyright (C) 2018 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_ID_DECL_H +#define _TOOLS_D2C_ID_DECL_H + + +#include <stdbool.h> + + +#include "manager.h" + + + +/* Interprête des données relatives à un identifiant. */ +bool load_id_from_raw_line(instr_id *, const char *); + + + +#endif /* _TOOLS_D2C_BITS_DECL_H */ diff --git a/tools/d2c/id/grammar.y b/tools/d2c/id/grammar.y new file mode 100644 index 0000000..4799fcc --- /dev/null +++ b/tools/d2c/id/grammar.y @@ -0,0 +1,107 @@ + +%{ + +#include "tokens.h" + + +/* Affiche un message d'erreur suite à l'analyse en échec. */ +static int yyerror(instr_id *, char *); + +%} + + +%code requires { + +#include "decl.h" + +} + + +%union { + + unsigned int value; /* Valeur numérique */ + +} + + +%define api.pure full + +%parse-param { instr_id *id } + +%code provides { + +#define YY_DECL \ + int id_lex(YYSTYPE *yylvalp) + +YY_DECL; + +} + + +%token VALUE + +%type <value> VALUE + + + +%% + + +id : VALUE { set_instruction_id_value(id, $1); } + + +%% + + +/****************************************************************************** +* * +* Paramètres : id = 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(instr_id *id, char *msg) +{ + printf("id yyerror line %d: %s\n", yyget_lineno(), msg); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : id = structure à constituer à partir de données lues. * +* raw = données brutes à analyser. * +* * +* Description : Interprête des données relatives à un identifiant. * +* * +* Retour : true si l'opération s'est bien déroulée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_id_from_raw_line(instr_id *id, 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(id); + + result = (status == 0); + + yy_delete_buffer(state); + + return result; + +} diff --git a/tools/d2c/id/manager.c b/tools/d2c/id/manager.c new file mode 100644 index 0000000..7cfc916 --- /dev/null +++ b/tools/d2c/id/manager.c @@ -0,0 +1,126 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.c - enregistrement de la définition d'un identifiant + * + * Copyright (C) 2016-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 <stdbool.h> + + + +/* Mémorisation de la définition d'un identifiant */ +struct _instr_id +{ + unsigned int value; /* Identifiant numérique unique*/ + bool set; /* Validité de la valeur */ + +}; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau gestionnaire de définitions d'identifiant. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +instr_id *create_instruction_id(void) +{ + instr_id *result; /* Définition vierge à renvoyer*/ + + result = (instr_id *)calloc(1, sizeof(instr_id)); + + result->set = false; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : id = gestionnaire de définition d'identifiant à libérer. * +* * +* Description : Supprime de la mémoire un gestionnaire d'identifiant. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_instruction_id(instr_id *id) +{ + free(id); + +} + + +/****************************************************************************** +* * +* Paramètres : id = gestionnaire de définition d'identifiant à traiter. * +* value = valeur à attribuer à une instruction. * +* * +* Description : Associe une valeur unique à une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_instruction_id_value(instr_id *id, unsigned int value) +{ + id->value = value; + id->set = true; + +} + + +/****************************************************************************** +* * +* Paramètres : id = gestionnaire de définition d'identifiant à traiter. * +* * +* Description : Associe une valeur unique à une instruction. * +* * +* Retour : Valeur attribuée à une instruction. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int get_instruction_id_value(const instr_id *id) +{ + assert(id->set); + + return id->value; + +} diff --git a/tools/d2c/id/manager.h b/tools/d2c/id/manager.h new file mode 100644 index 0000000..d24fbd7 --- /dev/null +++ b/tools/d2c/id/manager.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.h - prototypes pour l'enregistrement de la définition d'un identifiant + * + * Copyright (C) 2018 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_ID_MANAGER_H +#define _TOOLS_D2C_ID_MANAGER_H + + + +/* Mémorisation de la définition d'un identifiant */ +typedef struct _instr_id instr_id; + + +/* Crée un nouveau gestionnaire de définitions d'identifiant. */ +instr_id *create_instruction_id(void); + +/* Supprime de la mémoire un gestionnaire d'identifiant. */ +void delete_instruction_id(instr_id *); + +/* Associe une valeur unique à une instruction. */ +void set_instruction_id_value(instr_id *, unsigned int); + +/* Associe une valeur unique à une instruction. */ +unsigned int get_instruction_id_value(const instr_id *); + + + +#endif /* _TOOLS_D2C_ID_MANAGER_H */ diff --git a/tools/d2c/id/tokens.l b/tools/d2c/id/tokens.l new file mode 100644 index 0000000..24f18f1 --- /dev/null +++ b/tools/d2c/id/tokens.l @@ -0,0 +1,33 @@ + +%top { + +#include <stdlib.h> + +#include "grammar.h" + +} + + +%option noyywrap +%option nounput +%option noinput +%option yylineno +%option noyy_top_state + + +%% + + +" " { } + +[0-9_]* { yylvalp->value = strtoul(yytext, NULL, 10); return VALUE; } + +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c id block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + + +%% diff --git a/tools/d2c/manual.h b/tools/d2c/manual.h index e3375b8..4106702 100644 --- a/tools/d2c/manual.h +++ b/tools/d2c/manual.h @@ -25,40 +25,43 @@ #define _TOOLS_D2C_MANUAL_H -#define read_block(tmp) \ - ({ \ - unsigned int __depth; \ - bool __is_string; \ - char *__iter; \ - \ - __depth = 1; \ - __is_string = false; \ - \ - for (__iter = temp; __depth > 0; __iter += (__depth > 0 ? 1 : 0)) \ - { \ - *__iter = input(); \ - \ - switch (*__iter) \ - { \ - case '"': \ - __is_string = !__is_string; \ - break; \ - \ - case '{': \ - if (!__is_string) __depth++; \ - break; \ - \ - case '}': \ - if (!__is_string) __depth--; \ - break; \ - \ - } \ - \ - } \ - \ - *__iter = '\0'; \ - \ - printf("\n\nBLOCK\n''''\n%s\n''''\n\n", temp); \ +#define read_block(tmp) \ + ({ \ + unsigned int __depth; \ + bool __is_string; \ + char *__iter; \ + \ + __depth = 1; \ + __is_string = false; \ + \ + for (__iter = temp; __depth > 0; __iter += (__depth > 0 ? 1 : 0)) \ + { \ + *__iter = input(); \ + \ + switch (*__iter) \ + { \ + case '"': \ + __is_string = !__is_string; \ + break; \ + \ + case '{': \ + if (!__is_string) __depth++; \ + break; \ + \ + case '}': \ + if (!__is_string) \ + { \ + __depth--; \ + if (__depth == 0) unput('}'); \ + } \ + break; \ + \ + } \ + \ + } \ + \ + *__iter = '\0'; \ + \ }) diff --git a/tools/d2c/pattern/Makefile.am b/tools/d2c/pattern/Makefile.am new file mode 100644 index 0000000..458eed0 --- /dev/null +++ b/tools/d2c/pattern/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 pattern_ + +AM_LFLAGS = -P pattern_ -o lex.yy.c --header-file=tokens.h \ + -Dyyget_lineno=pattern_get_lineno \ + -Dyy_scan_string=pattern__scan_string \ + -Dyy_delete_buffer=pattern__delete_buffer + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) + + +noinst_LTLIBRARIES = libd2cpattern.la + +.NOTPARALLEL: $(noinst_LTLIBRARIES) + +libd2cpattern_la_SOURCES = \ + decl.h \ + manager.h manager.c \ + tokens.l \ + grammar.y + +# _GNU_SOURCE : asprintf +libd2cpattern_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/syntax/decl.h b/tools/d2c/pattern/decl.h index 300ab80..c834ced 100644 --- a/tools/d2c/syntax/decl.h +++ b/tools/d2c/pattern/decl.h @@ -21,8 +21,8 @@ */ -#ifndef _TOOLS_D2C_SYNTAX_DECL_H -#define _TOOLS_D2C_SYNTAX_DECL_H +#ifndef _TOOLS_D2C_PATTERN_DECL_H +#define _TOOLS_D2C_PATTERN_DECL_H #include "manager.h" @@ -30,8 +30,8 @@ /* Interprête des données liées à une définition de syntaxe. */ -bool load_syntax_from_raw_line(asm_syntax *, const char *); +bool load_asm_pattern_from_raw_line(asm_pattern *, const char *); -#endif /* _TOOLS_D2C_SYNTAX_DECL_H */ +#endif /* _TOOLS_D2C_PATTERN_DECL_H */ diff --git a/tools/d2c/syntax/grammar.y b/tools/d2c/pattern/grammar.y index 3952b9a..c3399cc 100644 --- a/tools/d2c/syntax/grammar.y +++ b/tools/d2c/pattern/grammar.y @@ -5,7 +5,7 @@ /* Affiche un message d'erreur suite à l'analyse en échec. */ -static int yyerror(asm_syntax *, char *); +static int yyerror(asm_pattern *, char *); %} @@ -26,30 +26,28 @@ static int yyerror(asm_syntax *, char *); %define api.pure full -%parse-param { asm_syntax *syntax } +%parse-param { asm_pattern *pattern } %code provides { #define YY_DECL \ - int syntax_lex(YYSTYPE *yylvalp) + int pattern_lex(YYSTYPE *yylvalp) YY_DECL; } -%token OPERAND_NAME OPERAND_INTERNAL OPERAND_VISIBLE +%token OPERAND -%type <string> OPERAND_NAME OPERAND_INTERNAL OPERAND_VISIBLE +%type <string> OPERAND %% operands : /* empty */ - | operands OPERAND_NAME { register_syntax_item(syntax, $2, SIT_KEYWORD); } - | operands OPERAND_INTERNAL { register_syntax_item(syntax, $2, SIT_INT_OPERAND); } - | operands OPERAND_VISIBLE { register_syntax_item(syntax, $2, SIT_EXT_OPERAND); } + | operands OPERAND { register_asm_pattern_item(pattern, $2); } %% @@ -57,8 +55,8 @@ operands : /* empty */ /****************************************************************************** * * -* Paramètres : syntax = structure impliquée dans le processus. * -* msg = message d'erreur. * +* Paramètres : pattern = structure impliquée dans le processus. * +* msg = message d'erreur. * * * * Description : Affiche un message d'erreur suite à l'analyse en échec. * * * @@ -68,7 +66,7 @@ operands : /* empty */ * * ******************************************************************************/ -static int yyerror(asm_syntax *syntax, char *msg) +static int yyerror(asm_pattern *pattern, char *msg) { printf("syntax yyerror line %d: %s\n", yyget_lineno(), msg); @@ -79,8 +77,8 @@ static int yyerror(asm_syntax *syntax, char *msg) /****************************************************************************** * * -* Paramètres : syntax = structure à constituer à partir de données lues. * -* raw = données brutes à analyser. * +* Paramètres : pattern = structure à constituer à partir de données lues. * +* raw = données brutes à analyser. * * * * Description : Interprête des données liées à une définition de syntaxe. * * * @@ -90,7 +88,7 @@ static int yyerror(asm_syntax *syntax, char *msg) * * ******************************************************************************/ -bool load_syntax_from_raw_line(asm_syntax *syntax, const char *raw) +bool load_asm_pattern_from_raw_line(asm_pattern *pattern, const char *raw) { bool result; /* Bilan à faire remonter */ YY_BUFFER_STATE state; /* Support d'analyse */ @@ -98,7 +96,7 @@ bool load_syntax_from_raw_line(asm_syntax *syntax, const char *raw) state = yy_scan_string(raw); - status = yyparse(syntax); + status = yyparse(pattern); result = (status == 0); diff --git a/tools/d2c/syntax/manager.c b/tools/d2c/pattern/manager.c index 6857e9a..a756745 100644 --- a/tools/d2c/syntax/manager.c +++ b/tools/d2c/pattern/manager.c @@ -24,6 +24,7 @@ #include "manager.h" +#include <assert.h> #include <malloc.h> #include <string.h> @@ -45,13 +46,12 @@ typedef enum _SyntaxItemFlags typedef struct _syntax_item { char *name; /* Désignation humaine */ - SyntaxItemType impact; /* Portée de l'élément */ SyntaxItemFlags flags; /* Propriétés supplémentaires */ } syntax_item; /* Syntaxe d'une ligne d'assembleur */ -struct _asm_syntax +struct _asm_pattern { syntax_item *items; /* Eléments de la syntaxe */ size_t items_count; /* Nombre de ces éléments */ @@ -72,11 +72,11 @@ struct _asm_syntax * * ******************************************************************************/ -asm_syntax *create_asm_syntax(void) +asm_pattern *create_asm_pattern(void) { - asm_syntax *result; /* Définition vierge à renvoyer*/ + asm_pattern *result; /* Définition vierge à renvoyer*/ - result = (asm_syntax *)calloc(1, sizeof(asm_syntax)); + result = (asm_pattern *)calloc(1, sizeof(asm_pattern)); return result; @@ -85,7 +85,7 @@ asm_syntax *create_asm_syntax(void) /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * * * * Description : Supprime de la mémoire un indicateur d'écriture ASM. * * * @@ -95,26 +95,25 @@ asm_syntax *create_asm_syntax(void) * * ******************************************************************************/ -void delete_asm_syntax(asm_syntax *syntax) +void delete_asm_pattern(asm_pattern *pattern) { size_t i; /* Boucle de parcours */ - for (i = 0; i < syntax->items_count; i++) - free(syntax->items[i].name); + for (i = 0; i < pattern->items_count; i++) + free(pattern->items[i].name); - if (syntax->items != NULL) - free(syntax->items); + if (pattern->items != NULL) + free(pattern->items); - free(syntax); + free(pattern); } /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * -* name = désignation de l'opérande dans la spécification. * -* impact = précise la portée effective de l'opérande * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * +* name = désignation de l'opérande dans la spécification. * * * * Description : Enregistre la présence d'un nouvel opérande dans la syntaxe. * * * @@ -124,14 +123,14 @@ void delete_asm_syntax(asm_syntax *syntax) * * ******************************************************************************/ -void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact) +void register_asm_pattern_item(asm_pattern *pattern, char *name) { syntax_item *item; /* Nouvelle prise en compte */ size_t len; /* Taille du nom fourni */ - syntax->items = (syntax_item *)realloc(syntax->items, ++syntax->items_count * sizeof(syntax_item)); + pattern->items = (syntax_item *)realloc(pattern->items, ++pattern->items_count * sizeof(syntax_item)); - item = &syntax->items[syntax->items_count - 1]; + item = &pattern->items[pattern->items_count - 1]; /* Récupération des drapeaux */ @@ -156,21 +155,16 @@ void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact) } - if (impact == SIT_KEYWORD) - item->name = name; - else - item->name = make_string_lower(name); - - item->impact = impact; + item->name = make_string_lower(name); } /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * -* bits = gestionnaire des bits d'encodage. * -* list = liste de l'ensemble des fonctions de conversion. * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * * * * Description : Marque les champs de bits effectivement utilisés. * * * @@ -180,7 +174,7 @@ void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact) * * ******************************************************************************/ -bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const conv_list *list) +bool mark_asm_pattern_items(const asm_pattern *pattern, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ @@ -189,10 +183,9 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const result = true; - for (i = 0; i < syntax->items_count && result; i++) + for (i = 1; i < pattern->items_count && result; i++) { - item = &syntax->items[i]; - if (item->impact == SIT_KEYWORD) continue; + item = &pattern->items[i]; func = find_named_conv_in_list(list, item->name); if (func == NULL) @@ -212,11 +205,12 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * -* 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. * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* tab = décalage éventuel selon l'inclusion. * +* imm_decl = une déclaration d'immédiat est déjà faite ? [OUT] * * * * Description : Déclare les variables C associées aux opérandes de syntaxe. * * * @@ -226,36 +220,31 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const * * ******************************************************************************/ -bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) +bool declare_asm_pattern(const asm_pattern *pattern, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *imm_decl) { bool result; /* Bilan à retourner */ - bool has_operand; /* Présence d'un opérande */ - bool has_immediate; /* Présence d'une conversion */ size_t i; /* Boucle de parcours */ syntax_item *item; /* Lien vers un opérande */ + conv_func *func; /* Fonction de conversion */ result = true; - has_operand = false; - has_immediate = false; - - for (i = 0; i < syntax->items_count && result; i++) + for (i = 1; i < pattern->items_count && result; i++) { - item = &syntax->items[i]; - if (item->impact == SIT_KEYWORD) continue; - - has_operand |= (item->impact == SIT_EXT_OPERAND); + item = &pattern->items[i]; - if (has_operand) - has_immediate = (item->flags & SIF_DECIMAL); + func = find_named_conv_in_list(list, item->name); + assert(func != NULL); - } + result = declare_conv_func(func, fd, bits, list, tab); - if (has_operand) - dprintf(fd, "\t\tGArchOperand *op;\n"); + if (result && item->flags & SIF_DECIMAL && !*imm_decl) + { + dprintf(fd, "\t%sGImmOperand *imm;\n", tab); + *imm_decl = true; + } - if (has_immediate) - dprintf(fd, "\t\tGImmOperand *imm;\n"); + } return result; @@ -264,7 +253,7 @@ bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *b /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * * * * Description : Fournit si elle existe un nom nouveau pour une instruction. * * * @@ -274,17 +263,13 @@ bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *b * * ******************************************************************************/ -const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax) +const char *get_keyword_from_asm_pattern(const asm_pattern *pattern) { const char *result; /* Nom éventuel à renvoyer */ - result = NULL; + assert(pattern->items_count > 0); - if (syntax->items_count > 0 - && syntax->items[0].impact == SIT_KEYWORD) - { - result = syntax->items[0].name; - } + result = pattern->items[0].name; return result; @@ -293,13 +278,13 @@ const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax) /****************************************************************************** * * -* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * -* 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. * -* exit = exprime le besoin d'une voie de sortie. [OUT] * +* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. * +* 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. * +* tab = décalage éventuel selon l'inclusion. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : Définit les variables C associées aux opérandes de syntaxe. * * * @@ -309,109 +294,105 @@ const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax) * * ******************************************************************************/ -bool define_syntax_items(const asm_syntax *syntax, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) +bool define_asm_pattern(const asm_pattern *pattern, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ syntax_item *item; /* Lien vers un opérande */ conv_func *func; /* Fonction de conversion */ - bool internal; /* Usage interne ou non ? */ + bool optional; /* Opérande optionnelle ? */ result = true; - for (i = 0; i < syntax->items_count && result; i++) + for (i = 1; i < pattern->items_count; i++) { - item = &syntax->items[i]; + item = &pattern->items[i]; - switch (item->impact) - { - case SIT_KEYWORD: + func = find_named_conv_in_list(list, item->name); + assert(func != NULL); - /** - * TODO : à faire évoluer vers extend... - */ - //_exit(123); + optional = item->flags & SIF_OPTIONAL; - // rev_A88146 - /* - if (i > 0) - dprintf(fd, "\t\tg_arch_instruction_append_suffix(instr, \"%s\");\n", item->name); - else - continue; - */ + result = define_conv_func(func, fd, bits, list, tab, optional, exit); + if (!result) break; - break; + if (optional) + { + dprintf(fd, "\t%sif (", tab); - case SIT_INT_OPERAND: // A supprimer - case SIT_EXT_OPERAND: + write_conv_func(func, fd, false); - internal = (item->impact == SIT_INT_OPERAND); + dprintf(fd, " != NULL)"); - func = find_named_conv_in_list(list, item->name); - if (func == NULL) - { - fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); - result = false; - } + dprintf(fd, "\n"); - /* Appel proprement dit */ + if (item->flags & SIF_DECIMAL) + { + dprintf(fd, "\t%s{\n", tab); - if (is_conv_func_already_defined(func)) - { - dprintf(fd, "\t\top = val_%s;\n", item->name); + dprintf(fd, "\t%s\timm = G_IMM_OPERAND(", tab); - dprintf(fd, "\n"); + write_conv_func(func, fd, false); - if (item->flags & SIF_DECIMAL) - { - dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n"); - dprintf(fd, "\t\tg_imm_operand_set_default_display(&imm, IOD_DEC, NULL);\n"); - dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n"); - } + dprintf(fd, ");\n"); - dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n"); + dprintf(fd, "\t%s\tg_imm_operand_set_default_display(imm, IOD_DEC);\n", tab); - } + dprintf(fd, "\n"); - else - { - result &= define_conv_func(func, true, internal, fd, arch, bits, list, pp, exit); - if (!result) break; + dprintf(fd, "\t%s\tg_arch_instruction_attach_extra_operand(result, ", tab); - /* Raccordement : propriété ou opérande ? */ + write_conv_func(func, fd, false); - if (internal) - { - dprintf(fd, "\t\t\tgoto bad_exit;\n"); - *exit = true; - } + dprintf(fd, ");\n"); - else - { - dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n"); - *exit = true; + dprintf(fd, "\n"); - dprintf(fd, "\n"); + dprintf(fd, "\t%s}\n", tab); - if (item->flags & SIF_DECIMAL) - { - dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n"); - dprintf(fd, "\t\tg_imm_operand_set_default_display(&imm, IOD_DEC, NULL);\n"); - dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n"); - } + dprintf(fd, "\n"); - dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n"); + } - } + else + { + dprintf(fd, "\t%s\tg_arch_instruction_attach_extra_operand(result, ", tab); - } + write_conv_func(func, fd, false); - *exit = true; - break; + dprintf(fd, ");\n"); + + dprintf(fd, "\n"); + + } } - dprintf(fd, "\n"); + else + { + if (item->flags & SIF_DECIMAL) + { + dprintf(fd, "\t%simm = G_IMM_OPERAND(", tab); + + write_conv_func(func, fd, false); + + dprintf(fd, ");\n"); + + dprintf(fd, "\t%sg_imm_operand_set_default_display(imm, IOD_DEC);\n", tab); + + dprintf(fd, "\n"); + + } + + dprintf(fd, "\t%sg_arch_instruction_attach_extra_operand(result, ", tab); + + write_conv_func(func, fd, false); + + dprintf(fd, ");\n"); + + dprintf(fd, "\n"); + + } } diff --git a/tools/d2c/syntax/manager.h b/tools/d2c/pattern/manager.h index 9cdaa8b..592b169 100644 --- a/tools/d2c/syntax/manager.h +++ b/tools/d2c/pattern/manager.h @@ -28,45 +28,35 @@ #include <stdbool.h> -#include "../pproc.h" #include "../bits/manager.h" #include "../conv/manager.h" -/* Type d'éléments de syntaxe */ -typedef enum _SyntaxItemType -{ - SIT_KEYWORD, /* Elément de l'instruction */ - SIT_INT_OPERAND, /* Propriété d'architecture */ - SIT_EXT_OPERAND /* Opérande généraliste */ - -} SyntaxItemType; - /* Syntaxe d'une ligne d'assembleur */ -typedef struct _asm_syntax asm_syntax; +typedef struct _asm_pattern asm_pattern; /* Crée un nouvel indicateur pour l'écriture d'une instruction. */ -asm_syntax *create_asm_syntax(void); +asm_pattern *create_asm_pattern(void); /* Supprime de la mémoire un indicateur d'écriture ASM. */ -void delete_asm_syntax(asm_syntax *); +void delete_asm_pattern(asm_pattern *); /* Enregistre la présence d'un nouvel opérande dans la syntaxe. */ -void register_syntax_item(asm_syntax *, char *, SyntaxItemType); +void register_asm_pattern_item(asm_pattern *, char *); /* Marque les champs de bits effectivement utilisés. */ -bool mark_syntax_items(const asm_syntax *, const coding_bits *, const conv_list *); +bool mark_asm_pattern_items(const asm_pattern *, const coding_bits *, const conv_list *); /* Déclare les variables C associées aux opérandes de syntaxe. */ -bool declare_syntax_items(const asm_syntax *, int, const coding_bits *, const conv_list *, unsigned int); +bool declare_asm_pattern(const asm_pattern *, int, const coding_bits *, const conv_list *, const char *, bool *); /* Fournit si elle existe un nom nouveau pour une instruction. */ -const char *get_new_keyword_from_syntax_items(const asm_syntax *); +const char *get_keyword_from_asm_pattern(const asm_pattern *); /* Définit les variables C associées aux opérandes de syntaxe. */ -bool define_syntax_items(const asm_syntax *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); +bool define_asm_pattern(const asm_pattern *, int, const char *, const coding_bits *, const conv_list *, const char *, bool *); diff --git a/tools/d2c/pattern/tokens.l b/tools/d2c/pattern/tokens.l new file mode 100644 index 0000000..bef1e44 --- /dev/null +++ b/tools/d2c/pattern/tokens.l @@ -0,0 +1,34 @@ + +%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] { } + +[^ ]+ { yylvalp->string = strdup(yytext); return OPERAND; } + +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c pattern block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + + +%% diff --git a/tools/d2c/qckcall.c b/tools/d2c/qckcall.c index 828a379..f8f8641 100644 --- a/tools/d2c/qckcall.c +++ b/tools/d2c/qckcall.c @@ -96,13 +96,11 @@ char *build_cast_if_needed(const char *callee) /****************************************************************************** * * -* Paramètres : top = indique si l'écriture se fait au plus haut niveau. * -* callee = fonction appelée à nommer. * +* Paramètres : callee = fonction appelée à nommer. * * args = précise si la conversion est la dernière. * * fd = descripteur d'un flux ouvert en écriture. * * 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 : Réalise un appel à une fonction liée à une instruction. * * * @@ -112,7 +110,7 @@ char *build_cast_if_needed(const char *callee) * * ******************************************************************************/ -bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp) +bool call_instr_func(const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ char *cast; /* Macro de transtypage */ @@ -120,21 +118,12 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f cast = build_cast_if_needed(callee); if (cast == NULL) - { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\t%s(%s, ", callee, top ? "result" : "instr"); + dprintf(fd, "\t%s(result, ", callee); - } else { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\t%s(%s(%s), ", callee, cast, top ? "result" : "instr"); + dprintf(fd, "\t%s(%s(result), ", callee, cast); free(cast); - } result = define_arg_list(args, fd, bits, list); @@ -148,13 +137,11 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f /****************************************************************************** * * -* Paramètres : top = indique si l'écriture se fait au plus haut niveau. * -* callee = fonction appelée à nommer. * +* Paramètres : callee = fonction appelée à nommer. * * args = précise si la conversion est la dernière. * * fd = descripteur d'un flux ouvert en écriture. * * 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 : Réalise un appel à une fonction liée à une instruction. * * * @@ -164,7 +151,7 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f * * ******************************************************************************/ -bool checked_call_instr_func(bool top, const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp) +bool checked_call_instr_func(const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list) { bool result; /* Bilan à remonter */ char *cast; /* Macro de transtypage */ @@ -172,21 +159,12 @@ bool checked_call_instr_func(bool top, const char *callee, const arg_list_t *arg cast = build_cast_if_needed(callee); if (cast == NULL) - { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\tif (!%s(%s, ", callee, top ? "result" : "instr"); + dprintf(fd, "\tif (!%s(result, ", callee); - } else { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\tif (!%s(%s(%s), ", callee, cast, top ? "result" : "instr"); + dprintf(fd, "\tif (!%s(%s(result), ", callee, cast); free(cast); - } result = define_arg_list(args, fd, bits, list); diff --git a/tools/d2c/qckcall.h b/tools/d2c/qckcall.h index 28e607c..dea4792 100644 --- a/tools/d2c/qckcall.h +++ b/tools/d2c/qckcall.h @@ -28,7 +28,6 @@ #include <stdbool.h> -#include "pproc.h" #include "args/manager.h" #include "bits/manager.h" #include "conv/manager.h" @@ -39,10 +38,10 @@ char *build_cast_if_needed(const char *); /* Réalise un appel à une fonction liée à une instruction. */ -bool call_instr_func(bool, const char *, const arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *); +bool call_instr_func(const char *, const arg_list_t *, int, const coding_bits *, const conv_list *); /* Réalise un appel à une fonction liée à une instruction. */ -bool checked_call_instr_func(bool, const char *, const arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *); +bool checked_call_instr_func(const char *, const arg_list_t *, int, const coding_bits *, const conv_list *); diff --git a/tools/d2c/rules/Makefile.am b/tools/d2c/rules/Makefile.am index 81bf7b8..93d3040 100644 --- a/tools/d2c/rules/Makefile.am +++ b/tools/d2c/rules/Makefile.am @@ -26,6 +26,9 @@ libd2crules_la_SOURCES = \ tokens.l \ grammar.y +# _GNU_SOURCE : asprintf +libd2crules_la_CFLAGS = -D_GNU_SOURCE + # Automake fait les choses à moitié CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/rules/manager.c b/tools/d2c/rules/manager.c index 74be5fc..20f1a2b 100644 --- a/tools/d2c/rules/manager.c +++ b/tools/d2c/rules/manager.c @@ -290,9 +290,6 @@ static bool mark_cond_expr(const cond_expr *expr, const coding_bits *bits, const } - - printf("=== USE '%s' : %d\n", name, status); - if (!status) fprintf(stderr, "Error: nothing defined for the requested variable '%s'.\n", name); @@ -603,16 +600,14 @@ bool mark_decoding_rules(const decoding_rules *rules, const coding_bits *bits, c /****************************************************************************** * * -* Paramètres : rules = ensemble de règles à consulter. * -* top = indique si l'écriture se fait au plus haut niveau. * -* filter = filtre sur les règles à effectivement imprimer. * -* fd = descripteur d'un flux ouvert en écriture. * -* arch = architecture visée par l'opération. * -* subarch = sous-catégorie de cette même architecture. * -* bits = gestionnaire des bits d'encodage. * -* list = liste de l'ensemble des fonctions de conversion. * -* pp = pré-processeur pour les échanges de chaînes. * -* exit = exprime le besoin d'une voie de sortie. [OUT] * +* Paramètres : rules = ensemble de règles à consulter. * +* filter = filtre sur les règles à effectivement imprimer. * +* fd = descripteur d'un flux ouvert en écriture. * +* arch = architecture visée par l'opération. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* tab = décalage éventuel selon l'inclusion. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * * * * Description : Traduit en code les éventuelles règles présentes. * * * @@ -622,7 +617,7 @@ bool mark_decoding_rules(const decoding_rules *rules, const coding_bits *bits, c * * ******************************************************************************/ -bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter, int fd, const char *arch, const char *subarch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) +bool write_decoding_rules(decoding_rules *rules, CondActionType filter, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit) { bool result; /* Bilan à remonter */ size_t i; /* Boucle de parcours */ @@ -642,6 +637,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter switch (rule->action.type) { case CAT_CALL: + case CAT_CHECKED_CALL: multi_lines = false; break; @@ -653,10 +649,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter if (rule->expr != NULL) { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\tif "); + dprintf(fd, "\t%sif ", tab); result = write_cond_expr(rule->expr, fd, bits, list); if (!result) break; @@ -664,13 +657,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter dprintf(fd, "\n"); if (multi_lines) - { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\t{\n"); - - } + dprintf(fd, "\t%s{\n", tab); } @@ -695,37 +682,42 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter case CAT_CALL: + /* callable = find_macro(pp, rule->action.callee); if (callable == NULL) + */ callable = rule->action.callee; if (rule->expr != NULL) - dprintf(fd, "\t"); + dprintf(fd, "\t") +; + dprintf(fd, "%s", tab); - result = call_instr_func(top, callable, rule->action.args, fd, bits, list, pp); + result = call_instr_func(callable, rule->action.args, fd, bits, list); break; case CAT_CHECKED_CALL: + /* callable = find_macro(pp, rule->action.callee); if (callable == NULL) + */ callable = rule->action.callee; if (rule->expr != NULL) dprintf(fd, "\t"); - result = checked_call_instr_func(top, callable, rule->action.args, fd, bits, list, pp); + dprintf(fd, "%s", tab); - if (rule->expr != NULL) - dprintf(fd, "\t"); + result = checked_call_instr_func(callable, rule->action.args, fd, bits, list); - if (!top) + if (rule->expr != NULL) dprintf(fd, "\t"); - dprintf(fd, "\t\tgoto quick_exit;\n"); + dprintf(fd, "\t\t%sgoto bad_exit;\n", tab); *exit = true; break; @@ -733,13 +725,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter } if (rule->expr != NULL && multi_lines) - { - if (!top) - dprintf(fd, "\t"); - - dprintf(fd, "\t}\n"); - - } + dprintf(fd, "\t%s}\n", tab); dprintf(fd, "\n"); diff --git a/tools/d2c/rules/manager.h b/tools/d2c/rules/manager.h index 7f8ef11..88d1d46 100644 --- a/tools/d2c/rules/manager.h +++ b/tools/d2c/rules/manager.h @@ -25,7 +25,6 @@ #define _TOOLS_D2C_RULES_MANAGER_H -#include "../pproc.h" #include "../args/manager.h" #include "../bits/manager.h" #include "../conv/manager.h" @@ -119,7 +118,7 @@ void register_conditional_rule(decoding_rules *, cond_expr *, const rule_action bool mark_decoding_rules(const decoding_rules *, const coding_bits *, const conv_list *); /* Traduit en code les éventuelles règles présentes. */ -bool write_decoding_rules(decoding_rules *, bool, CondActionType, int, const char *, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); +bool write_decoding_rules(decoding_rules *, CondActionType, int, const char *, const coding_bits *, const conv_list *, const char *, bool *); diff --git a/tools/d2c/rules/tokens.l b/tools/d2c/rules/tokens.l index 36d6c4a..6b14a85 100644 --- a/tools/d2c/rules/tokens.l +++ b/tools/d2c/rules/tokens.l @@ -23,7 +23,7 @@ %% -\/\/[^\n]+ { printf("SKIP '%s'\n", yytext); } +\/\/[^\n]+ { } "if" { yy_push_state(cond); return IF; } <cond>[ ]+ { } @@ -41,17 +41,24 @@ <cond>";" { yy_pop_state(); return THEN; } -[ ] { } +[ \t\n] { } "see " { yy_push_state(raw_line); return SEE; } "unpredictable" { return UNPREDICTABLE; } "call" { yy_push_state(raw_line); return CALL; } -"chk_call" { yy_push_state(raw_line); return CHK_CALL; } +"check" { yy_push_state(raw_line); return CHK_CALL; } <raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; } <raw_line>"\n" { yy_pop_state(); } +. { + char *msg; + asprintf(&msg, "Unhandled token in d2c rules block: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + %% diff --git a/tools/d2c/syntax.c b/tools/d2c/syntax.c new file mode 100644 index 0000000..c0842a7 --- /dev/null +++ b/tools/d2c/syntax.c @@ -0,0 +1,313 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * syntax.c - représentation complète d'une syntaxe + * + * 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 "syntax.h" + + +#include <assert.h> +#include <malloc.h> + + + +/* Mémorisation d'une définition de syntaxe */ +struct _encoding_syntax +{ + disass_assert *assertions; /* Conditions de désassemblage */ + conv_list *conversions; /* Conversions des données */ + asm_pattern *pattern; /* Calligraphe d'assemblage */ + decoding_rules *rules; /* Règles supplémentaires */ + +}; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau suivi d'une définition de syntaxe. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +encoding_syntax *create_encoding_syntax(void) +{ + encoding_syntax *result; /* Définition vierge à renvoyer*/ + + result = (encoding_syntax *)calloc(1, sizeof(encoding_syntax)); + + result->assertions = create_disass_assert(); + result->conversions = create_conv_list(); + result->pattern = create_asm_pattern(); + result->rules = create_decoding_rules(); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = définition de syntaxe à libérer de la mémoire. * +* * +* Description : Supprime de la mémoire le suivi d'une définition de syntaxe. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_encoding_syntax(encoding_syntax *syntax) +{ + delete_disass_assert(syntax->assertions); + delete_conv_list(syntax->conversions); + delete_asm_pattern(syntax->pattern); + delete_decoding_rules(syntax->rules); + + free(syntax); + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = définition de syntaxe à consulter. * +* * +* Description : Fournit la liste de conditions préalables. * +* * +* Retour : Structure assurant la gestion de conditions de désassemblage.* +* * +* Remarques : - * +* * +******************************************************************************/ + +disass_assert *get_assertions_for_encoding_syntax(const encoding_syntax *syntax) +{ + return syntax->assertions; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = définition de syntaxe à consulter. * +* * +* Description : Fournit la liste des fonctions de conversion. * +* * +* Retour : Structure assurant la gestion des fonctions de conversion. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_list *get_conversions_in_encoding_syntax(const encoding_syntax *syntax) +{ + return syntax->conversions; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = définition de syntaxe à consulter. * +* * +* Description : Fournit l'indicateur des écritures correctes d'assembleur. * +* * +* Retour : Structure assurant la gestion des éléments de syntaxe. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_pattern *get_asm_pattern_in_encoding_syntax(const encoding_syntax *syntax) +{ + return syntax->pattern; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = définition de syntaxe à consulter. * +* * +* Description : Fournit un ensemble de règles supplémentaires éventuel. * +* * +* Retour : Structure assurant la gestion de ces règles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +decoding_rules *get_rules_in_encoding_syntax(const encoding_syntax *syntax) +{ + return syntax->rules; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* bits = gestionnaire des bits d'encodage. * +* * +* Description : Marque les éléments de syntaxe effectivement utilisés. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mark_syntax_items(const encoding_syntax *syntax, const coding_bits *bits) +{ + bool result; /* Bilan à retourner */ + + result = mark_disass_assert(syntax->assertions, bits); + + if (result) + result = mark_asm_pattern_items(syntax->pattern, bits, syntax->conversions); + + if (result) + result = mark_decoding_rules(syntax->rules, bits, syntax->conversions); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* * +* Description : Déclare les éléments d'une syntaxe isolée. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool declare_encoding_syntax(const encoding_syntax *syntax, int fd, const coding_bits *bits) +{ + bool result; /* Bilan à retourner */ + bool imm_decl; /* Suivi des déclaration */ + + imm_decl = false; + + result = declare_asm_pattern(syntax->pattern, fd, bits, syntax->conversions, "", &imm_decl); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* fd = descripteur d'un flux ouvert en écriture. * +* arch = architecture visée par l'opération globale. * +* bits = gestionnaire des bits d'encodage. * +* alone = peut-on se placer en zone principale ? * +* pp = pré-processeur pour les échanges de chaînes. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * +* * +* Description : Amorce la construction des éléments d'une syntaxe. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool write_encoding_syntax(const encoding_syntax *syntax, int fd, const char *arch, const coding_bits *bits, bool alone, bool *exit) +{ + bool result; /* Bilan à retourner */ + bool conditional; /* Définition sous condition ? */ + const char *tab; /* Décallage supplémentaire ? */ + bool imm_decl; /* Suivi des déclaration */ + + conditional = !is_disass_assert_empty(syntax->assertions); + + assert((conditional && !alone) || (!conditional && alone)); + + if (conditional) + { + dprintf(fd, "\tif ("); + + result = define_disass_assert(syntax->assertions, fd, bits); + if (!result) goto wes_exit; + + dprintf(fd, ")\n"); + dprintf(fd, "\t{\n"); + + tab = "\t"; + + } + + else + tab = (alone ? "" : "\t"); + + if (!alone) + { + imm_decl = false; + + result = declare_asm_pattern(syntax->pattern, fd, bits, syntax->conversions, "\t", &imm_decl); + if (!result) goto wes_exit; + + dprintf(fd, "\n"); + + } + + dprintf(fd, "\t%sresult = g_%s_instruction_new(\"%s\");\n", + tab, arch, get_keyword_from_asm_pattern(syntax->pattern)); + + dprintf(fd, "\n"); + + result = define_asm_pattern(syntax->pattern, fd, arch, bits, syntax->conversions, tab, exit); + if (!result) goto wes_exit; + + result = write_decoding_rules(syntax->rules, CAT_CHECKED_CALL, fd, arch, bits, syntax->conversions, tab, exit); + if (!result) goto wes_exit; + + result = write_decoding_rules(syntax->rules, CAT_CALL, fd, arch, bits, syntax->conversions, tab, exit); + if (!result) goto wes_exit; + + if (conditional) + { + dprintf(fd, "\t}\n"); + + dprintf(fd, "\n"); + + } + + wes_exit: + + return result; + +} diff --git a/tools/d2c/syntax.h b/tools/d2c/syntax.h new file mode 100644 index 0000000..5aa4716 --- /dev/null +++ b/tools/d2c/syntax.h @@ -0,0 +1,70 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * syntax.h - prototypes pour la représentation complète d'une syntaxe + * + * 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_SYNTAX_H +#define _TOOLS_D2C_SYNTAX_H + + + +#include "assert/manager.h" +#include "bits/manager.h" +#include "conv/manager.h" +#include "pattern/manager.h" +#include "rules/manager.h" + + + +/* Mémorisation d'une définition de syntaxe */ +typedef struct _encoding_syntax encoding_syntax; + + +/* Crée un nouveau suivi d'une définition de syntaxe. */ +encoding_syntax *create_encoding_syntax(void); + +/* Supprime de la mémoire le suivi d'une définition de syntaxe. */ +void delete_encoding_syntax(encoding_syntax *); + +/* Fournit la liste de conditions préalables. */ +disass_assert *get_assertions_for_encoding_syntax(const encoding_syntax *); + +/* Fournit la liste des fonctions de conversion. */ +conv_list *get_conversions_in_encoding_syntax(const encoding_syntax *); + +/* Fournit l'indicateur des écritures correctes d'assembleur. */ +asm_pattern *get_asm_pattern_in_encoding_syntax(const encoding_syntax *); + +/* Fournit un ensemble de règles supplémentaires éventuel. */ +decoding_rules *get_rules_in_encoding_syntax(const encoding_syntax *); + +/* Marque les éléments de syntaxe effectivement utilisés. */ +bool mark_syntax_items(const encoding_syntax *, const coding_bits *); + +/* Déclare les éléments d'une syntaxe isolée. */ +bool declare_encoding_syntax(const encoding_syntax *, int, const coding_bits *); + +/* Amorce la construction des éléments d'une syntaxe. */ +bool write_encoding_syntax(const encoding_syntax *, int, const char *, const coding_bits *, bool, bool *); + + + +#endif /* _TOOLS_D2C_SYNTAX_H */ diff --git a/tools/d2c/syntax/tokens.l b/tools/d2c/syntax/tokens.l deleted file mode 100644 index ab1b0f3..0000000 --- a/tools/d2c/syntax/tokens.l +++ /dev/null @@ -1,39 +0,0 @@ - -%top { - -#include "grammar.h" - -} - - -%option noyywrap -%option nounput -%option noinput -%option yylineno -%option stack -%option noyy_top_state - -%x named -%x internal -%x visible - - -%% - - -" " { } - -"\"" { yy_push_state(named); } -<named>[^ \"]+ { yylvalp->string = strdup(yytext); return OPERAND_NAME; } -<named>"\"" { yy_pop_state(); } - -"{" { yy_push_state(internal); } -<internal>[^ }]+ { yylvalp->string = strdup(yytext); return OPERAND_INTERNAL; } -<internal>"}" { yy_pop_state(); } - -"<" { yy_push_state (visible); } -<visible>[^ >]+ { yylvalp->string = strdup(yytext); return OPERAND_VISIBLE; } -<visible>">" { yy_pop_state(); } - - -%% diff --git a/tools/d2c/tokens.l b/tools/d2c/tokens.l index 220e5d6..60dd257 100644 --- a/tools/d2c/tokens.l +++ b/tools/d2c/tokens.l @@ -14,7 +14,6 @@ %option noyywrap -%option nounput %option yylineno %option stack %option noyy_top_state @@ -23,11 +22,12 @@ %x comments %x ins_name try_details ins_details -%x encoding encoding_type encoding_content +%x encoding encoding_type encoding_content syntax_content %x encoding_bits encoding_bits_size -%x raw_line +%x top_brace +%x raw_line raw_block %% @@ -52,45 +52,75 @@ <ins_details>[^\n]* { yylvalp->cstring = yytext; return INS_DETAILS; } <ins_details>[\n] { BEGIN(INITIAL); } +"@id" { yy_push_state(raw_line); return ID; } -"@desc" { yy_push_state(raw_line); return DESC; } +"@desc" { yy_push_state(raw_block); return DESC; } -"@encoding" { BEGIN(encoding); return ENCODING; } +"@encoding" { yy_push_state(encoding); return ENCODING; } <encoding>[ ] { } -<encoding>"(" { BEGIN(encoding_type); } +<encoding>"(" { yy_push_state(encoding_type); } <encoding_type>[A-Za-z] { yylvalp->string = strdup(yytext); return TYPE; } <encoding_type>[0-9]+ { yylvalp->integer = atoi(yytext); return NUMBER; } -<encoding_type>")" { BEGIN(encoding); } +<encoding_type>")" { yy_pop_state(); } + +<encoding>"{" { yy_push_state(encoding_content); } -<encoding>"{" { BEGIN(encoding_content); } <encoding_content>[ \t\n]+ { } -<encoding_content>"}" { BEGIN(INITIAL); } +<encoding_content>"}" { yy_pop_state(); yy_pop_state(); } <encoding_content>"@format" { yy_push_state(raw_line); return FORMAT; } +<encoding_content>"@unused" { yy_push_state(raw_line); return UNUSED; } <encoding_content>"@half" { yy_push_state(raw_line); return HALF; } <encoding_content>"@word" { yy_push_state(raw_line); return WORD; } -<encoding_content>"@syntax" { yy_push_state(raw_line); return SYNTAX; } +<encoding_content>"@syntax" { yy_push_state(syntax_content); yy_push_state(top_brace); return SYNTAX; } + +<encoding_content>"@hooks" { yy_push_state(raw_block); return HOOKS; } + + +<syntax_content>[ \t\n]+ { } + +<syntax_content>"@assert" { yy_push_state(raw_block); return ASSERT; } + +<syntax_content>"@conv" { yy_push_state(raw_block); return CONV; } + +<syntax_content>"@asm" { yy_push_state(raw_line); return ASM; } -<encoding_content>"@conv" { return CONV; } +<syntax_content>"@rules" { yy_push_state(raw_block); return RULES; } -<encoding_content>"@hooks" { return HOOKS; } +<syntax_content>"}" { yy_pop_state(); } -<encoding_content>"@rules" { return RULES; } +<top_brace>[ \t\n]+ { } +<top_brace>"{" { yy_pop_state(); } <raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; } <raw_line>"\n" { yy_pop_state(); } +<raw_block>[ \t\n]+ { } +<raw_block>"{" { + read_block(temp); + yylvalp->cstring = temp; return RAW_BLOCK; + } +<raw_block>"}" { yy_pop_state(); } + + <encoding_content>"{" { read_block(temp); yylvalp->cstring = temp; return RAW_BLOCK; } +<*>. { + char *msg; + asprintf(&msg, "Unhandled token in d2c definition: '%s'", yytext); + YY_FATAL_ERROR(msg); + free(msg); + } + %% |