/* 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 Chrysalide. If not, see . */ #include #include #include #include #include #include #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] \n", argv0); printf("\n"); printf("General options:\n"); printf("\n"); printf("\t-h | --help\t\t\tDisplay this messsage.\n"); printf("\t-x | --exec \t\tRun as compiler mode or complete the generation.\n"); printf("\t-o | --outdir \t\tSpecify the main output directory.\n"); printf("\t-t | --type \tSet the type of the input file.\n"); printf("\t-a | --arch \t\tDefine the archicture to handle (CamelCase allowed).\n"); printf("\t-n | --name \t\tSet the name of the archicture for source code (CamelCase allowed).\n"); printf("\t-G | --guard \t\tSet the base of the header macros guards.\n"); printf("\t-e | --encoding \tDefine one encoding prefix for files.\n"); printf("\n"); printf("\t--id-prefix \t\tDefine a common prefix for all uniq identifiers.\n"); printf("\t--id-expected \t\tProvide the expected number of instructions.\n"); printf("\n"); printf("Raw specific options:\n"); printf("\n"); printf("\t--filename-reuse \t\tSet the length of filename to include in identifiers (default = 0).\n"); printf("\n"); printf("Format specific options:\n"); printf("\n"); printf("\t--op-prefix \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 }, { "filename-reuse", required_argument, NULL, 0x200 }, { "op-prefix", required_argument, NULL, 0x300 }, { 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:G:e:", 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.filename_reuse = strtoul(optarg, NULL, 10); break; case 0x300: 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_RAW) { status = output_coder_sub_identifier(coder, &info); if (!status) goto clean_exit; } status = output_coder_keyword(coder, &info); if (!status) goto clean_exit; status = output_coder_hooks(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 (strcmp(base, "subidentifiers.h") == 0 && info.type == IOT_RAW) status = fini_coder_sub_identifiers_file(argv[optind], &info); else if (strcmp(base, "keywords.h") == 0) status = fini_coder_keywords_file(argv[optind], &info); else if (strcmp(base, "hooks.h") == 0) status = fini_coder_hooks_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; }